• 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/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
  ui->passPath->setText(QtPassSettings::getPassExecutable());
×
35
  setGitPath(QtPassSettings::getGitExecutable());
×
36
  ui->gpgPath->setText(QtPassSettings::getGpgExecutable());
×
37
  ui->storePath->setText(QtPassSettings::getPassStore());
×
38

39
  ui->spinBoxAutoclearSeconds->setValue(QtPassSettings::getAutoclearSeconds());
×
40
  ui->spinBoxAutoclearPanelSeconds->setValue(
×
41
      QtPassSettings::getAutoclearPanelSeconds());
×
42
  ui->checkBoxHidePassword->setChecked(QtPassSettings::isHidePassword());
×
43
  ui->checkBoxHideContent->setChecked(QtPassSettings::isHideContent());
×
44
  ui->checkBoxUseMonospace->setChecked(QtPassSettings::isUseMonospace());
×
45
  ui->checkBoxDisplayAsIs->setChecked(QtPassSettings::isDisplayAsIs());
×
46
  ui->checkBoxNoLineWrapping->setChecked(QtPassSettings::isNoLineWrapping());
×
47
  ui->checkBoxAddGPGId->setChecked(QtPassSettings::isAddGPGId(true));
×
48

49
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
50
    ui->checkBoxHideOnClose->setChecked(QtPassSettings::isHideOnClose());
×
51
    ui->checkBoxStartMinimized->setChecked(QtPassSettings::isStartMinimized());
×
52
  } else {
53
    ui->checkBoxUseTrayIcon->setEnabled(false);
×
54
    ui->checkBoxUseTrayIcon->setToolTip(tr("System tray is not available"));
×
55
    ui->checkBoxHideOnClose->setEnabled(false);
×
56
    ui->checkBoxStartMinimized->setEnabled(false);
×
57
  }
58

59
  ui->checkBoxAvoidCapitals->setChecked(QtPassSettings::isAvoidCapitals());
×
60
  ui->checkBoxAvoidNumbers->setChecked(QtPassSettings::isAvoidNumbers());
×
61
  ui->checkBoxLessRandom->setChecked(QtPassSettings::isLessRandom());
×
62
  ui->checkBoxUseSymbols->setChecked(QtPassSettings::isUseSymbols());
×
63
  ui->plainTextEditTemplate->setPlainText(QtPassSettings::getPassTemplate());
×
64
  ui->checkBoxTemplateAllFields->setChecked(
×
65
      QtPassSettings::isTemplateAllFields());
×
66
  ui->checkBoxAutoPull->setChecked(QtPassSettings::isAutoPull());
×
67
  ui->checkBoxAutoPush->setChecked(QtPassSettings::isAutoPush());
×
68
  ui->checkBoxAlwaysOnTop->setChecked(QtPassSettings::isAlwaysOnTop());
×
69

70
#if defined(Q_OS_WIN)
71
  ui->checkBoxUseOtp->hide();
72
  ui->checkBoxUseQrencode->hide();
73
  ui->label_10->hide();
74
#endif
75

76
  if (!isPassOtpAvailable()) {
×
77
    ui->checkBoxUseOtp->setEnabled(false);
×
78
    ui->checkBoxUseOtp->setToolTip(
×
79
        tr("Pass OTP extension needs to be installed"));
×
80
  }
81

82
  if (!isQrencodeAvailable()) {
×
83
    ui->checkBoxUseQrencode->setEnabled(false);
×
84
    ui->checkBoxUseQrencode->setToolTip(tr("qrencode needs to be installed"));
×
85
  }
86

87
  setProfiles(QtPassSettings::getProfiles(), QtPassSettings::getProfile());
×
88
  setPwgenPath(QtPassSettings::getPwgenExecutable());
×
89
  setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
×
90

91
  usePass(QtPassSettings::isUsePass());
×
92
  useAutoclear(QtPassSettings::isUseAutoclear());
×
93
  useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
×
94
  useTrayIcon(QtPassSettings::isUseTrayIcon());
×
95
  useGit(QtPassSettings::isUseGit());
×
96

97
  useOtp(QtPassSettings::isUseOtp());
×
98
  useQrencode(QtPassSettings::isUseQrencode());
×
99

100
  usePwgen(QtPassSettings::isUsePwgen());
×
101
  useTemplate(QtPassSettings::isUseTemplate());
×
102

103
  ui->profileTable->verticalHeader()->hide();
×
104
  ui->profileTable->horizontalHeader()->setSectionResizeMode(
×
105
      1, QHeaderView::Stretch);
106
  ui->label->setText(ui->label->text() + VERSION);
×
107
  ui->comboBoxClipboard->clear();
×
108

109
  ui->comboBoxClipboard->addItem(tr("No Clipboard"));
