summaryrefslogtreecommitdiff
path: root/src/export-import
diff options
context:
space:
mode:
Diffstat (limited to 'src/export-import')
-rw-r--r--src/export-import/CsvData.h36
-rw-r--r--src/export-import/CsvDialog.cpp176
-rw-r--r--src/export-import/CsvDialog.h62
-rw-r--r--src/export-import/CsvExportDialog.cpp137
-rw-r--r--src/export-import/CsvExportDialog.h52
-rw-r--r--src/export-import/CsvImportDialog.cpp155
-rw-r--r--src/export-import/CsvImportDialog.h64
7 files changed, 682 insertions, 0 deletions
diff --git a/src/export-import/CsvData.h b/src/export-import/CsvData.h
new file mode 100644
index 0000000..c6ea9ad
--- /dev/null
+++ b/src/export-import/CsvData.h
@@ -0,0 +1,36 @@
+#ifndef CSVDATA_H
+#define CSVDATA_H
+
+#include <QtCore>
+
+enum FieldSeparationMode
+{
+ EFieldSeparatorAnyCharacter = 0,
+ EFieldSeparatorAnyCombination,
+ EFieldSeparatorExactString
+};
+
+struct CsvParams
+{
+ QString fieldSeparators;
+ QChar textDelimiter;
+ QChar commentChar;
+};
+
+struct CsvImportData: public CsvParams
+{
+ QTextCodec* textCodec;
+ int fromLine;
+ bool firstLineIsHeader;
+ FieldSeparationMode fieldSeparationMode;
+ int colsToImport; // 0 = All columns
+};
+
+struct CsvExportData: public CsvParams
+{
+ QList<int> usedCols; // Empty = use all columns
+ bool quoteAllFields;
+ bool writeColumnNames;
+};
+
+#endif
diff --git a/src/export-import/CsvDialog.cpp b/src/export-import/CsvDialog.cpp
new file mode 100644
index 0000000..b19d029
--- /dev/null
+++ b/src/export-import/CsvDialog.cpp
@@ -0,0 +1,176 @@
+#include "CsvDialog.h"
+
+QChar CsvDialog::SpaceChar(0x2423);
+QChar CsvDialog::TabChar(0x21A6);
+QString CsvDialog::ExtendedTab(QString(QChar(0x21A6)) + "\t");
+
+CsvDialog::CsvDialog(QWidget* parent):
+ QDialog(parent)
+{
+ resize(600, 550);
+}
+
+void CsvDialog::init()
+{
+ setLayout(createMainLayout());
+ updatePreview();
+ connectControlsToPreview();
+}
+
+void CsvDialog::connectControlsToPreview()
+{
+ connect(separatorsEdit, SIGNAL(textChanged(QString)), SLOT(updatePreview()) );
+ connect(textDelimiterCB, SIGNAL(stateChanged(int)), SLOT(updatePreview()) );
+ connect(textDelimiterCombo, SIGNAL(editTextChanged(QString)), SLOT(updatePreview()) );
+ connect(commentCharCombo, SIGNAL(editTextChanged(QString)), SLOT(updatePreview()) );
+}
+
+QLayout* CsvDialog::createMainLayout()
+{
+ QVBoxLayout* lt = new QVBoxLayout;
+ lt->addLayout(createTopLayout());
+ lt->addWidget(new QLabel(tr("Preview:")));
+ lt->addLayout(createPreviewLt());
+ lt->addWidget(createButtonBox());
+ return lt;
+}
+
+QLayout* CsvDialog::createTopLayout()
+{
+ QHBoxLayout* lt = new QHBoxLayout;
+ lt->addWidget(createLeftGroup());
+ lt->addWidget(createSeparatorsGroup());
+ return lt;
+}
+
+QWidget* CsvDialog::createCharSetCombo()
+{
+ charSetCombo = new QComboBox;
+ charSetCombo->setEditable(false);
+ QList<QByteArray> codecNames = QTextCodec::availableCodecs();
+ qSort( codecNames );
+ for( int i=0; i<codecNames.size(); i++)
+ charSetCombo->addItem(codecNames[i],
+ QTextCodec::codecForName(codecNames[i] )->mibEnum());
+ int utf8Ix = codecNames.indexOf( "UTF-8" );
+ charSetCombo->setCurrentIndex( utf8Ix );
+ return charSetCombo;
+}
+
+QGroupBox* CsvDialog::createLeftGroup()
+{
+ QGroupBox* group = new QGroupBox(getLeftGroupTitle());
+ group->setLayout(createLeftGroupLayout());
+ return group;
+}
+
+QGroupBox* CsvDialog::createSeparatorsGroup()
+{
+ QGroupBox* group = new QGroupBox(tr("Separators"));
+ group->setLayout(createSeparatorsLayout());
+ return group;
+}
+
+QDialogButtonBox* CsvDialog::createButtonBox()
+{
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(
+ QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()), SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), SLOT(reject()));
+ return buttonBox;
+}
+
+QWidget* CsvDialog::createFieldSeparatorWidget(const QString& additionalSeparators)
+{
+ separatorsEdit = new QLineEdit(QString(TabChar) + "&" + additionalSeparators);
+ connect(separatorsEdit, SIGNAL(textChanged(const QString&)),
+ SLOT(showInvisibleInSeparatorsEdit()));
+
+ QPushButton* addSeparatorBtn = new QPushButton(tr("Ta&b"));
+ addSeparatorBtn->setMinimumWidth(40);
+ connect(addSeparatorBtn, SIGNAL(clicked()), SLOT(insertTabToSeparators()));
+
+ QHBoxLayout* lt = new QHBoxLayout;
+ lt->addWidget(separatorsEdit);
+ lt->addWidget(addSeparatorBtn);
+ lt->setContentsMargins(QMargins());
+
+ // Workaround for a bug in QFormLayout::addRow(text, layout)
+ QWidget* widget = new QWidget;
+ widget->setLayout(lt);
+ return widget;
+}
+
+QWidget* CsvDialog::createTextDelimiterBox()
+{
+ textDelimiterCB = new QCheckBox(tr("&Text delimiter:"));
+ textDelimiterCB->setChecked(true);
+ return textDelimiterCB;
+}
+
+QWidget* CsvDialog::createTextDelimiterCombo()
+{
+ return textDelimiterCombo = createEditableCombo(QStringList() << "\"" << "\'");
+}
+
+QWidget* CsvDialog::createCommentCharCombo()
+{
+ return commentCharCombo = createEditableCombo(QStringList() << "#" << ";");
+}
+
+QComboBox* CsvDialog::createEditableCombo(const QStringList& items)
+{
+ QComboBox* combo = new QComboBox;
+ combo->setEditable(true);
+ combo->setInsertPolicy(QComboBox::NoInsert);
+ combo->setValidator(new QRegExpValidator(QRegExp("\\S{1}"), this));
+ combo->addItems(items);
+ return combo;
+}
+
+QChar CsvDialog::getTextDelimiterChar() const
+{
+ if(textDelimiterCB->isChecked() && !textDelimiterCombo->currentText().isEmpty())
+ return textDelimiterCombo->currentText()[0];
+ else
+ return QChar(0);
+}
+
+void CsvDialog::showInvisibleInSeparatorsEdit()
+{
+ separatorsEdit->setText(setCharVisibility(separatorsEdit->text(), true));
+}
+
+void CsvDialog::insertTabToSeparators()
+{
+ separatorsEdit->insert(TabChar);
+}
+
+QTextCodec* CsvDialog::getTextCodec()
+{
+ return QTextCodec::codecForMib(
+ charSetCombo->itemData(charSetCombo->currentIndex()).toInt());
+}
+
+/// Convert invisible chars like space and tab to visible equivalents or vice versa.
+QString CsvDialog::setCharVisibility(const QString& input, bool visible)
+{
+ QString res = input;
+ if(visible)
+ {
+ res.replace(' ', SpaceChar);
+ res.replace('\t', ExtendedTab);
+ }
+ else
+ {
+ res.replace(SpaceChar, ' ');
+ res.replace(ExtendedTab, "\t");
+ res.replace(TabChar, '\t');
+ }
+ return res;
+}
+
+void CsvDialog::updateTextDelimiterCombo()
+{
+ textDelimiterCombo->setEnabled( textDelimiterCB->isChecked() );
+}
diff --git a/src/export-import/CsvDialog.h b/src/export-import/CsvDialog.h
new file mode 100644
index 0000000..f50cd62
--- /dev/null
+++ b/src/export-import/CsvDialog.h
@@ -0,0 +1,62 @@
+#ifndef CSV_DIALOG_H
+#define CSV_DIALOG_H
+
+#include <QtCore>
+#include <QtWidgets>
+
+class CsvDialog: public QDialog
+{
+ Q_OBJECT
+
+public:
+ CsvDialog(QWidget* parent);
+
+protected:
+ static QString setCharVisibility(const QString& input, bool visible);
+
+protected:
+ void init();
+ virtual QLayout* createLeftGroupLayout() = 0;
+ virtual QString getLeftGroupTitle() = 0;
+ QWidget* createCharSetCombo();
+ virtual QLayout* createSeparatorsLayout() = 0;
+ QWidget* createFieldSeparatorWidget(const QString& additionalSeparators = "");
+ QWidget* createTextDelimiterBox();
+ QWidget* createTextDelimiterCombo();
+ QWidget* createCommentCharCombo();
+ QComboBox* createEditableCombo(const QStringList& items);
+ virtual QLayout* createPreviewLt() = 0;
+ QDialogButtonBox* createButtonBox();
+ QTextCodec* getTextCodec();
+ QChar getTextDelimiterChar() const;
+
+protected slots:
+ virtual void updatePreview() = 0;
+ void updateTextDelimiterCombo();
+
+private:
+ QLayout* createMainLayout();
+ void connectControlsToPreview();
+ QLayout* createTopLayout();
+ QGroupBox* createLeftGroup();
+ QGroupBox* createSeparatorsGroup();
+ void doUpdatePreview() { updatePreview(); }
+
+private slots:
+ void showInvisibleInSeparatorsEdit();
+ void insertTabToSeparators();
+
+protected:
+ static QChar SpaceChar;
+ static QChar TabChar;
+ static QString ExtendedTab;
+
+protected:
+ QComboBox* charSetCombo;
+ QLineEdit* separatorsEdit;
+ QCheckBox* textDelimiterCB;
+ QComboBox* textDelimiterCombo;
+ QComboBox* commentCharCombo;
+};
+
+#endif
diff --git a/src/export-import/CsvExportDialog.cpp b/src/export-import/CsvExportDialog.cpp
new file mode 100644
index 0000000..9e4dc90
--- /dev/null
+++ b/src/export-import/CsvExportDialog.cpp
@@ -0,0 +1,137 @@
+#include "CsvExportDialog.h"
+
+#include "../strings.h"
+#include "../dictionary/Dictionary.h"
+#include "../dictionary/DicCsvWriter.h"
+
+CsvExportDialog::CsvExportDialog(QWidget* parent, const Dictionary* dict):
+ CsvDialog(parent),
+ dictionary(dict),
+ dicWriter(new DicCsvWriter(dict))
+{
+ init();
+ setWindowTitle(tr("Export to CSV"));
+
+ connect( textDelimiterCB, SIGNAL(stateChanged(int)), this, SLOT(updateTextDelimiterCombo()) );
+ connect( showInvisibleCharsCB, SIGNAL(stateChanged(int)), this, SLOT(UpdateCharVisibility()) );
+ connect( textDelimiterCB, SIGNAL(stateChanged(int)), this, SLOT(UpdateQuoteAllFieldsCB()) );
+
+ connect( usedColsEdit, SIGNAL(textChanged(QString)), this, SLOT(updatePreview()) );
+ connect( quoteAllFieldsCB, SIGNAL(stateChanged(int)), this, SLOT(updatePreview()) );
+ connect( writeColumnNamesCB, SIGNAL(stateChanged(int)), this, SLOT(updatePreview()) );
+}
+
+CsvExportDialog::~CsvExportDialog()
+{
+ delete dicWriter;
+}
+
+QLayout* CsvExportDialog::createLeftGroupLayout()
+{
+ QFormLayout* lt = new QFormLayout;
+ lt->addRow(tr("C&haracter set:"), createCharSetCombo());
+ lt->addRow(tr("Used &columns:"), createUsedColsEdit());
+ lt->addRow(createWriteColumnNamesBox());
+ return lt;
+}
+
+QWidget* CsvExportDialog::createUsedColsEdit()
+{
+ usedColsEdit = new QLineEdit("123");
+ usedColsEdit->setValidator(new QRegExpValidator(QRegExp("[1-9]+"), this));
+ return usedColsEdit;
+}
+
+QWidget* CsvExportDialog::createWriteColumnNamesBox()
+{
+ writeColumnNamesCB = new QCheckBox(tr("Write column &names"));
+ writeColumnNamesCB->setChecked( true );
+ return writeColumnNamesCB;
+}
+
+QLayout* CsvExportDialog::createSeparatorsLayout()
+{
+ quoteAllFieldsCB = new QCheckBox(tr("&Quote all fields"));
+
+ QFormLayout* lt = new QFormLayout;
+ lt->addRow(tr("Field &separator:"), createFieldSeparatorWidget(SpaceChar));
+ lt->addRow(createTextDelimiterBox(), createTextDelimiterCombo());
+ lt->addRow(quoteAllFieldsCB);
+ lt->addRow(tr("Co&mment character:"), createCommentCharCombo());
+ return lt;
+}
+
+QLayout* CsvExportDialog::createPreviewLt()
+{
+ QVBoxLayout* lt = new QVBoxLayout;
+ lt->addWidget(createPreview());
+ lt->addWidget(createShowInvisibleBox());
+ return lt;
+}
+
+QWidget* CsvExportDialog::createPreview()
+{
+ csvPreview = new QTextEdit;
+ csvPreview->setReadOnly(true);
+ csvPreview->setLineWrapMode( QTextEdit::NoWrap );
+ csvPreview->setFontPointSize( 10 );
+ return csvPreview;
+}
+
+QCheckBox* CsvExportDialog::createShowInvisibleBox()
+{
+ showInvisibleCharsCB = new QCheckBox(tr("Show &invisible characters"));
+ showInvisibleCharsCB->setChecked( false );
+ return showInvisibleCharsCB;
+}
+
+void CsvExportDialog::UpdateQuoteAllFieldsCB()
+{
+ quoteAllFieldsCB->setEnabled( textDelimiterCB->isChecked() );
+}
+
+void CsvExportDialog::updatePreview()
+{
+ CsvExportData params;
+ params.usedCols = getUsedColumns();
+ params.fieldSeparators = setCharVisibility( separatorsEdit->text(), false );
+ params.textDelimiter = getTextDelimiterChar();
+ params.quoteAllFields = quoteAllFieldsCB->isChecked();
+ params.commentChar = commentCharCombo->currentText()[0];
+ params.writeColumnNames = writeColumnNamesCB->isChecked();
+
+ QString csvString = dicWriter->toCsvString( params );
+ csvPreview->setPlainText(
+ setCharVisibility(csvString, showInvisibleCharsCB->isChecked()));
+}
+
+QList<int> CsvExportDialog::getUsedColumns()
+{
+ QList<int> res;
+ for(int i = 0; i < usedColsEdit->text().length(); i++)
+ {
+ int col = usedColsEdit->text()[i].digitValue();
+ if(col > 0 && col <= dictionary->fieldsNum())
+ res << col - 1;
+ }
+ return res;
+}
+
+void CsvExportDialog::SaveCSVToFile( const QString& aFilePath )
+{
+ QFile file( aFilePath );
+ if( !file.open( QIODevice::WriteOnly | QFile::Text ) ) // \r\n --> \n
+ {
+ QMessageBox::warning( this, Strings::errorTitle(), tr("Cannot save to file:\n %1.").arg(aFilePath) );
+ return;
+ }
+ QTextStream outStream( &file );
+ outStream.setCodec( getTextCodec() );
+ outStream << setCharVisibility( csvPreview->toPlainText(), false );
+}
+
+void CsvExportDialog::UpdateCharVisibility()
+{
+ csvPreview->setPlainText(
+ setCharVisibility(csvPreview->toPlainText(), showInvisibleCharsCB->isChecked()) );
+}
diff --git a/src/export-import/CsvExportDialog.h b/src/export-import/CsvExportDialog.h
new file mode 100644
index 0000000..d99c421
--- /dev/null
+++ b/src/export-import/CsvExportDialog.h
@@ -0,0 +1,52 @@
+#ifndef CSVEXPORTDIALOG_H
+#define CSVEXPORTDIALOG_H
+
+#include <QtCore>
+#include <QtWidgets>
+
+#include "CsvDialog.h"
+
+class Dictionary;
+class DicCsvWriter;
+
+class CsvExportDialog: public CsvDialog
+{
+ Q_OBJECT
+
+public:
+ CsvExportDialog(QWidget* parent, const Dictionary* dict );
+ ~CsvExportDialog();
+
+ void SaveCSVToFile( const QString& aFilePath );
+
+protected:
+ QLayout* createLeftGroupLayout();
+ QString getLeftGroupTitle() { return tr("Output"); }
+ QLayout* createSeparatorsLayout();
+ QLayout* createPreviewLt();
+
+protected slots:
+ void updatePreview();
+
+private slots:
+ void UpdateQuoteAllFieldsCB();
+ void UpdateCharVisibility();
+
+private:
+ QWidget* createUsedColsEdit();
+ QWidget* createWriteColumnNamesBox();
+ QList<int> getUsedColumns();
+ QWidget* createPreview();
+ QCheckBox* createShowInvisibleBox();
+
+private:
+ const Dictionary* dictionary; // not own, created here
+ DicCsvWriter* dicWriter;
+ QLineEdit* usedColsEdit;
+ QCheckBox* writeColumnNamesCB;
+ QCheckBox* quoteAllFieldsCB;
+ QTextEdit* csvPreview;
+ QCheckBox* showInvisibleCharsCB;
+};
+
+#endif
diff --git a/src/export-import/CsvImportDialog.cpp b/src/export-import/CsvImportDialog.cpp
new file mode 100644
index 0000000..51c3c87
--- /dev/null
+++ b/src/export-import/CsvImportDialog.cpp
@@ -0,0 +1,155 @@
+#include "CsvImportDialog.h"
+
+#include "../main-view/DictTableView.h"
+#include "../main-view/DictTableModel.h"
+#include "../dictionary/Dictionary.h"
+#include "../dictionary/DicCsvReader.h"
+
+CsvImportDialog::CsvImportDialog(QWidget* parent, QString filePath, const AppModel* appModel):
+ CsvDialog(parent),
+ filePath(filePath),
+ dictionary(NULL),
+ appModel(appModel)
+{
+ init();
+ setWindowTitle(tr("Import from CSV"));
+
+ connect( textDelimiterCB, SIGNAL(stateChanged(int)), this, SLOT(updateTextDelimiterCombo()) );
+ connect( commentCharCB, SIGNAL(stateChanged(int)), this, SLOT(UpdateCommentCharacterCombo()) );
+ connect( this, SIGNAL(rejected()), this, SLOT(DeleteDictionary()) );
+
+ connect( charSetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePreview()) );
+ connect( fromLineSpin, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
+ connect( firstLineIsHeaderCB, SIGNAL(stateChanged(int)), this, SLOT(updatePreview()) );
+ connect( anyCharacterRB, SIGNAL(toggled(bool)), this, SLOT(updatePreview()) );
+ connect( anyCombinationRB, SIGNAL(toggled(bool)), this, SLOT(updatePreview()) );
+ connect( exactStringRB, SIGNAL(toggled(bool)), this, SLOT(updatePreview()) );
+ connect( commentCharCB, SIGNAL(stateChanged(int)), this, SLOT(updatePreview()) );
+ connect( colsToImportSpin, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
+}
+
+CsvImportDialog::~CsvImportDialog()
+{
+ delete iPreviewModel;
+ delete dicReader;
+}
+
+QLayout* CsvImportDialog::createLeftGroupLayout()
+{
+ QFormLayout* lt = new QFormLayout;
+ lt->addRow(tr("C&haracter set:"), createCharSetCombo());
+ lt->addRow(tr("From &line:"), createFromLineSpin());
+ lt->addRow(tr("Number of colum&ns:"), createColsToImportSpin());
+ lt->addRow(createFirstLineIsHeaderCB());
+ return lt;
+}
+
+QWidget* CsvImportDialog::createFromLineSpin()
+{
+ fromLineSpin = new QSpinBox();
+ fromLineSpin->setRange(1, 100);
+ return fromLineSpin;
+}
+
+QWidget* CsvImportDialog::createColsToImportSpin()
+{
+ colsToImportSpin = new QSpinBox();
+ colsToImportSpin->setRange(0, 9);
+ colsToImportSpin->setSpecialValueText(tr("All"));
+ return colsToImportSpin;
+}
+
+QWidget* CsvImportDialog::createFirstLineIsHeaderCB()
+{
+ firstLineIsHeaderCB = new QCheckBox(tr("&First line has field names"));
+ firstLineIsHeaderCB->setChecked(false);
+ return firstLineIsHeaderCB;
+}
+
+QLayout* CsvImportDialog::createSeparatorsLayout()
+{
+ createSeparationRadioButtons();
+
+ QFormLayout* lt = new QFormLayout;
+ lt->addRow(tr("Field &separator:"),
+ createFieldSeparatorWidget());
+ lt->addRow(tr("Separation mode:"), anyCharacterRB);
+ // The label is a workaround to make enough space for the radio button text
+ lt->addRow(" ", anyCombinationRB);
+ lt->addRow(NULL, exactStringRB);
+ lt->addRow(createTextDelimiterBox(), createTextDelimiterCombo());
+ lt->addRow(createCommentCharBox(), createCommentCharCombo());
+ return lt;
+}
+
+void CsvImportDialog::createSeparationRadioButtons()
+{
+ anyCharacterRB = new QRadioButton(tr("An&y character"));
+ anyCharacterRB->setToolTip(tr("Fields are separated by any separator character"));
+ anyCombinationRB = new QRadioButton(tr("A co&mbination of characters"));
+ anyCombinationRB->setToolTip(tr("Fields are separated by a combination of separator characters, in any order"));
+ anyCombinationRB->setChecked( true );
+ exactStringRB = new QRadioButton(tr("E&xact string"));
+ exactStringRB->setToolTip(tr("Fields are separated by the exact string of separators, in the above defined order"));
+}
+
+QWidget* CsvImportDialog::createCommentCharBox()
+{
+ commentCharCB = new QCheckBox(tr("&Comment character:"));
+ commentCharCB->setChecked(true);
+ return commentCharCB;
+}
+
+QLayout* CsvImportDialog::createPreviewLt()
+{
+ QVBoxLayout* lt = new QVBoxLayout;
+ lt->addWidget(createPreview());
+ return lt;
+}
+
+QWidget* CsvImportDialog::createPreview()
+{
+ dictionary = new Dictionary( filePath + Dictionary::DictFileExtension, true, appModel );
+ dicReader = new DicCsvReader( dictionary );
+ iPreviewModel = new DictTableModel( dictionary );
+ previewTable = new DictTableView(iPreviewModel);
+ return previewTable;
+}
+
+void CsvImportDialog::UpdateCommentCharacterCombo()
+{
+ commentCharCombo->setEnabled( commentCharCB->isChecked() );
+}
+
+void CsvImportDialog::updatePreview()
+{
+ CsvImportData params;
+ params.textCodec = getTextCodec();
+ params.fromLine = fromLineSpin->value();
+ params.fieldSeparators = setCharVisibility(separatorsEdit->text(), false);
+ params.fieldSeparationMode = getSeparationMode();
+ params.commentChar = commentCharCB->isChecked()?
+ commentCharCombo->currentText()[0]: QChar(0);
+ params.textDelimiter = getTextDelimiterChar();
+ params.colsToImport = colsToImportSpin->value();
+ params.firstLineIsHeader = firstLineIsHeaderCB->isChecked();
+
+ dicReader->readDict( filePath, params );
+ iPreviewModel->resetData();
+}
+
+FieldSeparationMode CsvImportDialog::getSeparationMode()
+{
+ if(anyCharacterRB->isChecked())
+ return EFieldSeparatorAnyCharacter;
+ else if (anyCombinationRB->isChecked())
+ return EFieldSeparatorAnyCombination;
+ else
+ return EFieldSeparatorExactString;
+}
+
+void CsvImportDialog::DeleteDictionary()
+{
+delete dictionary;
+dictionary = NULL;
+}
diff --git a/src/export-import/CsvImportDialog.h b/src/export-import/CsvImportDialog.h
new file mode 100644
index 0000000..bc3a9d1
--- /dev/null
+++ b/src/export-import/CsvImportDialog.h
@@ -0,0 +1,64 @@
+#ifndef CSVIMPORTDIALOG_H
+#define CSVIMPORTDIALOG_H
+
+#include <QtCore>
+#include <QtWidgets>
+
+#include "CsvData.h"
+#include "CsvDialog.h"
+
+class DictTableView;
+class Dictionary;
+class DicCsvReader;
+class DictTableModel;
+class AppModel;
+
+class CsvImportDialog: public CsvDialog
+{
+ Q_OBJECT
+
+public:
+ CsvImportDialog(QWidget* parent, QString filePath, const AppModel* appModel );
+ ~CsvImportDialog();
+
+ Dictionary* getDictionary() { return dictionary; }
+
+protected:
+ QLayout* createLeftGroupLayout();
+ QString getLeftGroupTitle() { return tr("Input"); }
+ QLayout* createSeparatorsLayout();
+ QLayout* createPreviewLt();
+
+protected slots:
+ void updatePreview();
+
+private slots:
+ void UpdateCommentCharacterCombo();
+ void DeleteDictionary();
+
+private:
+ QWidget* createFromLineSpin();
+ QWidget* createColsToImportSpin();
+ QWidget* createFirstLineIsHeaderCB();
+ void createSeparationRadioButtons();
+ FieldSeparationMode getSeparationMode();
+ QWidget* createCommentCharBox();
+ QWidget* createPreview();
+
+private:
+ QString filePath;
+ Dictionary* dictionary; // not own, created here
+ const AppModel* appModel;
+ DicCsvReader* dicReader;
+ DictTableModel* iPreviewModel;
+ QSpinBox* fromLineSpin; // 1-based
+ QSpinBox* colsToImportSpin; // 1-based; 0 = all
+ QCheckBox* firstLineIsHeaderCB;
+ QRadioButton* anyCharacterRB;
+ QRadioButton* anyCombinationRB;
+ QRadioButton* exactStringRB;
+ QCheckBox* commentCharCB;
+ DictTableView* previewTable;
+};
+
+#endif