ver:一个可用版本,基本包含导入导出数据,备份,替换,搜索等功能。
This commit is contained in:
		
							parent
							
								
									6d13738078
								
							
						
					
					
						commit
						8cb4d5aa2f
					
				@ -3,16 +3,18 @@
 | 
			
		||||
#include <QSettings>
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#include <QKeyEvent>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include "src/data_edit.h"
 | 
			
		||||
#include "./ui_MainWidget.h"
 | 
			
		||||
 | 
			
		||||
constexpr std::size_t g_OnePage = 100;
 | 
			
		||||
 | 
			
		||||
namespace fs = std::filesystem;
 | 
			
		||||
MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget)
 | 
			
		||||
{
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    setWindowTitle(u8"OneLevelXmlOpr v1.2.8");
 | 
			
		||||
    setWindowTitle(u8"OneLevelXmlOpr v1.2.9");
 | 
			
		||||
    setWindowIcon(QIcon("://resource/xml.ico"));
 | 
			
		||||
 | 
			
		||||
    setMinimumWidth(900);
 | 
			
		||||
@ -45,11 +47,12 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
 | 
			
		||||
        read(file);
 | 
			
		||||
    });
 | 
			
		||||
    connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(); });
 | 
			
		||||
    connect(ui->btnRead, &QPushButton::clicked, this,
 | 
			
		||||
            [&]() { read(ui->edStatus->text().trimmed()); });
 | 
			
		||||
    connect(ui->btnBackup, &QPushButton::clicked, this, [&]() { backup_file(); });
 | 
			
		||||
    connect(ui->btnRead, &QPushButton::clicked, this, [&]() { read(ui->edStatus->text().trimmed()); });
 | 
			
		||||
    connect(ui->btnSave, &QPushButton::clicked, this, [&]() { save(); });
 | 
			
		||||
    connect(ui->btnExit, &QPushButton::clicked, this, [&]() { QApplication::exit(0); });
 | 
			
		||||
    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->btnPagePre, &QPushButton::clicked, this, [&]() {
 | 
			
		||||
        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.set_xml_opr(&xml_);
 | 
			
		||||
        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, [&]() {
 | 
			
		||||
        unsigned int cur = ui->edCurPage->text().toUInt();
 | 
			
		||||
@ -159,8 +170,7 @@ void MainWidget::generate_table_widget()
 | 
			
		||||
    tab_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
			
		||||
    connect(tab_widget_, &QTableWidget::itemChanged, this,
 | 
			
		||||
            [&](QTableWidgetItem* item) { item_changed_handle(item); });
 | 
			
		||||
    connect(tab_widget_, &QTableWidget::customContextMenuRequested, this,
 | 
			
		||||
            &MainWidget::show_custom_menu);
 | 
			
		||||
    connect(tab_widget_, &QTableWidget::customContextMenuRequested, this, &MainWidget::show_custom_menu);
 | 
			
		||||
    auto config = ini_.get_config();
 | 
			
		||||
    auto keys = splitString(config.purpose, ",");
 | 
			
		||||
    keys_.clear();
 | 
			
		||||
@ -620,3 +630,73 @@ void MainWidget::copy_multi_data()
 | 
			
		||||
    edit.set_data(ret);
 | 
			
		||||
    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 sort_by_repeat(std::vector<Element_t*>& vec);
 | 
			
		||||
    void copy_multi_data();
 | 
			
		||||
    void replace_content();
 | 
			
		||||
    void backup_file();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void closeEvent(QCloseEvent* event);
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@
 | 
			
		||||
       <widget class="QLineEdit" name="edRepPre"/>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QPushButton" name="pushButton">
 | 
			
		||||
       <widget class="QPushButton" name="btnReplace">
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>替换为</string>
 | 
			
		||||
        </property>
 | 
			
		||||
@ -261,6 +261,30 @@
 | 
			
		||||
   </item>
 | 
			
		||||
  </layout>
 | 
			
		||||
 </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/>
 | 
			
		||||
 <connections/>
 | 
			
		||||
</ui>
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,7 @@ void CDataEdit::set_xml_opr(CXmlOpr* xml_opr)
 | 
			
		||||
 | 
			
		||||
void CDataEdit::import_data()
 | 
			
		||||
{
 | 
			
		||||
    is_import_sucess_ = false;
 | 
			
		||||
    QString data = ui->plainTextEdit->toPlainText();
 | 
			
		||||
    if (data.trimmed().isEmpty()) {
 | 
			
		||||
        CUtil::msg(this, u8"内容为空");
 | 
			
		||||
@ -50,6 +51,10 @@ void CDataEdit::import_data()
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!CUtil::affirm(this, u8"提示", u8"如果出现重复的 key 将跳过,继续吗?")) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<std::string> valid_data{};
 | 
			
		||||
    QStringList              list = data.trimmed().split("\n");
 | 
			
		||||
    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);
 | 
			
		||||
    CUtil::msg(this, info);
 | 
			
		||||
    close();
 | 
			
		||||
    is_import_sucess_ = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CDataEdit::showEvent(QShowEvent* event)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,7 @@
 | 
			
		||||
#include "xml_opr.h"
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
 | 
			
		||||
namespace fs = std::filesystem;
 | 
			
		||||
 | 
			
		||||
CXmlOpr::CXmlOpr() = default;
 | 
			
		||||
CXmlOpr::~CXmlOpr() = default;
 | 
			
		||||
@ -12,11 +15,35 @@ bool CXmlOpr::open(const std::string& xml_path)
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    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();
 | 
			
		||||
    }
 | 
			
		||||
    get_all_elements(vec);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -159,6 +181,7 @@ bool CXmlOpr::import_newer_data(const std::vector<std::string>& vec, std::size_t
 | 
			
		||||
    if (last_item == nullptr) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    // 检查重复性
 | 
			
		||||
    for (const auto& data : vec) {
 | 
			
		||||
        tinyxml2::XMLDocument doc;
 | 
			
		||||
        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) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        const char* key_str = item->Attribute(keys_[0].c_str());
 | 
			
		||||
        if (check_key_exists(std::string(key_str))) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        ++success_count;
 | 
			
		||||
        auto* nitem = copy_element(item);
 | 
			
		||||
        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) {
 | 
			
		||||
        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());
 | 
			
		||||
    while (purpose_node) {
 | 
			
		||||
        const char* value = purpose_node->Attribute(keys_[0].c_str());
 | 
			
		||||
        if (property[0].value == std::string(value)) {
 | 
			
		||||
        if (key == std::string(value)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        purpose_node = purpose_node->NextSiblingElement();
 | 
			
		||||
 | 
			
		||||
@ -22,18 +22,21 @@ public:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    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);
 | 
			
		||||
    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 insert_brother_node(Element_t* brother, Element_t* newer);
 | 
			
		||||
    void del_element(Element_t* ele);
 | 
			
		||||
    bool check_key_exists(const Property_t& property);
 | 
			
		||||
    bool check_key_exists(const std::string& key);
 | 
			
		||||
    bool save();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Element_t* copy_element(Element_t* ele);
 | 
			
		||||
    // 检查 xml 格式合法性
 | 
			
		||||
    bool       check_valid_xml_data(const std::string& data);
 | 
			
		||||
    bool check_valid_xml_data(const std::string& data);
 | 
			
		||||
    // 不检查 xml 格式合法性,请自行调用 check_valid_xml_data
 | 
			
		||||
    bool check_same_struct(const std::string& data);
 | 
			
		||||
    // 不检查 xml 格式合法性,请自行调用 check_valid_xml_data
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user