18#include "ui_mainwindow.h"
22#include <QDesktopServices>
24#include <QDirIterator>
26#include <QInputDialog>
41 : QMainWindow(parent), ui(new
Ui::
MainWindow), keygen(nullptr),
46 qt_set_sequence_auto_mnemonic(
true);
50 m_qtPass =
new QtPass(
this);
53 new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q),
this, SLOT(close()));
55 new QShortcut(QKeySequence(QKeySequence::StandardKey::Copy),
this,
56 SLOT(copyPasswordFromTreeview()));
58 model.setNameFilters(QStringList() <<
"*.gpg");
59 model.setNameFilterDisables(
false);
70 QModelIndex rootDir = model.setRootPath(passStore);
71 model.fetchMore(rootDir);
73 proxyModel.setModelAndStore(&model, passStore);
74 selectionModel.reset(
new QItemSelectionModel(&proxyModel));
76 ui->treeView->setModel(&proxyModel);
77 ui->treeView->setRootIndex(proxyModel.mapFromSource(rootDir));
78 ui->treeView->setColumnHidden(1,
true);
79 ui->treeView->setColumnHidden(2,
true);
80 ui->treeView->setColumnHidden(3,
true);
81 ui->treeView->setHeaderHidden(
true);
82 ui->treeView->setIndentation(15);
83 ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
84 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
85 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
86 ui->treeView->sortByColumn(0, Qt::AscendingOrder);
87 connect(ui->treeView, &QWidget::customContextMenuRequested,
this,
88 &MainWindow::showContextMenu);
93 QFont monospace(
"Monospace");
94 monospace.setStyleHint(QFont::Monospace);
95 ui->textBrowser->setFont(monospace);
98 ui->textBrowser->setLineWrapMode(QTextBrowser::NoWrap);
100 ui->textBrowser->setOpenExternalLinks(
true);
101 ui->textBrowser->setContextMenuPolicy(Qt::CustomContextMenu);
102 connect(ui->textBrowser, &QWidget::customContextMenuRequested,
this,
103 &MainWindow::showBrowserContextMenu);
110 clearPanelTimer.setSingleShot(
true);
111 connect(&clearPanelTimer, &QTimer::timeout,
this, [
this]() { clearPanel(); });
113 searchTimer.setInterval(350);
114 searchTimer.setSingleShot(
true);
116 connect(&searchTimer, &QTimer::timeout,
this, &MainWindow::onTimeoutSearch);
118 initToolBarButtons();
121 ui->lineEdit->setClearButtonEnabled(
true);
125 QTimer::singleShot(10,
this, SLOT(focusInput()));
127 ui->lineEdit->setText(searchText);
129 if (!m_qtPass->init()) {
131 QApplication::quit();
143void MainWindow::focusInput() {
144 ui->lineEdit->selectAll();
145 ui->lineEdit->setFocus();
153 QWidget::changeEvent(event);
154 if (event->type() == QEvent::ActivationChange) {
155 if (isActiveWindow()) {
164void MainWindow::initToolBarButtons() {
165 connect(ui->actionAddPassword, &QAction::triggered,
this,
166 &MainWindow::addPassword);
167 connect(ui->actionAddFolder, &QAction::triggered,
this,
168 &MainWindow::addFolder);
169 connect(ui->actionEdit, &QAction::triggered,
this, &MainWindow::onEdit);
170 connect(ui->actionDelete, &QAction::triggered,
this, &MainWindow::onDelete);
172 connect(ui->actionUpdate, &QAction::triggered,
this, &MainWindow::onUpdate);
173 connect(ui->actionUsers, &QAction::triggered,
this, &MainWindow::onUsers);
174 connect(ui->actionConfig, &QAction::triggered,
this, &MainWindow::onConfig);
175 connect(ui->actionOtp, &QAction::triggered,
this, &MainWindow::onOtp);
177 ui->actionAddPassword->setIcon(
178 QIcon::fromTheme(
"document-new", QIcon(
":/icons/document-new.svg")));
179 ui->actionAddFolder->setIcon(
180 QIcon::fromTheme(
"folder-new", QIcon(
":/icons/folder-new.svg")));
181 ui->actionEdit->setIcon(QIcon::fromTheme(
182 "document-properties", QIcon(
":/icons/document-properties.svg")));
183 ui->actionDelete->setIcon(
184 QIcon::fromTheme(
"edit-delete", QIcon(
":/icons/edit-delete.svg")));
185 ui->actionPush->setIcon(
186 QIcon::fromTheme(
"go-up", QIcon(
":/icons/go-top.svg")));
187 ui->actionUpdate->setIcon(
188 QIcon::fromTheme(
"go-down", QIcon(
":/icons/go-bottom.svg")));
189 ui->actionUsers->setIcon(QIcon::fromTheme(
190 "x-office-address-book", QIcon(
":/icons/x-office-address-book.svg")));
191 ui->actionConfig->setIcon(QIcon::fromTheme(
192 "applications-system", QIcon(
":/icons/applications-system.svg")));
198void MainWindow::initStatusBar() {
199 ui->statusBar->showMessage(tr(
"Welcome to QtPass %1").arg(VERSION), 2000);
201 QPixmap logo = QPixmap::fromImage(QImage(
":/artwork/icon.svg"))
202 .scaledToHeight(statusBar()->height());
203 auto *logoApp =
new QLabel(statusBar());
204 logoApp->setPixmap(logo);
205 statusBar()->addPermanentWidget(logoApp);
209 return ui->treeView->currentIndex();
213 this->keygen->close();
214 this->keygen =
nullptr;
234 ui->textBrowser->setTextColor(Qt::red);
238 QString _text = text;
239 if (!ui->textBrowser->toPlainText().isEmpty()) {
240 _text = ui->textBrowser->toHtml() + _text;
242 ui->textBrowser->setHtml(_text);
244 ui->textBrowser->setText(text);
252void MainWindow::applyTextBrowserSettings() {
254 QFont monospace(
"Monospace");
255 monospace.setStyleHint(QFont::Monospace);
256 ui->textBrowser->setFont(monospace);
258 ui->textBrowser->setFont(QFont());
262 ui->textBrowser->setLineWrapMode(QTextBrowser::NoWrap);
264 ui->textBrowser->setLineWrapMode(QTextBrowser::WidgetWidth);
268void MainWindow::applyWindowFlagsSettings() {
270 Qt::WindowFlags flags = windowFlags();
271 this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
273 this->setWindowFlags(Qt::Window);
290 if (m_qtPass->isFreshStart() &&
295 if (m_qtPass->isFreshStart()) {
299 if (d->result() == QDialog::Accepted) {
300 applyTextBrowserSettings();
301 applyWindowFlagsSettings();
304 ui->treeView->setRootIndex(proxyModel.mapFromSource(
313 m_qtPass->setClipboardTimer();
315 updateGitButtonVisibility();
316 updateOtpButtonVisibility();
324 m_qtPass->setFreshStart(
false);
331void MainWindow::onUpdate(
bool block) {
332 ui->statusBar->showMessage(tr(
"Updating password-store"), 2000);
345 ui->statusBar->showMessage(tr(
"Updating password-store"), 2000);
357auto MainWindow::getFile(
const QModelIndex &index,
bool forPass) -> QString {
358 if (!index.isValid() ||
359 !model.fileInfo(proxyModel.mapToSource(index)).isFile()) {
362 QString filePath = model.filePath(proxyModel.mapToSource(index));
375 bool cleared = ui->treeView->currentIndex().flags() == Qt::NoItemFlags;
377 Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel);
379 m_qtPass->clearClippedText();
380 QString file = getFile(index,
true);
381 ui->passwordName->setText(getFile(index,
true));
382 if (!file.isEmpty() && !cleared) {
386 ui->actionEdit->setEnabled(
false);
387 ui->actionDelete->setEnabled(
true);
396void MainWindow::on_treeView_doubleClicked(
const QModelIndex &index) {
397 QFileInfo fileOrFolder =
398 model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
400 if (fileOrFolder.isFile()) {
401 editPassword(getFile(index,
true));
410 m_qtPass->clearClipboard();
411 ui->treeView->clearSelection();
412 ui->actionEdit->setEnabled(
false);
413 ui->actionDelete->setEnabled(
false);
414 ui->passwordName->setText(
"");
419 clearTemplateWidgets();
420 ui->textBrowser->clear();
422 clearPanelTimer.stop();
442 QString output = p_output;
446 m_qtPass->setClippedText(password, p_output);
449 clearTemplateWidgets();
453 output =
"***" + tr(
"Content hidden") +
"***";
455 if (!password.isEmpty()) {
457 addToGridLayout(0, tr(
"Password"), password);
461 for (
int j = 0; j < namedValues.length(); ++j) {
463 addToGridLayout(j + 1, nv.
name, nv.
value);
465 if (ui->gridLayout->count() == 0) {
466 ui->verticalLayoutPassword->setSpacing(0);
468 ui->verticalLayoutPassword->setSpacing(6);
475 clearPanelTimer.start();
493 if (!p_output.isEmpty()) {
494 addToGridLayout(ui->gridLayout->count() + 1, tr(
"OTP Code"), p_output);
495 m_qtPass->copyTextToClipboard(p_output);
498 flashText(tr(
"No OTP code found in this password entry"),
true);
501 clearPanelTimer.start();
509void MainWindow::clearPanel(
bool notify) {
510 while (ui->gridLayout->count() > 0) {
511 QLayoutItem *item = ui->gridLayout->takeAt(0);
512 delete item->widget();
516 QString output =
"***" + tr(
"Password and Content hidden") +
"***";
517 ui->textBrowser->setHtml(output);
519 ui->textBrowser->setHtml(
"");
529 ui->treeView->setEnabled(state);
530 ui->lineEdit->setEnabled(state);
531 ui->lineEdit->installEventFilter(
this);
532 ui->actionAddPassword->setEnabled(state);
533 ui->actionAddFolder->setEnabled(state);
534 ui->actionUsers->setEnabled(state);
535 ui->actionConfig->setEnabled(state);
537 state &= ui->treeView->currentIndex().isValid();
538 ui->actionDelete->setEnabled(state);
539 ui->actionEdit->setEnabled(state);
540 updateGitButtonVisibility();
541 updateOtpButtonVisibility();
555 restoreGeometry(geometry);
557 restoreState(savestate);
567 Qt::WindowFlags flags = windowFlags();
568 setWindowFlags(flags | Qt::WindowStaysOnTopHint);
576 QTimer::singleShot(10,
this, SLOT(hide()));
586void MainWindow::onConfig() {
config(); }
593void MainWindow::on_lineEdit_textChanged(
const QString &arg1) {
594 ui->statusBar->showMessage(tr(
"Looking for: %1").arg(arg1), 1000);
595 ui->treeView->expandAll();
597 ui->passwordName->setText(
"");
598 ui->actionEdit->setEnabled(
false);
599 ui->actionDelete->setEnabled(
false);
607void MainWindow::onTimeoutSearch() {
608 QString query = ui->lineEdit->text();
610 if (query.isEmpty()) {
611 ui->treeView->collapseAll();
615 query.replace(QStringLiteral(
" "),
".*");
616 QRegularExpression regExp(query, QRegularExpression::CaseInsensitiveOption);
617 proxyModel.setFilterRegularExpression(regExp);
618 ui->treeView->setRootIndex(proxyModel.mapFromSource(
621 if (proxyModel.rowCount() > 0 && !query.isEmpty()) {
624 ui->actionEdit->setEnabled(
false);
625 ui->actionDelete->setEnabled(
false);
634void MainWindow::on_lineEdit_returnPressed() {
636 dbg() <<
"on_lineEdit_returnPressed" << proxyModel.rowCount();
639 if (proxyModel.rowCount() > 0) {
649void MainWindow::selectFirstFile() {
650 QModelIndex index = proxyModel.mapFromSource(
652 index = firstFile(index);
653 ui->treeView->setCurrentIndex(index);
661auto MainWindow::firstFile(QModelIndex parentIndex) -> QModelIndex {
662 QModelIndex index = parentIndex;
663 int numRows = proxyModel.rowCount(parentIndex);
664 for (
int row = 0; row < numRows; ++row) {
665 index = proxyModel.index(row, 0, parentIndex);
666 if (model.fileInfo(proxyModel.mapToSource(index)).isFile()) {
669 if (proxyModel.hasChildren(index)) {
670 return firstFile(index);
681void MainWindow::setPassword(
const QString &file,
bool isNew) {
682 PasswordDialog d(file, isNew,
this);
685 ui->treeView->setFocus();
693void MainWindow::addPassword() {
696 Util::getDir(ui->treeView->currentIndex(),
true, model, proxyModel);
698 QInputDialog::getText(
this, tr(
"New file"),
699 tr(
"New password file: \n(Will be placed in %1 )")
702 true, model, proxyModel)),
703 QLineEdit::Normal,
"", &ok);
704 if (!ok || file.isEmpty()) {
715void MainWindow::onDelete() {
716 QModelIndex currentIndex = ui->treeView->currentIndex();
717 if (!currentIndex.isValid()) {
724 QFileInfo fileOrFolder =
725 model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
729 if (fileOrFolder.isFile()) {
730 file = getFile(ui->treeView->currentIndex(),
true);
732 file =
Util::getDir(ui->treeView->currentIndex(),
true, model, proxyModel);
736 QString dirMessage = tr(
" and the whole content?");
738 QDirIterator it(model.rootPath() + QDir::separator() + file,
739 QDirIterator::Subdirectories);
741 while (it.hasNext() && okDir) {
743 if (QFileInfo(it.filePath()).isFile()) {
744 if (QFileInfo(it.filePath()).suffix() !=
"gpg") {
746 dirMessage = tr(
" and the whole content? <br><strong>Attention: "
747 "there are unexpected files in the given folder, "
748 "check them before continue.</strong>");
754 if (QMessageBox::question(
755 this, isDir ? tr(
"Delete folder?") : tr(
"Delete password?"),
756 tr(
"Are you sure you want to delete %1%2?")
757 .arg(QDir::separator() + file, isDir ? dirMessage :
"?"),
758 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
768void MainWindow::onOtp() {
769 QString file = getFile(ui->treeView->currentIndex(),
true);
770 if (!file.isEmpty()) {
776 flashText(tr(
"No password selected for OTP generation"),
true);
783void MainWindow::onEdit() {
784 QString file = getFile(ui->treeView->currentIndex(),
true);
793 if (!dir.isEmpty()) {
804void MainWindow::onUsers() {
807 ?
Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel)
812 ui->treeView->setFocus();
821 if (message.isEmpty()) {
824 ui->treeView->expandAll();
825 ui->lineEdit->setText(message);
826 on_lineEdit_returnPressed();
838 keygen = keygenWindow;
846void MainWindow::updateProfileBox() {
847 QHash<QString, QHash<QString, QString>> profiles =
850 if (profiles.isEmpty()) {
851 ui->profileWidget->hide();
853 ui->profileWidget->show();
854 ui->profileBox->setEnabled(profiles.size() > 1);
855 ui->profileBox->clear();
856 QHashIterator<QString, QHash<QString, QString>> i(profiles);
857 while (i.hasNext()) {
859 if (!i.key().isEmpty()) {
860 ui->profileBox->addItem(i.key());
863 ui->profileBox->model()->sort(0);
867 ui->profileBox->setCurrentIndex(index);
876#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
877void MainWindow::on_profileBox_currentIndexChanged(QString name) {
890void MainWindow::on_profileBox_currentTextChanged(
const QString &name) {
896 ui->lineEdit->clear();
904 ui->statusBar->showMessage(tr(
"Profile changed to %1").arg(name), 2000);
908 ui->treeView->selectionModel()->clear();
909 ui->treeView->setRootIndex(proxyModel.mapFromSource(
912 ui->actionEdit->setEnabled(
false);
913 ui->actionDelete->setEnabled(
false);
921void MainWindow::initTrayIcon() {
922 this->tray =
new TrayIcon(
this);
925 if (tray ==
nullptr) {
927 dbg() <<
"Allocating tray icon failed.";
931 if (!tray->getIsAllocated()) {
939void MainWindow::destroyTrayIcon() {
953 m_qtPass->clearClipboard();
958 if (!isMaximized()) {
974 if (obj == ui->lineEdit && event->type() == QEvent::KeyPress) {
975 auto *key =
dynamic_cast<QKeyEvent *
>(event);
976 if (key !=
nullptr && key->key() == Qt::Key_Down) {
977 ui->treeView->setFocus();
980 return QObject::eventFilter(obj, event);
988 switch (event->key()) {
994 if (proxyModel.rowCount() > 0) {
999 ui->lineEdit->clear();
1011void MainWindow::showContextMenu(
const QPoint &pos) {
1012 QModelIndex index = ui->treeView->indexAt(pos);
1013 bool selected =
true;
1014 if (!index.isValid()) {
1015 ui->treeView->clearSelection();
1016 ui->actionDelete->setEnabled(
false);
1017 ui->actionEdit->setEnabled(
false);
1022 ui->treeView->setCurrentIndex(index);
1024 QPoint globalPos = ui->treeView->viewport()->mapToGlobal(pos);
1026 QFileInfo fileOrFolder =
1027 model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
1030 if (!selected || fileOrFolder.isDir()) {
1031 QAction *openFolder =
1032 contextMenu.addAction(tr(
"Open folder with file manager"));
1033 QAction *addFolder = contextMenu.addAction(tr(
"Add folder"));
1034 QAction *addPassword = contextMenu.addAction(tr(
"Add password"));
1035 QAction *users = contextMenu.addAction(tr(
"Users"));
1036 connect(openFolder, &QAction::triggered,
this, &MainWindow::openFolder);
1037 connect(addFolder, &QAction::triggered,
this, &MainWindow::addFolder);
1038 connect(addPassword, &QAction::triggered,
this, &MainWindow::addPassword);
1039 connect(users, &QAction::triggered,
this, &MainWindow::onUsers);
1040 }
else if (fileOrFolder.isFile()) {
1041 QAction *edit = contextMenu.addAction(tr(
"Edit"));
1042 connect(edit, &QAction::triggered,
this, &MainWindow::onEdit);
1045 contextMenu.addSeparator();
1046 if (fileOrFolder.isDir()) {
1047 QAction *renameFolder = contextMenu.addAction(tr(
"Rename folder"));
1048 connect(renameFolder, &QAction::triggered,
this,
1049 &MainWindow::renameFolder);
1050 }
else if (fileOrFolder.isFile()) {
1051 QAction *renamePassword = contextMenu.addAction(tr(
"Rename password"));
1052 connect(renamePassword, &QAction::triggered,
this,
1053 &MainWindow::renamePassword);
1055 QAction *deleteItem = contextMenu.addAction(tr(
"Delete"));
1056 connect(deleteItem, &QAction::triggered,
this, &MainWindow::onDelete);
1058 contextMenu.exec(globalPos);
1066void MainWindow::showBrowserContextMenu(
const QPoint &pos) {
1067 QMenu *contextMenu = ui->textBrowser->createStandardContextMenu(pos);
1068 QPoint globalPos = ui->textBrowser->viewport()->mapToGlobal(pos);
1070 contextMenu->exec(globalPos);
1077void MainWindow::openFolder() {
1079 Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel);
1081 QString path = QDir::toNativeSeparators(dir);
1082 QDesktopServices::openUrl(QUrl::fromLocalFile(path));
1088void MainWindow::addFolder() {
1091 Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel);
1093 QInputDialog::getText(
this, tr(
"New file"),
1094 tr(
"New Folder: \n(Will be placed in %1 )")
1097 true, model, proxyModel)),
1098 QLineEdit::Normal,
"", &ok);
1099 if (!ok || newdir.isEmpty()) {
1102 newdir.prepend(dir);
1103 if (!QDir().mkdir(newdir)) {
1104 QMessageBox::warning(
this, tr(
"Error"),
1105 tr(
"Failed to create folder: %1").arg(newdir));
1109 QString gpgIdFile = newdir +
"/.gpg-id";
1110 QFile gpgId(gpgIdFile);
1111 if (!gpgId.open(QIODevice::WriteOnly)) {
1112 QMessageBox::warning(
1114 tr(
"Failed to create .gpg-id file in: %1").arg(newdir));
1118 for (
const UserInfo &user : users) {
1120 gpgId.write((user.key_id +
"\n").toUtf8());
1130void MainWindow::renameFolder() {
1132 QString srcDir = QDir::cleanPath(
1133 Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel));
1134 QString srcDirName = QDir(srcDir).dirName();
1136 QInputDialog::getText(
this, tr(
"Rename file"), tr(
"Rename Folder To: "),
1137 QLineEdit::Normal, srcDirName, &ok);
1138 if (!ok || newName.isEmpty()) {
1141 QString destDir = srcDir;
1142 destDir.replace(srcDir.lastIndexOf(srcDirName), srcDirName.length(), newName);
1150void MainWindow::editPassword(
const QString &file) {
1151 if (!file.isEmpty()) {
1155 setPassword(file,
false);
1162void MainWindow::renamePassword() {
1164 QString file = getFile(ui->treeView->currentIndex(),
false);
1165 QString filePath = QFileInfo(file).path();
1166 QString fileName = QFileInfo(file).fileName();
1167 if (fileName.endsWith(
".gpg", Qt::CaseInsensitive)) {
1172 QInputDialog::getText(
this, tr(
"Rename file"), tr(
"Rename File To: "),
1173 QLineEdit::Normal, fileName, &ok);
1174 if (!ok || newName.isEmpty()) {
1177 QString newFile = QDir(filePath).filePath(newName);
1185void MainWindow::clearTemplateWidgets() {
1186 while (ui->gridLayout->count() > 0) {
1187 QLayoutItem *item = ui->gridLayout->takeAt(0);
1188 delete item->widget();
1191 ui->verticalLayoutPassword->setSpacing(0);
1202void MainWindow::copyPasswordFromTreeview() {
1203 QFileInfo fileOrFolder =
1204 model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
1206 if (fileOrFolder.isFile()) {
1207 QString file = getFile(ui->treeView->currentIndex(),
true);
1210 &MainWindow::passwordFromFileToClipboard);
1212 &MainWindow::passwordFromFileToClipboard);
1217void MainWindow::passwordFromFileToClipboard(
const QString &text) {
1218 QStringList tokens = text.split(
'\n');
1219 m_qtPass->copyTextToClipboard(tokens[0]);
1228void MainWindow::addToGridLayout(
int position,
const QString &field,
1229 const QString &value) {
1230 QString trimmedField = field.trimmed();
1231 QString trimmedValue = value.trimmed();
1233 const QString buttonStyle =
1234 "border-style: none; background: transparent; padding: 0; margin: 0; "
1235 "icon-size: 16px; color: inherit;";
1238 auto *frame =
new QFrame();
1239 QLayout *ly =
new QHBoxLayout();
1240 ly->setContentsMargins(5, 2, 2, 2);
1242 frame->setLayout(ly);
1244 auto *fieldLabel =
new QPushButtonWithClipboard(trimmedValue,
this);
1248 fieldLabel->setStyleSheet(buttonStyle);
1249 frame->layout()->addWidget(fieldLabel);
1253 auto *qrbutton =
new QPushButtonAsQRCode(trimmedValue,
this);
1256 qrbutton->setStyleSheet(buttonStyle);
1257 frame->layout()->addWidget(qrbutton);
1261 const QString lineStyle =
1263 ?
"border-style: none; background: transparent; font-family: "
1265 :
"border-style: none; background: transparent;";
1268 auto *line =
new QLineEdit();
1269 line->setObjectName(trimmedField);
1270 line->setText(trimmedValue);
1271 line->setReadOnly(
true);
1272 line->setStyleSheet(lineStyle);
1273 line->setContentsMargins(0, 0, 0, 0);
1274 line->setEchoMode(QLineEdit::Password);
1275 auto *showButton =
new QPushButtonShowPassword(line,
this);
1276 showButton->setStyleSheet(buttonStyle);
1277 showButton->setContentsMargins(0, 0, 0, 0);
1278 frame->layout()->addWidget(showButton);
1279 frame->layout()->addWidget(line);
1281 auto *line =
new QTextBrowser();
1282 line->setOpenExternalLinks(
true);
1283 line->setOpenLinks(
true);
1284 line->setMaximumHeight(26);
1285 line->setMinimumHeight(26);
1286 line->setSizePolicy(
1287 QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
1288 line->setObjectName(trimmedField);
1290 line->setText(trimmedValue);
1291 line->setReadOnly(true);
1292 line->setStyleSheet(lineStyle);
1293 line->setContentsMargins(0, 0, 0, 0);
1294 frame->layout()->addWidget(line);
1297 frame->setStyleSheet(
1298 ".QFrame{border: 1px solid lightgrey; border-radius: 5px;}");
1301 ui->gridLayout->addWidget(
new QLabel(trimmedField), position, 0);
1302 ui->gridLayout->addWidget(frame, position, 1);
1312 ui->statusBar->showMessage(msg, timeout);
1320 ui->treeView->setDisabled(
true);
1328void MainWindow::updateGitButtonVisibility() {
1332 enableGitButtons(
false);
1334 enableGitButtons(
true);
1338void MainWindow::updateOtpButtonVisibility() {
1339#if defined(Q_OS_WIN) || defined(__APPLE__)
1340 ui->actionOtp->setVisible(
false);
1343 ui->actionOtp->setEnabled(
false);
1345 ui->actionOtp->setEnabled(
true);
1349void MainWindow::enableGitButtons(
const bool &state) {
1351 ui->actionPush->setEnabled(state);
1352 ui->actionUpdate->setEnabled(state);
1361 QMessageBox::critical(
this, title, msg);
The ConfigDialog handles the configuration interface.
void emptyClicked()
emptyClicked event
auto getNamedValues() const -> NamedValues
Gets named value pairs from the parsed file.
auto getRemainingDataForDisplay() const -> QString
Gets remaining data for display (excludes hidden fields like OTP).
auto getPassword() const -> QString
Gets the password from the parsed file.
static auto parse(const QString &fileContent, const QStringList &templateFields, bool allFields) -> FileContent
parse parses the given fileContent in a FileContent object. The password is accessible through getPas...
void startReencryptPath()
MainWindow::startReencryptPath disable ui elements and treeview.
void closeEvent(QCloseEvent *event) override
MainWindow::closeEvent hide or quit.
void passShowHandler(const QString &)
void endReencryptPath()
MainWindow::endReencryptPath re-enable ui elements.
void executeWrapperStarted()
void generateKeyPair(const QString &, QDialog *)
MainWindow::generateKeyPair internal gpg keypair generator . .
void changeEvent(QEvent *event) override
MainWindow::changeEvent sets focus to the search box.
void critical(const QString &, const QString &)
MainWindow::critical critical message popup wrapper.
void messageAvailable(const QString &message)
MainWindow::messageAvailable we have some text/message/search to do.
MainWindow(const QString &searchText=QString(), QWidget *parent=nullptr)
MainWindow::MainWindow handles all of the main functionality and also the main window.
void keyPressEvent(QKeyEvent *event) override
MainWindow::keyPressEvent did anyone press return, enter or escape?
void onPush()
MainWindow::onPush do a git push.
void showStatusMessage(const QString &msg, int timeout=2000)
Displays message in status bar.
void passOtpHandler(const QString &)
void passShowHandlerFinished(const QString &output)
void generateGPGKeyPair(const QString &batch)
auto eventFilter(QObject *obj, QEvent *event) -> bool override
MainWindow::eventFilter filter out some events and focus the treeview.
void flashText(const QString &text, const bool isError, const bool isHtml=false)
void userDialog(const QString &="")
MainWindow::userDialog see MainWindow::onUsers().
void setUiElementsEnabled(bool state)
MainWindow::setUiElementsEnabled enable or disable the relevant UI elements.
auto getCurrentTreeViewIndex() -> QModelIndex
void deselect()
MainWindow::deselect clear the selection, password and copy buffer.
void on_treeView_clicked(const QModelIndex &index)
MainWindow::on_treeView_clicked read the selected password file.
The NamedValues class is mostly a list of NamedValue but also has a method to take a specific NamedVa...
void finishedShow(const QString &)
Emitted when show finishes.
void copyTextToClipboard(const QString &text)
MainWindow::copyTextToClipboard copies text to your clipboard.
void showTextAsQRCode(const QString &text)
displays the text as qrcode
static void setMaximized(const bool &maximized)
Save maximized state.
static auto isStartMinimized(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether application should start minimized.
static auto isUseOtp(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether OTP support is enabled.
static void setProfile(const QString &profile)
Save active profile name.
static auto isNoLineWrapping(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to disable line wrapping.
static void setPassStore(const QString &passStore)
Save password store path.
static auto isHideContent(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to hide content (password + username).
static auto getSize(const QSize &defaultValue=QVariant().toSize()) -> QSize
Get saved window size.
static auto getPass() -> Pass *
Get currently active pass backend instance.
static auto isUseQrencode(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether qrencode support is enabled.
static auto isUseAutoclearPanel(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use panel autoclear.
static auto isAutoPull(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether automatic pull is enabled.
static auto isUseGit(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether Git integration is enabled.
static auto getClipBoardType(const Enums::clipBoardType &defaultValue=Enums::CLIPBOARD_NEVER) -> Enums::clipBoardType
Get clipboard type as enum.
static auto isTemplateAllFields(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether template applies to all fields.
static void setPassSigningKey(const QString &passSigningKey)
Save GPG signing key.
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto isUseTemplate(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether template usage is enabled.
static auto isUseTrayIcon(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether tray icon support is enabled.
static auto isAddGPGId(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to auto-add GPG ID when receiving files.
static void setPos(const QPoint &pos)
Save window position.
static auto getPassTemplate(const QString &defaultValue=QVariant().toString()) -> QString
Get pass entry template.
static auto isMaximized(const bool &defaultValue=QVariant().toBool()) -> bool
Get maximized state.
static auto getProfile(const QString &defaultValue=QVariant().toString()) -> QString
Get active profile name.
static auto isUseMonospace(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use monospace font.
static void setUsePass(const bool &usePass)
Save use pass setting.
static auto getAutoclearPanelSeconds(const int &defaultValue=QVariant().toInt()) -> int
Get panel autoclear delay in seconds.
static void setSavestate(const QByteArray &saveState)
Save window state.
static auto isAlwaysOnTop(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether main window should stay always on top.
static auto isHidePassword(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to hide password in UI.
static auto getPassExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get pass executable path.
static auto getPos(const QPoint &defaultValue=QVariant().toPoint()) -> QPoint
Get saved window position.
static auto isHideOnClose(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether closing the window hides the application.
static auto getProfiles() -> QHash< QString, QHash< QString, QString > >
Get all configured profiles.
static void setSize(const QSize &size)
Save window size.
static void setGeometry(const QByteArray &geometry)
Save window geometry.
static auto getGitExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get git executable path.
static auto getGeometry(const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved window geometry.
static auto isDisplayAsIs(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to display password as-is (no modification).
static auto getSavestate(const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved window state.
Dialog for selecting GPG recipients for password encryption.
static auto protocolRegex() -> const QRegularExpression &
Returns a regex to match URL protocols.
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
static auto findPasswordStore() -> QString
Locate the password store directory.
static auto getDir(const QModelIndex &index, bool forPass, const QFileSystemModel &model, const StoreModel &storeModel) -> QString
Get the selected folder path, either relative to the configured pass store or absolute.
static auto configIsValid() -> bool
Verify that the required configuration is complete.
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.
constexpr int MS_PER_SECOND