ver:一个可用版本,基本包含导入导出数据,备份,替换,搜索等功能。
This commit is contained in:
parent
6d13738078
commit
8cb4d5aa2f
@ -3,16 +3,18 @@
|
|||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <filesystem>
|
||||||
#include "src/data_edit.h"
|
#include "src/data_edit.h"
|
||||||
#include "./ui_MainWidget.h"
|
#include "./ui_MainWidget.h"
|
||||||
|
|
||||||
constexpr std::size_t g_OnePage = 100;
|
constexpr std::size_t g_OnePage = 100;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget)
|
MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
setWindowTitle(u8"OneLevelXmlOpr v1.2.8");
|
setWindowTitle(u8"OneLevelXmlOpr v1.2.9");
|
||||||
setWindowIcon(QIcon("://resource/xml.ico"));
|
setWindowIcon(QIcon("://resource/xml.ico"));
|
||||||
|
|
||||||
setMinimumWidth(900);
|
setMinimumWidth(900);
|
||||||
@ -45,11 +47,12 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
|
|||||||
read(file);
|
read(file);
|
||||||
});
|
});
|
||||||
connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(); });
|
connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(); });
|
||||||
connect(ui->btnRead, &QPushButton::clicked, this,
|
connect(ui->btnBackup, &QPushButton::clicked, this, [&]() { backup_file(); });
|
||||||
[&]() { read(ui->edStatus->text().trimmed()); });
|
connect(ui->btnRead, &QPushButton::clicked, this, [&]() { read(ui->edStatus->text().trimmed()); });
|
||||||
connect(ui->btnSave, &QPushButton::clicked, this, [&]() { save(); });
|
connect(ui->btnSave, &QPushButton::clicked, this, [&]() { save(); });
|
||||||
connect(ui->btnExit, &QPushButton::clicked, this, [&]() { QApplication::exit(0); });
|
connect(ui->btnExit, &QPushButton::clicked, this, [&]() { QApplication::exit(0); });
|
||||||
connect(ui->btnReset, &QPushButton::clicked, this, &MainWidget::reset);
|
connect(ui->btnReset, &QPushButton::clicked, this, &MainWidget::reset);
|
||||||
|
connect(ui->btnReplace, &QPushButton::clicked, this, &MainWidget::replace_content);
|
||||||
connect(ui->btnExport, &QPushButton::clicked, this, &MainWidget::copy_multi_data);
|
connect(ui->btnExport, &QPushButton::clicked, this, &MainWidget::copy_multi_data);
|
||||||
connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
|
connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
|
||||||
unsigned int cur = ui->edCurPage->text().toUInt();
|
unsigned int cur = ui->edCurPage->text().toUInt();
|
||||||
@ -60,6 +63,14 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
|
|||||||
edit.is_import_ = true;
|
edit.is_import_ = true;
|
||||||
edit.set_xml_opr(&xml_);
|
edit.set_xml_opr(&xml_);
|
||||||
edit.exec();
|
edit.exec();
|
||||||
|
|
||||||
|
if (!edit.is_import_sucess_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xml_.get_all_elements(vec_);
|
||||||
|
current_.clear();
|
||||||
|
current_ = vec_;
|
||||||
|
push_content(current_);
|
||||||
});
|
});
|
||||||
connect(ui->btnPageNext, &QPushButton::clicked, this, [&]() {
|
connect(ui->btnPageNext, &QPushButton::clicked, this, [&]() {
|
||||||
unsigned int cur = ui->edCurPage->text().toUInt();
|
unsigned int cur = ui->edCurPage->text().toUInt();
|
||||||
@ -159,8 +170,7 @@ void MainWidget::generate_table_widget()
|
|||||||
tab_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
|
tab_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(tab_widget_, &QTableWidget::itemChanged, this,
|
connect(tab_widget_, &QTableWidget::itemChanged, this,
|
||||||
[&](QTableWidgetItem* item) { item_changed_handle(item); });
|
[&](QTableWidgetItem* item) { item_changed_handle(item); });
|
||||||
connect(tab_widget_, &QTableWidget::customContextMenuRequested, this,
|
connect(tab_widget_, &QTableWidget::customContextMenuRequested, this, &MainWidget::show_custom_menu);
|
||||||
&MainWidget::show_custom_menu);
|
|
||||||
auto config = ini_.get_config();
|
auto config = ini_.get_config();
|
||||||
auto keys = splitString(config.purpose, ",");
|
auto keys = splitString(config.purpose, ",");
|
||||||
keys_.clear();
|
keys_.clear();
|
||||||
@ -620,3 +630,73 @@ void MainWidget::copy_multi_data()
|
|||||||
edit.set_data(ret);
|
edit.set_data(ret);
|
||||||
edit.exec();
|
edit.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWidget::replace_content()
|
||||||
|
{
|
||||||
|
if (tab_widget_ == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString key = ui->edRepPre->text();
|
||||||
|
QString after = ui->edRepAfter->text();
|
||||||
|
if (key.isEmpty()) {
|
||||||
|
CUtil::msg(this, u8"替换前数据为空。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ui->cbRepOnlySelect->isChecked()) {
|
||||||
|
QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
|
||||||
|
if (indexList.size() < 1) {
|
||||||
|
CUtil::msg(this, u8"无选择数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString ret;
|
||||||
|
for (int i = 0; i < indexList.size(); ++i) {
|
||||||
|
Element_t* e = get_element_by_row(indexList[i].row());
|
||||||
|
if (e == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto* element = e->FirstAttribute();
|
||||||
|
while (element) {
|
||||||
|
QString content(element->Value());
|
||||||
|
if (content.contains(key)) {
|
||||||
|
content.replace(key, after);
|
||||||
|
e->SetAttribute(element->Name(), content.toStdString().c_str());
|
||||||
|
}
|
||||||
|
element = element->Next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!CUtil::affirm(this, u8"确认", u8"确认进行全局替换吗?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& data : vec_) {
|
||||||
|
auto* element = data->FirstAttribute();
|
||||||
|
while (element) {
|
||||||
|
QString content(element->Value());
|
||||||
|
content.replace(key, after);
|
||||||
|
data->SetAttribute(element->Name(), content.toStdString().c_str());
|
||||||
|
element = element->Next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_.get_all_elements(vec_);
|
||||||
|
current_.clear();
|
||||||
|
current_ = vec_;
|
||||||
|
push_content(current_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWidget::backup_file()
|
||||||
|
{
|
||||||
|
if (tab_widget_ == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString time = QDateTime::currentDateTime().toString("yyyy-MMdd-hhmmss");
|
||||||
|
if (!xml_.backup_file(fs::path(exe_path_).parent_path().append("backup").string(), time.toStdString())) {
|
||||||
|
CUtil::msg(this, u8"备份失败。");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CUtil::msg(this, u8"备份完成。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -46,6 +46,8 @@ private:
|
|||||||
void show_custom_menu();
|
void show_custom_menu();
|
||||||
void sort_by_repeat(std::vector<Element_t*>& vec);
|
void sort_by_repeat(std::vector<Element_t*>& vec);
|
||||||
void copy_multi_data();
|
void copy_multi_data();
|
||||||
|
void replace_content();
|
||||||
|
void backup_file();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent* event);
|
void closeEvent(QCloseEvent* event);
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
<widget class="QLineEdit" name="edRepPre"/>
|
<widget class="QLineEdit" name="edRepPre"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton">
|
<widget class="QPushButton" name="btnReplace">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>替换为</string>
|
<string>替换为</string>
|
||||||
</property>
|
</property>
|
||||||
@ -261,6 +261,30 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>btnSelectFile</tabstop>
|
||||||
|
<tabstop>edStatus</tabstop>
|
||||||
|
<tabstop>btnRead</tabstop>
|
||||||
|
<tabstop>btnSave</tabstop>
|
||||||
|
<tabstop>btnExport</tabstop>
|
||||||
|
<tabstop>btnImport</tabstop>
|
||||||
|
<tabstop>btnBackup</tabstop>
|
||||||
|
<tabstop>cbRepOnlySelect</tabstop>
|
||||||
|
<tabstop>edRepPre</tabstop>
|
||||||
|
<tabstop>edRepAfter</tabstop>
|
||||||
|
<tabstop>btnReplace</tabstop>
|
||||||
|
<tabstop>cbCaseSensitive</tabstop>
|
||||||
|
<tabstop>edSearchKey</tabstop>
|
||||||
|
<tabstop>btnSearch</tabstop>
|
||||||
|
<tabstop>btnReset</tabstop>
|
||||||
|
<tabstop>btnResort</tabstop>
|
||||||
|
<tabstop>btnExit</tabstop>
|
||||||
|
<tabstop>edCurPage</tabstop>
|
||||||
|
<tabstop>edAllPage</tabstop>
|
||||||
|
<tabstop>btnJump</tabstop>
|
||||||
|
<tabstop>btnPagePre</tabstop>
|
||||||
|
<tabstop>btnPageNext</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -39,6 +39,7 @@ void CDataEdit::set_xml_opr(CXmlOpr* xml_opr)
|
|||||||
|
|
||||||
void CDataEdit::import_data()
|
void CDataEdit::import_data()
|
||||||
{
|
{
|
||||||
|
is_import_sucess_ = false;
|
||||||
QString data = ui->plainTextEdit->toPlainText();
|
QString data = ui->plainTextEdit->toPlainText();
|
||||||
if (data.trimmed().isEmpty()) {
|
if (data.trimmed().isEmpty()) {
|
||||||
CUtil::msg(this, u8"内容为空");
|
CUtil::msg(this, u8"内容为空");
|
||||||
@ -50,6 +51,10 @@ void CDataEdit::import_data()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!CUtil::affirm(this, u8"提示", u8"如果出现重复的 key 将跳过,继续吗?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> valid_data{};
|
std::vector<std::string> valid_data{};
|
||||||
QStringList list = data.trimmed().split("\n");
|
QStringList list = data.trimmed().split("\n");
|
||||||
for (int i = 0; i < list.size(); ++i) {
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
@ -72,6 +77,7 @@ void CDataEdit::import_data()
|
|||||||
QString info = QString(u8"需要导入 %1 条数据,成功导入 %2 条。").arg(task_count).arg(success_count);
|
QString info = QString(u8"需要导入 %1 条数据,成功导入 %2 条。").arg(task_count).arg(success_count);
|
||||||
CUtil::msg(this, info);
|
CUtil::msg(this, info);
|
||||||
close();
|
close();
|
||||||
|
is_import_sucess_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataEdit::showEvent(QShowEvent* event)
|
void CDataEdit::showEvent(QShowEvent* event)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#include "xml_opr.h"
|
#include "xml_opr.h"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
CXmlOpr::CXmlOpr() = default;
|
CXmlOpr::CXmlOpr() = default;
|
||||||
CXmlOpr::~CXmlOpr() = default;
|
CXmlOpr::~CXmlOpr() = default;
|
||||||
@ -12,11 +15,35 @@ bool CXmlOpr::open(const std::string& xml_path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CXmlOpr::backup_file(const std::string& desti_folder, const std::string& time)
|
||||||
|
{
|
||||||
|
if (!fs::exists(xml_path_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!fs::exists(desti_folder)) {
|
||||||
|
fs::create_directories(desti_folder);
|
||||||
|
}
|
||||||
|
fs::path file_path = fs::path(xml_path_);
|
||||||
|
fs::path des = fs::path(desti_folder).append(file_path.stem().string() + "_" + time + ".xml");
|
||||||
|
return fs::copy_file(xml_path_, des);
|
||||||
|
}
|
||||||
|
|
||||||
void CXmlOpr::set_baseinfo(const OprBase& base)
|
void CXmlOpr::set_baseinfo(const OprBase& base)
|
||||||
{
|
{
|
||||||
opr_base_ = base;
|
opr_base_ = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CXmlOpr::get_all_elements(std::vector<Element_t*>& vec)
|
||||||
|
{
|
||||||
|
vec.clear();
|
||||||
|
Element_t* purpose_node = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
|
||||||
|
while (purpose_node) {
|
||||||
|
vec.push_back(purpose_node);
|
||||||
|
purpose_node = purpose_node->NextSiblingElement();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CXmlOpr::parse_xml(std::vector<tinyxml2::XMLElement*>& vec)
|
bool CXmlOpr::parse_xml(std::vector<tinyxml2::XMLElement*>& vec)
|
||||||
{
|
{
|
||||||
std::string next_node{};
|
std::string next_node{};
|
||||||
@ -43,12 +70,7 @@ bool CXmlOpr::parse_xml(std::vector<tinyxml2::XMLElement*>& vec)
|
|||||||
parent_node_ = parent_node_->FirstChildElement(item.c_str());
|
parent_node_ = parent_node_->FirstChildElement(item.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vec.clear();
|
get_all_elements(vec);
|
||||||
Element_t* purpose_node = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
|
|
||||||
while (purpose_node) {
|
|
||||||
vec.push_back(purpose_node);
|
|
||||||
purpose_node = purpose_node->NextSiblingElement();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +181,7 @@ bool CXmlOpr::import_newer_data(const std::vector<std::string>& vec, std::size_t
|
|||||||
if (last_item == nullptr) {
|
if (last_item == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// 检查重复性
|
||||||
for (const auto& data : vec) {
|
for (const auto& data : vec) {
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
doc.Parse(data.c_str());
|
doc.Parse(data.c_str());
|
||||||
@ -166,6 +189,10 @@ bool CXmlOpr::import_newer_data(const std::vector<std::string>& vec, std::size_t
|
|||||||
if (item == nullptr) {
|
if (item == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const char* key_str = item->Attribute(keys_[0].c_str());
|
||||||
|
if (check_key_exists(std::string(key_str))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
++success_count;
|
++success_count;
|
||||||
auto* nitem = copy_element(item);
|
auto* nitem = copy_element(item);
|
||||||
insert_brother_node(last_item, nitem);
|
insert_brother_node(last_item, nitem);
|
||||||
@ -183,10 +210,18 @@ bool CXmlOpr::check_key_exists(const Property_t& property)
|
|||||||
if (keys_.size() < 1 || property.size() < 1) {
|
if (keys_.size() < 1 || property.size() < 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return check_key_exists(property[0].key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CXmlOpr::check_key_exists(const std::string& key)
|
||||||
|
{
|
||||||
|
if (keys_.size() < 1 || key.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Element_t* purpose_node = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
|
Element_t* purpose_node = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
|
||||||
while (purpose_node) {
|
while (purpose_node) {
|
||||||
const char* value = purpose_node->Attribute(keys_[0].c_str());
|
const char* value = purpose_node->Attribute(keys_[0].c_str());
|
||||||
if (property[0].value == std::string(value)) {
|
if (key == std::string(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
purpose_node = purpose_node->NextSiblingElement();
|
purpose_node = purpose_node->NextSiblingElement();
|
||||||
|
@ -22,18 +22,21 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool open(const std::string& xml_path);
|
bool open(const std::string& xml_path);
|
||||||
|
bool backup_file(const std::string& desti_folder, const std::string& time);
|
||||||
void set_baseinfo(const OprBase& base);
|
void set_baseinfo(const OprBase& base);
|
||||||
bool parse_xml(std::vector<Element_t*>& vec);
|
bool parse_xml(std::vector<Element_t*>& vec);
|
||||||
|
bool get_all_elements(std::vector<Element_t*>& vec);
|
||||||
void copy_and_del(std::vector<Element_t*>& vec, std::vector<Element_t*>& out);
|
void copy_and_del(std::vector<Element_t*>& vec, std::vector<Element_t*>& out);
|
||||||
void insert_brother_node(Element_t* brother, Element_t* newer);
|
void insert_brother_node(Element_t* brother, Element_t* newer);
|
||||||
void del_element(Element_t* ele);
|
void del_element(Element_t* ele);
|
||||||
bool check_key_exists(const Property_t& property);
|
bool check_key_exists(const Property_t& property);
|
||||||
|
bool check_key_exists(const std::string& key);
|
||||||
bool save();
|
bool save();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Element_t* copy_element(Element_t* ele);
|
Element_t* copy_element(Element_t* ele);
|
||||||
// 检查 xml 格式合法性
|
// 检查 xml 格式合法性
|
||||||
bool check_valid_xml_data(const std::string& data);
|
bool check_valid_xml_data(const std::string& data);
|
||||||
// 不检查 xml 格式合法性,请自行调用 check_valid_xml_data
|
// 不检查 xml 格式合法性,请自行调用 check_valid_xml_data
|
||||||
bool check_same_struct(const std::string& data);
|
bool check_same_struct(const std::string& data);
|
||||||
// 不检查 xml 格式合法性,请自行调用 check_valid_xml_data
|
// 不检查 xml 格式合法性,请自行调用 check_valid_xml_data
|
||||||
|
Loading…
x
Reference in New Issue
Block a user