Final fixes

This commit is contained in:
Jonathan White
2025-09-20 23:42:51 -04:00
committed by Janek Bevendorff
parent fc5f504509
commit 66ff42c78b
6 changed files with 47 additions and 32 deletions

View File

@@ -1799,6 +1799,10 @@ Are you sure you want to continue with this file?.</source>
<source>Press ESC again to close this database</source> <source>Press ESC again to close this database</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>The database file does not exist or is not accessible.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>DatabaseSettingWidgetMetaData</name> <name>DatabaseSettingWidgetMetaData</name>
@@ -2608,10 +2612,6 @@ This is definitely a bug, please report it to the developers.</source>
<source>Open database</source> <source>Open database</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Failed to open %1. It either does not exist or is not accessible.</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>CSV file</source> <source>CSV file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View File

@@ -38,6 +38,7 @@
namespace namespace
{ {
constexpr int clearFormsDelay = 30000; constexpr int clearFormsDelay = 30000;
constexpr int fileExistsCheckInterval = 5000;
bool isQuickUnlockAvailable() bool isQuickUnlockAvailable()
{ {
@@ -68,6 +69,16 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
m_ui->editPassword->setShowPassword(false); m_ui->editPassword->setShowPassword(false);
}); });
m_fileExistsTimer.setInterval(fileExistsCheckInterval);
m_fileExistsTimer.setSingleShot(false);
connect(&m_fileExistsTimer, &QTimer::timeout, this, [this] {
if (!QFile::exists(m_filename)) {
m_ui->messageWidget->showMessage(tr("The database file does not exist or is not accessible."),
MessageWidget::Warning,
fileExistsCheckInterval + 500);
}
});
QFont font; QFont font;
font.setPointSize(font.pointSize() + 4); font.setPointSize(font.pointSize() + 4);
font.setBold(true); font.setBold(true);
@@ -215,6 +226,7 @@ bool DatabaseOpenWidget::event(QEvent* event)
} }
if (isVisible()) { if (isVisible()) {
m_fileExistsTimer.start();
m_hideTimer.stop(); m_hideTimer.stop();
pollHardwareKey(); pollHardwareKey();
} }
@@ -226,6 +238,8 @@ bool DatabaseOpenWidget::event(QEvent* event)
m_hideTimer.start(); m_hideTimer.start();
} }
m_fileExistsTimer.stop();
#ifdef WITH_XC_YUBIKEY #ifdef WITH_XC_YUBIKEY
if (type == QEvent::Hide) { if (type == QEvent::Hide) {
m_deviceListener->deregisterAllHotplugCallbacks(); m_deviceListener->deregisterAllHotplugCallbacks();
@@ -257,12 +271,7 @@ void DatabaseOpenWidget::load(const QString& filename)
// Read public headers // Read public headers
QString error; QString error;
m_db.reset(new Database()); m_db.reset(new Database());
bool openSuccess = m_db->open(m_filename, nullptr, &error); m_db->open(m_filename, nullptr, &error);
// If opening failed (e.g., file doesn't exist), show an informative message
if (!openSuccess && !error.isEmpty()) {
m_ui->messageWidget->showMessage(error, MessageWidget::MessageType::Warning);
}
m_ui->fileNameLabel->setRawText(m_filename); m_ui->fileNameLabel->setRawText(m_filename);

View File

@@ -97,6 +97,7 @@ private:
bool m_triedToQuit = false; bool m_triedToQuit = false;
QTimer m_hideTimer; QTimer m_hideTimer;
QTimer m_hideNoHardwareKeysFoundTimer; QTimer m_hideNoHardwareKeysFoundTimer;
QTimer m_fileExistsTimer;
Q_DISABLE_COPY(DatabaseOpenWidget) Q_DISABLE_COPY(DatabaseOpenWidget)
}; };

View File

