diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index d988d6a55..59a8e940d 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -1391,6 +1391,15 @@ Do you want to overwrite the passkey in %1 - %2?
+
+
+
+
+
+
+
+
CsvParserModel
diff --git a/src/gui/csvImport/CsvImportWidget.cpp b/src/gui/csvImport/CsvImportWidget.cpp
index dfd3606da..91613d1f8 100644
--- a/src/gui/csvImport/CsvImportWidget.cpp
+++ b/src/gui/csvImport/CsvImportWidget.cpp
@@ -25,6 +25,7 @@
#include "core/Totp.h"
#include "format/CsvParser.h"
#include "format/KeePass2Writer.h"
+#include "gui/MessageBox.h"
#include "gui/csvImport/CsvParserModel.h"
#include
@@ -213,19 +214,29 @@ void CsvImportWidget::parse()
QSharedPointer CsvImportWidget::buildDatabase()
{
+ // Warn if the title column wasn't specified
+ if (m_combos[1]->currentIndex() == 0) {
+ auto ans = MessageBox::question(
+ this,
+ tr("No Title Selected"),
+ tr("No title column was selected, entries will be hard to tell apart.\nAre you sure you want to import?"),
+ MessageBox::Continue | MessageBox::Cancel);
+ if (ans == MessageBox::Cancel) {
+ return {};
+ }
+ }
+
auto db = QSharedPointer::create();
db->rootGroup()->setNotes(tr("Imported from CSV file: %1").arg(m_filename));
- for (int r = 0; r < m_parserModel->rowCount(); ++r) {
- // use validity of second column as a GO/NOGO for all others fields
- if (!m_parserModel->data(m_parserModel->index(r, 1)).isValid()) {
- continue;
- }
+ auto rows = m_parserModel->rowCount() - m_parserModel->skippedRows();
+ for (int r = 0; r < rows; ++r) {
auto group = createGroupStructure(db.data(), m_parserModel->data(m_parserModel->index(r, 0)).toString());
if (!group) {
continue;
}
+ // Standard entry fields
auto entry = new Entry();
entry->setUuid(QUuid::createUuid());
entry->setGroup(group);
@@ -235,6 +246,7 @@ QSharedPointer CsvImportWidget::buildDatabase()
entry->setUrl(m_parserModel->data(m_parserModel->index(r, 4)).toString());
entry->setNotes(m_parserModel->data(m_parserModel->index(r, 5)).toString());
+ // TOTP
auto otpString = m_parserModel->data(m_parserModel->index(r, 6));
if (otpString.isValid() && !otpString.toString().isEmpty()) {
auto totp = Totp::parseSettings(otpString.toString());
@@ -245,12 +257,14 @@ QSharedPointer CsvImportWidget::buildDatabase()
entry->setTotp(totp);
}
+ // Icon
bool ok;
int icon = m_parserModel->data(m_parserModel->index(r, 7)).toInt(&ok);
if (ok) {
entry->setIcon(icon);
}
+ // Modified Time
TimeInfo timeInfo;
if (m_parserModel->data(m_parserModel->index(r, 8)).isValid()) {
auto datetime = m_parserModel->data(m_parserModel->index(r, 8)).toString();
@@ -270,6 +284,7 @@ QSharedPointer CsvImportWidget::buildDatabase()
}
}
}
+ // Creation Time
if (m_parserModel->data(m_parserModel->index(r, 9)).isValid()) {
auto datetime = m_parserModel->data(m_parserModel->index(r, 9)).toString();
if (datetime.contains(QRegularExpression("^\\d+$"))) {
diff --git a/src/gui/csvImport/CsvParserModel.cpp b/src/gui/csvImport/CsvParserModel.cpp
index eb59157d3..892b8917b 100644
--- a/src/gui/csvImport/CsvParserModel.cpp
+++ b/src/gui/csvImport/CsvParserModel.cpp
@@ -92,6 +92,11 @@ void CsvParserModel::setSkippedRows(int skipped)
emit layoutChanged();
}
+int CsvParserModel::skippedRows() const
+{
+ return m_skipped;
+}
+
void CsvParserModel::setHeaderLabels(const QStringList& labels)
{
m_columnHeader = labels;
diff --git a/src/gui/csvImport/CsvParserModel.h b/src/gui/csvImport/CsvParserModel.h
index 2717b826d..d9fb4af46 100644
--- a/src/gui/csvImport/CsvParserModel.h
+++ b/src/gui/csvImport/CsvParserModel.h
@@ -45,8 +45,8 @@ public:
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
-public slots:
void setSkippedRows(int skipped);
+ int skippedRows() const;
private:
CsvParser* m_parser;