×
110
  ui->comboBoxClipboard->addItem(tr("Always copy to clipboard"));
×
111
  ui->comboBoxClipboard->addItem(tr("On-demand copy to clipboard"));
×
112

113
  int currentIndex = QtPassSettings::getClipBoardTypeRaw();
×
114
  ui->comboBoxClipboard->setCurrentIndex(currentIndex);
×
115
  on_comboBoxClipboard_activated(currentIndex);
×
116

117
  QClipboard *clip = QApplication::clipboard();
×
118
  if (!clip->supportsSelection()) {
×
119
    useSelection(false);
×
120
    ui->checkBoxSelection->setVisible(false);
×
121
  } else {
122
    useSelection(QtPassSettings::isUseSelection());
×
123
  }
124

125
  if (Util::checkConfig()) {
×
126
    // Show Programs tab, which is likely
127
    // what the user needs to fix now.
128
    ui->tabWidget->setCurrentIndex(1);
×
129
  }
130

131
  connect(ui->profileTable, &QTableWidget::itemChanged, this,
×
132
          &ConfigDialog::onProfileTableItemChanged);
×
133
  connect(this, &ConfigDialog::accepted, this, &ConfigDialog::on_accepted);
×
134
}
×
135

136
/**
137
 * @brief ConfigDialog::~ConfigDialog config destructor, makes sure the
138
 * mainWindow knows about git, gpg and pass executables.
139
 */
140
ConfigDialog::~ConfigDialog() {
×
141
  QtPassSettings::setGitExecutable(ui->gitPath->text());
×
142
  QtPassSettings::setGpgExecutable(ui->gpgPath->text());
×
143
  QtPassSettings::setPassExecutable(ui->passPath->text());
×
144
}
×
145

146
/**
147
 * @brief ConfigDialog::setGitPath set the git executable path.
148
 * Make sure the checkBoxUseGit is updated.
149
 * @param path
150
 */
151
void ConfigDialog::setGitPath(const QString &path) {
×
152
  ui->gitPath->setText(path);
×
153
  ui->checkBoxUseGit->setEnabled(!path.isEmpty());
×
154
  if (path.isEmpty()) {
×
155
    useGit(false);
×
156
  }
157
}
×
158

159
/**
160
 * @brief ConfigDialog::usePass set wether or not we want to use pass.
161
 * Update radio buttons accordingly.
162
 * @param usePass
163
 */
164
void ConfigDialog::usePass(bool usePass) {
×
165
  ui->radioButtonNative->setChecked(!usePass);
×
166
  ui->radioButtonPass->setChecked(usePass);
×
167
  setGroupBoxState();
×
168
}
×
169

170
void ConfigDialog::validate(QTableWidgetItem *item) {
×
171
  bool status = true;
172

173
  if (item == nullptr) {
×
174
    for (int i = 0; i < ui->profileTable->rowCount(); i++) {
×
175
      for (int j = 0; j < ui->profileTable->columnCount(); j++) {
×
176
        QTableWidgetItem *_item = ui->profileTable->item(i, j);
×
177

178
        if (_item->text().isEmpty() && j != 2) {
×
179
          _item->setBackground(Qt::red);
×
NEW
180
          _item->setToolTip(tr("This field is required"));
×
181
          status = false;
182
          break;
183
        } else {
NEW
184
          _item->setToolTip(QString());
×
185
        }
186
      }
187

188
      if (!status) {
189
        break;
190
      }
191
    }
192
  } else {
193
    if (item->text().isEmpty() && item->column() != 2) {
×
194
      item->setBackground(Qt::red);
×
NEW
195
      item->setToolTip(tr("This field is required"));
×
196
      status = false;
197
    } else {
NEW
198
      item->setToolTip(QString());
×
199
    }
200
  }
201

202
  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
×
203
}
×
204

