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

IJHack / QtPass / 24829425913

23 Apr 2026 10:08AM UTC coverage: 27.299% (-0.06%) from 27.36%
24829425913

push

github

web-flow
Fix profile initialization for new directories (#1034) (#1134)

* Fix profile initialization for new directories (#1034)

When creating a new profile with a new folder (that doesn't exist yet), the
directory was never created and pass/git initialization never ran because
ProfileInit::needsInit() returns false for non-existent directories.

This fix:
- Normalizes the path with QDir::cleanPath() for cross-platform compatibility
- Creates the directory if it doesn't exist
- Shows a visible error message with QMessageBox if directory creation fails
- Then proceeds with pass init and git init as expected

* fix: apply CodeRabbit auto-fixes

Fixed 1 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

0 of 16 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

1597 of 5850 relevant lines covered (27.3%)

30.36 hits per line

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

0.0
/src/configdialog.cpp
1
// SPDX-FileCopyrightText: 2014 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 "profileinit.h"
7
#include "qtpasssettings.h"
8
#include "ui_configdialog.h"
9
#include "usersdialog.h"
10
#include "util.h"
11
#include <QClipboard>
12
#include <QDir>
13
#include <QFileDialog>
14
#include <QMessageBox>
15
#include <QPushButton>
16
#include <QSystemTrayIcon>
17
#include <QTableWidgetItem>
18
#include <utility>
19
#ifdef Q_OS_WIN
20
#include <windows.h>
21
#endif
22

23
#ifdef QT_DEBUG
24
#include "debughelper.h"
25
#endif
26

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

36
  // Restore dialog state
37
  QByteArray savedGeometry = QtPassSettings::getDialogGeometry("configDialog");
×
38
  bool hasSavedGeometry = !savedGeometry.isEmpty();
39
  if (hasSavedGeometry) {
×
40
    restoreGeometry(savedGeometry);
×
41
  }
42
  if (QtPassSettings::isDialogMaximized("configDialog")) {
×
43
    showMaximized();
×
44
  } else if (!hasSavedGeometry) {
45
    // Let window manager handle positioning for first launch
46
  }
47

48
  ui->passPath->setText(QtPassSettings::getPassExecutable());
×
49
  setGitPath(QtPassSettings::getGitExecutable());
×
50
  ui->gpgPath->setText(QtPassSettings::getGpgExecutable());
×
51
  ui->storePath->setText(QtPassSettings::getPassStore());
×
52

53
  ui->spinBoxAutoclearSeconds->setValue(QtPassSettings::getAutoclearSeconds());
×
54
  ui->spinBoxAutoclearPanelSeconds->setValue(
×
55
      QtPassSettings::getAutoclearPanelSeconds());
×
56
  ui->checkBoxHidePassword->setChecked(QtPassSettings::isHidePassword());
×
57
  ui->checkBoxHideContent->setChecked(QtPassSettings::isHideContent());
×
58
  ui->checkBoxUseMonospace->setChecked(QtPassSettings::isUseMonospace());
×
59
  ui->checkBoxDisplayAsIs->setChecked(QtPassSettings::isDisplayAsIs());
×
60
  ui->checkBoxNoLineWrapping->setChecked(QtPassSettings::isNoLineWrapping());
×
61
  ui->checkBoxAddGPGId->setChecked(QtPassSettings::isAddGPGId(true));
×
62

63
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
64
    ui->checkBoxHideOnClose->setChecked(QtPassSettings::isHideOnClose());
×
65
    ui->checkBoxStartMinimized->setChecked(QtPassSettings::isStartMinimized());
×
66
  } else {
67
    ui->checkBoxUseTrayIcon->setEnabled(false);
×
68
    ui->checkBoxUseTrayIcon->setToolTip(tr("System tray is not available"));
×
69
    ui->checkBoxHideOnClose->setEnabled(false);
×
70
    ui->checkBoxStartMinimized->setEnabled(false);
×
71
  }
72

73
  ui->checkBoxAvoidCapitals->setChecked(QtPassSettings::isAvoidCapitals());
×
74
  ui->checkBoxAvoidNumbers->setChecked(QtPassSettings::isAvoidNumbers());
×
75
  ui->checkBoxLessRandom->setChecked(QtPassSettings::isLessRandom());
×
76
  ui->checkBoxUseSymbols->setChecked(QtPassSettings::isUseSymbols());
×
77
  ui->plainTextEditTemplate->setPlainText(QtPassSettings::getPassTemplate());
×
78
  ui->checkBoxTemplateAllFields->setChecked(
×
79
      QtPassSettings::isTemplateAllFields());
×
80
  ui->checkBoxAutoPull->setChecked(QtPassSettings::isAutoPull());
×
81
  ui->checkBoxAutoPush->setChecked(QtPassSettings::isAutoPush());
×
82
  ui->checkBoxAlwaysOnTop->setChecked(QtPassSettings::isAlwaysOnTop());
×
83

84
#if defined(Q_OS_WIN)
85
  ui->checkBoxUseOtp->hide();
86
  ui->checkBoxUseQrencode->hide();
87
  ui->label_10->hide();
88
#endif
89

90
  if (!isPassOtpAvailable()) {
×
91
    ui->checkBoxUseOtp->setEnabled(false);
×
92
    ui->checkBoxUseOtp->setToolTip(
×
93
        tr("Pass OTP extension needs to be installed"));
×
94
  }
95

96
  if (!isQrencodeAvailable()) {
×
97
    ui->checkBoxUseQrencode->setEnabled(false);
×
98
    ui->checkBoxUseQrencode->setToolTip(tr("qrencode needs to be installed"));
×
99
  }
100

101
  setProfiles(QtPassSettings::getProfiles(), QtPassSettings::getProfile());
×
102
  setPwgenPath(QtPassSettings::getPwgenExecutable());
×
103
  setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
×
104

105
  usePass(QtPassSettings::isUsePass());
×
106
  useAutoclear(QtPassSettings::isUseAutoclear());
×
107
  useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
×
108
  useTrayIcon(QtPassSettings::isUseTrayIcon());
×
109
  useGit(QtPassSettings::isUseGit());
×
110

111
  useOtp(QtPassSettings::isUseOtp());
×
112
  useGrepSearch(QtPassSettings::isUseGrepSearch());
×
113
  useQrencode(QtPassSettings::isUseQrencode());
×
114

115
  usePwgen(QtPassSettings::isUsePwgen());
×
116
  useTemplate(QtPassSettings::isUseTemplate());
×
117

118
  ui->profileTable->verticalHeader()->hide();
×
119
  ui->profileTable->horizontalHeader()->setSectionResizeMode(
×
120
      1, QHeaderView::Stretch);
121
  ui->label->setText(ui->label->text() + VERSION);
×
122
  ui->comboBoxClipboard->clear();
×
123

124
  ui->comboBoxClipboard->addItem(tr("No Clipboard"));
×
125
  ui->comboBoxClipboard->addItem(tr("Always copy to clipboard"));
×
126
  ui->comboBoxClipboard->addItem(tr("On-demand copy to clipboard"));
×
127

128
  int currentIndex = QtPassSettings::getClipBoardTypeRaw();
×
129
  ui->comboBoxClipboard->setCurrentIndex(currentIndex);
×
130
  on_comboBoxClipboard_activated(currentIndex);
×
131

132
  QClipboard *clip = QApplication::clipboard();
×
133
  if (!clip->supportsSelection()) {
×
134
    useSelection(false);
×
135
    ui->checkBoxSelection->setVisible(false);
×
136
  } else {
137
    useSelection(QtPassSettings::isUseSelection());
×
138
  }
139

140
  if (!Util::configIsValid()) {
×
141
    // Show Programs tab, which is likely
142
    // what the user needs to fix now.
143
    ui->tabWidget->setCurrentIndex(1);
×
144
  }
145

146
  connect(ui->profileTable, &QTableWidget::itemChanged, this,
×
147
          &ConfigDialog::onProfileTableItemChanged);
×
148
  connect(this, &ConfigDialog::accepted, this, &ConfigDialog::on_accepted);
×
149
}
×
150

151
/**
152
 * @brief ConfigDialog::~ConfigDialog config destructor, makes sure the
153
 * mainWindow knows about git, gpg and pass executables.
154
 */
155
ConfigDialog::~ConfigDialog() {
×
156
  QtPassSettings::setGitExecutable(ui->gitPath->text());
×
157
  QtPassSettings::setGpgExecutable(ui->gpgPath->text());
×
158
  QtPassSettings::setPassExecutable(ui->passPath->text());
×
159
}
×
160

161
/**
162
 * @brief ConfigDialog::setGitPath set the git executable path.
163
 * Make sure the checkBoxUseGit is updated.
164
 * @param path
165
 */
166
void ConfigDialog::setGitPath(const QString &path) {
×
167
  ui->gitPath->setText(path);
×
168
  ui->checkBoxUseGit->setEnabled(!path.isEmpty());
×
169
  if (path.isEmpty()) {
×
170
    useGit(false);
×
171
  }
172
}
×
173

174
/**
175
 * @brief ConfigDialog::usePass set wether or not we want to use pass.
176
 * Update radio buttons accordingly.
177
 * @param usePass
178
 */
179
void ConfigDialog::usePass(bool usePass) {
×
180
  ui->radioButtonNative->setChecked(!usePass);
×
181
  ui->radioButtonPass->setChecked(usePass);
×
182
  setGroupBoxState();
×
183
}
×
184

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

200
  if (item == nullptr) {
×
201
    for (int i = 0; i < ui->profileTable->rowCount(); i++) {
×
202
      for (int j = 0; j < ui->profileTable->columnCount(); j++) {
×
203
        QTableWidgetItem *_item = ui->profileTable->item(i, j);
×
204

205
        if (_item->text().isEmpty() && j != 2) {
×
206
          _item->setBackground(Qt::red);
×
207
          _item->setToolTip(tr("This field is required"));
×
208
          status = false;
209
          break;
210
        } else {
211
          _item->setBackground(QBrush());
×
212
          _item->setToolTip(QString());
×
213
        }
214
      }
215

216
      if (!status) {
217
        break;
218
      }
219
    }
220
  } else {
221
    if (item->text().isEmpty() && item->column() != 2) {
×
222
      item->setBackground(Qt::red);
×
223
      item->setToolTip(tr("This field is required"));
×
224
      status = false;
225
    } else {
226
      item->setBackground(QBrush());
×
227
      item->setToolTip(QString());
×
228
    }
229
  }
230

231
  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
×
232
}
×
233

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

