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

IJHack / QtPass / 23825672923

01 Apr 2026 12:21AM UTC coverage: 20.071% (+0.3%) from 19.722%
23825672923

push

github

web-flow
fix: resolve remaining TODOs and save window state (#877)

* fix: resolve remaining TODOs and save window state

- Remove TODO from on_toolButtonStore_clicked (comment was outdated)
- Implement window size/position saving in ConfigDialog::closeEvent
- Implement window size/position saving in KeygenDialog::closeEvent
- Implement window size/position saving in UsersDialog::closeEvent
- Convert TODO comment in qtpass.cpp to a note (existing code is correct)

- Add dialog-specific settings to avoid clobbering mainwindow state:
  * Add QtPassSettings::getDialogGeometry/setDialogGeometry
  * Add QtPassSettings::getDialogPos/setDialogPos
  * Add QtPassSettings::getDialogSize/setDialogSize
  * Add QtPassSettings::isDialogMaximized/setDialogMaximized

- Update ConfigDialog, KeygenDialog, UsersDialog to use dialog-specific
  settings with unique keys (e.g., 'configDialog', 'keygenDialog', 'usersDialog')
- Add SettingsConstants for dialog-specific settings

* docs: add doxygen documentation and unit tests for dialog settings

29 of 59 new or added lines in 5 files covered. (49.15%)

1023 of 5097 relevant lines covered (20.07%)

7.88 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
NEW
35
  restoreGeometry(QtPassSettings::getDialogGeometry("configDialog"));
×
NEW
36
  if (QtPassSettings::isDialogMaximized("configDialog")) {
×
NEW
37
    showMaximized();
×
38
  } else {
NEW
39
    move(QtPassSettings::getDialogPos("configDialog"));
×
NEW
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
void ConfigDialog::validate(QTableWidgetItem *item) {
×
180
  bool status = true;
181

182
  if (item == nullptr) {
×
183
    for (int i = 0; i < ui->profileTable->rowCount(); i++) {
×
184
      for (int j = 0; j < ui->profileTable->columnCount(); j++) {
×
185
        QTableWidgetItem *_item = ui->profileTable->item(i, j);
×
186

187
        if (_item->text().isEmpty() && j != 2) {
×
188
          _item->setBackground(Qt::red);
×
189
          _item->setToolTip(tr("This field is required"));
×
190
          status = false;
191
          break;
192
        } else {
193
          _item->setToolTip(QString());
×
194
        }
195
      }
196

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

211
  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
×
212
}
×
213

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

259
  QtPassSettings::setVersion(VERSION);
×
260
}
×
261

262
void ConfigDialog::on_autodetectButton_clicked() {
×
263
  QString pass = Util::findBinaryInPath("pass");
×
264
  if (!pass.isEmpty()) {
×
265
    ui->passPath->setText(pass);
×
266
  }
267
  usePass(!pass.isEmpty());
×
268
  QString gpg = Util::findBinaryInPath("gpg2");
×
269
  if (gpg.isEmpty()) {
×
270
    gpg = Util::findBinaryInPath("gpg");
×
271
  }
272
  if (!gpg.isEmpty()) {
×
273
    ui->gpgPath->setText(gpg);
×
274
  }
275
  QString git = Util::findBinaryInPath("git");
×
276
  if (!git.isEmpty()) {
×
277
    ui->gitPath->setText(git);
×
278
  }
279
  QString pwgen = Util::findBinaryInPath("pwgen");
×
280
  if (!pwgen.isEmpty()) {
×
281
    ui->pwgenPath->setText(pwgen);
×
282
  }
283
}
×
284

285
/**
286
 * @brief ConfigDialog::on_radioButtonNative_clicked wrapper for
287
 * ConfigDialog::setGroupBoxState()
288
 */
289
void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
×
290

291
/**
292
 * @brief ConfigDialog::on_radioButtonPass_clicked wrapper for
293
 * ConfigDialog::setGroupBoxState()
294
 */
295
void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
×
296

297
/**
298
 * @brief ConfigDialog::getSecretKeys get list of secret/private keys
299
 * @return QStringList keys
300
 */
301
auto ConfigDialog::getSecretKeys() -> QStringList {
×
302
  QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
×
303
  QStringList names;
×
304

305
  if (keys.empty()) {
×
306
    return names;
307
  }
308

309
  foreach (const UserInfo &sec, keys)
×
310
    names << sec.name;
×
311

312
  return names;
×
313
}
314

315
/**
316
 * @brief ConfigDialog::setGroupBoxState update checkboxes.
317
 */
318
void ConfigDialog::setGroupBoxState() {
×
319
  bool state = ui->radioButtonPass->isChecked();
×
320
  ui->groupBoxNative->setEnabled(!state);
×
321
  ui->groupBoxPass->setEnabled(state);
×
322
}
×
323

324
/**
325
 * @brief ConfigDialog::selectExecutable pop-up to choose an executable.
326
 * @return
327
 */
328
auto ConfigDialog::selectExecutable() -> QString {
×
329
  QFileDialog dialog(this);
×
330
  dialog.setFileMode(QFileDialog::ExistingFile);
×
331
  dialog.setOption(QFileDialog::ReadOnly);
×
332
  if (dialog.exec()) {
×
333
    return dialog.selectedFiles().constFirst();
×
334
  }
335

336
  return {};
337
}
×
338

339
/**
340
 * @brief ConfigDialog::selectFolder pop-up to choose a folder.
341
 * @return
342
 */
343
auto ConfigDialog::selectFolder() -> QString {
×
344
  QFileDialog dialog(this);
×
345
  dialog.setFileMode(QFileDialog::Directory);
×
346
  dialog.setFilter(QDir::NoFilter);
×
347
  dialog.setOption(QFileDialog::ShowDirsOnly);
×
348
  if (dialog.exec()) {
×
349
    return dialog.selectedFiles().constFirst();
×
350
  }
351

352
  return {};
353
}
×
354

355
/**
356
 * @brief ConfigDialog::on_toolButtonGit_clicked get git application.
357
 * Enable checkboxes if found.
358
 */
359
void ConfigDialog::on_toolButtonGit_clicked() {
×
360
  QString git = selectExecutable();
×
361
  bool state = !git.isEmpty();
×
362
  if (state) {
×
363
    ui->gitPath->setText(git);
×
364
  } else {
365
    useGit(false);
×
366
  }
367

368
  ui->checkBoxUseGit->setEnabled(state);
×
369
}
×
370

371
/**
372
 * @brief ConfigDialog::on_toolButtonGpg_clicked get gpg application.
373
 */
374
void ConfigDialog::on_toolButtonGpg_clicked() {
×
375
  QString gpg = selectExecutable();
×
376
  if (!gpg.isEmpty()) {
×
377
    ui->gpgPath->setText(gpg);
×
378
  }
379
}
×
380

381
/**
382
 * @brief ConfigDialog::on_pushButtonGenerateKey_clicked open keygen dialog.
383
 */
384
void ConfigDialog::on_pushButtonGenerateKey_clicked() {
×
385
  KeygenDialog d(this);
×
386
  d.exec();
×
387
}
×
388

389
/**
390
 * @brief ConfigDialog::on_toolButtonPass_clicked get pass application.
391
 */
392
void ConfigDialog::on_toolButtonPass_clicked() {
×
393
  QString pass = selectExecutable();
×
394
  if (!pass.isEmpty()) {
×
395
    ui->passPath->setText(pass);
×
396
  }
397
}
×
398

399
/**
400
 * @brief ConfigDialog::on_toolButtonStore_clicked get .password-store
401
 * location.s
402
 */
403
void ConfigDialog::on_toolButtonStore_clicked() {
×
404
  QString store = selectFolder();
×
NEW
405
  if (!store.isEmpty()) {
×
406
    ui->storePath->setText(store);
×
407
  }
408
}
×
409

410
/**
411
 * @brief ConfigDialog::on_comboBoxClipboard_activated show and hide options.
412
 * @param index of selectbox (0 = no clipboard).
413
 */
414
void ConfigDialog::on_comboBoxClipboard_activated(int index) {
×
415
  bool state = index > 0;
×
416

417
  ui->checkBoxSelection->setEnabled(state);
×
418
  ui->checkBoxAutoclear->setEnabled(state);
×
419
  ui->checkBoxHidePassword->setEnabled(state);
×
420
  ui->checkBoxHideContent->setEnabled(state);
×
421
  if (state) {
×
422
    ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
423
    ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
424
  } else {
425
    ui->spinBoxAutoclearSeconds->setEnabled(false);
×
426
    ui->labelSeconds->setEnabled(false);
×
427
  }
428
}
×
429

430
/**
431
 * @brief ConfigDialog::on_checkBoxAutoclearPanel_clicked enable and disable
432
 * options based on autoclear use.
433
 */
434
void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
×
435
  bool state = ui->checkBoxAutoclearPanel->isChecked();
×
436
  ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
×
437
  ui->labelPanelSeconds->setEnabled(state);
×
438
}
×
439

440
/**
441
 * @brief ConfigDialog::useSelection set the clipboard type use from
442
 * MainWindow.
443
 * @param useSelection
444
 */
445
void ConfigDialog::useSelection(bool useSelection) {
×
446
  ui->checkBoxSelection->setChecked(useSelection);
×
447
  on_checkBoxSelection_clicked();
×
448
}
×
449

450
/**
451
 * @brief ConfigDialog::useAutoclear set the clipboard autoclear use from
452
 * MainWindow.
453
 * @param useAutoclear
454
 */
455
void ConfigDialog::useAutoclear(bool useAutoclear) {
×
456
  ui->checkBoxAutoclear->setChecked(useAutoclear);
×
457
  on_checkBoxAutoclear_clicked();
×
458
}
×
459

460
/**
461
 * @brief ConfigDialog::useAutoclearPanel set the panel autoclear use from
462
 * MainWindow.
463
 * @param useAutoclearPanel
464
 */
465
void ConfigDialog::useAutoclearPanel(bool useAutoclearPanel) {
×
466
  ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
×
467
  on_checkBoxAutoclearPanel_clicked();
×
468
}
×
469

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

478
/**
479
 * @brief ConfigDialog::on_checkBoxAutoclear_clicked checkbox clicked, update
480
 * state via ConfigDialog::on_comboBoxClipboard_activated
481
 */
482
void ConfigDialog::on_checkBoxAutoclear_clicked() {
×
483
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
484
}
×
485

486
/**
487
 * @brief ConfigDialog::genKey tunnel function to make MainWindow generate a
488
 * gpg key pair.
489
 * @todo refactor the process to not be entangled so much.
490
 * @param batch
491
 * @param dialog
492
 */
493
void ConfigDialog::genKey(const QString &batch, QDialog *dialog) {
×
494
  mainWindow->generateKeyPair(batch, dialog);
×
495
}
×
496

497
/**
498
 * @brief ConfigDialog::setProfiles set the profiles and chosen profile from
499
 * MainWindow.
500
 * @param profiles
501
 * @param profile
502
 */
503
void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
×
504
                               const QString &currentProfile) {
505
  // dbg()<< profiles;
506
  if (profiles.contains("")) {
×
507
    profiles.remove("");
×
508
    // remove weird "" key value pairs
509
  }
510

511
  ui->profileTable->setRowCount(profiles.count());
×
512
  QHashIterator<QString, QHash<QString, QString>> i(profiles);
×
513
  int n = 0;
514
  while (i.hasNext()) {
×
515
    i.next();
516
    if (!i.value().isEmpty() && !i.key().isEmpty()) {
×
517
      ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
×
518
      ui->profileTable->setItem(n, 1,
×
519
                                new QTableWidgetItem(i.value().value("path")));
×
520
      ui->profileTable->setItem(
×
521
          n, 2, new QTableWidgetItem(i.value().value("signingKey")));
×
522
      // dbg()<< "naam:" + i.key();
523
      if (i.key() == currentProfile) {
×
524
        ui->profileTable->selectRow(n);
×
525
      }
526
    }
527
    ++n;
×
528
  }
529
}
×
530

531
/**
532
 * @brief ConfigDialog::getProfiles return profile list.
533
 * @return
534
 */
535
auto ConfigDialog::getProfiles() -> QHash<QString, QHash<QString, QString>> {
×
536
  QHash<QString, QHash<QString, QString>> profiles;
×
537
  // Check?
538
  for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
×
539
    QHash<QString, QString> profile;
×
540
    QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
×
541
    if (nullptr != pathItem) {
×
542
      QTableWidgetItem *item = ui->profileTable->item(i, 0);
×
543
      if (item == nullptr) {
×
544
        continue;
545
      }
546
      profile["path"] = pathItem->text();
×
547
      QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
×
548
      if (nullptr != signingKeyItem) {
×
549
        profile["signingKey"] = signingKeyItem->text();
×
550
      }
551
      profiles.insert(item->text(), profile);
×
552
    }
553
  }
×
554
  return profiles;
×
555
}
×
556