205
void ConfigDialog::on_accepted() {
×
206
  QtPassSettings::setPassExecutable(ui->passPath->text());
×
207
  QtPassSettings::setGitExecutable(ui->gitPath->text());
×
208
  QtPassSettings::setGpgExecutable(ui->gpgPath->text());
×
209
  QtPassSettings::setPassStore(
×
210
      Util::normalizeFolderPath(ui->storePath->text()));
×
211
  QtPassSettings::setUsePass(ui->radioButtonPass->isChecked());
×
212
  QtPassSettings::setClipBoardType(ui->comboBoxClipboard->currentIndex());
×
213
  QtPassSettings::setUseSelection(ui->checkBoxSelection->isChecked());
×
214
  QtPassSettings::setUseAutoclear(ui->checkBoxAutoclear->isChecked());
×
215
  QtPassSettings::setAutoclearSeconds(ui->spinBoxAutoclearSeconds->value());
×
216
  QtPassSettings::setUseAutoclearPanel(ui->checkBoxAutoclearPanel->isChecked());
×
217
  QtPassSettings::setAutoclearPanelSeconds(
×
218
      ui->spinBoxAutoclearPanelSeconds->value());
×
219
  QtPassSettings::setHidePassword(ui->checkBoxHidePassword->isChecked());
×
220
  QtPassSettings::setHideContent(ui->checkBoxHideContent->isChecked());
×
221
  QtPassSettings::setUseMonospace(ui->checkBoxUseMonospace->isChecked());
×
222
  QtPassSettings::setDisplayAsIs(ui->checkBoxDisplayAsIs->isChecked());
×
223
  QtPassSettings::setNoLineWrapping(ui->checkBoxNoLineWrapping->isChecked());
×
224
  QtPassSettings::setAddGPGId(ui->checkBoxAddGPGId->isChecked());
×
225
  QtPassSettings::setUseTrayIcon(ui->checkBoxUseTrayIcon->isEnabled() &&
×
226
                                 ui->checkBoxUseTrayIcon->isChecked());
×
227
  QtPassSettings::setHideOnClose(ui->checkBoxHideOnClose->isEnabled() &&
×
228
                                 ui->checkBoxHideOnClose->isChecked());
×
229
  QtPassSettings::setStartMinimized(ui->checkBoxStartMinimized->isEnabled() &&
×
230
                                    ui->checkBoxStartMinimized->isChecked());
×
231
  QtPassSettings::setProfiles(getProfiles());
×
232
  QtPassSettings::setUseGit(ui->checkBoxUseGit->isChecked());
×
233
  QtPassSettings::setUseOtp(ui->checkBoxUseOtp->isChecked());
×
234
  QtPassSettings::setUseQrencode(ui->checkBoxUseQrencode->isChecked());
×
235
  QtPassSettings::setPwgenExecutable(ui->pwgenPath->text());
×
236
  QtPassSettings::setUsePwgen(ui->checkBoxUsePwgen->isChecked());
×
237
  QtPassSettings::setAvoidCapitals(ui->checkBoxAvoidCapitals->isChecked());
×
238
  QtPassSettings::setAvoidNumbers(ui->checkBoxAvoidNumbers->isChecked());
×
239
  QtPassSettings::setLessRandom(ui->checkBoxLessRandom->isChecked());
×
240
  QtPassSettings::setUseSymbols(ui->checkBoxUseSymbols->isChecked());
×
241
  QtPassSettings::setPasswordConfiguration(getPasswordConfiguration());
×
242
  QtPassSettings::setUseTemplate(ui->checkBoxUseTemplate->isChecked());
×
243
  QtPassSettings::setPassTemplate(ui->plainTextEditTemplate->toPlainText());
×
244
  QtPassSettings::setTemplateAllFields(
×
245
      ui->checkBoxTemplateAllFields->isChecked());
×
246
  QtPassSettings::setAutoPush(ui->checkBoxAutoPush->isChecked());
×
247
  QtPassSettings::setAutoPull(ui->checkBoxAutoPull->isChecked());
×
248
  QtPassSettings::setAlwaysOnTop(ui->checkBoxAlwaysOnTop->isChecked());
×
249

250
  QtPassSettings::setVersion(VERSION);
×
251
}
×
252

253
void ConfigDialog::on_autodetectButton_clicked() {
×
254
  QString pass = Util::findBinaryInPath("pass");
×
255
  if (!pass.isEmpty()) {
×
256
    ui->passPath->setText(pass);
×
257
  }
258
  usePass(!pass.isEmpty());
×
259
  QString gpg = Util::findBinaryInPath("gpg2");
×
260
  if (gpg.isEmpty()) {
×
261
    gpg = Util::findBinaryInPath("gpg");
×
262
  }
263
  if (!gpg.isEmpty()) {
×
264
    ui->gpgPath->setText(gpg);
×
265
  }
266
  QString git = Util::findBinaryInPath("git");
×
267
  if (!git.isEmpty()) {
×
268
    ui->gitPath->setText(git);
×
269
  }
270
  QString pwgen = Util::findBinaryInPath("pwgen");
×
271
  if (!pwgen.isEmpty()) {
×
272
    ui->pwgenPath->setText(pwgen);
×
273
  }
274
}
×
275

276
/**
277
 * @brief ConfigDialog::on_radioButtonNative_clicked wrapper for
278
 * ConfigDialog::setGroupBoxState()
279
 */
280
void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
×
281

282
/**
283
 * @brief ConfigDialog::on_radioButtonPass_clicked wrapper for
284
 * ConfigDialog::setGroupBoxState()
285
 */
286
void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
×
287

288
/**
289
 * @brief ConfigDialog::getSecretKeys get list of secret/private keys
290
 * @return QStringList keys
291
 */
292
auto ConfigDialog::getSecretKeys() -> QStringList {
×
293
  QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
×
294
  QStringList names;
×
295

296
  if (keys.empty()) {
×
297
    return names;
298
  }
299

300
  foreach (const UserInfo &sec, keys)
×
301
    names << sec.name;
×
302

303
  return names;
×
304
}
305

306
/**
307
 * @brief ConfigDialog::setGroupBoxState update checkboxes.
308
 */
309
void ConfigDialog::setGroupBoxState() {
×
310
  bool state = ui->radioButtonPass->isChecked();
×
311
  ui->groupBoxNative->setEnabled(!state);
×
312
  ui->groupBoxPass->setEnabled(state);
×
313
}
×
314

315
/**
316
 * @brief ConfigDialog::selectExecutable pop-up to choose an executable.
317
 * @return
318
 */
319
auto ConfigDialog::selectExecutable() -> QString {
×
320
  QFileDialog dialog(this);
×
321
  dialog.setFileMode(QFileDialog::ExistingFile);
×
322
  dialog.setOption(QFileDialog::ReadOnly);
×
323
  if (dialog.exec()) {
×
324
    return dialog.selectedFiles().constFirst();
×
325
  }
326

327
  return {};
328
}
×
329

330
/**
331
 * @brief ConfigDialog::selectFolder pop-up to choose a folder.
332
 * @return
333
 */
334
auto ConfigDialog::selectFolder() -> QString {
×
335
  QFileDialog dialog(this);
×
336
  dialog.setFileMode(QFileDialog::Directory);
×
337
  dialog.setFilter(QDir::NoFilter);
×
338
  dialog.setOption(QFileDialog::ShowDirsOnly);
×
339
  if (dialog.exec()) {
×
340
    return dialog.selectedFiles().constFirst();
×
341
  }
342

343
  return {};
344
}
×
345

346
/**
347
 * @brief ConfigDialog::on_toolButtonGit_clicked get git application.
348
 * Enable checkboxes if found.
349
 */
350
void ConfigDialog::on_toolButtonGit_clicked() {
×
351
  QString git = selectExecutable();
×
352
  bool state = !git.isEmpty();
×
353
  if (state) {
×
354
    ui->gitPath->setText(git);
×
355
  } else {
356
    useGit(false);
×
357
  }
358

359
  ui->checkBoxUseGit->setEnabled(state);
×
360
}
×
361

362
/**
363
 * @brief ConfigDialog::on_toolButtonGpg_clicked get gpg application.
364
 */
365
void ConfigDialog::on_toolButtonGpg_clicked() {
×
366
  QString gpg = selectExecutable();
×
367
  if (!gpg.isEmpty()) {
×
368
    ui->gpgPath->setText(gpg);
×
369
  }
370
}
×
371

372
/**
373
 * @brief ConfigDialog::on_pushButtonGenerateKey_clicked open keygen dialog.
374
 */
375
void ConfigDialog::on_pushButtonGenerateKey_clicked() {
×
376
  KeygenDialog d(this);
×
377
  d.exec();
×
378
}
×
379

380
/**
381
 * @brief ConfigDialog::on_toolButtonPass_clicked get pass application.
382
 */
383
void ConfigDialog::on_toolButtonPass_clicked() {
×
384
  QString pass = selectExecutable();
×
385
  if (!pass.isEmpty()) {
×
386
    ui->passPath->setText(pass);
×
387
  }
388
}
×
389

390
/**
391
 * @brief ConfigDialog::on_toolButtonStore_clicked get .password-store
392
 * location.s
393
 */
394
void ConfigDialog::on_toolButtonStore_clicked() {
×
395
  QString store = selectFolder();
×
396
  if (!store.isEmpty()) { // TODO(annejan): call check
×
397
    ui->storePath->setText(store);
×
398
  }
399
}
×
400

401
/**
402
 * @brief ConfigDialog::on_comboBoxClipboard_activated show and hide options.
403
 * @param index of selectbox (0 = no clipboard).
404
 */
405
void ConfigDialog::on_comboBoxClipboard_activated(int index) {
×
406
  bool state = index > 0;
×
407

408
  ui->checkBoxSelection->setEnabled(state);
×
409
  ui->checkBoxAutoclear->setEnabled(state);
×
410
  ui->checkBoxHidePassword->setEnabled(state);
×
411
  ui->checkBoxHideContent->setEnabled(state);
×
412
  if (state) {
×
413
    ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
414
    ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
415
  } else {
416
    ui->spinBoxAutoclearSeconds->setEnabled(false);
×
417
    ui->labelSeconds->setEnabled(false);
×
418
  }
419
}
×
420

421
/**
422
 * @brief ConfigDialog::on_checkBoxAutoclearPanel_clicked enable and disable
423
 * options based on autoclear use.
424
 */
425
void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
×
426
  bool state = ui->checkBoxAutoclearPanel->isChecked();
