diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index f974db170..6bba8c8f9 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -1799,6 +1799,10 @@ Are you sure you want to continue with this file?.
Press ESC again to close this database
+
+ The database file does not exist or is not accessible.
+
+ DatabaseSettingWidgetMetaData
@@ -2608,10 +2612,6 @@ This is definitely a bug, please report it to the developers.
Open database
-
- Failed to open %1. It either does not exist or is not accessible.
-
- CSV file
diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp
index 167ee32f5..35fc34800 100644
--- a/src/gui/DatabaseOpenWidget.cpp
+++ b/src/gui/DatabaseOpenWidget.cpp
@@ -38,6 +38,7 @@
namespace
{
constexpr int clearFormsDelay = 30000;
+ constexpr int fileExistsCheckInterval = 5000;
bool isQuickUnlockAvailable()
{
@@ -68,6 +69,16 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
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;
font.setPointSize(font.pointSize() + 4);
font.setBold(true);
@@ -215,6 +226,7 @@ bool DatabaseOpenWidget::event(QEvent* event)
}
if (isVisible()) {
+ m_fileExistsTimer.start();
m_hideTimer.stop();
pollHardwareKey();
}
@@ -226,6 +238,8 @@ bool DatabaseOpenWidget::event(QEvent* event)
m_hideTimer.start();
}
+ m_fileExistsTimer.stop();
+
#ifdef WITH_XC_YUBIKEY
if (type == QEvent::Hide) {
m_deviceListener->deregisterAllHotplugCallbacks();
@@ -257,12 +271,7 @@ void DatabaseOpenWidget::load(const QString& filename)
// Read public headers
QString error;
m_db.reset(new Database());
- bool openSuccess = 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_db->open(m_filename, nullptr, &error);
m_ui->fileNameLabel->setRawText(m_filename);
diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h
index d730634b3..14e15e711 100644
--- a/src/gui/DatabaseOpenWidget.h
+++ b/src/gui/DatabaseOpenWidget.h
@@ -97,6 +97,7 @@ private:
bool m_triedToQuit = false;
QTimer m_hideTimer;
QTimer m_hideNoHardwareKeysFoundTimer;
+ QTimer m_fileExistsTimer;
Q_DISABLE_COPY(DatabaseOpenWidget)
};
diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp
index 825bceb1e..70712028f 100644
--- a/src/gui/DatabaseTabWidget.cpp
+++ b/src/gui/DatabaseTabWidget.cpp
@@ -163,24 +163,29 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath,
QString canonicalFilePath = fileInfo.canonicalFilePath();
if (canonicalFilePath.isEmpty()) {
- // Don't return early - continue to show unlock dialog even if file is missing
- // This allows user to retry when file becomes available (e.g., cloud storage mounting)
- 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
+ // The file does not exist, revert back to the cleaned path for comparison
+ canonicalFilePath = cleanFilePath;
}
+ // Try to find an existing tab with the same file path
for (int i = 0, c = count(); i < c; ++i) {
auto* dbWidget = databaseWidgetFromIndex(i);
- Q_ASSERT(dbWidget);
- if (dbWidget
- && dbWidget->database()->canonicalFilePath().compare(canonicalFilePath, FILE_CASE_SENSITIVE) == 0) {
- dbWidget->performUnlockDatabase(password, keyfile);
- if (!inBackground) {
- // switch to existing tab if file is already open
- setCurrentIndex(indexOf(dbWidget));
+ if (dbWidget) {
+ auto dbFilePath = dbWidget->database()->canonicalFilePath();
+ if (dbFilePath.isEmpty()) {
+ // The file does not exist, revert back to the cleaned path for comparison
+ dbFilePath = QDir::toNativeSeparators(dbWidget->database()->filePath());
+ }
+ 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;
}
}
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index d51588ac5..47ef32eac 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -714,7 +714,7 @@ void MainWindow::restoreConfigState()
if (config()->get(Config::OpenPreviousDatabasesOnStartup).toBool()) {
const QStringList fileNames = config()->get(Config::LastOpenedDatabases).toStringList();
for (const QString& filename : fileNames) {
- if (!filename.isEmpty() && QFile::exists(filename)) {
+ if (!filename.isEmpty()) {
openDatabase(filename);
}
}
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp
index 9a0f8c1d0..798e621f9 100644
--- a/tests/gui/TestGui.cpp
+++ b/tests/gui/TestGui.cpp
@@ -2469,31 +2469,31 @@ void TestGui::testOpenMissingDatabaseFile()
// Test that when trying to open a non-existent database file,
// 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)
-
+
const QString nonExistentPath = "/tmp/does_not_exist.kdbx";
-
+
// Ensure the file doesn't exist
QFile::remove(nonExistentPath);
QVERIFY(!QFile::exists(nonExistentPath));
-
+
// Record initial tab count
int initialTabCount = m_tabWidget->count();
-
+
// Try to add database tab with non-existent file
// This should NOT fail but should create a tab and show unlock dialog
m_tabWidget->addDatabaseTab(nonExistentPath);
-
+
// Verify that a tab was created (unlock dialog shown)
QCOMPARE(m_tabWidget->count(), initialTabCount + 1);
-
+
// Get the database widget for the new tab
auto* dbWidget = m_tabWidget->currentDatabaseWidget();
QVERIFY(dbWidget);
-
+
// Verify the database is in a state where it can be unlocked
// (not closed/rejected due to missing file)
QVERIFY(dbWidget->isLocked());
-
+
// Close the tab to clean up
m_tabWidget->closeDatabaseTab(m_tabWidget->currentIndex());
QCOMPARE(m_tabWidget->count(), initialTabCount);