557
/**
558
 * @brief ConfigDialog::on_addButton_clicked add a profile row.
559
 */
560
void ConfigDialog::on_addButton_clicked() {
×
561
  int n = ui->profileTable->rowCount();
×
562
  ui->profileTable->insertRow(n);
×
563
  ui->profileTable->setItem(n, 0, new QTableWidgetItem());
×
564
  ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
×
565
  ui->profileTable->setItem(n, 2, new QTableWidgetItem());
×
566
  ui->profileTable->selectRow(n);
×
567
  ui->deleteButton->setEnabled(true);
×
568

569
  validate();
×
570
}
×
571

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

596
  validate();
×
597
}
598

599
/**
600
 * @brief ConfigDialog::criticalMessage weapper for showing critical messages
601
 * in a popup.
602
 * @param title
603
 * @param text
604
 */
605
void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
×
606
  QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
×
607
}
×
608

609
auto ConfigDialog::isQrencodeAvailable() -> bool {
×
610
#ifdef Q_OS_WIN
611
  return false;
612
#else
613
  QProcess which;
×
614
  which.start("which", QStringList() << "qrencode");
×
615
  which.waitForFinished();
×
616
  QtPassSettings::setQrencodeExecutable(
×
617
      which.readAllStandardOutput().trimmed());
×
618
  return which.exitCode() == 0;
×
619
#endif
620
}
×
621

