From 60254fe39a75eb5a4ff46715b9eb99c290970333 Mon Sep 17 00:00:00 2001 From: "Kiselev K.V" Date: Sun, 25 Nov 2018 14:26:34 +0700 Subject: [PATCH] first commit --- .gitignore | 3 + README.md | 7 ++ XmlParser.pro | 29 +++++ database.cpp | 148 +++++++++++++++++++++++++ database.h | 40 +++++++ dialogeditrecord.cpp | 52 +++++++++ dialogeditrecord.h | 40 +++++++ dialogeditrecord.ui | 52 +++++++++ main.cpp | 11 ++ mainwindow.cpp | 235 ++++++++++++++++++++++++++++++++++++++++ mainwindow.h | 57 ++++++++++ mainwindow.ui | 90 +++++++++++++++ parserxmlworker.cpp | 58 ++++++++++ parserxmlworker.h | 23 ++++ test_xml_dir/param1.xml | 93 ++++++++++++++++ test_xml_dir/param2.xml | 87 +++++++++++++++ test_xml_dir/param3.xml | 93 ++++++++++++++++ 17 files changed, 1118 insertions(+) create mode 100644 .gitignore create mode 100644 XmlParser.pro create mode 100644 database.cpp create mode 100644 database.h create mode 100644 dialogeditrecord.cpp create mode 100644 dialogeditrecord.h create mode 100644 dialogeditrecord.ui create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 parserxmlworker.cpp create mode 100644 parserxmlworker.h create mode 100644 test_xml_dir/param1.xml create mode 100644 test_xml_dir/param2.xml create mode 100644 test_xml_dir/param3.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d4320b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +Makefile +*.user diff --git a/README.md b/README.md index 42110dd..7dd74dd 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # XmlParser GUI program parse xml files, mapping in QTableView and save in SQLite. Qt5 + +#For build +qmake +make + +#For run +./XmlParser \ No newline at end of file diff --git a/XmlParser.pro b/XmlParser.pro new file mode 100644 index 0000000..993718e --- /dev/null +++ b/XmlParser.pro @@ -0,0 +1,29 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-11-21T12:15:31 +# +#------------------------------------------------- + +QT += core gui xml sql + +CONFIG += c++11 + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = XmlParser +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp \ + database.cpp \ + parserxmlworker.cpp \ + dialogeditrecord.cpp + +HEADERS += mainwindow.h \ + database.h \ + parserxmlworker.h \ + dialogeditrecord.h + +FORMS += mainwindow.ui \ + dialogeditrecord.ui diff --git a/database.cpp b/database.cpp new file mode 100644 index 0000000..f9b61ae --- /dev/null +++ b/database.cpp @@ -0,0 +1,148 @@ +#include "database.h" + +DataBase::DataBase(QObject *parent) : QObject(parent) +{ +} + + +void DataBase::connectToDataBase() +{ + if(!QFile(DATABASE_NAME).exists()) + { + this->restoreDataBase(); + } + else + { + this->openDataBase(); + } +} + + +/* Методы восстановления базы данных + * */ +bool DataBase::restoreDataBase() +{ + if(this->openDataBase()) + { + if(!this->createTable()) + { + return false; + } + else + { + return true; + } + } + else + { + qDebug() << "Не удалось восстановить базу данных"; + return false; + } + return false; +} + +/* Метод для открытия базы данных */ +bool DataBase::openDataBase() +{ + /* База данных открывается по заданному пути + * и имени базы данных, если она существует + * */ + db = QSqlDatabase::addDatabase("QSQLITE"); + db.setHostName(HOST_NAME); + db.setDatabaseName(DATABASE_NAME); + + if(db.open()) + { + return true; + } + else + { + return false; + } +} + +bool DataBase::createTable() +{ + QSqlQuery query; + QString strCreate = "CREATE TABLE "; + strCreate +=TABLE; + strCreate += " (name INTEGER, value VARCHAR(255));"; + + if(!query.exec(strCreate)) + { + qDebug() << "Error crate table " << query.lastError(); + return false; + } + + return true; +} + +void DataBase::printTables() +{ + foreach(QString str, db.tables()) + { + qDebug() << "Tables:" << str; + } +} + +void DataBase::doInsert(QMultiMap *arrayXml) +{ + int count = 0; + + //doCleanData(); + createTable(); + + QSqlQuery query; + //Insert data in database + //QString strInsert = "INSERT INTO "; + //strInsert += TABLE; + //strInsert += " (name, value) VALUES('%1', '%2');"; + + QString strInsert = "INSERT INTO "; + strInsert += TABLE; + strInsert += " (name, value) VALUES(:name, :value)"; + + query.prepare(strInsert); + + for(QMultiMap::iterator iii = arrayXml->begin(); iii != arrayXml->end(); iii++) + { + //QString strInsert2 = strInsert.arg(iii.key()) + // .arg(iii.value()); + + query.bindValue(":name", iii.key()); + query.bindValue(":value", iii.value()); + + if(!query.exec()) + { + qDebug() << "Error insert data"; + break; + } + + if((count % 10) == 0) + { + + emit changeProgressInsert(count); + } + count++; + + } + + + + emit changeProgressInsert(arrayXml->size()); +} + +void DataBase::doCleanData() +{ + QSqlQuery query; + + QString strDrop = "DROP TABLE "; + strDrop += TABLE; + strDrop += " ;"; + + if(!query.exec(strDrop)) + { + qDebug() << "Error drop table " << query.lastError(); + } + +} diff --git a/database.h b/database.h new file mode 100644 index 0000000..9b7f67d --- /dev/null +++ b/database.h @@ -0,0 +1,40 @@ +#ifndef DATABASE_H +#define DATABASE_H + +#include +#include + +#define DATABASE_NAME "my_sqllite" +#define USER_NAME "user" +#define HOST_NAME "127.0.0.1" +#define PASSWORD "1" + +#define TABLE "xmldata" + + +/* Вспомогтаельный класс для работы с БД */ +class DataBase : public QObject +{ + Q_OBJECT + bool restoreDataBase(); + bool openDataBase(); + + QSqlDatabase db; + +public: + explicit DataBase(QObject *parent = 0); + void connectToDataBase(); + void printTables(); + + bool createTable(); + +signals: + void changeProgressInsert(int value); + +public slots: + void doInsert(QMultiMap *arrayXml); + void doCleanData(); + +}; + +#endif // DATABASE_H diff --git a/dialogeditrecord.cpp b/dialogeditrecord.cpp new file mode 100644 index 0000000..15003e6 --- /dev/null +++ b/dialogeditrecord.cpp @@ -0,0 +1,52 @@ +#include "dialogeditrecord.h" +#include "ui_dialogeditrecord.h" + +DialogEditRecord::DialogEditRecord(int row, QWidget *parent) : + QDialog(parent), + ui(new Ui::DialogEditRecord) +{ + ui->setupUi(this); + + setupModel(); + + if(row != -1) + { + mapper->setCurrentModelIndex(model->index(row,0)); + } + +} + +DialogEditRecord::~DialogEditRecord() +{ + delete ui; +} + +void DialogEditRecord::setupModel() +{ + // Инициализируем модель и делаем выборку + model = new QSqlTableModel(this); + model->setTable(TABLE); + model->setEditStrategy(QSqlTableModel::OnManualSubmit); + model->select(); + + // Инициализируем mapper и привязываем поля данных к объектам LineEdit + mapper = new QDataWidgetMapper(); + mapper->setModel(model); + + mapper->addMapping(ui->lineEditName, 0); + mapper->addMapping(ui->lineEditValue, 1); + + //mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); + //connect(ui->previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious())); + //connect(ui->nextButton, SIGNAL(clicked()), mapper, SLOT(toNext())); + + connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int))); +} + +void DialogEditRecord::on_pushButton_clicked() +{ + mapper->submit(); + model->submitAll(); + emit readyToUpdate(); + this->close(); +} diff --git a/dialogeditrecord.h b/dialogeditrecord.h new file mode 100644 index 0000000..87e9237 --- /dev/null +++ b/dialogeditrecord.h @@ -0,0 +1,40 @@ +#ifndef DIALOGEDITRECORD_H +#define DIALOGEDITRECORD_H + +#include "database.h" + +#include +#include +#include +#include +#include + + + +namespace Ui { +class DialogEditRecord; +} + +class DialogEditRecord : public QDialog +{ + Q_OBJECT + +public: + explicit DialogEditRecord(int row, QWidget *parent = 0); + ~DialogEditRecord(); + +signals: + void readyToUpdate(); + +private slots: + void on_pushButton_clicked(); + +private: + void setupModel(); + + Ui::DialogEditRecord *ui; + QSqlTableModel *model; + QDataWidgetMapper *mapper; +}; + +#endif // DIALOGEDITRECORD_H diff --git a/dialogeditrecord.ui b/dialogeditrecord.ui new file mode 100644 index 0000000..8b5fd66 --- /dev/null +++ b/dialogeditrecord.ui @@ -0,0 +1,52 @@ + + + DialogEditRecord + + + + 0 + 0 + 247 + 157 + + + + Dialog + + + + + + + + + + + + + + Имя + + + + + + + Значение + + + + + + + + + Запись + + + + + + + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..9abea4d --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,235 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include +#include +#include +#include + + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + workerBD = new DataBase(); + workerBD->connectToDataBase(); + workerBD->printTables(); + workerBD->moveToThread(&workerBDThread); + + connect(this, &MainWindow::startInsert, workerBD, &DataBase::doInsert); + connect(workerBD, &DataBase::changeProgressInsert, this, &MainWindow::setProgressInsert); + connect(this, &MainWindow::cleanData, workerBD, &DataBase::doCleanData); + + tableModel = new QSqlTableModel(this); + tableModel->setTable(TABLE); + + QStringList headers; + + headers << trUtf8("Имя") + << trUtf8("Значение"); + + for(int i = 0, j = 0; i < tableModel->columnCount(); i++, j++) + { + tableModel->setHeaderData(i,Qt::Horizontal,headers[j]); + } + tableModel->setEditStrategy(QSqlTableModel::OnRowChange); + // Устанавливаем сортировку по возрастанию данных по нулевой колонке + tableModel->setSort(0,Qt::AscendingOrder); + // Делаем выборку данных из таблицы + tableModel->select(); + + // Устанавливаем модель на TableView + ui->tableView->setModel(tableModel); + // Разрешаем выделение строк + ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + // Устанавливаем режим выделения лишь одно строки в таблице + ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); + // Устанавливаем размер колонок по содержимому + ui->tableView->resizeColumnsToContents(); + ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->tableView->horizontalHeader()->setStretchLastSection(true); + // Устанавливаем Контекстное Меню + ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); + + //connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotEditRecord())); + // Подключаем СЛОТ вызова контекстного меню + connect(ui->tableView, &QTableView::customContextMenuRequested, this, &MainWindow::customMenuRequested); + + workerXML = new ParserXMLWorker(); + workerXML->moveToThread(&workerXMLThread); + + //connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &MainWindow::startParseXML, workerXML, &ParserXMLWorker::doParser); + connect(workerXML, &ParserXMLWorker::changeProgressParseXML, this, &MainWindow::setProgressParseXML); + + workerXMLThread.start(); + workerBDThread.start(); + + fileList = NULL; +} + + +void MainWindow::customMenuRequested(QPoint pos) +{ + /* Создаем объект контекстного меню */ + QMenu * menu = new QMenu(this); + /* Создаём действия для контекстного меню */ + QAction * editDevice = new QAction(trUtf8("Редактировать"), this); + QAction * deleteDevice = new QAction(trUtf8("Удалить"), this); + /* Подключаем СЛОТы обработчики для действий контекстного меню */ + connect(editDevice, &QAction::triggered, this, &MainWindow::editRecord); // Обработчик вызова диалога редактирования + connect(deleteDevice, &QAction::triggered, this, &MainWindow::removeRecord); // Обработчик удаления записи + + /* Устанавливаем действия в меню */ + menu->addAction(editDevice); + menu->addAction(deleteDevice); + /* Вызываем контекстное меню */ + menu->popup(ui->tableView->viewport()->mapToGlobal(pos)); +} + +void MainWindow::removeRecord() +{ + // Выясняем, какая из строк была выбрана + int row = ui->tableView->selectionModel()->currentIndex().row(); + + // Проверяем, что строка была действительно выбрана + if(row >= 0) + { + tableModel->removeRow(row); + tableModel->select(); + ui->tableView->setCurrentIndex(tableModel->index(-1, -1)); + } +} + +void MainWindow::editRecord() +{ + DialogEditRecord *editDialog = new DialogEditRecord(ui->tableView->selectionModel()->currentIndex().row()); + connect(editDialog, &DialogEditRecord::readyToUpdate, this, &MainWindow::updateModel); + + editDialog->setWindowTitle(trUtf8("Редактировать запись")); + editDialog->exec(); +} + +void MainWindow::updateModel() +{ + tableModel->select(); + ui->tableView->resizeColumnsToContents(); +} + + +MainWindow::~MainWindow() +{ + workerXMLThread.quit(); + workerXMLThread.wait(); + + workerBDThread.quit(); + workerBDThread.wait(); + + delete workerXML; + delete ui; +} + +void MainWindow::on_loadButton_clicked() +{ + // QString fileName = QFileDialog::getOpenFileName(this, tr("Open xml file"), "./", tr("XML files (*.xml)")); + QString dirName = QFileDialog::getExistingDirectory(this, tr("Выбирите директорию с xml файлами"), + "./", + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + if(dirName == "") + { + return; + } + + + QDir dir(dirName); + + dir.setFilter(QDir::NoDotAndDotDot | QDir::Files); + dir.setNameFilters(QStringList("*.xml")); + + fileList = new QFileInfoList (dir.entryInfoList()); + + if(fileList->size() == 0) + { + QMessageBox::warning(this, "Сообщение", "В выбранной директории нет xml файлов"); + return; + } + + progressDialog = new QProgressDialog("Parse file ...", QString(), 0, fileList->size(), this); + progressDialog->setMinimumDuration(0); + progressDialog->setWindowTitle("Пожалуйста подождите"); + progressDialog->setAutoClose(true); + + emit startParseXML(fileList, &arrayXml); +} + +void MainWindow::on_clearButton_clicked() +{ + qDebug () << "clear"; + tableModel->clear(); + + qDebug () << "reset"; + ui->tableView->reset(); + + emit cleanData(); +} + +void MainWindow::on_closeButton_clicked() +{ + this->close(); +} + + +void MainWindow::setProgressInsert(int value) +{ + QString mess = "Загрузка данных в БД"; + progressDialog->setValue(value); + progressDialog->setLabelText(mess); + + if(value == arrayXml.size()) + { + qDebug() << "!!! updateTableView"; + tableModel->setTable(TABLE); + tableModel->select(); + + // Устанавливаем размер колонок по содержимому + ui->tableView->resizeColumnsToContents(); + + } + + QApplication::instance()->processEvents(); +} + +void MainWindow::setProgressParseXML(int value, QString fileName, bool result) +{ + if(value == fileList->size()) + { + QString mess = "Загрузка данных в БД"; + + progressDialog->setLabelText(mess); + progressDialog->setValue(0); + progressDialog->setRange(0, arrayXml.size()); + + for(QMultiMap::iterator iii = arrayXml.begin(); iii != arrayXml.end(); iii++) + { + qDebug() << "key" << iii.key() << " value" << iii.value(); + } + + emit startInsert(&arrayXml); + + delete fileList; + } + else + { + QString mess = "Разбор файла " + fileName; + mess += (result)?" успешено":" ошибка"; + + progressDialog->setValue(value); + progressDialog->setLabelText(mess); + } + + QApplication::instance()->processEvents(); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..75161de --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,57 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include + +#include "database.h" +#include "parserxmlworker.h" +#include "dialogeditrecord.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_loadButton_clicked(); + void on_clearButton_clicked(); + void on_closeButton_clicked(); + void setProgressInsert(int value); + void setProgressParseXML(int value, QString fileName, bool result); + void customMenuRequested(QPoint pos); + void removeRecord(); + void editRecord(); + void updateModel(); + +signals: + void startParseXML(QFileInfoList *fileList, QMultiMap *array); + void startInsert(QMultiMap *array); + void cleanData(); + +private: + DataBase *workerBD; + QSqlTableModel *tableModel; + + ParserXMLWorker *workerXML; + + Ui::MainWindow *ui; + QMultiMap arrayXml; + + QThread workerXMLThread; + QThread workerBDThread; + + QFileInfoList *fileList; + QProgressDialog *progressDialog; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..aa6f6bd --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,90 @@ + + + MainWindow + + + + 0 + 0 + 902 + 702 + + + + Xml parser + + + + + + + + + + + + Загрузить + + + + + + + -3 + + + Qt::LeftToRight + + + Отчистить + + + + + + + Закрыть + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + 902 + 26 + + + + + + TopToolBarArea + + + false + + + + + + + + diff --git a/parserxmlworker.cpp b/parserxmlworker.cpp new file mode 100644 index 0000000..556e8e4 --- /dev/null +++ b/parserxmlworker.cpp @@ -0,0 +1,58 @@ +#include "parserxmlworker.h" + +#include +#include + +ParserXMLWorker::ParserXMLWorker() +{ +} + +void ParserXMLWorker::doParser(QFileInfoList *fileList, QMultiMap *arrayXml) +{ + + for(int iii = 0; iiisize(); iii++) + { + bool result = true; + + QString fileName(fileList->at(iii).absoluteFilePath()); + qDebug() << "Try work with file" << fileName; + + QFile file(fileName); + + if(file.open(QIODevice::ReadOnly)) + { + QXmlStreamReader sr(&file); + do + { + sr.readNext(); + if(sr.attributes().size() > 0) + { + for(auto jjj : sr.attributes()) + { + arrayXml->insert(jjj.name().toString(), jjj.value().toString()); + } + } + + } while(!sr.atEnd()); + + if(sr.hasError()) + { + qDebug() << "Error:" << sr.errorString(); + result = false; + } + file.close(); + } + else + { + qDebug() << "Error open file" << fileName; + result = false; + } + + emit changeProgressParseXML(iii, fileList->at(iii).fileName(), result); + + QThread::sleep(1); + } + + emit changeProgressParseXML(fileList->size(), QString(""), true); + +} diff --git a/parserxmlworker.h b/parserxmlworker.h new file mode 100644 index 0000000..64c401a --- /dev/null +++ b/parserxmlworker.h @@ -0,0 +1,23 @@ +#ifndef PARSERXMLWORKER_H +#define PARSERXMLWORKER_H + +#include +#include +#include +#include + +class ParserXMLWorker: public QObject +{ + Q_OBJECT + +public: + ParserXMLWorker(); + +public slots: + void doParser(QFileInfoList *fileList, QMultiMap *arrayXml); + +signals: + void changeProgressParseXML(int value, QString fileName, bool result); +}; + +#endif // PARSERXMLWORKER_H diff --git a/test_xml_dir/param1.xml b/test_xml_dir/param1.xml new file mode 100644 index 0000000..4c86001 --- /dev/null +++ b/test_xml_dir/param1.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/test_xml_dir/param2.xml b/test_xml_dir/param2.xml new file mode 100644 index 0000000..decf25c --- /dev/null +++ b/test_xml_dir/param2.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test_xml_dir/param3.xml b/test_xml_dir/param3.xml new file mode 100644 index 0000000..6e0aec7 --- /dev/null +++ b/test_xml_dir/param3.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + +