Displays the given text in the main window text browser, optionally marking it as an error and/or rendering it as HTML.
Displays the given text in the main window text browser, optionally marking it as an error and/or rendering it as HTML.
#ifdef QT_DEBUG
#endif
#include "ui_mainwindow.h"
#include <QCloseEvent>
#include <QDesktopServices>
#include <QDialog>
#include <QDirIterator>
#include <QFileInfo>
#include <QInputDialog>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QShortcut>
#include <QTimer>
#include <utility>
: QMainWindow(parent), ui(new
Ui::
MainWindow), keygen(nullptr),
tray(nullptr) {
#ifdef __APPLE__
qt_set_sequence_auto_mnemonic(true);
#endif
ui->setupUi(this);
new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this, SLOT(close()));
new QShortcut(QKeySequence(QKeySequence::StandardKey::Copy), this,
SLOT(copyPasswordFromTreeview()));
model.setNameFilters(QStringList() << "*.gpg");
model.setNameFilterDisables(false);
QModelIndex rootDir = model.setRootPath(passStore);
model.fetchMore(rootDir);
proxyModel.setModelAndStore(&model, passStore);
selectionModel.reset(new QItemSelectionModel(&proxyModel));
ui->treeView->setModel(&proxyModel);
ui->treeView->setRootIndex(proxyModel.mapFromSource(rootDir));
ui->treeView->setColumnHidden(1, true);
ui->treeView->setColumnHidden(2, true);
ui->treeView->setColumnHidden(3, true);
ui->treeView->setHeaderHidden(true);
ui->treeView->setIndentation(15);
ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
ui->treeView->sortByColumn(0, Qt::AscendingOrder);
connect(ui->treeView, &QWidget::customContextMenuRequested, this,
&MainWindow::showContextMenu);
QFont monospace("Monospace");
monospace.setStyleHint(QFont::Monospace);
ui->textBrowser->setFont(monospace);
}
ui->textBrowser->setLineWrapMode(QTextBrowser::NoWrap);
}
ui->textBrowser->setOpenExternalLinks(true);
ui->textBrowser->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->textBrowser, &QWidget::customContextMenuRequested, this,
&MainWindow::showBrowserContextMenu);
updateProfileBox();
clearPanelTimer.setSingleShot(true);
connect(&clearPanelTimer, &QTimer::timeout, this, [this]() { clearPanel(); });
searchTimer.setInterval(350);
searchTimer.setSingleShot(true);
connect(&searchTimer, &QTimer::timeout, this, &MainWindow::onTimeoutSearch);
initToolBarButtons();
initStatusBar();
ui->lineEdit->setClearButtonEnabled(true);
setUiElementsEnabled(true);
QTimer::singleShot(10, this, SLOT(focusInput()));
ui->lineEdit->setText(searchText);
if (!m_qtPass->init()) {
QApplication::quit();
}
}
void MainWindow::focusInput() {
ui->lineEdit->selectAll();
ui->lineEdit->setFocus();
}
QWidget::changeEvent(event);
if (event->type() == QEvent::ActivationChange) {
if (isActiveWindow()) {
focusInput();
}
}
}
void MainWindow::initToolBarButtons() {
connect(ui->actionAddPassword, &QAction::triggered, this,
&MainWindow::addPassword);
connect(ui->actionAddFolder, &QAction::triggered, this,
&MainWindow::addFolder);
connect(ui->actionEdit, &QAction::triggered, this, &MainWindow::onEdit);
connect(ui->actionDelete, &QAction::triggered, this, &MainWindow::onDelete);
connect(ui->actionUpdate, &QAction::triggered, this, &MainWindow::onUpdate);
connect(ui->actionUsers, &QAction::triggered, this, &MainWindow::onUsers);
connect(ui->actionConfig, &QAction::triggered, this, &MainWindow::onConfig);
connect(ui->actionOtp, &QAction::triggered, this, &MainWindow::onOtp);
ui->actionAddPassword->setIcon(
QIcon::fromTheme("document-new", QIcon(":/icons/document-new.svg")));
ui->actionAddFolder->setIcon(
QIcon::fromTheme("folder-new", QIcon(":/icons/folder-new.svg")));
ui->actionEdit->setIcon(QIcon::fromTheme(
"document-properties", QIcon(":/icons/document-properties.svg")));
ui->actionDelete->setIcon(
QIcon::fromTheme("edit-delete", QIcon(":/icons/edit-delete.svg")));
ui->actionPush->setIcon(
QIcon::fromTheme("go-up", QIcon(":/icons/go-top.svg")));
ui->actionUpdate->setIcon(
QIcon::fromTheme("go-down", QIcon(":/icons/go-bottom.svg")));
ui->actionUsers->setIcon(QIcon::fromTheme(
"x-office-address-book", QIcon(":/icons/x-office-address-book.svg")));
ui->actionConfig->setIcon(QIcon::fromTheme(
"applications-system", QIcon(":/icons/applications-system.svg")));
}
void MainWindow::initStatusBar() {
ui->statusBar->showMessage(tr("Welcome to QtPass %1").arg(VERSION), 2000);
QPixmap logo = QPixmap::fromImage(QImage(":/artwork/icon.svg"))
.scaledToHeight(statusBar()->height());
auto *logoApp = new QLabel(statusBar());
logoApp->setPixmap(logo);
statusBar()->addPermanentWidget(logoApp);
}
return ui->treeView->currentIndex();
}
this->keygen->close();
this->keygen = nullptr;
}
const bool isHtml) {
if (isError) {
ui->textBrowser->setTextColor(Qt::red);
}
if (isHtml) {
QString _text = text;
if (!ui->textBrowser->toPlainText().isEmpty()) {
_text = ui->textBrowser->toHtml() + _text;
}
ui->textBrowser->setHtml(_text);
} else {
ui->textBrowser->setText(text);
}
}
void MainWindow::applyTextBrowserSettings() {
QFont monospace("Monospace");
monospace.setStyleHint(QFont::Monospace);
ui->textBrowser->setFont(monospace);
} else {
ui->textBrowser->setFont(QFont());
}
ui->textBrowser->setLineWrapMode(QTextBrowser::NoWrap);
} else {
ui->textBrowser->setLineWrapMode(QTextBrowser::WidgetWidth);
}
}
void MainWindow::applyWindowFlagsSettings() {
Qt::WindowFlags flags = windowFlags();
this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
} else {
this->setWindowFlags(Qt::Window);
}
this->show();
}
QScopedPointer<ConfigDialog> d(new ConfigDialog(this));
d->setModal(true);
if (m_qtPass->isFreshStart() &&
}
if (m_qtPass->isFreshStart()) {
d->wizard();
}
if (d->exec()) {
if (d->result() == QDialog::Accepted) {
applyTextBrowserSettings();
applyWindowFlagsSettings();
updateProfileBox();
ui->treeView->setRootIndex(proxyModel.mapFromSource(
}
m_qtPass->setClipboardTimer();
updateGitButtonVisibility();
updateOtpButtonVisibility();
initTrayIcon();
destroyTrayIcon();
}
}
m_qtPass->setFreshStart(false);
}
}
void MainWindow::onUpdate(bool block) {
ui->statusBar->showMessage(tr("Updating password-store"), 2000);
if (block) {
} else {
}
}
ui->statusBar->showMessage(tr("Updating password-store"), 2000);
}
}
auto MainWindow::getFile(const QModelIndex &index, bool forPass) -> QString {
if (!index.isValid() ||
!model.fileInfo(proxyModel.mapToSource(index)).isFile()) {
return {};
}
QString filePath = model.filePath(proxyModel.mapToSource(index));
if (forPass) {
}
return filePath;
}
bool cleared = ui->treeView->currentIndex().flags() == Qt::NoItemFlags;
currentDir =
Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel);
m_qtPass->clearClippedText();
QString file = getFile(index, true);
ui->passwordName->setText(getFile(index, true));
if (!file.isEmpty() && !cleared) {
} else {
clearPanel(false);
ui->actionEdit->setEnabled(false);
ui->actionDelete->setEnabled(true);
}
}
void MainWindow::on_treeView_doubleClicked(const QModelIndex &index) {
QFileInfo fileOrFolder =
model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
if (fileOrFolder.isFile()) {
editPassword(getFile(index, true));
}
}
currentDir = "";
m_qtPass->clearClipboard();
ui->treeView->clearSelection();
ui->actionEdit->setEnabled(false);
ui->actionDelete->setEnabled(false);
ui->passwordName->setText("");
clearPanel(false);
}
clearTemplateWidgets();
ui->textBrowser->clear();
clearPanelTimer.stop();
}
: QStringList();
bool allFields =
QString output = p_output;
m_qtPass->setClippedText(password, p_output);
clearTemplateWidgets();
output = "***" + tr("Content hidden") + "***";
if (!password.isEmpty()) {
addToGridLayout(0, tr("Password"), password);
}
for (int j = 0; j < namedValues.length(); ++j) {
const NamedValue &nv = namedValues.at(j);
}
if (ui->gridLayout->count() == 0) {
ui->verticalLayoutPassword->setSpacing(0);
} else {
ui->verticalLayoutPassword->setSpacing(6);
}
}
clearPanelTimer.start();
}
}
if (!p_output.isEmpty()) {
addToGridLayout(ui->gridLayout->count() + 1, tr("OTP Code"), p_output);
m_qtPass->copyTextToClipboard(p_output);
} else {
flashText(tr(
"No OTP code found in this password entry"),
true);
}
clearPanelTimer.start();
}
}
void MainWindow::clearPanel(bool notify) {
while (ui->gridLayout->count() > 0) {
QLayoutItem *item = ui->gridLayout->takeAt(0);
delete item->widget();
delete item;
}
if (notify) {
QString output = "***" + tr("Password and Content hidden") + "***";
ui->textBrowser->setHtml(output);
} else {
ui->textBrowser->setHtml("");
}
}
ui->treeView->setEnabled(state);
ui->lineEdit->setEnabled(state);
ui->lineEdit->installEventFilter(this);
ui->actionAddPassword->setEnabled(state);
ui->actionAddFolder->setEnabled(state);
ui->actionUsers->setEnabled(state);
ui->actionConfig->setEnabled(state);
state &= ui->treeView->currentIndex().isValid();
ui->actionDelete->setEnabled(state);
ui->actionEdit->setEnabled(state);
updateGitButtonVisibility();
updateOtpButtonVisibility();
}
restoreGeometry(geometry);
restoreState(savestate);
move(position);
resize(newSize);
showMaximized();
}
Qt::WindowFlags flags = windowFlags();
setWindowFlags(flags | Qt::WindowStaysOnTopHint);
show();
}
initTrayIcon();
QTimer::singleShot(10, this, SLOT(hide()));
}
destroyTrayIcon();
}
}
void MainWindow::onConfig() {
config(); }
void MainWindow::on_lineEdit_textChanged(const QString &arg1) {
ui->statusBar->showMessage(tr("Looking for: %1").arg(arg1), 1000);
ui->treeView->expandAll();
clearPanel(false);
ui->passwordName->setText("");
ui->actionEdit->setEnabled(false);
ui->actionDelete->setEnabled(false);
searchTimer.start();
}
void MainWindow::onTimeoutSearch() {
QString query = ui->lineEdit->text();
if (query.isEmpty()) {
ui->treeView->collapseAll();
}
query.replace(QStringLiteral(" "), ".*");
QRegularExpression regExp(query, QRegularExpression::CaseInsensitiveOption);
proxyModel.setFilterRegularExpression(regExp);
ui->treeView->setRootIndex(proxyModel.mapFromSource(
if (proxyModel.rowCount() > 0 && !query.isEmpty()) {
selectFirstFile();
} else {
ui->actionEdit->setEnabled(false);
ui->actionDelete->setEnabled(false);
}
}
void MainWindow::on_lineEdit_returnPressed() {
#ifdef QT_DEBUG
dbg() <<
"on_lineEdit_returnPressed" << proxyModel.rowCount();
#endif
if (proxyModel.rowCount() > 0) {
selectFirstFile();
}
}
void MainWindow::selectFirstFile() {
QModelIndex index = proxyModel.mapFromSource(
index = firstFile(index);
ui->treeView->setCurrentIndex(index);
}
auto MainWindow::firstFile(QModelIndex parentIndex) -> QModelIndex {
QModelIndex index = parentIndex;
int numRows = proxyModel.rowCount(parentIndex);
for (int row = 0; row < numRows; ++row) {
index = proxyModel.index(row, 0, parentIndex);
if (model.fileInfo(proxyModel.mapToSource(index)).isFile()) {
return index;
}
if (proxyModel.hasChildren(index)) {
return firstFile(index);
}
}
return index;
}
void MainWindow::setPassword(const QString &file, bool isNew) {
PasswordDialog d(file, isNew, this);
if (!d.exec()) {
ui->treeView->setFocus();
}
}
void MainWindow::addPassword() {
bool ok;
QString dir =
Util::getDir(ui->treeView->currentIndex(),
true, model, proxyModel);
QString file =
QInputDialog::getText(this, tr("New file"),
tr("New password file: \n(Will be placed in %1 )")
true, model, proxyModel)),
QLineEdit::Normal, "", &ok);
if (!ok || file.isEmpty()) {
return;
}
file = dir + file;
setPassword(file);
}
void MainWindow::onDelete() {
QModelIndex currentIndex = ui->treeView->currentIndex();
if (!currentIndex.isValid()) {
return;
}
QFileInfo fileOrFolder =
model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
QString file = "";
bool isDir = false;
if (fileOrFolder.isFile()) {
file = getFile(ui->treeView->currentIndex(), true);
} else {
file =
Util::getDir(ui->treeView->currentIndex(),
true, model, proxyModel);
isDir = true;
}
QString dirMessage = tr(" and the whole content?");
if (isDir) {
QDirIterator it(model.rootPath() + QDir::separator() + file,
QDirIterator::Subdirectories);
bool okDir = true;
while (it.hasNext() && okDir) {
it.next();
if (QFileInfo(it.filePath()).isFile()) {
if (QFileInfo(it.filePath()).suffix() != "gpg") {
okDir = false;
dirMessage = tr(" and the whole content? <br><strong>Attention: "
"there are unexpected files in the given folder, "
"check them before continue.</strong>");
}
}
}
}
if (QMessageBox::question(
this, isDir ? tr("Delete folder?") : tr("Delete password?"),
tr("Are you sure you want to delete %1%2?")
.arg(QDir::separator() + file, isDir ? dirMessage : "?"),
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
return;
}
}
void MainWindow::onOtp() {
QString file = getFile(ui->treeView->currentIndex(), true);
if (!file.isEmpty()) {
}
} else {
flashText(tr(
"No password selected for OTP generation"),
true);
}
}
void MainWindow::onEdit() {
QString file = getFile(ui->treeView->currentIndex(), true);
editPassword(file);
}
if (!dir.isEmpty()) {
currentDir = dir;
}
onUsers();
}
void MainWindow::onUsers() {
QString dir =
currentDir.isEmpty()
?
Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel)
: currentDir;
UsersDialog d(dir, this);
if (!d.exec()) {
ui->treeView->setFocus();
}
}
if (message.isEmpty()) {
focusInput();
} else {
ui->treeView->expandAll();
ui->lineEdit->setText(message);
on_lineEdit_returnPressed();
}
show();
raise();
}
keygen = keygenWindow;
}
void MainWindow::updateProfileBox() {
QHash<QString, QHash<QString, QString>> profiles =
if (profiles.isEmpty()) {
ui->profileWidget->hide();
} else {
ui->profileWidget->show();
ui->profileBox->setEnabled(profiles.size() > 1);
ui->profileBox->clear();
QHashIterator<QString, QHash<QString, QString>> i(profiles);
while (i.hasNext()) {
i.next();
if (!i.key().isEmpty()) {
ui->profileBox->addItem(i.key());
}
}
ui->profileBox->model()->sort(0);
}
if (index != -1) {
ui->profileBox->setCurrentIndex(index);
}
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void MainWindow::on_profileBox_currentIndexChanged(QString name) {
#else
void MainWindow::on_profileBox_currentTextChanged(const QString &name) {
#endif
return;
}
ui->lineEdit->clear();
ui->statusBar->showMessage(tr("Profile changed to %1").arg(name), 2000);
ui->treeView->selectionModel()->clear();
ui->treeView->setRootIndex(proxyModel.mapFromSource(
ui->actionEdit->setEnabled(false);
ui->actionDelete->setEnabled(false);
}
void MainWindow::initTrayIcon() {
this->tray = new TrayIcon(this);
if (tray == nullptr) {
#ifdef QT_DEBUG
dbg() <<
"Allocating tray icon failed.";
#endif
}
if (!tray->getIsAllocated()) {
destroyTrayIcon();
}
}
void MainWindow::destroyTrayIcon() {
delete this->tray;
tray = nullptr;
}
this->hide();
event->ignore();
} else {
m_qtPass->clearClipboard();
if (!isMaximized()) {
}
event->accept();
}
}
if (obj == ui->lineEdit && event->type() == QEvent::KeyPress) {
auto *key = dynamic_cast<QKeyEvent *>(event);
if (key != nullptr && key->key() == Qt::Key_Down) {
ui->treeView->setFocus();
}
}
return QObject::eventFilter(obj, event);
}
switch (event->key()) {
case Qt::Key_Delete:
onDelete();
break;
case Qt::Key_Return:
case Qt::Key_Enter:
if (proxyModel.rowCount() > 0) {
}
break;
case Qt::Key_Escape:
ui->lineEdit->clear();
break;
default:
break;
}
}
void MainWindow::showContextMenu(const QPoint &pos) {
QModelIndex index = ui->treeView->indexAt(pos);
bool selected = true;
if (!index.isValid()) {
ui->treeView->clearSelection();
ui->actionDelete->setEnabled(false);
ui->actionEdit->setEnabled(false);
currentDir = "";
selected = false;
}
ui->treeView->setCurrentIndex(index);
QPoint globalPos = ui->treeView->viewport()->mapToGlobal(pos);
QFileInfo fileOrFolder =
model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
QMenu contextMenu;
if (!selected || fileOrFolder.isDir()) {
QAction *openFolder =
contextMenu.addAction(tr("Open folder with file manager"));
QAction *addFolder = contextMenu.addAction(tr("Add folder"));
QAction *addPassword = contextMenu.addAction(tr("Add password"));
QAction *users = contextMenu.addAction(tr("Users"));
connect(openFolder, &QAction::triggered, this, &MainWindow::openFolder);
connect(addFolder, &QAction::triggered, this, &MainWindow::addFolder);
connect(addPassword, &QAction::triggered, this, &MainWindow::addPassword);
connect(users, &QAction::triggered, this, &MainWindow::onUsers);
} else if (fileOrFolder.isFile()) {
QAction *edit = contextMenu.addAction(tr("Edit"));
connect(edit, &QAction::triggered, this, &MainWindow::onEdit);
}
if (selected) {
contextMenu.addSeparator();
if (fileOrFolder.isDir()) {
QAction *renameFolder = contextMenu.addAction(tr("Rename folder"));
connect(renameFolder, &QAction::triggered, this,
&MainWindow::renameFolder);
} else if (fileOrFolder.isFile()) {
QAction *renamePassword = contextMenu.addAction(tr("Rename password"));
connect(renamePassword, &QAction::triggered, this,
&MainWindow::renamePassword);
}
QAction *deleteItem = contextMenu.addAction(tr("Delete"));
connect(deleteItem, &QAction::triggered, this, &MainWindow::onDelete);
}
contextMenu.exec(globalPos);
}
void MainWindow::showBrowserContextMenu(const QPoint &pos) {
QMenu *contextMenu = ui->textBrowser->createStandardContextMenu(pos);
QPoint globalPos = ui->textBrowser->viewport()->mapToGlobal(pos);
contextMenu->exec(globalPos);
delete contextMenu;
}
void MainWindow::openFolder() {
QString dir =
Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel);
QString path = QDir::toNativeSeparators(dir);
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
void MainWindow::addFolder() {
bool ok;
QString dir =
Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel);
QString newdir =
QInputDialog::getText(this, tr("New file"),
tr("New Folder: \n(Will be placed in %1 )")
true, model, proxyModel)),
QLineEdit::Normal, "", &ok);
if (!ok || newdir.isEmpty()) {
return;
}
newdir.prepend(dir);
if (!QDir().mkdir(newdir)) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to create folder: %1").arg(newdir));
return;
}
QString gpgIdFile = newdir + "/.gpg-id";
QFile gpgId(gpgIdFile);
if (!gpgId.open(QIODevice::WriteOnly)) {
QMessageBox::warning(
this, tr("Error"),
tr("Failed to create .gpg-id file in: %1").arg(newdir));
return;
}
for (const UserInfo &user : users) {
if (user.enabled) {
gpgId.write((user.key_id + "\n").toUtf8());
}
}
gpgId.close();
}
}
void MainWindow::renameFolder() {
bool ok;
QString srcDir = QDir::cleanPath(
Util::getDir(ui->treeView->currentIndex(),
false, model, proxyModel));
QString srcDirName = QDir(srcDir).dirName();
QString newName =
QInputDialog::getText(this, tr("Rename file"), tr("Rename Folder To: "),
QLineEdit::Normal, srcDirName, &ok);
if (!ok || newName.isEmpty()) {
return;
}
QString destDir = srcDir;
destDir.replace(srcDir.lastIndexOf(srcDirName), srcDirName.length(), newName);
}
void MainWindow::editPassword(const QString &file) {
if (!file.isEmpty()) {
onUpdate(true);
}
setPassword(file, false);
}
}
void MainWindow::renamePassword() {
bool ok;
QString file = getFile(ui->treeView->currentIndex(), false);
QString filePath = QFileInfo(file).path();
QString fileName = QFileInfo(file).fileName();
if (fileName.endsWith(".gpg", Qt::CaseInsensitive)) {
fileName.chop(4);
}
QString newName =
QInputDialog::getText(this, tr("Rename file"), tr("Rename File To: "),
QLineEdit::Normal, fileName, &ok);
if (!ok || newName.isEmpty()) {
return;
}
QString newFile = QDir(filePath).filePath(newName);
}
void MainWindow::clearTemplateWidgets() {
while (ui->gridLayout->count() > 0) {
QLayoutItem *item = ui->gridLayout->takeAt(0);
delete item->widget();
delete item;
}
ui->verticalLayoutPassword->setSpacing(0);
}
void MainWindow::copyPasswordFromTreeview() {
QFileInfo fileOrFolder =
model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
if (fileOrFolder.isFile()) {
QString file = getFile(ui->treeView->currentIndex(), true);
&MainWindow::passwordFromFileToClipboard);
&MainWindow::passwordFromFileToClipboard);
}
}
void MainWindow::passwordFromFileToClipboard(const QString &text) {
QStringList tokens = text.split('\n');
m_qtPass->copyTextToClipboard(tokens[0]);
}
void MainWindow::addToGridLayout(int position, const QString &field,
const QString &value) {
QString trimmedField = field.trimmed();
QString trimmedValue = value.trimmed();
const QString buttonStyle =
"border-style: none; background: transparent; padding: 0; margin: 0; "
"icon-size: 16px; color: inherit;";
auto *frame = new QFrame();
QLayout *ly = new QHBoxLayout();
ly->setContentsMargins(5, 2, 2, 2);
ly->setSpacing(0);
frame->setLayout(ly);
auto *fieldLabel = new QPushButtonWithClipboard(trimmedValue, this);
fieldLabel->setStyleSheet(buttonStyle);
frame->layout()->addWidget(fieldLabel);
}
auto *qrbutton = new QPushButtonAsQRCode(trimmedValue, this);
qrbutton->setStyleSheet(buttonStyle);
frame->layout()->addWidget(qrbutton);
}
const QString lineStyle =
? "border-style: none; background: transparent; font-family: "
"monospace;"
: "border-style: none; background: transparent;";
auto *line = new QLineEdit();
line->setObjectName(trimmedField);
line->setText(trimmedValue);
line->setReadOnly(true);
line->setStyleSheet(lineStyle);
line->setContentsMargins(0, 0, 0, 0);
line->setEchoMode(QLineEdit::Password);
auto *showButton = new QPushButtonShowPassword(line, this);
showButton->setStyleSheet(buttonStyle);
showButton->setContentsMargins(0, 0, 0, 0);
frame->layout()->addWidget(showButton);
frame->layout()->addWidget(line);
} else {
auto *line = new QTextBrowser();
line->setOpenExternalLinks(true);
line->setOpenLinks(true);
line->setMaximumHeight(26);
line->setMinimumHeight(26);
line->setSizePolicy(
QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
line->setObjectName(trimmedField);
line->setText(trimmedValue);
line->setReadOnly(true);
line->setStyleSheet(lineStyle);
line->setContentsMargins(0, 0, 0, 0);
frame->layout()->addWidget(line);
}
frame->setStyleSheet(
".QFrame{border: 1px solid lightgrey; border-radius: 5px;}");
ui->gridLayout->addWidget(new QLabel(trimmedField), position, 0);
ui->gridLayout->addWidget(frame, position, 1);
}
ui->statusBar->showMessage(msg, timeout);
}
ui->treeView->setDisabled(true);
}
void MainWindow::updateGitButtonVisibility() {
enableGitButtons(false);
} else {
enableGitButtons(true);
}
}
void MainWindow::updateOtpButtonVisibility() {
#if defined(Q_OS_WIN) || defined(__APPLE__)
ui->actionOtp->setVisible(false);
#endif
ui->actionOtp->setEnabled(false);
} else {
ui->actionOtp->setEnabled(true);
}
}
void MainWindow::enableGitButtons(const bool &state) {
ui->actionPush->setEnabled(state);
ui->actionUpdate->setEnabled(state);
}
QMessageBox::critical(this, title, msg);
}
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...
The MainWindow class does way too much, not only is it a switchboard, configuration handler and more,...
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.
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.
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