622
auto ConfigDialog::isPassOtpAvailable() -> bool {
×
623
#ifdef Q_OS_WIN
624
  return false;
625
#else
626
  QProcess pass;
×
627
  pass.start(QtPassSettings::getPassExecutable(), QStringList() << "otp"
×
628
                                                                << "--help");
×
629
  pass.waitForFinished(2000);
×
630
  return pass.exitCode() == 0;
×
631
#endif
632
}
×
633

634
/**
635
 * @brief ConfigDialog::wizard first-time use wizard.
636
 * @todo make this thing more reliable.
637
 */
638
void ConfigDialog::wizard() {
×
639
  (void)Util::configIsValid();
×
640
  on_autodetectButton_clicked();
×
641

642
  if (!checkGpgExistence()) {
×
643
    return;
644
  }
645
  if (!checkSecretKeys()) {
×
646
    return;
647
  }
648
  if (!checkPasswordStore()) {
×
649
    return;
650
  }
651
  handleGpgIdFile();
×
652

653
  ui->checkBoxHidePassword->setCheckState(Qt::Checked);
×
654
}
655

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

686
auto ConfigDialog::checkSecretKeys() -> bool {
×
687
  QString gpg = ui->gpgPath->text();
×
688
  QStringList names = getSecretKeys();
×
689

690
#ifdef QT_DEBUG
691
  dbg() << names;
692
#endif
693

694
  if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
×
695
    KeygenDialog d(this);
×
696
    return d.exec();
×
697
  }