×
427
  ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
×
428
  ui->labelPanelSeconds->setEnabled(state);
×
429
}
×
430

431
/**
432
 * @brief ConfigDialog::useSelection set the clipboard type use from
433
 * MainWindow.
434
 * @param useSelection
435
 */
436
void ConfigDialog::useSelection(bool useSelection) {
×
437
  ui->checkBoxSelection->setChecked(useSelection);
×
438
  on_checkBoxSelection_clicked();
×
439
}
×
440

441
/**
442
 * @brief ConfigDialog::useAutoclear set the clipboard autoclear use from
443
 * MainWindow.
444
 * @param useAutoclear
445
 */
446
void ConfigDialog::useAutoclear(bool useAutoclear) {
×
447
  ui->checkBoxAutoclear->setChecked(useAutoclear);
×
448
  on_checkBoxAutoclear_clicked();
×
449
}
×
450

451
/**
452
 * @brief ConfigDialog::useAutoclearPanel set the panel autoclear use from
453
 * MainWindow.
454
 * @param useAutoclearPanel
455
 */
456
void ConfigDialog::useAutoclearPanel(bool useAutoclearPanel) {
×
457
  ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
×
458
  on_checkBoxAutoclearPanel_clicked();
×
459
}
×
460

461
/**
462
 * @brief ConfigDialog::on_checkBoxSelection_clicked checkbox clicked, update
463
 * state via ConfigDialog::on_comboBoxClipboard_activated
464
 */
465
void ConfigDialog::on_checkBoxSelection_clicked() {
×
466
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
467
}
×
468

469
/**
470
 * @brief ConfigDialog::on_checkBoxAutoclear_clicked checkbox clicked, update
471
 * state via ConfigDialog::on_comboBoxClipboard_activated
472
 */
473
void ConfigDialog::on_checkBoxAutoclear_clicked() {
×
474
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
475
}
×
476

477
/**
478
 * @brief ConfigDialog::genKey tunnel function to make MainWindow generate a
479
 * gpg key pair.
480
 * @todo refactor the process to not be entangled so much.
481
 * @param batch
482
 * @param dialog
483
 */
484
void ConfigDialog::genKey(const QString &batch, QDialog *dialog) {
×
485
  mainWindow->generateKeyPair(batch, dialog);
×
486
}
×
487

488
/**
489
 * @brief ConfigDialog::setProfiles set the profiles and chosen profile from
490
 * MainWindow.
491
 * @param profiles
492
 * @param profile
493
 */
494
void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
×
495
                               const QString &currentProfile) {
496
  // dbg()<< profiles;
497
  if (profiles.contains("")) {
×
498
    profiles.remove("");
×
499
    // remove weird "" key value pairs
500
  }
501

502
  ui->profileTable->setRowCount(profiles.count());
×
503
  QHashIterator<QString, QHash<QString, QString>> i(profiles);
×
504
  int n = 0;
505
  while (i.hasNext()) {
×
506
    i.next();
507
    if (!i.value().isEmpty() && !i.key().isEmpty()) {
×
508
      ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
×
509
      ui->profileTable->setItem(n, 1,
×
510
                                new QTableWidgetItem(i.value().value("path")));
×
511
      ui->profileTable->setItem(
×
512
          n, 2, new QTableWidgetItem(i.value().value("signingKey")));
×
513
      // dbg()<< "naam:" + i.key();
514
      if (i.key() == currentProfile) {
×
515
        ui->profileTable->selectRow(n);
×
516
      }
517
    }
518
    ++n;
×
519
  }
520
}
×
521

522
/**
523
 * @brief ConfigDialog::getProfiles return profile list.
524
 * @return
525
 */
526
auto ConfigDialog::getProfiles() -> QHash<QString, QHash<QString, QString>> {
×
527
  QHash<QString, QHash<QString, QString>> profiles;
×
528
  // Check?
529
  for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
×
530
    QHash<QString, QString> profile;
×
531
    QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
×
532
    if (nullptr != pathItem) {
×
533
      QTableWidgetItem *item = ui->profileTable->item(i, 0);
×
534
      if (item == nullptr) {
×
535
        continue;
536
      }
537
      profile["path"] = pathItem->text();
×
538
      QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
×
539
      if (nullptr != signingKeyItem) {
×
540
        profile["signingKey"] = signingKeyItem->text();
×
541
      }
542
      profiles.insert(item->text(), profile);
×
543
    }
544
  }
×
545
  return profiles;
×
546
}
×
547

548
/**
549
 * @brief ConfigDialog::on_addButton_clicked add a profile row.
550
 */