293
  QtPassSettings::setVersion(VERSION);
×
294

295
  // Initialize new profiles that need pass/git initialization
296
  initializeNewProfiles(existingProfiles);
×
297
}
×
298

299
/**
300
 * @brief Automatically detects required external binaries in the system PATH
301
 * and updates the dialog fields.
302
 * @example
303
 * ConfigDialog configDialog;
304
 * configDialog.on_autodetectButton_clicked();
305
 *
306
 * @return void - This function does not return a value.
307
 */
308
void ConfigDialog::on_autodetectButton_clicked() {
×
309
  QString pass = Util::findBinaryInPath("pass");
×
310
  if (!pass.isEmpty()) {
×
311
    ui->passPath->setText(pass);
×
312
  }
313
  usePass(!pass.isEmpty());
×
314
  QString gpg = Util::findBinaryInPath("gpg2");
×
315
  if (gpg.isEmpty()) {
×
316
    gpg = Util::findBinaryInPath("gpg");
×
317
  }
318
  if (!gpg.isEmpty()) {
×
319
    ui->gpgPath->setText(gpg);
×
320
  }
321
  QString git = Util::findBinaryInPath("git");
×
322
  if (!git.isEmpty()) {
×
323
    ui->gitPath->setText(git);
×
324
  }
325
  QString pwgen = Util::findBinaryInPath("pwgen");
×
326
  if (!pwgen.isEmpty()) {
×
327
    ui->pwgenPath->setText(pwgen);
×
328
  }
329
}
×
330