×
698
  return true;
699
}
700

701
auto ConfigDialog::checkPasswordStore() -> bool {
×
702
  QString passStore = ui->storePath->text();
×
703

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

729
void ConfigDialog::handleGpgIdFile() {
×
730
  QString passStore = ui->storePath->text();
×
731
  if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
×
732
#ifdef QT_DEBUG
733
    dbg() << ".gpg-id file does not exist";
734
#endif
735
    criticalMessage(tr("Password store not initialised"),
×
736
                    tr("The folder %1 doesn't seem to be a password store or "
×
737
                       "is not yet initialised.")
738
                        .arg(passStore));
×
739

740
    while (!QFile(passStore).exists()) {
×
741
      on_toolButtonStore_clicked();
×
742
      if (passStore == ui->storePath->text()) {
×
743
        return;
744
      }
745
      passStore = ui->storePath->text();
×
746
    }
747
    if (!QFile(passStore + ".gpg-id").exists()) {
×
748
#ifdef QT_DEBUG
749
      dbg() << ".gpg-id file still does not exist :/";
750
#endif
751
      mainWindow->userDialog(passStore);
×
752
    }
753
  }
754
}
755

756
/**
757
 * @brief ConfigDialog::useTrayIcon set preference for using trayicon.
758
 * Enable or disable related checkboxes accordingly.
759
 * @param useSystray
760
 */