551
void ConfigDialog::on_addButton_clicked() {
×
552
  int n = ui->profileTable->rowCount();
×
553
  ui->profileTable->insertRow(n);
×
554
  ui->profileTable->setItem(n, 0, new QTableWidgetItem());
×
555
  ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
×
556
  ui->profileTable->setItem(n, 2, new QTableWidgetItem());
×
557
  ui->profileTable->selectRow(n);
×
558
  ui->deleteButton->setEnabled(true);
×
559

560
  validate();
×
561
}
×
562

563
/**
564
 * @brief ConfigDialog::on_deleteButton_clicked remove a profile row.
565
 */
566
void ConfigDialog::on_deleteButton_clicked() {
×
567
  QSet<int> selectedRows; //  we use a set to prevent doubles
568
  QList<QTableWidgetItem *> itemList = ui->profileTable->selectedItems();
×
569
  if (itemList.count() == 0) {
×
570
    QMessageBox::warning(this, tr("No profile selected"),
×
571
                         tr("No profile selected to delete"));
×
572
    return;
573
  }
574
  QTableWidgetItem *item;
575
  foreach (item, itemList)
×
576
    selectedRows.insert(item->row());
×
577
  // get a list, and sort it big to small
578
  QList<int> rows = selectedRows.values();
×
579
  std::sort(rows.begin(), rows.end());
×
580
  // now actually do the removing:
581
  foreach (int row, rows)
×
582
    ui->profileTable->removeRow(row);
×
583
  if (ui->profileTable->rowCount() < 1) {
×
584
    ui->deleteButton->setEnabled(false);
×
585
  }
586

587
  validate();
×
588
}
589

590
/**
591
 * @brief ConfigDialog::criticalMessage weapper for showing critical messages
592
 * in a popup.
593
 * @param title
594
 * @param text
595
 */
596
void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
×
597
  QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
×
598
}
×
599

600
auto ConfigDialog::isQrencodeAvailable() -> bool {
×
601
#ifdef Q_OS_WIN
602
  return false;
603
#else
604
  QProcess which;
×
605
  which.start("which", QStringList() << "qrencode");
×
606
  which.waitForFinished();
×
607
  QtPassSettings::setQrencodeExecutable(
×
608
      which.readAllStandardOutput().trimmed());
×
609
  return which.exitCode() == 0;
×
610
#endif
611
}
×
612

613
auto ConfigDialog::isPassOtpAvailable() -> bool {
×
614
#ifdef Q_OS_WIN
615
  return false;
616
#else
617
  QProcess pass;
×
618
  pass.start(QtPassSettings::getPassExecutable(), QStringList() << "otp"
×
619
                                                                << "--help");
×
620
  pass.waitForFinished(2000);
×
621
  return pass.exitCode() == 0;
×
622
#endif
623
}
×
624

625
/**
626
 * @brief ConfigDialog::wizard first-time use wizard.
627
 * @todo make this thing more reliable.
628
 */
629
void ConfigDialog::wizard() {
×
630
  Util::checkConfig();
×
631
  on_autodetectButton_clicked();
×
632

633
  if (!checkGpgExistence()) {
×
634
    return;
635
  }
636
  if (!checkSecretKeys()) {
×
637
    return;
638
  }
639
  if (!checkPasswordStore()) {
×
640
    return;
641
  }
642
  handleGpgIdFile();
×
643

644
  ui->checkBoxHidePassword->setCheckState(Qt::Checked);
×
645
}
646

647
auto ConfigDialog::checkGpgExistence() -> bool {
×
648
  QString gpg = ui->gpgPath->text();
×
649
  if (!gpg.startsWith("wsl ") && !QFile(gpg).exists()) {
×
650
    criticalMessage(
×
651
        tr("GnuPG not found"),
×
652
#ifdef Q_OS_WIN
653
#ifdef WINSTORE
654
        tr("Please install GnuPG on your system.<br>Install "
655
           "<strong>Ubuntu</strong> from the Microsoft Store to get it.<br>"
656
           "If you already did so, make sure you started it once and<br>"
657
           "click \"Autodetect\" in the next dialog.")
658
#else
659
        tr("Please install GnuPG on your system.<br>Install "
660
           "<strong>Ubuntu</strong> from the Microsoft Store<br>or <a "
661
           "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
662
           "from GnuPG.org")
663
#endif
664
#else
665
        tr("Please install GnuPG on your system.<br>Install "
×
666
           "<strong>gpg</strong> using your favorite package manager<br>or "
667
           "<a "
668
           "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
669
           "from GnuPG.org")
670
#endif
671
    );
672
    return false;
×
673
  }
674
  return true;
675
}
676

677
auto ConfigDialog::checkSecretKeys() -> bool {
×
678
  QString gpg = ui->gpgPath->text();
×
679
  QStringList names = getSecretKeys();
×
680

681
#ifdef QT_DEBUG
682
  dbg() << names;
683
#endif
684

685
  if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
×
686
    KeygenDialog d(this);
×
687
    return d.exec();
×
688
  }