331
/**
332
 * @brief ConfigDialog::on_radioButtonNative_clicked wrapper for
333
 * ConfigDialog::setGroupBoxState()
334
 */
335
void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
×
336

337
/**
338
 * @brief ConfigDialog::on_radioButtonPass_clicked wrapper for
339
 * ConfigDialog::setGroupBoxState()
340
 */
341
void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
×
342

343
/**
344
 * @brief ConfigDialog::getSecretKeys get list of secret/private keys
345
 * @return QStringList keys
346
 */
347
auto ConfigDialog::getSecretKeys() -> QStringList {
×
348
  QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
×
349
  QStringList names;
×
350

351
  if (keys.empty()) {
×
352
    return names;
353
  }
354

355
  foreach (const UserInfo &sec, keys)
×
356
    names << sec.name;
×
357

358
  return names;
×
359
}
360

361
/**
362
 * @brief ConfigDialog::setGroupBoxState update checkboxes.
363
 */
364
void ConfigDialog::setGroupBoxState() {
×
365
  bool state = ui->radioButtonPass->isChecked();
×
366
  ui->groupBoxNative->setEnabled(!state);
×
367
  ui->groupBoxPass->setEnabled(state);
×
368
  if (state) {
×
369
    // pass mode: disable all password generation controls
370
    ui->spinBoxPasswordLength->setEnabled(false);
×
371
    ui->checkBoxUsePwgen->setEnabled(false);
×
372
    ui->checkBoxAvoidCapitals->setEnabled(false);
×
373
    ui->checkBoxUseSymbols->setEnabled(false);
×
374
    ui->checkBoxLessRandom->setEnabled(false);
×
375
    ui->checkBoxAvoidNumbers->setEnabled(false);
×
376
    ui->labelPasswordChars->setEnabled(false);
×
377
    ui->passwordCharTemplateSelector->setEnabled(false);
×
378
    ui->lineEditPasswordChars->setEnabled(false);
×
379
  } else {
380
    // native mode: restore pwgen/charset state from existing handlers
381
    ui->spinBoxPasswordLength->setEnabled(true);
×
382
    ui->checkBoxUsePwgen->setEnabled(!ui->pwgenPath->text().isEmpty());
×
383
    on_checkBoxUsePwgen_clicked();
×
384
  }
385
}
×
386

387
/**
388
 * @brief ConfigDialog::selectExecutable pop-up to choose an executable.
389
 * @return
390
 */
391
auto ConfigDialog::selectExecutable() -> QString {
×
392
  QFileDialog dialog(this);
×
393
  dialog.setFileMode(QFileDialog::ExistingFile);
×
394
  dialog.setOption(QFileDialog::ReadOnly);
×
395
  if (dialog.exec()) {
×
396
    return dialog.selectedFiles().constFirst();
×
397
  }
398

399
  return {};
400
}
×
401

402
/**
403
 * @brief ConfigDialog::selectFolder pop-up to choose a folder.
404
 * @return
405
 */
406
auto ConfigDialog::selectFolder() -> QString {
×
407
  QFileDialog dialog(this);
×
408
  dialog.setFileMode(QFileDialog::Directory);
×
409
  dialog.setFilter(QDir::NoFilter);
×
410
  dialog.setOption(QFileDialog::ShowDirsOnly);
×
411
  if (dialog.exec()) {
×
412
    return dialog.selectedFiles().constFirst();
×
413
  }
414

415
  return {};
416
}
×
417

418
/**
419
 * @brief ConfigDialog::on_toolButtonGit_clicked get git application.
420
 * Enable checkboxes if found.
421
 */
422
void ConfigDialog::on_toolButtonGit_clicked() {
×
423
  QString git = selectExecutable();
×
424
  bool state = !git.isEmpty();
×
425
  if (state) {
×
426
    ui->gitPath->setText(git);
×
427
  } else {
428
    useGit(false);
×
429
  }
430

431
  ui->checkBoxUseGit->setEnabled(state);
×
432
}
×
433

434
/**
435
 * @brief ConfigDialog::on_toolButtonGpg_clicked get gpg application.
436
 */
437
void ConfigDialog::on_toolButtonGpg_clicked() {
×
438
  QString gpg = selectExecutable();
×
439
  if (!gpg.isEmpty()) {
×
440
    ui->gpgPath->setText(gpg);
×
441
  }
442
}
×
443

444
/**
445
 * @brief ConfigDialog::on_pushButtonGenerateKey_clicked open keygen dialog.
446
 */
