Syntax style, spaces and pretty indentation

This commit is contained in:
seatedscribe 2017-02-18 01:51:31 +01:00
parent afdf02b4be
commit a7e358c27d
13 changed files with 273 additions and 295 deletions

View File

@ -15,10 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "CsvParser.h"
#include <QTextCodec> #include <QTextCodec>
#include <QObject> #include <QObject>
#include "core/Tools.h" #include "core/Tools.h"
#include "CsvParser.h"
CsvParser::CsvParser() CsvParser::CsvParser()
: m_ch(0) : m_ch(0)
@ -61,16 +63,14 @@ bool CsvParser::parse(QFile *device) {
m_statusMsg += QObject::tr("NULL device\n"); m_statusMsg += QObject::tr("NULL device\n");
return false; return false;
} }
if (!readFile(device)) { if (!readFile(device))
return false; return false;
}
return parseFile(); return parseFile();
} }
bool CsvParser::readFile(QFile *device) { bool CsvParser::readFile(QFile *device) {
if (device->isOpen()) { if (device->isOpen())
device->close(); device->close();
}
device->open(QIODevice::ReadOnly); device->open(QIODevice::ReadOnly);
if (!Tools::readAllFromDevice(device, m_array)) { if (!Tools::readAllFromDevice(device, m_array)) {
@ -78,14 +78,14 @@ bool CsvParser::readFile(QFile *device) {
m_isFileLoaded = false; m_isFileLoaded = false;
} }
else { else {
device->close(); device->close();
m_array.replace("\r\n", "\n"); m_array.replace("\r\n", "\n");
m_array.replace("\r", "\n"); m_array.replace("\r", "\n");
if (0 == m_array.size()) { if (0 == m_array.size()) {
m_statusMsg += QObject::tr("File empty\n"); m_statusMsg += QObject::tr("File empty\n");
} }
m_isFileLoaded = true; m_isFileLoaded = true;
} }
return m_isFileLoaded; return m_isFileLoaded;
} }
@ -117,11 +117,9 @@ void CsvParser::clear() {
bool CsvParser::parseFile() { bool CsvParser::parseFile() {
parseRecord(); parseRecord();
while (!m_isEof) while (!m_isEof) {
{ if (!skipEndline())
if (!skipEndline()) {
appendStatusMsg(QObject::tr("malformed string")); appendStatusMsg(QObject::tr("malformed string"));
}
m_currRow++; m_currRow++;
m_currCol = 1; m_currCol = 1;
parseRecord(); parseRecord();
@ -131,43 +129,36 @@ bool CsvParser::parseFile() {
} }
void CsvParser::parseRecord() { void CsvParser::parseRecord() {
csvrow row; CsvRow row;
if (isComment()) { if (isComment()) {
skipLine(); skipLine();
return; return;
} }
else { do {
do { parseField(row);
parseField(row); getChar(m_ch);
getChar(m_ch); } while (isSeparator(m_ch) && !m_isEof);
} while (isSeparator(m_ch) && !m_isEof);
if (!m_isEof) { if (!m_isEof)
ungetChar(); ungetChar();
} if (isEmptyRow(row)) {
if (isEmptyRow(row)) { row.clear();
row.clear(); return;
return;
}
m_table.push_back(row);
if (m_maxCols < row.size()) {
m_maxCols = row.size();
}
m_currCol++;
} }
m_table.push_back(row);
if (m_maxCols < row.size())
m_maxCols = row.size();
m_currCol++;
} }
void CsvParser::parseField(csvrow& row) { void CsvParser::parseField(CsvRow& row) {
QString field; QString field;
peek(m_ch); peek(m_ch);
if (!isTerminator(m_ch)) if (!isTerminator(m_ch)) {
{ if (isQualifier(m_ch))
if (isQualifier(m_ch)) {
parseQuoted(field); parseQuoted(field);
} else
else { parseSimple(field);
parseSimple(field);
}
} }
row.push_back(field); row.push_back(field);
} }
@ -175,14 +166,12 @@ void CsvParser::parseField(csvrow& row) {
void CsvParser::parseSimple(QString &s) { void CsvParser::parseSimple(QString &s) {
QChar c; QChar c;
getChar(c); getChar(c);
while ((isText(c)) && (!m_isEof)) while ((isText(c)) && (!m_isEof)) {
{
s.append(c); s.append(c);
getChar(c); getChar(c);
} }
if (!m_isEof) { if (!m_isEof)
ungetChar(); ungetChar();
}
} }
void CsvParser::parseQuoted(QString &s) { void CsvParser::parseQuoted(QString &s) {
@ -190,25 +179,21 @@ void CsvParser::parseQuoted(QString &s) {
getChar(m_ch); getChar(m_ch);
parseEscaped(s); parseEscaped(s);
//getChar(m_ch); //getChar(m_ch);
if (!isQualifier(m_ch)) { if (!isQualifier(m_ch))
appendStatusMsg(QObject::tr("missing closing quote")); appendStatusMsg(QObject::tr("missing closing quote"));
}
} }
void CsvParser::parseEscaped(QString &s) { void CsvParser::parseEscaped(QString &s) {
parseEscapedText(s); parseEscapedText(s);
while (processEscapeMark(s, m_ch)) { while (processEscapeMark(s, m_ch))
parseEscapedText(s); parseEscapedText(s);
} if (!m_isEof)
if (!m_isEof) {
ungetChar(); ungetChar();
}
} }
void CsvParser::parseEscapedText(QString &s) { void CsvParser::parseEscapedText(QString &s) {
getChar(m_ch); getChar(m_ch);
while ((!isQualifier(m_ch)) && !m_isEof) while ((!isQualifier(m_ch)) && !m_isEof) {
{
s.append(m_ch); s.append(m_ch);
getChar(m_ch); getChar(m_ch);
} }
@ -218,30 +203,25 @@ bool CsvParser::processEscapeMark(QString &s, QChar c) {
QChar buf; QChar buf;
peek(buf); peek(buf);
QChar c2; QChar c2;
//escape-character syntax, e.g. \" if (true == m_isBackslashSyntax) {
if (true == m_isBackslashSyntax) //escape-character syntax, e.g. \"
{
if (c != '\\') { if (c != '\\') {
return false; return false;
} }
//consume (and append) second qualifier //consume (and append) second qualifier
getChar(c2); getChar(c2);
if (m_isEof){ if (m_isEof) {
c2='\\'; c2='\\';
s.append('\\'); s.append('\\');
return false; return false;
} } else {
else {
s.append(c2); s.append(c2);
return true; return true;
} }
} } else {
//double quote syntax, e.g. "" //double quote syntax, e.g. ""
else if (!isQualifier(c))
{
if (!isQualifier(c)) {
return false; return false;
}
peek(c2); peek(c2);
if (!m_isEof) { //not EOF, can read one char if (!m_isEof) { //not EOF, can read one char
if (isQualifier(c2)) { if (isQualifier(c2)) {
@ -255,13 +235,12 @@ bool CsvParser::processEscapeMark(QString &s, QChar c) {
} }
void CsvParser::fillColumns() { void CsvParser::fillColumns() {
//fill the rows with lesser columns with empty fields //fill shorter rows with empty placeholder columns
for (int i = 0; i < m_table.size(); ++i) {
for (int i=0; i<m_table.size(); ++i) {
int gap = m_maxCols-m_table.at(i).size(); int gap = m_maxCols-m_table.at(i).size();
if (gap > 0) { if (gap > 0) {
csvrow r = m_table.at(i); CsvRow r = m_table.at(i);
for (int j=0; j<gap; ++j) { for (int j = 0; j < gap; ++j) {
r.append(QString("")); r.append(QString(""));
} }
m_table.replace(i, r); m_table.replace(i, r);
@ -271,7 +250,7 @@ void CsvParser::fillColumns() {
void CsvParser::skipLine() { void CsvParser::skipLine() {
m_ts.readLine(); m_ts.readLine();
m_ts.seek(m_ts.pos()-1); m_ts.seek(m_ts.pos() - 1);
} }
bool CsvParser::skipEndline() { bool CsvParser::skipEndline() {
@ -295,18 +274,15 @@ void CsvParser::ungetChar() {
void CsvParser::peek(QChar& c) { void CsvParser::peek(QChar& c) {
getChar(c); getChar(c);
if (!m_isEof) { if (!m_isEof)
ungetChar(); ungetChar();
}
} }
bool CsvParser::isQualifier(const QChar c) const { bool CsvParser::isQualifier(const QChar &c) const {
if (true == m_isBackslashSyntax && (c != m_qualifier)) { if (true == m_isBackslashSyntax && (c != m_qualifier))
return (c == '\\'); return (c == '\\');
} else
else { return (c == m_qualifier);
return (c == m_qualifier);
}
} }
bool CsvParser::isComment() { bool CsvParser::isComment() {
@ -314,13 +290,11 @@ bool CsvParser::isComment() {
QChar c2; QChar c2;
qint64 pos = m_ts.pos(); qint64 pos = m_ts.pos();
do { do getChar(c2);
getChar(c2); while ((isSpace(c2) || isTab(c2)) && (!m_isEof));
} while ((isSpace(c2) || isTab(c2)) && (!m_isEof));
if (c2 == m_comment) { if (c2 == m_comment)
result = true; result = true;
}
m_ts.seek(pos); m_ts.seek(pos);
return result; return result;
} }
@ -329,32 +303,31 @@ bool CsvParser::isText(QChar c) const {
return !( (isCRLF(c)) || (isSeparator(c)) ); return !( (isCRLF(c)) || (isSeparator(c)) );
} }
bool CsvParser::isEmptyRow(csvrow row) const { bool CsvParser::isEmptyRow(CsvRow row) const {
csvrow::const_iterator it = row.constBegin(); CsvRow::const_iterator it = row.constBegin();
for (; it != row.constEnd(); ++it) { for (; it != row.constEnd(); ++it)
if ( ((*it) != "\n") && ((*it) != "") ) if ( ((*it) != "\n") && ((*it) != "") )
return false; return false;
}
return true; return true;
} }
bool CsvParser::isCRLF(const QChar c) const { bool CsvParser::isCRLF(const QChar &c) const {
return (c == '\n'); return (c == '\n');
} }
bool CsvParser::isSpace(const QChar c) const { bool CsvParser::isSpace(const QChar &c) const {
return (c == 0x20); return (c == 0x20);
} }
bool CsvParser::isTab(const QChar c) const { bool CsvParser::isTab(const QChar &c) const {
return (c == '\t'); return (c == '\t');
} }
bool CsvParser::isSeparator(const QChar c) const { bool CsvParser::isSeparator(const QChar &c) const {
return (c == m_separator); return (c == m_separator);
} }
bool CsvParser::isTerminator(const QChar c) const { bool CsvParser::isTerminator(const QChar &c) const {
return (isSeparator(c) || (c == '\n') || (c == '\r')); return (isSeparator(c) || (c == '\n') || (c == '\r'));
} }
@ -362,19 +335,19 @@ void CsvParser::setBackslashSyntax(bool set) {
m_isBackslashSyntax = set; m_isBackslashSyntax = set;
} }
void CsvParser::setComment(const QChar c) { void CsvParser::setComment(const QChar &c) {
m_comment = c.unicode(); m_comment = c.unicode();
} }
void CsvParser::setCodec(const QString s) { void CsvParser::setCodec(const QString &s) {
m_ts.setCodec(QTextCodec::codecForName(s.toLocal8Bit())); m_ts.setCodec(QTextCodec::codecForName(s.toLocal8Bit()));
} }
void CsvParser::setFieldSeparator(const QChar c) { void CsvParser::setFieldSeparator(const QChar &c) {
m_separator = c.unicode(); m_separator = c.unicode();
} }
void CsvParser::setTextQualifier(const QChar c) { void CsvParser::setTextQualifier(const QChar &c) {
m_qualifier = c.unicode(); m_qualifier = c.unicode();
} }
@ -382,11 +355,14 @@ int CsvParser::getFileSize() const {
return m_csv.size(); return m_csv.size();
} }
const csvtable CsvParser::getCsvTable() const { const CsvTable CsvParser::getCsvTable() const {
return m_table; return m_table;
} }
QString CsvParser::getStatus() const { QString CsvParser::getStatus() const {
if (m_statusMsg.size() > 100)
return m_statusMsg.section('\n', 0, 4)
.append("\n[...]\n").append(QObject::tr("More messages, skipped!"));
return m_statusMsg; return m_statusMsg;
} }

View File

@ -23,8 +23,8 @@
#include <QQueue> #include <QQueue>
#include <QTextStream> #include <QTextStream>
typedef QStringList csvrow; typedef QStringList CsvRow;
typedef QList<csvrow> csvtable; typedef QList<CsvRow> CsvTable;
class CsvParser { class CsvParser {
@ -36,19 +36,19 @@ public:
bool isFileLoaded(); bool isFileLoaded();
//reparse the same buffer (device is not opened again) //reparse the same buffer (device is not opened again)
bool reparse(); bool reparse();
void setCodec(const QString s); void setCodec(const QString &s);
void setComment(const QChar c); void setComment(const QChar &c);
void setFieldSeparator(const QChar c); void setFieldSeparator(const QChar &c);
void setTextQualifier(const QChar c); void setTextQualifier(const QChar &c);
void setBackslashSyntax(bool set); void setBackslashSyntax(bool set);
int getFileSize() const; int getFileSize() const;
int getCsvRows() const; int getCsvRows() const;
int getCsvCols() const; int getCsvCols() const;
QString getStatus() const; QString getStatus() const;
const csvtable getCsvTable() const; const CsvTable getCsvTable() const;
protected: protected:
csvtable m_table; CsvTable m_table;
private: private:
QByteArray m_array; QByteArray m_array;
@ -72,22 +72,22 @@ private:
void ungetChar(); void ungetChar();
void peek(QChar &c); void peek(QChar &c);
void fillColumns(); void fillColumns();
bool isTerminator(const QChar c) const; bool isTerminator(const QChar &c) const;
bool isSeparator(const QChar c) const; bool isSeparator(const QChar &c) const;
bool isQualifier(const QChar c) const; bool isQualifier(const QChar &c) const;
bool processEscapeMark(QString &s, QChar c); bool processEscapeMark(QString &s, QChar c);
bool isText(QChar c) const; bool isText(QChar c) const;
bool isComment(); bool isComment();
bool isCRLF(const QChar c) const; bool isCRLF(const QChar &c) const;
bool isSpace(const QChar c) const; bool isSpace(const QChar &c) const;
bool isTab(const QChar c) const; bool isTab(const QChar &c) const;
bool isEmptyRow(csvrow row) const; bool isEmptyRow(CsvRow row) const;
bool parseFile(); bool parseFile();
void parseRecord(); void parseRecord();
void parseField(csvrow& row); void parseField(CsvRow &row);
void parseSimple(QString& s); void parseSimple(QString &s);
void parseQuoted(QString& s); void parseQuoted(QString &s);
void parseEscaped(QString& s); void parseEscaped(QString &s);
void parseEscapedText(QString &s); void parseEscapedText(QString &s);
bool readFile(QFile *device); bool readFile(QFile *device);
void reset(); void reset();

View File

@ -196,6 +196,9 @@ DatabaseWidget::Mode DatabaseWidget::currentMode() const
if (currentWidget() == nullptr) { if (currentWidget() == nullptr) {
return DatabaseWidget::None; return DatabaseWidget::None;
} }
else if (currentWidget() == m_csvImportWizard) {
return DatabaseWidget::ImportMode;
}
else if (currentWidget() == m_mainWidget) { else if (currentWidget() == m_mainWidget) {
return DatabaseWidget::ViewMode; return DatabaseWidget::ViewMode;
} }

View File

@ -61,6 +61,7 @@ public:
enum Mode enum Mode
{ {
None, None,
ImportMode,
ViewMode, ViewMode,
EditMode, EditMode,
LockedMode LockedMode

View File

@ -425,6 +425,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
break; break;
} }
case DatabaseWidget::EditMode: case DatabaseWidget::EditMode:
case DatabaseWidget::ImportMode:
case DatabaseWidget::LockedMode: { case DatabaseWidget::LockedMode: {
const QList<QAction*> entryActions = m_ui->menuEntries->actions(); const QList<QAction*> entryActions = m_ui->menuEntries->actions();
for (QAction* action : entryActions) { for (QAction* action : entryActions) {

View File

@ -17,15 +17,17 @@
#include "CsvImportWidget.h" #include "CsvImportWidget.h"
#include "ui_CsvImportWidget.h" #include "ui_CsvImportWidget.h"
#include "gui/MessageBox.h"
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include "gui/MessageBox.h"
#include "gui/MessageWidget.h"
//I wanted to make the CSV import GUI future-proof, so if one day you need entries //I wanted to make the CSV import GUI future-proof, so if one day you need entries
//to have a new field, all you have to do is uncomment a row or two here, and the GUI will follow: //to have a new field, all you have to do is uncomment a row or two here, and the GUI will follow:
//dynamic generation of comboBoxes, labels, placement and so on. Try it for immense fun! //dynamic generation of comboBoxes, labels, placement and so on. Try it for immense fun!
const QStringList CsvImportWidget::m_columnheader = QStringList() const QStringList CsvImportWidget::m_columnHeader = QStringList()
<< QObject::tr("Group") << QObject::tr("Group")
<< QObject::tr("Title") << QObject::tr("Title")
<< QObject::tr("Username") << QObject::tr("Username")
@ -46,10 +48,7 @@ CsvImportWidget::CsvImportWidget(QWidget *parent)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
QFont font = m_ui->labelHeadline->font(); m_ui->messageWidget->setHidden(true);
font.setBold(true);
font.setPointSize(font.pointSize() + 2);
m_ui->labelHeadline->setFont(font);
m_ui->comboBoxCodec->addItems(QStringList() <<"UTF-8" <<"Windows-1252" <<"UTF-16" <<"UTF-16LE"); m_ui->comboBoxCodec->addItems(QStringList() <<"UTF-8" <<"Windows-1252" <<"UTF-16" <<"UTF-16LE");
m_ui->comboBoxFieldSeparator->addItems(QStringList() <<"," <<";" <<"-" <<":" <<"."); m_ui->comboBoxFieldSeparator->addItems(QStringList() <<"," <<";" <<"-" <<":" <<".");
@ -59,10 +58,10 @@ CsvImportWidget::CsvImportWidget(QWidget *parent)
m_ui->tableViewFields->setSelectionMode(QAbstractItemView::NoSelection); m_ui->tableViewFields->setSelectionMode(QAbstractItemView::NoSelection);
m_ui->tableViewFields->setFocusPolicy(Qt::NoFocus); m_ui->tableViewFields->setFocusPolicy(Qt::NoFocus);
for (int i=0; i<m_columnheader.count(); ++i) { for (int i = 0; i < m_columnHeader.count(); ++i) {
QLabel* label = new QLabel(m_columnheader.at(i), this); QLabel* label = new QLabel(m_columnHeader.at(i), this);
label->setFixedWidth(label->minimumSizeHint().width()); label->setFixedWidth(label->minimumSizeHint().width());
font = label->font(); QFont font = label->font();
font.setBold(false); font.setBold(false);
label->setFont(font); label->setFont(font);
@ -76,14 +75,14 @@ CsvImportWidget::CsvImportWidget(QWidget *parent)
connect(combo, SIGNAL(currentIndexChanged(int)), m_comboMapper, SLOT(map())); connect(combo, SIGNAL(currentIndexChanged(int)), m_comboMapper, SLOT(map()));
//layout labels and combo fields in column-first order //layout labels and combo fields in column-first order
int combo_rows = 1+(m_columnheader.count()-1)/2; int combo_rows = 1+(m_columnHeader.count()-1)/2;
int x=i%combo_rows; int x = i%combo_rows;
int y= 2*(i/combo_rows); int y = 2*(i/combo_rows);
m_ui->gridLayout_combos->addWidget(label, x, y); m_ui->gridLayout_combos->addWidget(label, x, y);
m_ui->gridLayout_combos->addWidget(combo, x, y+1); m_ui->gridLayout_combos->addWidget(combo, x, y+1);
} }
m_parserModel->setHeaderLabels(m_columnheader); m_parserModel->setHeaderLabels(m_columnHeader);
m_ui->tableViewFields->setModel(m_parserModel); m_ui->tableViewFields->setModel(m_parserModel);
connect(m_ui->spinBoxSkip, SIGNAL(valueChanged(int)), SLOT(skippedChanged(int))); connect(m_ui->spinBoxSkip, SIGNAL(valueChanged(int)), SLOT(skippedChanged(int)));
@ -101,10 +100,9 @@ CsvImportWidget::CsvImportWidget(QWidget *parent)
void CsvImportWidget::comboChanged(int comboId) { void CsvImportWidget::comboChanged(int comboId) {
QComboBox* currentSender = qobject_cast<QComboBox*>(m_comboMapper->mapping(comboId)); QComboBox* currentSender = qobject_cast<QComboBox*>(m_comboMapper->mapping(comboId));
if (currentSender->currentIndex() != -1) { if (currentSender->currentIndex() != -1)
//here is the line that actually updates the GUI table //this line is the one that actually updates GUI table
m_parserModel->mapColumns(currentSender->currentIndex(), comboId); m_parserModel->mapColumns(currentSender->currentIndex(), comboId);
}
updateTableview(); updateTableview();
} }
@ -127,7 +125,7 @@ void CsvImportWidget::updateTableview() {
m_ui->tableViewFields->resizeRowsToContents(); m_ui->tableViewFields->resizeRowsToContents();
m_ui->tableViewFields->resizeColumnsToContents(); m_ui->tableViewFields->resizeColumnsToContents();
for (int c=0; c<m_ui->tableViewFields->horizontalHeader()->count(); ++c) { for (int c = 0; c < m_ui->tableViewFields->horizontalHeader()->count(); ++c) {
m_ui->tableViewFields->horizontalHeader()->setSectionResizeMode( m_ui->tableViewFields->horizontalHeader()->setSectionResizeMode(
c, QHeaderView::Stretch); c, QHeaderView::Stretch);
} }
@ -137,12 +135,12 @@ void CsvImportWidget::updatePreview() {
m_ui->labelSizeRowsCols->setText(m_parserModel->getFileInfo()); m_ui->labelSizeRowsCols->setText(m_parserModel->getFileInfo());
m_ui->spinBoxSkip->setValue(0); m_ui->spinBoxSkip->setValue(0);
m_ui->spinBoxSkip->setMaximum(m_parserModel->rowCount()-1); m_ui->spinBoxSkip->setMaximum(m_parserModel->rowCount() - 1);
int i; int i;
QStringList list(tr("Not present in CSV file")); QStringList list(tr("Not present in CSV file"));
for (i=1; i<m_parserModel->getCsvCols(); i++) { for (i = 1; i < m_parserModel->getCsvCols(); i++) {
QString s = QString(tr("Column ")) + QString::number(i); QString s = QString(tr("Column ")) + QString::number(i);
list << s; list << s;
} }
@ -150,12 +148,10 @@ void CsvImportWidget::updatePreview() {
i=1; i=1;
Q_FOREACH (QComboBox* b, m_combos) { Q_FOREACH (QComboBox* b, m_combos) {
if (i < m_parserModel->getCsvCols()) { if (i < m_parserModel->getCsvCols())
b->setCurrentIndex(i); b->setCurrentIndex(i);
} else
else {
b->setCurrentIndex(0); b->setCurrentIndex(0);
}
++i; ++i;
} }
} }
@ -166,7 +162,7 @@ void CsvImportWidget::load(const QString& filename, Database* const db) {
m_ui->labelFilename->setText(filename); m_ui->labelFilename->setText(filename);
Group* group = m_db->rootGroup(); Group* group = m_db->rootGroup();
group->setUuid(Uuid::random()); group->setUuid(Uuid::random());
group->setNotes(tr("Imported from CSV file\nOriginal data: ") + filename); group->setNotes(tr("Imported from CSV file").append("\n").append(tr("Original data: ")) + filename);
parse(); parse();
} }
@ -181,47 +177,48 @@ void CsvImportWidget::parse() {
} }
void CsvImportWidget::showReport() { void CsvImportWidget::showReport() {
MessageBox::warning(this, tr("Syntax error"), tr("While parsing file...\n") // MessageBox::warning(this, tr("Syntax error"), tr("While parsing file...\n")
.append(m_parserModel->getStatus()), QMessageBox::Ok, QMessageBox::Ok); // .append(m_parserModel->getStatus()), QMessageBox::Ok, QMessageBox::Ok);
m_ui->messageWidget->showMessage(tr("Syntax error while parsing file.").append("\n")
.append(m_parserModel->getStatus()), MessageWidget::Warning);
} }
void CsvImportWidget::writeDatabase() { void CsvImportWidget::writeDatabase() {
checkGroupNames(); setRootGroup();
for (int r=0; r<m_parserModel->rowCount(); r++) { for (int r = 0; r < m_parserModel->rowCount(); r++)
//use the validity of second column as a GO/NOGO hint for all others fields //use the validity of second column as a GO/NOGO hint for all others fields
if (m_parserModel->data(m_parserModel->index(r, 1)).isValid()) { if (m_parserModel->data(m_parserModel->index(r, 1)).isValid()) {
Entry* entry = new Entry(); Entry* entry = new Entry();
entry->setUuid(Uuid::random()); entry->setUuid(Uuid::random());
entry->setGroup(splitGroups(m_parserModel->data(m_parserModel->index(r, 0)).toString())); entry->setGroup(splitGroups(m_parserModel->data(m_parserModel->index(r, 0)).toString()));
entry->setTitle( m_parserModel->data(m_parserModel->index(r, 1)).toString()); entry->setTitle(m_parserModel->data(m_parserModel->index(r, 1)).toString());
entry->setUsername( m_parserModel->data(m_parserModel->index(r, 2)).toString()); entry->setUsername(m_parserModel->data(m_parserModel->index(r, 2)).toString());
entry->setPassword( m_parserModel->data(m_parserModel->index(r, 3)).toString()); entry->setPassword(m_parserModel->data(m_parserModel->index(r, 3)).toString());
entry->setUrl( m_parserModel->data(m_parserModel->index(r, 4)).toString()); entry->setUrl(m_parserModel->data(m_parserModel->index(r, 4)).toString());
entry->setNotes( m_parserModel->data(m_parserModel->index(r, 5)).toString()); entry->setNotes(m_parserModel->data(m_parserModel->index(r, 5)).toString());
} }
}
QBuffer buffer; QBuffer buffer;
buffer.open(QBuffer::ReadWrite); buffer.open(QBuffer::ReadWrite);
KeePass2Writer writer; KeePass2Writer writer;
writer.writeDatabase(&buffer, m_db); writer.writeDatabase(&buffer, m_db);
if (writer.hasError()) { if (writer.hasError())
MessageBox::warning(this, tr("Error"), tr("CSV import: writer has errors:\n") MessageBox::warning(this, tr("Error"), tr("CSV import: writer has errors:\n")
.append((writer.errorString())), QMessageBox::Ok, QMessageBox::Ok); .append((writer.errorString())), QMessageBox::Ok, QMessageBox::Ok);
}
Q_EMIT editFinished(true); Q_EMIT editFinished(true);
} }
void CsvImportWidget::checkGroupNames() { void CsvImportWidget::setRootGroup() {
QString groupLabel; QString groupLabel;
QStringList groupList; QStringList groupList;
bool is_root = false bool is_root = false;
, is_empty = false bool is_empty = false;
, is_label = false; bool is_label = false;
for (int r=0; r<m_parserModel->rowCount(); r++) {
for (int r = 0; r < m_parserModel->rowCount(); r++) {
groupLabel = m_parserModel->data(m_parserModel->index(r, 0)).toString(); groupLabel = m_parserModel->data(m_parserModel->index(r, 0)).toString();
//check if group name is either "root", "" (empty) or some other label //check if group name is either "root", "" (empty) or some other label
groupList = groupLabel.split("/", QString::SkipEmptyParts); groupList = groupLabel.split("/", QString::SkipEmptyParts);
@ -234,18 +231,13 @@ void CsvImportWidget::checkGroupNames() {
groupList.clear(); groupList.clear();
} }
if ((not is_label and (is_empty xor is_root)) if ((not is_label and (is_empty xor is_root)) or (is_label and not is_root))
or (is_label and not is_root)) {
m_db->rootGroup()->setName("Root"); m_db->rootGroup()->setName("Root");
} else if ((is_empty and is_root) or (is_label and not is_empty and is_root))
else if ((is_empty and is_root)
or (is_label and not is_empty and is_root)) {
m_db->rootGroup()->setName("CSV IMPORTED"); m_db->rootGroup()->setName("CSV IMPORTED");
} else
else {
//SHOULD NEVER GET HERE //SHOULD NEVER GET HERE
m_db->rootGroup()->setName("ROOT_FALLBACK"); m_db->rootGroup()->setName("ROOT_FALLBACK");
}
} }
Group *CsvImportWidget::splitGroups(QString label) { Group *CsvImportWidget::splitGroups(QString label) {
@ -254,9 +246,8 @@ Group *CsvImportWidget::splitGroups(QString label) {
QStringList groupList = label.split("/", QString::SkipEmptyParts); QStringList groupList = label.split("/", QString::SkipEmptyParts);
//skip the creation of a subgroup of Root with the same name //skip the creation of a subgroup of Root with the same name
if (m_db->rootGroup()->name() == "Root" && groupList.first() == "Root") { if (m_db->rootGroup()->name() == "Root" && groupList.first() == "Root")
groupList.removeFirst(); groupList.removeFirst();
}
for (const QString& groupName : groupList) { for (const QString& groupName : groupList) {
Group *children = hasChildren(current, groupName); Group *children = hasChildren(current, groupName);
@ -265,8 +256,7 @@ Group *CsvImportWidget::splitGroups(QString label) {
brandNew->setParent(current); brandNew->setParent(current);
brandNew->setName(groupName); brandNew->setName(groupName);
current = brandNew; current = brandNew;
} } else {
else {
Q_ASSERT(children != nullptr); Q_ASSERT(children != nullptr);
current = children; current = children;
} }
@ -277,9 +267,8 @@ Group *CsvImportWidget::splitGroups(QString label) {
Group* CsvImportWidget::hasChildren(Group* current, QString groupName) { Group* CsvImportWidget::hasChildren(Group* current, QString groupName) {
//returns the group whose name is "groupName" and is child of "current" group //returns the group whose name is "groupName" and is child of "current" group
for (Group * group : current->children()) { for (Group * group : current->children()) {
if (group->name() == groupName) { if (group->name() == groupName)
return group; return group;
}
} }
return nullptr; return nullptr;
} }

View File

@ -26,10 +26,10 @@
#include <QComboBox> #include <QComboBox>
#include <QStackedWidget> #include <QStackedWidget>
#include "core/Metadata.h"
#include "format/KeePass2Writer.h" #include "format/KeePass2Writer.h"
#include "gui/csvImport/CsvParserModel.h" #include "gui/csvImport/CsvParserModel.h"
#include "keys/PasswordKey.h" #include "keys/PasswordKey.h"
#include "core/Metadata.h"
namespace Ui { namespace Ui {
@ -42,7 +42,7 @@ class CsvImportWidget : public QWidget
public: public:
explicit CsvImportWidget(QWidget *parent = nullptr); explicit CsvImportWidget(QWidget *parent = nullptr);
virtual ~CsvImportWidget(); ~CsvImportWidget();
void load(const QString& filename, Database* const db); void load(const QString& filename, Database* const db);
Q_SIGNALS: Q_SIGNALS:
@ -54,7 +54,7 @@ private Q_SLOTS:
void comboChanged(int comboId); void comboChanged(int comboId);
void skippedChanged(int rows); void skippedChanged(int rows);
void writeDatabase(); void writeDatabase();
void checkGroupNames(); void setRootGroup();
void reject(); void reject();
private: private:
@ -67,7 +67,7 @@ private:
Database *m_db; Database *m_db;
KeePass2Writer m_writer; KeePass2Writer m_writer;
static const QStringList m_columnheader; static const QStringList m_columnHeader;
void configParser(); void configParser();
void updatePreview(); void updatePreview();
void updateTableview(); void updateTableview();

View File

@ -14,7 +14,33 @@
<string/> <string/>
</property> </property>
<layout class="QGridLayout" name="gridLayout_4"> <layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="0"> <item row="2" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>758</width>
<height>24</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="Encoding"> <widget class="QGroupBox" name="Encoding">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
@ -377,17 +403,7 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="4" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupBoxColumnAssociations"> <widget class="QGroupBox" name="groupBoxColumnAssociations">
<property name="font"> <property name="font">
<font> <font>
@ -409,50 +425,7 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="5" column="0" colspan="2">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelHeadline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Import CSV fields</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelFilename">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>filename</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelSizeRowsCols">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>size, rows, columns</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="groupBoxPreview"> <widget class="QGroupBox" name="groupBoxPreview">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
@ -501,24 +474,69 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="0" column="0" rowspan="2">
<spacer name="verticalSpacer"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="orientation"> <item>
<enum>Qt::Vertical</enum> <widget class="MessageWidget" name="messageWidget" native="true"/>
</property> </item>
<property name="sizeType"> <item>
<enum>QSizePolicy::Fixed</enum> <widget class="QLabel" name="labelHeadline">
</property> <property name="sizePolicy">
<property name="sizeHint" stdset="0"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<size> <horstretch>0</horstretch>
<width>20</width> <verstretch>0</verstretch>
<height>27</height> </sizepolicy>
</size> </property>
</property> <property name="font">
</spacer> <font>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Import CSV fields</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelFilename">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>filename</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelSizeRowsCols">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>size, rows, columns</string>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>MessageWidget</class>
<extends>QWidget</extends>
<header>gui/MessageWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View File

@ -16,8 +16,10 @@
*/ */
#include "CsvImportWizard.h" #include "CsvImportWizard.h"
#include <QApplication> #include <QApplication>
#include <QLabel> #include <QLabel>
#include "gui/MessageBox.h" #include "gui/MessageBox.h"
@ -49,7 +51,7 @@ void CsvImportWizard::load(const QString& filename, Database* database)
void CsvImportWizard::keyFinished(bool accepted) void CsvImportWizard::keyFinished(bool accepted)
{ {
if (!accepted) { if (!accepted) {
Q_EMIT(importFinished(false)); emit(importFinished(false));
return; return;
} }
@ -61,12 +63,12 @@ void CsvImportWizard::keyFinished(bool accepted)
if (!result) { if (!result) {
MessageBox::critical(this, tr("Error"), tr("Unable to calculate master key")); MessageBox::critical(this, tr("Error"), tr("Unable to calculate master key"));
Q_EMIT importFinished(false); emit(importFinished(false));
return; return;
} }
} }
void CsvImportWizard::parseFinished(bool accepted) void CsvImportWizard::parseFinished(bool accepted)
{ {
Q_EMIT(importFinished(accepted)); emit(importFinished(accepted));
} }

View File

@ -18,10 +18,11 @@
#ifndef KEEPASSX_CSVIMPORTWIZARD_H #ifndef KEEPASSX_CSVIMPORTWIZARD_H
#define KEEPASSX_CSVIMPORTWIZARD_H #define KEEPASSX_CSVIMPORTWIZARD_H
#include "CsvImportWidget.h"
#include <QStackedWidget> #include <QStackedWidget>
#include <QGridLayout> #include <QGridLayout>
#include "CsvImportWidget.h"
#include "core/Database.h" #include "core/Database.h"
#include "gui/ChangeMasterKeyWidget.h" #include "gui/ChangeMasterKeyWidget.h"
#include "gui/DialogyWidget.h" #include "gui/DialogyWidget.h"
@ -34,7 +35,7 @@ class CsvImportWizard : public DialogyWidget
public: public:
explicit CsvImportWizard(QWidget *parent = nullptr); explicit CsvImportWizard(QWidget *parent = nullptr);
virtual ~CsvImportWizard(); ~CsvImportWizard();
void load(const QString& filename, Database *database); void load(const QString& filename, Database *database);
Q_SIGNALS: Q_SIGNALS:

View File

@ -42,39 +42,33 @@ bool CsvParserModel::parse() {
m_columnMap.clear(); m_columnMap.clear();
if (CsvParser::isFileLoaded()) { if (CsvParser::isFileLoaded()) {
r = CsvParser::reparse(); r = CsvParser::reparse();
} } else {
else {
QFile csv(m_filename); QFile csv(m_filename);
r = CsvParser::parse(&csv); r = CsvParser::parse(&csv);
} }
for (int i=0; i<columnCount(); i++) { for (int i = 0; i < columnCount(); i++)
m_columnMap.insert(i,0); m_columnMap.insert(i,0);
}
addEmptyColumn(); addEmptyColumn();
endResetModel(); endResetModel();
return r; return r;
} }
void CsvParserModel::addEmptyColumn() { void CsvParserModel::addEmptyColumn() {
for (int i=0; i<m_table.size(); ++i) { for (int i = 0; i < m_table.size(); ++i) {
csvrow r = m_table.at(i); CsvRow r = m_table.at(i);
r.prepend(QString("")); r.prepend(QString(""));
m_table.replace(i, r); m_table.replace(i, r);
} }
} }
void CsvParserModel::mapColumns(int csvColumn, int dbColumn) { void CsvParserModel::mapColumns(int csvColumn, int dbColumn) {
if ((csvColumn < 0) || (dbColumn < 0) ) { if ((csvColumn < 0) || (dbColumn < 0))
return; return;
}
beginResetModel(); beginResetModel();
if (csvColumn >= getCsvCols()) { if (csvColumn >= getCsvCols())
m_columnMap[dbColumn] = 0; //map to the empty column m_columnMap[dbColumn] = 0; //map to the empty column
} else
else {
m_columnMap[dbColumn] = csvColumn; m_columnMap[dbColumn] = csvColumn;
}
endResetModel(); endResetModel();
} }
@ -82,8 +76,8 @@ void CsvParserModel::setSkippedRows(int skipped) {
m_skipped = skipped; m_skipped = skipped;
QModelIndex topLeft = createIndex(skipped,0); QModelIndex topLeft = createIndex(skipped,0);
QModelIndex bottomRight = createIndex(m_skipped+rowCount(), columnCount()); QModelIndex bottomRight = createIndex(m_skipped+rowCount(), columnCount());
Q_EMIT dataChanged(topLeft, bottomRight); emit dataChanged(topLeft, bottomRight);
Q_EMIT layoutChanged(); emit layoutChanged();
} }
void CsvParserModel::setHeaderLabels(QStringList l) { void CsvParserModel::setHeaderLabels(QStringList l) {
@ -91,45 +85,37 @@ void CsvParserModel::setHeaderLabels(QStringList l) {
} }
int CsvParserModel::rowCount(const QModelIndex &parent) const { int CsvParserModel::rowCount(const QModelIndex &parent) const {
if (parent.isValid()) { if (parent.isValid())
return 0; return 0;
}
return getCsvRows(); return getCsvRows();
} }
int CsvParserModel::columnCount(const QModelIndex &parent) const { int CsvParserModel::columnCount(const QModelIndex &parent) const {
if (parent.isValid()) { if (parent.isValid())
return 0; return 0;
}
return m_columnHeader.size(); return m_columnHeader.size();
} }
QVariant CsvParserModel::data(const QModelIndex &index, int role) const { QVariant CsvParserModel::data(const QModelIndex &index, int role) const {
if ( (index.column() >= m_columnHeader.size()) if ((index.column() >= m_columnHeader.size())
|| (index.row()+m_skipped >= rowCount()) || (index.row()+m_skipped >= rowCount())
|| !index.isValid() ) || !index.isValid()) {
{
return QVariant(); return QVariant();
} }
if (role == Qt::DisplayRole)
if (role == Qt::DisplayRole) {
return m_table.at(index.row()+m_skipped).at(m_columnMap[index.column()]); return m_table.at(index.row()+m_skipped).at(m_columnMap[index.column()]);
}
return QVariant(); return QVariant();
} }
QVariant CsvParserModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant CsvParserModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) { if (orientation == Qt::Horizontal) {
if ( (section < 0) || (section >= m_columnHeader.size())) { if ((section < 0) || (section >= m_columnHeader.size()))
return QVariant(); return QVariant();
}
return m_columnHeader.at(section); return m_columnHeader.at(section);
} } else if (orientation == Qt::Vertical) {
else if (orientation == Qt::Vertical) { if (section+m_skipped >= rowCount())
if (section+m_skipped >= rowCount()) {
return QVariant(); return QVariant();
}
return QString::number(section+1); return QString::number(section+1);
} }
} }

View File

@ -20,8 +20,9 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QMap> #include <QMap>
#include "core/Group.h"
#include "core/CsvParser.h" #include "core/CsvParser.h"
#include "core/Group.h"
class CsvParserModel : public QAbstractTableModel, public CsvParser class CsvParserModel : public QAbstractTableModel, public CsvParser
{ {
@ -29,7 +30,7 @@ class CsvParserModel : public QAbstractTableModel, public CsvParser
public: public:
explicit CsvParserModel(QObject *parent = nullptr); explicit CsvParserModel(QObject *parent = nullptr);
virtual ~CsvParserModel(); ~CsvParserModel();
void setFilename(const QString& filename); void setFilename(const QString& filename);
QString getFileInfo(); QString getFileInfo();
bool parse(); bool parse();
@ -37,10 +38,10 @@ public:
void setHeaderLabels(QStringList l); void setHeaderLabels(QStringList l);
void mapColumns(int csvColumn, int dbColumn); void mapColumns(int csvColumn, int dbColumn);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
public Q_SLOTS: public Q_SLOTS:
void setSkippedRows(int skipped); void setSkippedRows(int skipped);

View File

@ -62,8 +62,8 @@ private Q_SLOTS:
private: private:
QFile file; QFile file;
CsvParser* parser; CsvParser* parser;
csvtable t; CsvTable t;
void dumpRow(csvtable table, int row); void dumpRow(CsvTable table, int row);
}; };
#endif // KEEPASSX_TESTCSVPARSER_H #endif // KEEPASSX_TESTCSVPARSER_H