@@ -163,24 +163,29 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath,
QString canonicalFilePath = fileInfo.canonicalFilePath(); QString canonicalFilePath = fileInfo.canonicalFilePath();
if (canonicalFilePath.isEmpty()) { if (canonicalFilePath.isEmpty()) {
// Don't return early - continue to show unlock dialog even if file is missing // The file does not exist, revert back to the cleaned path for comparison
// This allows user to retry when file becomes available (e.g., cloud storage mounting) canonicalFilePath = cleanFilePath;
emit messageGlobal(tr("Failed to open %1. It either does not exist or is not accessible.").arg(cleanFilePath),
MessageWidget::Error);
canonicalFilePath = cleanFilePath; // Use the original path for comparison
} }
// Try to find an existing tab with the same file path
for (int i = 0, c = count(); i < c; ++i) { for (int i = 0, c = count(); i < c; ++i) {
auto* dbWidget = databaseWidgetFromIndex(i); auto* dbWidget = databaseWidgetFromIndex(i);
Q_ASSERT(dbWidget); if (dbWidget) {
if (dbWidget auto dbFilePath = dbWidget->database()->canonicalFilePath();
&& dbWidget->database()->canonicalFilePath().compare(canonicalFilePath, FILE_CASE_SENSITIVE) == 0) { if (dbFilePath.isEmpty()) {
dbWidget->performUnlockDatabase(password, keyfile); // The file does not exist, revert back to the cleaned path for comparison
if (!inBackground) { dbFilePath = QDir::toNativeSeparators(dbWidget->database()->filePath());
// switch to existing tab if file is already open }
setCurrentIndex(indexOf(dbWidget)); if (dbFilePath.compare(canonicalFilePath, FILE_CASE_SENSITIVE) == 0) {
// Attempt to unlock the database if password and/or keyfile is provided
dbWidget->performUnlockDatabase(password, keyfile);
if (!inBackground) {
// switch to existing tab if file is already open
setCurrentIndex(indexOf(dbWidget));
}
// Prevent opening a new tab for this file
return;
} }
return;
} }
} }

View File

@@ -714,7 +714,7 @@ void MainWindow::restoreConfigState()
if (config()->get(Config::OpenPreviousDatabasesOnStartup).toBool()) { if (config()->get(Config::OpenPreviousDatabasesOnStartup).toBool()) {
const QStringList fileNames = config()->get(Config::LastOpenedDatabases).toStringList(); const QStringList fileNames = config()->get(Config::LastOpenedDatabases).toStringList();
for (const QString& filename : fileNames) { for (const QString& filename : fileNames) {
if (!filename.isEmpty() && QFile::exists(filename)) { if (!filename.isEmpty()) {
openDatabase(filename); openDatabase(filename);
} }
} }

View File

@@ -2469,31 +2469,31 @@ void TestGui::testOpenMissingDatabaseFile()
// Test that when trying to open a non-existent database file, // Test that when trying to open a non-existent database file,
// the unlock dialog is still shown (instead of auto-closing) // the unlock dialog is still shown (instead of auto-closing)
// This allows user to retry when the file becomes available (e.g., cloud storage mounting) // This allows user to retry when the file becomes available (e.g., cloud storage mounting)
const QString nonExistentPath = "/tmp/does_not_exist.kdbx"; const QString nonExistentPath = "/tmp/does_not_exist.kdbx";
// Ensure the file doesn't exist // Ensure the file doesn't exist
QFile::remove(nonExistentPath); QFile::remove(nonExistentPath);
QVERIFY(!QFile::exists(nonExistentPath)); QVERIFY(!QFile::exists(nonExistentPath));
// Record initial tab count // Record initial tab count
int initialTabCount = m_tabWidget->count(); int initialTabCount = m_tabWidget->count();
// Try to add database tab with non-existent file // Try to add database tab with non-existent file
// This should NOT fail but should create a tab and show unlock dialog // This should NOT fail but should create a tab and show unlock dialog
m_tabWidget->addDatabaseTab(nonExistentPath); m_tabWidget->addDatabaseTab(nonExistentPath);
// Verify that a tab was created (unlock dialog shown) // Verify that a tab was created (unlock dialog shown)
QCOMPARE(m_tabWidget->count(), initialTabCount + 1); QCOMPARE(m_tabWidget->count(), initialTabCount + 1);
// Get the database widget for the new tab // Get the database widget for the new tab
auto* dbWidget = m_tabWidget->currentDatabaseWidget(); auto* dbWidget = m_tabWidget->currentDatabaseWidget();
QVERIFY(dbWidget); QVERIFY(dbWidget);
// Verify the database is in a state where it can be unlocked // Verify the database is in a state where it can be unlocked
// (not closed/rejected due to missing file) // (not closed/rejected due to missing file)
QVERIFY(dbWidget->isLocked()); QVERIFY(dbWidget->isLocked());
// Close the tab to clean up // Close the tab to clean up
m_tabWidget->closeDatabaseTab(m_tabWidget->currentIndex()); m_tabWidget->closeDatabaseTab(m_tabWidget->currentIndex());
QCOMPARE(m_tabWidget->count(), initialTabCount); QCOMPARE(m_tabWidget->count(), initialTabCount);