447
void ConfigDialog::on_pushButtonGenerateKey_clicked() {
×
448
  KeygenDialog d(this);
×
449
  d.exec();
×
450
}
×
451

452
/**
453
 * @brief ConfigDialog::on_toolButtonPass_clicked get pass application.
454
 */
455
void ConfigDialog::on_toolButtonPass_clicked() {
×
456
  QString pass = selectExecutable();
×
457
  if (!pass.isEmpty()) {
×
458
    ui->passPath->setText(pass);
×
459
  }
460
}
×
461

462
/**
463
 * @brief ConfigDialog::on_toolButtonStore_clicked get .password-store
464
 * location.
465
 */
466
void ConfigDialog::on_toolButtonStore_clicked() {
×
467
  QString store = selectFolder();
×
468
  if (!store.isEmpty()) {
×
469
    ui->storePath->setText(store);
×
470
  }
471
}
×
472

473
/**
474
 * @brief ConfigDialog::on_comboBoxClipboard_activated show and hide options.
475
 * @param index of selectbox (0 = no clipboard).
476
 */
477
void ConfigDialog::on_comboBoxClipboard_activated(int index) {
×
478
  bool state = index > 0;
×
479

480
  ui->checkBoxSelection->setEnabled(state);
×
481
  ui->checkBoxAutoclear->setEnabled(state);
×
482
  ui->checkBoxHidePassword->setEnabled(state);
×
483
  ui->checkBoxHideContent->setEnabled(state);
×
484
  if (state) {
×
485
    ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
486
    ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
487
  } else {
488
    ui->spinBoxAutoclearSeconds->setEnabled(false);
×
489
    ui->labelSeconds->setEnabled(false);
×
490
  }
491
}
×
492

493
/**
494
 * @brief ConfigDialog::on_checkBoxAutoclearPanel_clicked enable and disable
495
 * options based on autoclear use.
496
 */
497
void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
×
498
  bool state = ui->checkBoxAutoclearPanel->isChecked();
×
499
  ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
×
500
  ui->labelPanelSeconds->setEnabled(state);
×
501
}
×
502

503
/**
504
 * @brief ConfigDialog::useSelection set the clipboard type use from
505
 * MainWindow.
506
 * @param useSelection
507
 */
508
void ConfigDialog::useSelection(bool useSelection) {
×
509
  ui->checkBoxSelection->setChecked(useSelection);
×
510
  on_checkBoxSelection_clicked();
×
511
}
×
512

513
/**
514
 * @brief ConfigDialog::useAutoclear set the clipboard autoclear use from
515
 * MainWindow.
516
 * @param useAutoclear
517
 */
518
void ConfigDialog::useAutoclear(bool useAutoclear) {
×
519
  ui->checkBoxAutoclear->setChecked(useAutoclear);
×
520
  on_checkBoxAutoclear_clicked();
×
521
}
×
522

523
/**
524
 * @brief ConfigDialog::useAutoclearPanel set the panel autoclear use from
525
 * MainWindow.
526
 * @param useAutoclearPanel
527
 */
528
void ConfigDialog::useAutoclearPanel(bool useAutoclearPanel) {
×
529
  ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
×
530
  on_checkBoxAutoclearPanel_clicked();
×
531
}
×
532

533
/**
534
 * @brief ConfigDialog::on_checkBoxSelection_clicked checkbox clicked, update
535
 * state via ConfigDialog::on_comboBoxClipboard_activated
536
 */
537
void ConfigDialog::on_checkBoxSelection_clicked() {
×
538
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
539
}
×
540

541
/**
542
 * @brief ConfigDialog::on_checkBoxAutoclear_clicked checkbox clicked, update
543
 * state via ConfigDialog::on_comboBoxClipboard_activated
544
 */
545
void ConfigDialog::on_checkBoxAutoclear_clicked() {
×
546
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
547
}
×
548

549
/**
550
 * @brief ConfigDialog::genKey tunnel function to make MainWindow generate a
551
 * gpg key pair.
552
 * @param batch
553
 * @param dialog
554
 */
555
void ConfigDialog::genKey(const QString &batch, QDialog *dialog) {
×
556
  mainWindow->generateKeyPair(batch, dialog);
×
557
}
×
558

559
/**
560
 * @brief ConfigDialog::setProfiles set the profiles and chosen profile from
561
 * MainWindow.
562
 * @param profiles
563
 * @param profile
564
 */
565
void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
×
566
                               const QString &currentProfile) {
567
  if (profiles.contains("")) {
×
568
    profiles.remove("");
×
569
    // remove weird "" key value pairs
570
  }
571

572
  ui->profileTable->setRowCount(profiles.count());
×
573
  QHashIterator<QString, QHash<QString, QString>> i(profiles);
×
574
  int n = 0;
575
  while (i.hasNext()) {
×
576
    i.next();
577
    if (!i.value().isEmpty() && !i.key().isEmpty()) {
×
578
      ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
×
579
      ui->profileTable->setItem(n, 1,
×
580
                                new QTableWidgetItem(i.value().value("path")));
×
581
      ui->profileTable->setItem(
×
582
          n, 2, new QTableWidgetItem(i.value().value("signingKey")));
×
583
      if (i.key() == currentProfile) {
×
584
        ui->profileTable->selectRow(n);
×
585
      }
586
    }
587
    ++n;
×
588
  }
589
}
×
590

591
/**
592
 * @brief ConfigDialog::getProfiles return profile list.
593
 * @return
594
 */