×
689
  return true;
690
}
691

692
auto ConfigDialog::checkPasswordStore() -> bool {
×
693
  QString passStore = ui->storePath->text();
×
694

695
  if (!QFile(passStore).exists()) {
×
696
    if (QMessageBox::question(
×
697
            this, tr("Create password-store?"),
×
698
            tr("Would you like to create a password-store at %1?")
×
699
                .arg(passStore),
×
700
            QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
701
      if (!QDir().mkdir(passStore)) {
×
702
        QMessageBox::warning(
×
703
            this, tr("Error"),
×
704
            tr("Failed to create password-store at: %1").arg(passStore));
×
705
        return false;
×
706
      }
707
#ifdef Q_OS_WIN
708
      SetFileAttributes(passStore.toStdWString().c_str(),
709
                        FILE_ATTRIBUTE_HIDDEN);
710
#endif
711
      if (ui->checkBoxUseGit->isChecked()) {
×
712
        emit mainWindow->passGitInitNeeded();
×
713
      }
714
      mainWindow->userDialog(passStore);
×
715
    }
716
  }
717
  return true;
718
}
719

720
void ConfigDialog::handleGpgIdFile() {
×
721
  QString passStore = ui->storePath->text();
×
722
  if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
×
723
#ifdef QT_DEBUG
724
    dbg() << ".gpg-id file does not exist";
725
#endif
726
    criticalMessage(tr("Password store not initialised"),
×
727
                    tr("The folder %1 doesn't seem to be a password store or "
×
728
                       "is not yet initialised.")
729
                        .arg(passStore));
×
730

731
    while (!QFile(passStore).exists()) {
×
732
      on_toolButtonStore_clicked();
×
733
      if (passStore == ui->storePath->text()) {
×
734
        return;
735
      }
736
      passStore = ui->storePath->text();
×
737
    }
738
    if (!QFile(passStore + ".gpg-id").exists()) {
×
739
#ifdef QT_DEBUG
740
      dbg() << ".gpg-id file still does not exist :/";
741
#endif
742
      mainWindow->userDialog(passStore);
×
743
    }
744
  }
745
}
746

747
/**
748
 * @brief ConfigDialog::useTrayIcon set preference for using trayicon.
749
 * Enable or disable related checkboxes accordingly.
750
 * @param useSystray
751
 */
752
void ConfigDialog::useTrayIcon(bool useSystray) {
×
753
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
754
    ui->checkBoxUseTrayIcon->setChecked(useSystray);
×
755
    ui->checkBoxHideOnClose->setEnabled(useSystray);
×
756
    ui->checkBoxStartMinimized->setEnabled(useSystray);
×
757

758
    if (!useSystray) {
×
759
      ui->checkBoxHideOnClose->setChecked(false);
×
760
      ui->checkBoxStartMinimized->setChecked(false);
×
761
    }
762
  }
763
}
×
764

765
/**
766
 * @brief ConfigDialog::on_checkBoxUseTrayIcon_clicked enable and disable
767
 * related checkboxes.
768
 */
769
void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
×
770
  bool state = ui->checkBoxUseTrayIcon->isChecked();
×
771
  ui->checkBoxHideOnClose->setEnabled(state);
×
772
  ui->checkBoxStartMinimized->setEnabled(state);
×
773
}
×
774

775
/**
776
 * @brief ConfigDialog::closeEvent close this window.
777
 * @param event
778
 */
779
void ConfigDialog::closeEvent(QCloseEvent *event) {
×
780
  // TODO(annejan): save window size or something?
781
  event->accept();
782
}
×
783

784
/**
785
 * @brief ConfigDialog::useGit set preference for using git.
786
 * @param useGit
787
 */
788
void ConfigDialog::useGit(bool useGit) {
×
789
  ui->checkBoxUseGit->setChecked(useGit);
×
790
  on_checkBoxUseGit_clicked();
×
791
}
×
792

793
/**
794
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
795
 * @param useOtp
796
 */
797
void ConfigDialog::useOtp(bool useOtp) {
×
798
  ui->checkBoxUseOtp->setChecked(useOtp);
×
799
}
×
800

801
/**
802
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
803
 * @param useOtp
804
 */
805
void ConfigDialog::useQrencode(bool useQrencode) {
×
806
  ui->checkBoxUseQrencode->setChecked(useQrencode);
×
807
}
×
808

809
/**
810
 * @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
811
 * checkboxes.
812
 */
813
void ConfigDialog::on_checkBoxUseGit_clicked() {
×
814
  ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
×
815
  ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
×
816
  ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
×
817
}
×
818

819
/**
820
 * @brief ConfigDialog::on_toolButtonPwgen_clicked enable or disable related
821
 * options in the interface.
822
 */