761
void ConfigDialog::useTrayIcon(bool useSystray) {
×
762
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
763
    ui->checkBoxUseTrayIcon->setChecked(useSystray);
×
764
    ui->checkBoxHideOnClose->setEnabled(useSystray);
×
765
    ui->checkBoxStartMinimized->setEnabled(useSystray);
×
766

767
    if (!useSystray) {
×
768
      ui->checkBoxHideOnClose->setChecked(false);
×
769
      ui->checkBoxStartMinimized->setChecked(false);
×
770
    }
771
  }
772
}
×
773

774
/**
775
 * @brief ConfigDialog::on_checkBoxUseTrayIcon_clicked enable and disable
776
 * related checkboxes.
777
 */
778
void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
×
779
  bool state = ui->checkBoxUseTrayIcon->isChecked();
×
780
  ui->checkBoxHideOnClose->setEnabled(state);
×
781
  ui->checkBoxStartMinimized->setEnabled(state);
×
782
}
×
783

784
/**
785
 * @brief ConfigDialog::closeEvent close this window.
786
 * @param event
787
 */
788
void ConfigDialog::closeEvent(QCloseEvent *event) {
×
NEW
789
  QtPassSettings::setDialogGeometry("configDialog", saveGeometry());
×
NEW
790
  QtPassSettings::setDialogPos("configDialog", pos());
×
NEW
791
  QtPassSettings::setDialogSize("configDialog", size());
×
NEW
792
  QtPassSettings::setDialogMaximized("configDialog", isMaximized());
×
793
  event->accept();
794
}
×
795

796
/**
797
 * @brief ConfigDialog::useGit set preference for using git.
798
 * @param useGit
799
 */
800
void ConfigDialog::useGit(bool useGit) {
×
801
  ui->checkBoxUseGit->setChecked(useGit);
×
802
  on_checkBoxUseGit_clicked();
×
803
}
×
804

805
/**
806
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
807
 * @param useOtp
808
 */
809
void ConfigDialog::useOtp(bool useOtp) {
×
810
  ui->checkBoxUseOtp->setChecked(useOtp);
×
811
}
×
812

813
/**
814
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
815
 * @param useOtp
816
 */
817
void ConfigDialog::useQrencode(bool useQrencode) {
×
818
  ui->checkBoxUseQrencode->setChecked(useQrencode);
×
819
}
×
820

821
/**
822
 * @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
823
 * checkboxes.
824
 */
825
void ConfigDialog::on_checkBoxUseGit_clicked() {
×
826
  ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
×
827
  ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
×
828
  ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
×
829
}
×
830

831
/**
832
 * @brief ConfigDialog::on_toolButtonPwgen_clicked enable or disable related
833
 * options in the interface.
834
 */
835
void ConfigDialog::on_toolButtonPwgen_clicked() {
×
836
  QString pwgen = selectExecutable();
×
837
  if (!pwgen.isEmpty()) {
×
838
    ui->pwgenPath->setText(pwgen);
×
839
    ui->checkBoxUsePwgen->setEnabled(true);
×
840
  } else {
841
    ui->checkBoxUsePwgen->setEnabled(false);
×
842
    ui->checkBoxUsePwgen->setChecked(false);
×
843
  }
844
}
×
845

846
/**
847
 * @brief ConfigDialog::setPwgenPath set pwgen executable path.
848
 * Enable or disable related options in the interface.
849
 * @param pwgen
850
 */