595
auto ConfigDialog::getProfiles() -> QHash<QString, QHash<QString, QString>> {
×
596
  QHash<QString, QHash<QString, QString>> profiles;
×
597
  // Check?
598
  for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
×
599
    QHash<QString, QString> profile;
×
600
    QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
×
601
    if (nullptr != pathItem) {
×
602
      QTableWidgetItem *item = ui->profileTable->item(i, 0);
×
603
      if (item == nullptr) {
×
604
        continue;
605
      }
606
      profile["path"] = pathItem->text();
×
607
      QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
×
608
      if (nullptr != signingKeyItem) {
×
609
        profile["signingKey"] = signingKeyItem->text();
×
610
      }
611
      profiles.insert(item->text(), profile);
×
612
    }
613
  }
×
614
  return profiles;
×
615
}
×
616

617
/**
618
 * @brief Initialize new profiles that need pass/git initialization.
619
 * @param existingProfiles The profiles that existed before the dialog was
620
 * opened.
621
 */
622
void ConfigDialog::initializeNewProfiles(
×
623
    const QHash<QString, QHash<QString, QString>> &existingProfiles) {
624
  QHash<QString, QHash<QString, QString>> newProfiles = getProfiles();
×
625

626
  // Collect keys and sort for deterministic iteration
627
  QStringList keys = newProfiles.keys();
×
628
  keys.sort();
629

630
  for (const QString &name : keys) {
×
631
    const QString &path = newProfiles.value(name).value("path");
×
632

633
    // Skip if already existed before (check by name and path)
634
    if (existingProfiles.contains(name) &&
×
635
        existingProfiles.value(name).value("path") == path) {
×
636
      continue;
×
637
    }
638

639
    // This is a new profile - create directory if needed and initialize
640
    // Note: needsInit returns false for non-existent directories, so we
641
    // must create the directory first.
NEW
642
    QString cleanPath = QDir::cleanPath(path);
×
NEW
643
    QDir dir(cleanPath);
×
NEW
644
    if (!dir.exists()) {
×
NEW
645
      if (QMessageBox::question(
×
NEW
646
              this, tr("Create profile directory?"),
×
NEW
647
              tr("Would you like to create a password store at %1?")
×
NEW
648
                  .arg(cleanPath),
×
649
              QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
NEW
650
        continue;
×
651
      }
NEW
652
      if (!QDir().mkpath(cleanPath)) {
×
NEW
653
        QMessageBox::warning(
×
NEW
654
            this, tr("Error"),
×
NEW
655
            tr("Could not create profile directory: %1").arg(cleanPath));
×
NEW
656
        continue;
×
657
      }
658
    }
659

660
    // Now check if initialization is needed (directory exists with no .gpg-id)
NEW
661
    if (!ProfileInit::needsInit(cleanPath)) {
×
UNCOV
662
      continue;
×
663
    }
664

665
    // Temporarily switch the active store so pass/git init operate on
666
    // the new profile's directory rather than the currently-saved one.
667
    const QString prevStore = QtPassSettings::getPassStore();
×
NEW
668
    QtPassSettings::setPassStore(cleanPath);
×
669

670
    // Show user selection dialog for GPG recipients
671
    // UsersDialog will run pass init when accepted
NEW
672
    UsersDialog usersDialog(cleanPath, this);
×
673
    usersDialog.setWindowTitle(tr("Select recipients for %1").arg(name));
×
674
    const int result = usersDialog.exec();
×
675

676
    if (result == QDialog::Accepted && ui->checkBoxUseGit->isChecked()) {
×
677
      QtPassSettings::getPass()->GitInit();
×
678
    }
679

680
    // Restore previous store setting
681
    QtPassSettings::setPassStore(prevStore);
×
682
  }
×
683
}
×
684

685
/**
686
 * @brief ConfigDialog::on_addButton_clicked add a profile row.
687
 */
688
void ConfigDialog::on_addButton_clicked() {
×
689
  int n = ui->profileTable->rowCount();
×
690
  ui->profileTable->insertRow(n);
×
691
  ui->profileTable->setItem(n, 0, new QTableWidgetItem(tr("New Profile")));
×
692
  ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
×
693
  ui->profileTable->setItem(n, 2, new QTableWidgetItem());
×
694
  ui->profileTable->selectRow(n);
×
695
  ui->deleteButton->setEnabled(true);
×
696

697
  ui->profileTable->editItem(ui->profileTable->item(n, 0));
×
698
  ui->profileTable->item(n, 0)->setSelected(true);
×
699

700
  validate();
×
701
}
×
702

703
/**
704
 * @brief ConfigDialog::on_profileTable_cellDoubleClicked open folder browser
705
 * for path column (column 1).
706
 */
707
void ConfigDialog::on_profileTable_cellDoubleClicked(int row, int column) {
×
708
  if (column == 1) {
×
709
    QString dir = selectFolder();
×
710
    if (!dir.isEmpty()) {
×
711
      ui->profileTable->item(row, 1)->setText(dir);
×
712
    }
713
  }
714
}
×
715

716
/**
717
 * @brief ConfigDialog::on_deleteButton_clicked remove a profile row.
718
 */
719
void ConfigDialog::on_deleteButton_clicked() {
×
720
  QSet<int> selectedRows; //  we use a set to prevent doubles
721
  QList<QTableWidgetItem *> itemList = ui->profileTable->selectedItems();
×
722
  if (itemList.count() == 0) {
×
723
    QMessageBox::warning(this, tr("No profile selected"),
×
724
                         tr("No profile selected to delete"));
×
725
    return;
726
  }
727
  QTableWidgetItem *item;
728
  foreach (item, itemList)
×
729
    selectedRows.insert(item->row());
×
730
  // get a list, and sort it big to small
731
  QList<int> rows = selectedRows.values();
×
732
  std::sort(rows.begin(), rows.end());
×
733
  // now actually do the removing:
734
  foreach (int row, rows)
×
735
    ui->profileTable->removeRow(row);
×
736
  if (ui->profileTable->rowCount() < 1) {
×
737
    ui->deleteButton->setEnabled(false);
×
738
  }
739

740
  validate();
×
741
}
742

743
/**
744
 * @brief ConfigDialog::criticalMessage wrapper for showing critical messages
745
 * in a popup.
746
 * @param title
747
 * @param text
748
 */
749
void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
×
750
  QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
×
751
}
×
752