823
void ConfigDialog::on_toolButtonPwgen_clicked() {
×
824
  QString pwgen = selectExecutable();
×
825
  if (!pwgen.isEmpty()) {
×
826
    ui->pwgenPath->setText(pwgen);
×
827
    ui->checkBoxUsePwgen->setEnabled(true);
×
828
  } else {
829
    ui->checkBoxUsePwgen->setEnabled(false);
×
830
    ui->checkBoxUsePwgen->setChecked(false);
×
831
  }
832
}
×
833

834
/**
835
 * @brief ConfigDialog::setPwgenPath set pwgen executable path.
836
 * Enable or disable related options in the interface.
837
 * @param pwgen
838
 */
839
void ConfigDialog::setPwgenPath(const QString &pwgen) {
×
840
  ui->pwgenPath->setText(pwgen);
×
841
  if (pwgen.isEmpty()) {
×
842
    ui->checkBoxUsePwgen->setChecked(false);
×
843
    ui->checkBoxUsePwgen->setEnabled(false);
×
844
  }
845
  on_checkBoxUsePwgen_clicked();
×
846
}
×
847

848
/**
849
 * @brief ConfigDialog::on_checkBoxUsPwgen_clicked enable or disable related
850
 * options in the interface.
851
 */
852
void ConfigDialog::on_checkBoxUsePwgen_clicked() {
×
853
  bool usePwgen = ui->checkBoxUsePwgen->isChecked();
×
854
  ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
×
855
  ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
×
856
  ui->checkBoxLessRandom->setEnabled(usePwgen);
×
857
  ui->checkBoxUseSymbols->setEnabled(usePwgen);
×
858
  ui->lineEditPasswordChars->setEnabled(!usePwgen);
×
859
  ui->labelPasswordChars->setEnabled(!usePwgen);
×
860
  ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
×
861
}
×
862

863
/**
864
 * @brief ConfigDialog::usePwgen set preference for using pwgen (can be
865
 * overruled buy empty pwgenPath).
866
 * enable or disable related options in the interface via
867
 * ConfigDialog::on_checkBoxUsePwgen_clicked
868
 * @param usePwgen
869
 */
870
void ConfigDialog::usePwgen(bool usePwgen) {
×
871
  if (ui->pwgenPath->text().isEmpty()) {
×
872
    usePwgen = false;
873
  }
874
  ui->checkBoxUsePwgen->setChecked(usePwgen);
×
875
  on_checkBoxUsePwgen_clicked();
×
876
}
×
877

878
void ConfigDialog::setPasswordConfiguration(
×
879
    const PasswordConfiguration &config) {
880
  ui->spinBoxPasswordLength->setValue(config.length);
×
881
  ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
×
882
  if (config.selected != PasswordConfiguration::CUSTOM) {
×
883
    ui->lineEditPasswordChars->setEnabled(false);
×
884
  }
885
  ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
×
886
}
×
887

888
auto ConfigDialog::getPasswordConfiguration() -> PasswordConfiguration {
×
889
  PasswordConfiguration config;
×
890
  config.length = ui->spinBoxPasswordLength->value();
×
891
  config.selected = static_cast<PasswordConfiguration::characterSet>(
×
892
      ui->passwordCharTemplateSelector->currentIndex());
×
893
  config.Characters[PasswordConfiguration::CUSTOM] =
894
      ui->lineEditPasswordChars->text();
×
895
  return config;
×
896
}
×
897

898
/**
899
 * @brief ConfigDialog::on_passwordCharTemplateSelector_activated sets the
900
 * passwordChar Template
901
 * combo box to the desired entry
902
 * @param entry of
903
 */
904
void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
×
905
  ui->lineEditPasswordChars->setText(
×
906
      QtPassSettings::getPasswordConfiguration().Characters[index]);
×
907
  if (index == 3) {
×
908
    ui->lineEditPasswordChars->setEnabled(true);
×
909
  } else {
910
    ui->lineEditPasswordChars->setEnabled(false);
×
911
  }
912
}
×
913

914
/**
915
 * @brief ConfigDialog::on_checkBoxUseTemplate_clicked enable or disable the
916
 * template field and options.
917
 */
918
void ConfigDialog::on_checkBoxUseTemplate_clicked() {
×
919
  ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
×
920
  ui->checkBoxTemplateAllFields->setEnabled(
×
921
      ui->checkBoxUseTemplate->isChecked());
×
922
}
×
923

924
void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
×
925
  validate(item);
×
926
}
×
927

928
/**
929
 * @brief ConfigDialog::useTemplate set preference for using templates.
930
 * @param useTemplate
931
 */
932
void ConfigDialog::useTemplate(bool useTemplate) {
×
933
  ui->checkBoxUseTemplate->setChecked(useTemplate);
×
934
  on_checkBoxUseTemplate_clicked();
×
935
}
×
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