851
void ConfigDialog::setPwgenPath(const QString &pwgen) {
×
852
  ui->pwgenPath->setText(pwgen);
×
853
  if (pwgen.isEmpty()) {
×
854
    ui->checkBoxUsePwgen->setChecked(false);
×
855
    ui->checkBoxUsePwgen->setEnabled(false);
×
856
  }
857
  on_checkBoxUsePwgen_clicked();
×
858
}
×
859

860
/**
861
 * @brief ConfigDialog::on_checkBoxUsPwgen_clicked enable or disable related
862
 * options in the interface.
863
 */
864
void ConfigDialog::on_checkBoxUsePwgen_clicked() {
×
865
  bool usePwgen = ui->checkBoxUsePwgen->isChecked();
×
866
  ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
×
867
  ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
×
868
  ui->checkBoxLessRandom->setEnabled(usePwgen);
×
869
  ui->checkBoxUseSymbols->setEnabled(usePwgen);
×
870
  ui->lineEditPasswordChars->setEnabled(!usePwgen);
×
871
  ui->labelPasswordChars->setEnabled(!usePwgen);
×
872
  ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
×
873
}
×
874

875
/**
876
 * @brief ConfigDialog::usePwgen set preference for using pwgen (can be
877
 * overruled buy empty pwgenPath).
878
 * enable or disable related options in the interface via
879
 * ConfigDialog::on_checkBoxUsePwgen_clicked
880
 * @param usePwgen
881
 */
882
void ConfigDialog::usePwgen(bool usePwgen) {
×
883
  if (ui->pwgenPath->text().isEmpty()) {
×
884
    usePwgen = false;
885
  }
886
  ui->checkBoxUsePwgen->setChecked(usePwgen);
×
887
  on_checkBoxUsePwgen_clicked();
×
888
}
×
889

890
void ConfigDialog::setPasswordConfiguration(
×
891
    const PasswordConfiguration &config) {
892
  ui->spinBoxPasswordLength->setValue(config.length);
×
893
  ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
×
894
  if (config.selected != PasswordConfiguration::CUSTOM) {
×
895
    ui->lineEditPasswordChars->setEnabled(false);
×
896
  }
897
  ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
×
898
}
×
899

900
auto ConfigDialog::getPasswordConfiguration() -> PasswordConfiguration {
×
901
  PasswordConfiguration config;
×
902
  config.length = ui->spinBoxPasswordLength->value();
×
903
  config.selected = static_cast<PasswordConfiguration::characterSet>(
×
904
      ui->passwordCharTemplateSelector->currentIndex());
×
905
  config.Characters[PasswordConfiguration::CUSTOM] =
906
      ui->lineEditPasswordChars->text();
×
907
  return config;
×
908
}
×
909

910
/**
911
 * @brief ConfigDialog::on_passwordCharTemplateSelector_activated sets the
912
 * passwordChar Template
913
 * combo box to the desired entry
914
 * @param entry of
915
 */
916
void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
×
917
  ui->lineEditPasswordChars->setText(
×
918
      QtPassSettings::getPasswordConfiguration().Characters[index]);
×
919
  if (index == 3) {
×
920
    ui->lineEditPasswordChars->setEnabled(true);
×
921
  } else {
922
    ui->lineEditPasswordChars->setEnabled(false);
×
923
  }
924
}
×
925

926
/**
927
 * @brief ConfigDialog::on_checkBoxUseTemplate_clicked enable or disable the
928
 * template field and options.
929
 */
930
void ConfigDialog::on_checkBoxUseTemplate_clicked() {
×
931
  ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
×
932
  ui->checkBoxTemplateAllFields->setEnabled(
×
933
      ui->checkBoxUseTemplate->isChecked());
×
934
}
×
935

936
void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
×
937
  validate(item);
×
938
}
×
939

940
/**
941
 * @brief ConfigDialog::useTemplate set preference for using templates.
942
 * @param useTemplate
943
 */
944
void ConfigDialog::useTemplate(bool useTemplate) {
×
945
  ui->checkBoxUseTemplate->setChecked(useTemplate);
×
946
  on_checkBoxUseTemplate_clicked();
×
947
}
×
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