753
/**
754
 * @brief Checks whether the qrencode executable is available on the system.
755
 * @example
756
 * bool result = ConfigDialog::isQrencodeAvailable();
757
 * std::cout << result << std::endl; // Expected output: true if qrencode is
758
 * found, otherwise false
759
 *
760
 * @return bool - True if qrencode is available; otherwise false. On Windows,
761
 * always returns false.
762
 */
763
auto ConfigDialog::isQrencodeAvailable() -> bool {
×
764
#ifdef Q_OS_WIN
765
  return false;
766
#else
767
  QProcess which;
×
768
  which.start("which", QStringList() << "qrencode");
×
769
  which.waitForFinished();
×
770
  QtPassSettings::setQrencodeExecutable(
×
771
      which.readAllStandardOutput().trimmed());
×
772
  return which.exitCode() == 0;
×
773
#endif
774
}
×
775

776
auto ConfigDialog::isPassOtpAvailable() -> bool {
×
777
#ifdef Q_OS_WIN
778
  return false;
779
#else
780
  QProcess pass;
×
781
  pass.start(QtPassSettings::getPassExecutable(), QStringList() << "otp"
×
782
                                                                << "--help");
×
783
  pass.waitForFinished(2000);
×
784
  return pass.exitCode() == 0;
×
785
#endif
786
}
×
787

788
/**
789
 * @brief ConfigDialog::wizard first-time use wizard.
790
 */
791
void ConfigDialog::wizard() {
×
792
  (void)Util::configIsValid();
×
793
  on_autodetectButton_clicked();
×
794

795
  if (!checkGpgExistence()) {
×
796
    return;
797
  }
798
  if (!checkSecretKeys()) {
×
799
    return;
800
  }
801
  if (!checkPasswordStore()) {
×
802
    return;
803
  }
804
  handleGpgIdFile();
×
805

806
  ui->checkBoxHidePassword->setCheckState(Qt::Checked);
×
807
}
808

809
/**
810
 * @brief Checks whether the configured GnuPG executable exists.
811
 * @example
812
 * bool result = ConfigDialog::checkGpgExistence();
813
 * std::cout << result << std::endl; // Expected output: true if GnuPG is found,
814
 * false otherwise
815
 *
816
 * @return bool - True if the GnuPG path is valid or uses a WSL command prefix;
817
 * false if the executable cannot be found and an error message is shown.
818
 */
819
auto ConfigDialog::checkGpgExistence() -> bool {
×
820
  QString gpg = ui->gpgPath->text();
×
821
  if (!gpg.startsWith("wsl ") && !QFile(gpg).exists()) {
×
822
    criticalMessage(
×
823
        tr("GnuPG not found"),
×
824
#ifdef Q_OS_WIN
825
#ifdef WINSTORE
826
        tr("Please install GnuPG on your system.<br>Install "
827
           "<strong>Ubuntu</strong> from the Microsoft Store to get it.<br>"
828
           "If you already did so, make sure you started it once and<br>"
829
           "click \"Autodetect\" in the next dialog.")
830
#else
831
        tr("Please install GnuPG on your system.<br>Install "
832
           "<strong>Ubuntu</strong> from the Microsoft Store<br>or <a "
833
           "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
834
           "from GnuPG.org")
835
#endif
836
#else
837
        tr("Please install GnuPG on your system.<br>Install "
×
838
           "<strong>gpg</strong> using your favorite package manager<br>or "
839
           "<a "
840
           "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
841
           "from GnuPG.org")
842
#endif
843
    );
844
    return false;
×
845
  }
846
  return true;
847
}
848

849
/**
850
 * @brief Checks whether secret keys are available and, if needed, prompts the
851
 * user to generate them.
852
 * @example
853
 * bool result = ConfigDialog.checkSecretKeys();
854
 * std::cout << result << std::endl; // Expected output: true if keys are
855
 * present or key generation dialog is accepted, false otherwise
856
 *
857
 * @return bool - Returns true when secret keys are already available or the key
858
 * generation dialog is accepted; false if the dialog is rejected.
859
 */
860
auto ConfigDialog::checkSecretKeys() -> bool {
×
861
  QString gpg = ui->gpgPath->text();
×
862
  QStringList names = getSecretKeys();
×
863

864
#ifdef QT_DEBUG
865
  dbg() << names;
866
#endif
867

868
  if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
×
869
    KeygenDialog d(this);
×
870
    return d.exec();
×
871
  }
×
872
  return true;
873
}
874

875
/**
876
 * @brief Checks whether the password-store path exists and prompts the user to
877
 * create it if it does not.
878
 * @example
879
 * bool result = ConfigDialog::checkPasswordStore();
880
 * std::cout << std::boolalpha << result << std::endl; // Expected output: true
881
 * if the store exists or is created successfully, false if creation fails
882
 *
883
 * @return bool - True if the password-store exists or is successfully created,
884
 * false if creation fails.
885
 */
886
auto ConfigDialog::checkPasswordStore() -> bool {
×
887
  QString passStore = ui->storePath->text();
×
888

889
  if (!QFile(passStore).exists()) {
×
890
    if (QMessageBox::question(
×
891
            this, tr("Create password-store?"),
×
892
            tr("Would you like to create a password-store at %1?")
×
893
                .arg(passStore),
×
894
            QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
895
      if (!QDir().mkdir(passStore)) {
×
896
        QMessageBox::warning(
×
897
            this, tr("Error"),
×
898
            tr("Failed to create password-store at: %1").arg(passStore));
×
899
        return false;
×
900
      }
901
#ifdef Q_OS_WIN
902
      SetFileAttributes(passStore.toStdWString().c_str(),
903
                        FILE_ATTRIBUTE_HIDDEN);
904
#endif
905
      if (ui->checkBoxUseGit->isChecked()) {
×
906
        emit mainWindow->passGitInitNeeded();
×
907
      }
908
      mainWindow->userDialog(passStore);
×
909
    }
910
  }
911
  return true;
912
}
913

914
/**
915
 * @brief Handles selection and validation of the password store's .gpg-id file.
916
 * @example
917
 * ConfigDialog dialog;
918
 * dialog.handleGpgIdFile();
919
 *
920
 * @return void - This method does not return a value; it updates the UI flow
921
 * and may prompt the user to choose a valid password store.
922
 */
923
void ConfigDialog::handleGpgIdFile() {
×
924
  QString passStore = ui->storePath->text();
×
925
  if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
×
926
#ifdef QT_DEBUG
927
    dbg() << ".gpg-id file does not exist";
928
#endif
929
    criticalMessage(tr("Password store not initialised"),
×
930
                    tr("The folder %1 doesn't seem to be a password store or "
×
931
                       "is not yet initialised.")
932
                        .arg(passStore));
×
933

934
    while (!QFile(passStore).exists()) {
×
935
      on_toolButtonStore_clicked();
×
936
      if (passStore == ui->storePath->text()) {
×
937
        return;
938
      }
939
      passStore = ui->storePath->text();
×
940
    }
941
    if (!QFile(passStore + ".gpg-id").exists()) {
×
942
#ifdef QT_DEBUG
943
      dbg() << ".gpg-id file still does not exist :/";
944
#endif
945
      mainWindow->userDialog(passStore);
×
946
    }
947
  }
948
}
949

950
/**
951
 * @brief ConfigDialog::useTrayIcon set preference for using trayicon.
952
 * Enable or disable related checkboxes accordingly.
953
 * @param useSystray
954
 */
955
void ConfigDialog::useTrayIcon(bool useSystray) {
×
956
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
957
    ui->checkBoxUseTrayIcon->setChecked(useSystray);
×
958
    ui->checkBoxHideOnClose->setEnabled(useSystray);
×
959
    ui->checkBoxStartMinimized->setEnabled(useSystray);
×
960

961
    if (!useSystray) {
×
962
      ui->checkBoxHideOnClose->setChecked(false);
×
963
      ui->checkBoxStartMinimized->setChecked(false);
×
964
    }
965
  }
966
}
×
967

968
/**
969
 * @brief ConfigDialog::on_checkBoxUseTrayIcon_clicked enable and disable
970
 * related checkboxes.
971
 */
972
void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
×
973
  bool state = ui->checkBoxUseTrayIcon->isChecked();
×
974
  ui->checkBoxHideOnClose->setEnabled(state);
×
975
  ui->checkBoxStartMinimized->setEnabled(state);
×
976
}
×
977

978
/**
979
 * @brief ConfigDialog::closeEvent close this window.
980
 * @param event
981
 */
982
void ConfigDialog::closeEvent(QCloseEvent *event) {
×
983
  QtPassSettings::setDialogGeometry("configDialog", saveGeometry());
×
984
  if (!isMaximized()) {
×
985
    QtPassSettings::setDialogPos("configDialog", pos());
×
986
    QtPassSettings::setDialogSize("configDialog", size());
×
987
  }
988
  QtPassSettings::setDialogMaximized("configDialog", isMaximized());
×
989
  event->accept();
990
}
×
991

992
/**
993
 * @brief ConfigDialog::useGit set preference for using git.
994
 * @param useGit
995
 */
996
void ConfigDialog::useGit(bool useGit) {
×
997
  ui->checkBoxUseGit->setChecked(useGit);
×
998
  on_checkBoxUseGit_clicked();
×
999
}
×
1000

1001
/**
1002
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
1003
 * @param useOtp
1004
 */
1005
void ConfigDialog::useOtp(bool useOtp) {
×
1006
  ui->checkBoxUseOtp->setChecked(useOtp);
×
1007
}
×
1008

1009
void ConfigDialog::useGrepSearch(bool useGrepSearch) {
×
1010
  ui->checkBoxUseGrepSearch->setChecked(useGrepSearch);
×
1011
}
×
1012

1013
/**
1014
 * @brief ConfigDialog::useQrencode set preference for using qrencode plugin.
1015
 * @param useQrencode
1016
 */
1017
void ConfigDialog::useQrencode(bool useQrencode) {
×
1018
  ui->checkBoxUseQrencode->setChecked(useQrencode);
×
1019
}
×
1020

1021
/**
1022
 * @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
1023
 * checkboxes.
1024
 */
1025
void ConfigDialog::on_checkBoxUseGit_clicked() {
×
1026
  ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
×
1027
  ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
×
1028
  ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
×
1029
}
×
1030

1031
/**
1032
 * @brief ConfigDialog::on_toolButtonPwgen_clicked enable or disable related
1033
 * options in the interface.
1034
 */
1035
void ConfigDialog::on_toolButtonPwgen_clicked() {
×
1036
  QString pwgen = selectExecutable();
×
1037
  if (!pwgen.isEmpty()) {
×
1038
    ui->pwgenPath->setText(pwgen);
×
1039
    ui->checkBoxUsePwgen->setEnabled(true);
×
1040
  } else {
1041
    ui->checkBoxUsePwgen->setEnabled(false);
×
1042
    ui->checkBoxUsePwgen->setChecked(false);
×
1043
  }
1044
}
×
1045

1046
/**
1047
 * @brief ConfigDialog::setPwgenPath set pwgen executable path.
1048
 * Enable or disable related options in the interface.
1049
 * @param pwgen
1050
 */
1051
void ConfigDialog::setPwgenPath(const QString &pwgen) {
×
1052
  ui->pwgenPath->setText(pwgen);
×
1053
  if (pwgen.isEmpty()) {
×
1054
    ui->checkBoxUsePwgen->setChecked(false);
×
1055
    ui->checkBoxUsePwgen->setEnabled(false);
×
1056
  }
1057
  on_checkBoxUsePwgen_clicked();
×
1058
}
×
1059

1060
/**
1061
 * @brief ConfigDialog::on_checkBoxUsePwgen_clicked enable or disable related
1062
 * options in the interface.
1063
 */
1064
void ConfigDialog::on_checkBoxUsePwgen_clicked() {
×
1065
  if (ui->radioButtonPass->isChecked())
×
1066
    return;
1067
  bool usePwgen = ui->checkBoxUsePwgen->isChecked();
×
1068
  ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
×
1069
  ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
×
1070
  ui->checkBoxLessRandom->setEnabled(usePwgen);
×
1071
  ui->checkBoxUseSymbols->setEnabled(usePwgen);
×
1072
  ui->lineEditPasswordChars->setEnabled(!usePwgen);
×
1073
  ui->labelPasswordChars->setEnabled(!usePwgen);
×
1074
  ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
×
1075
}
1076

1077
/**
1078
 * @brief ConfigDialog::usePwgen set preference for using pwgen (can be
1079
 * overruled by empty pwgenPath).
1080
 * enable or disable related options in the interface via
1081
 * ConfigDialog::on_checkBoxUsePwgen_clicked
1082
 * @param usePwgen
1083
 */
1084
void ConfigDialog::usePwgen(bool usePwgen) {
×
1085
  if (ui->pwgenPath->text().isEmpty()) {
×
1086
    usePwgen = false;
1087
  }
1088
  ui->checkBoxUsePwgen->setChecked(usePwgen);
×
1089
  on_checkBoxUsePwgen_clicked();
×
1090
}
×
1091

1092
void ConfigDialog::setPasswordConfiguration(
×
1093
    const PasswordConfiguration &config) {
1094
  ui->spinBoxPasswordLength->setValue(config.length);
×
1095
  ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
×
1096
  if (config.selected != PasswordConfiguration::CUSTOM) {
×
1097
    ui->lineEditPasswordChars->setEnabled(false);
×
1098
  }
1099
  ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
×
1100
}
×
1101

1102
auto ConfigDialog::getPasswordConfiguration() -> PasswordConfiguration {
×
1103
  PasswordConfiguration config;
×
1104
  config.length = ui->spinBoxPasswordLength->value();
×
1105
  config.selected = static_cast<PasswordConfiguration::characterSet>(
×
1106
      ui->passwordCharTemplateSelector->currentIndex());
×
1107
  config.Characters[PasswordConfiguration::CUSTOM] =
1108
      ui->lineEditPasswordChars->text();
×
1109
  return config;
×
1110
}
×
1111

1112
/**
1113
 * @brief ConfigDialog::on_passwordCharTemplateSelector_activated sets the
1114
 * passwordChar Template
1115
 * combo box to the desired entry
1116
 * @param entry of
1117
 */
1118
void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
×
1119
  ui->lineEditPasswordChars->setText(
×
1120
      QtPassSettings::getPasswordConfiguration().Characters[index]);
×
1121
  if (index == PasswordConfiguration::CUSTOM) {
×
1122
    ui->lineEditPasswordChars->setEnabled(true);
×
1123
  } else {
1124
    ui->lineEditPasswordChars->setEnabled(false);
×
1125
  }
1126
}
×
1127

1128
/**
1129
 * @brief ConfigDialog::on_checkBoxUseTemplate_clicked enable or disable the
1130
 * template field and options.
1131
 */
1132
void ConfigDialog::on_checkBoxUseTemplate_clicked() {
×
1133
  ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
×
1134
  ui->checkBoxTemplateAllFields->setEnabled(
×
1135
      ui->checkBoxUseTemplate->isChecked());
×
1136
}
×
1137

1138
void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
×
1139
  validate(item);
×
1140
}
×
1141

1142
/**
1143
 * @brief ConfigDialog::useTemplate set preference for using templates.
1144
 * @param useTemplate
1145
 */
1146
void ConfigDialog::useTemplate(bool useTemplate) {
×
1147
  ui->checkBoxUseTemplate->setChecked(useTemplate);
×
1148
  on_checkBoxUseTemplate_clicked();
×
1149
}
×
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