big-change:添加两种类型结构读写支持

This commit is contained in:
2024-08-27 17:30:48 +08:00
parent ff68e756ff
commit b05783191f
20 changed files with 975 additions and 195 deletions

View File

@@ -89,7 +89,7 @@ void CAttributeEdit::init_table()
table_->setSelectionBehavior(QAbstractItemView::SelectRows);
table_->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
table_->setColumnWidth(0, 100);
table_->setColumnWidth(1, 250);
table_->setColumnWidth(1, 550);
QHBoxLayout* ly = new QHBoxLayout();
ly->addWidget(table_);
ui->widget->setLayout(ly);
@@ -97,4 +97,4 @@ void CAttributeEdit::init_table()
table_->clearContents();
table_->setRowCount(0);
}
}
}

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<width>769</width>
<height>618</height>
</rect>
</property>
@@ -29,7 +29,7 @@
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -42,7 +42,7 @@
<item>
<widget class="QPushButton" name="btnOk">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
<enum>Qt::FocusPolicy::NoFocus</enum>
</property>
<property name="text">
<string>确认</string>
@@ -52,7 +52,7 @@
<item>
<widget class="QPushButton" name="btnCancel">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
<enum>Qt::FocusPolicy::NoFocus</enum>
</property>
<property name="text">
<string>取消</string>

View File

@@ -1,53 +1,108 @@
#include "config.h"
#include <QDir>
#include <filesystem>
namespace fs = std::filesystem;
bool ConfigIni::set_work_exe(const std::string& dir)
CGroupIni::CGroupIni()
{
work_dir_ = dir;
default_set();
}
auto ini_path = fs::path(work_dir_).parent_path().append("xmlopr.ini");
if (!fs::exists(ini_path)) {
return false;
void CGroupIni::default_set()
{
QDir dir;
std::string path = dir.homePath().toStdString();
fs::path p(path);
p.append(".config");
if (!fs::exists(p)) {
fs::create_directories(p);
}
ini_path_ = ini_path.string();
if (!parse_ini()) {
work_dir_ = p.string();
p.append("OneLevelXmlOpr.ini");
work_file_ = p.string();
}
bool CGroupIni::load_ini()
{
SI_Error rc = ini_.LoadFile(work_file_.c_str());
if (rc != SI_OK) {
rc = ini_.SaveFile(work_file_.c_str());
if (rc < 0) {
return false;
}
return true;
}
return true;
}
void CGroupIni::get_all_node(StrVec_t& vec)
{
vec.clear();
CSimpleIni::TNamesDepend secs;
ini_.GetAllSections(secs);
for (const auto& sec : secs) {
vec.push_back(sec.pItem);
}
}
bool CGroupIni::add_item(const OneGroupIni& group)
{
ini_.SetValue(group.name.c_str(), "MainNodes", group.main_nodes.c_str());
ini_.SetValue(group.name.c_str(), "RelativeNodes", group.relative_nodes.c_str());
ini_.SetValue(group.name.c_str(), "ItemKey", group.item_key.c_str());
ini_.SetValue(group.name.c_str(), "Properties", group.propertis.c_str());
ini_.SetLongValue(group.name.c_str(), "MaxColLen", group.max_col_len);
ini_.SetLongValue(group.name.c_str(), "MaxBlankAdd", group.max_blank_add);
ini_.SetBoolValue(group.name.c_str(), "IsSameStruct", group.is_same);
if (ini_.SaveFile(work_file_.c_str()) != SI_OK) {
return false;
}
return true;
}
bool ConfigIni::set_xml_path(const std::string& path)
bool CGroupIni::get_item(OneGroupIni& group)
{
if (ini_.IsEmpty()) {
StrVec_t vec;
get_all_node(vec);
bool find = false;
for (const auto& item : vec) {
if (group.name != item) {
continue;
}
find = true;
break;
}
if (!find) {
return false;
}
ini_.SetValue("Basic", "xml_path", path.c_str());
if (ini_.SaveFile(ini_path_.c_str()) != SI_OK) {
group.main_nodes = ini_.GetValue(group.name.c_str(), "MainNodes");
group.relative_nodes = ini_.GetValue(group.name.c_str(), "RelativeNodes");
group.item_key = ini_.GetValue(group.name.c_str(), "ItemKey");
group.propertis = ini_.GetValue(group.name.c_str(), "Properties");
group.max_col_len = ini_.GetLongValue(group.name.c_str(), "MaxColLen");
group.max_blank_add = ini_.GetLongValue(group.name.c_str(), "MaxBlankAdd");
group.is_same = ini_.GetBoolValue(group.name.c_str(), "IsSameStruct");
return true;
}
bool CGroupIni::del_item(const std::string &key)
{
ini_.Delete(key.c_str(), "MainNodes", true);
ini_.Delete(key.c_str(), "RelativeNodes", true);
ini_.Delete(key.c_str(), "ItemKey", true);
ini_.Delete(key.c_str(), "Properties", true);
ini_.Delete(key.c_str(), "MaxColLen", true);
ini_.Delete(key.c_str(), "MaxBlankAdd", true);
if (ini_.SaveFile(work_file_.c_str()) != SI_OK) {
return false;
}
return true;
}
OprBase ConfigIni::get_config()
{
return opr_base_;
}
bool ConfigIni::parse_ini()
{
if (ini_.LoadFile(ini_path_.c_str()) != SI_OK) {
return false;
}
ini_.SetUnicode();
opr_base_.node_path = ini_.GetValue("Basic", "oper_node");
opr_base_.purpose = ini_.GetValue("Basic", "purpose");
opr_base_.the_node = ini_.GetValue("Basic", "the_node");
opr_base_.xml_path = ini_.GetValue("Basic", "xml_path");
opr_base_.allow_max_width = ini_.GetLongValue("Basic", "max_col_width");
opr_base_.blank_width = ini_.GetLongValue("Basic", "blank_width");
return true;
}

View File

@@ -3,7 +3,6 @@
#include <string>
#include <SimpleIni.h>
#include "../public_def.h"
/*
@@ -12,25 +11,37 @@ oper_node=IODEF/ITEMS
*/
class ConfigIni
using StrVec_t = std::vector<std::string>;
struct OneGroupIni {
std::string name;
std::string main_nodes;
std::string relative_nodes;
std::string item_key;
std::string propertis;
long max_col_len{1000};
long max_blank_add{60};
bool is_same;
};
class CGroupIni
{
public:
ConfigIni() = default;
~ConfigIni() = default;
CGroupIni();
public:
bool set_work_exe(const std::string& dir);
bool set_xml_path(const std::string& path);
OprBase get_config();
bool load_ini();
void get_all_node(StrVec_t& vec);
bool add_item(const OneGroupIni& group);
bool get_item(OneGroupIni& group);
bool del_item(const std::string& key);
private:
bool parse_ini();
void default_set();
private:
std::string work_dir_{};
std::string ini_path_{};
std::string work_file_{};
CSimpleIniA ini_{};
OprBase opr_base_{};
};
#endif

80
src/history.cpp Normal file
View File

@@ -0,0 +1,80 @@
#include "history.h"
#include <QDir>
#include <algorithm>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
CHistory::CHistory()
{
default_set();
}
bool CHistory::push(const std::string& content)
{
std::vector<std::string> vec;
read_file(vec);
if (std::find(vec.begin(), vec.end(), content) == vec.end()) {
vec.push_back(content);
} else {
return true;
}
if (vec.size() > 10) {
vec.erase(vec.begin());
}
if (!write_file(vec)) {
return false;
}
return true;
}
bool CHistory::get_history(std::vector<std::string>& vec)
{
return read_file(vec);
}
void CHistory::default_set()
{
QDir dir;
std::string path = dir.homePath().toStdString();
fs::path p(path);
p.append(".config");
if (!fs::exists(p)) {
fs::create_directories(p);
}
work_dir_ = p.string();
p.append("OneLevelXmlOpr.history");
work_file_ = p.string();
}
bool CHistory::read_file(std::vector<std::string>& vec)
{
vec.clear();
std::ifstream file(work_file_);
if (!file.is_open()) {
return false;
}
std::string line;
while (std::getline(file, line)) {
vec.push_back(line);
}
return true;
}
bool CHistory::write_file(std::vector<std::string>& vec)
{
std::ofstream file(work_file_);
if (!file.is_open()) {
return false;
}
for (const auto& line : vec) {
file << line << std::endl;
}
file.close();
return true;
}

27
src/history.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef HISTORY_H
#define HISTORY_H
#include <string>
#include <vector>
// 只保留最近的10条数据
class CHistory
{
public:
CHistory();
public:
bool push(const std::string& content);
bool get_history(std::vector<std::string>& vec);
private:
void default_set();
bool read_file(std::vector<std::string>& vec);
bool write_file(std::vector<std::string>& vec);
private:
std::string work_dir_{};
std::string work_file_{};
};
#endif // HISTORY_H

44
src/uhistory.cpp Normal file
View File

@@ -0,0 +1,44 @@
#include "uhistory.h"
#include "src/ui_uhistory.h"
#include "ui_uhistory.h"
CUIHistory::CUIHistory(QWidget* parent, CHistory* his) : QDialog(parent), ui(new Ui::CUIHistory)
{
ui->setupUi(this);
his_ = his;
connect(ui->btnExit, &QPushButton::clicked, this, [&]() { close(); });
connect(ui->btnOk, &QPushButton::clicked, this, [&]() { select_ok(); });
}
CUIHistory::~CUIHistory()
{
delete ui;
}
void CUIHistory::showEvent(QShowEvent* event)
{
std::vector<std::string> vec;
his_->get_history(vec);
QStringList list;
for (const auto& data : vec) {
list.append(QString::fromStdString(data));
}
if (!list.empty()) {
ui->listWidget->addItems(list);
}
cur_.clear();
QDialog::showEvent(event);
}
void CUIHistory::select_ok()
{
auto re = ui->listWidget->selectedItems();
if (re.empty()) {
return ;
}
cur_ = re[0]->text();
close();
}

31
src/uhistory.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef UHISTORY_H
#define UHISTORY_H
#include <QDialog>
#include "history.h"
namespace Ui {
class CUIHistory;
}
class CUIHistory : public QDialog
{
Q_OBJECT
public:
explicit CUIHistory(QWidget *parent, CHistory* his);
~CUIHistory();
private:
void showEvent(QShowEvent* event);
void select_ok();
public:
QString cur_{};
private:
Ui::CUIHistory *ui;
CHistory* his_{};
};
#endif // UHISTORY_H

67
src/uhistory.ui Normal file
View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CUIHistory</class>
<widget class="QDialog" name="CUIHistory">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>561</width>
<height>277</height>
</rect>
</property>
<property name="windowTitle">
<string>历史文件加载</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="listWidget"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnOk">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>选择</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnExit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>退出</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,4 +1,5 @@
#include "xml_opr.h"
#include "../public_def.h"
#include <filesystem>
namespace fs = std::filesystem;
@@ -34,15 +35,30 @@ bool CXmlOpr::backup_file(const std::string& desti_folder, const std::string& ti
return fs::copy_file(xml_path_, des);
}
void CXmlOpr::set_baseinfo(const OprBase& base)
void CXmlOpr::set_baseinfo(const OneGroupIni& base)
{
opr_base_ = base;
}
bool CXmlOpr::get_all_elements(std::vector<Element_t*>& vec)
bool CXmlOpr::get_all_elements(std::vector<Element_t*>& vec, const std::string& unit)
{
vec.clear();
Element_t* purpose_node = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
Element_t* temp = parent_node_;
if (!unit.empty()) {
temp = temp->FirstChildElement(unit.c_str());
}
if (!opr_base_.relative_nodes.empty()) {
auto v = CUtil::splitString(opr_base_.relative_nodes, ",");
// 向下子项跳跃
for (const auto& it : v) {
temp = temp->FirstChildElement(it.c_str());
}
}
auto purpose_node = temp->FirstChildElement(opr_base_.item_key.c_str());
while (purpose_node) {
vec.push_back(purpose_node);
purpose_node = purpose_node->NextSiblingElement();
@@ -53,9 +69,9 @@ bool CXmlOpr::get_all_elements(std::vector<Element_t*>& vec)
bool CXmlOpr::parse_xml(std::vector<tinyxml2::XMLElement*>& vec)
{
std::string next_node{};
std::string node_path = opr_base_.node_path;
std::string node_path = opr_base_.item_key;
keys_.clear();
auto keys = CUtil::splitString(opr_base_.purpose, ",");
auto keys = CUtil::splitString(opr_base_.propertis, ",");
for (const auto& item : keys) {
if (item.empty()) {
continue;
@@ -63,7 +79,7 @@ bool CXmlOpr::parse_xml(std::vector<tinyxml2::XMLElement*>& vec)
keys_.push_back(item);
}
auto nodes = CUtil::splitString(opr_base_.node_path, "/");
auto nodes = CUtil::splitString(opr_base_.main_nodes, "/");
for (const auto& item : nodes) {
if (item.empty()) {
@@ -76,7 +92,27 @@ bool CXmlOpr::parse_xml(std::vector<tinyxml2::XMLElement*>& vec)
parent_node_ = parent_node_->FirstChildElement(item.c_str());
}
}
get_all_elements(vec);
if (opr_base_.is_same) {
units_.clear();
auto p = parent_node_->FirstChildElement();
while (p) {
units_.push_back(p->Name());
p = p->NextSiblingElement();
}
if (!units_.empty()) {
get_all_elements(vec, units_[0]);
}
} else {
get_all_elements(vec);
}
return true;
}
bool CXmlOpr::get_all_unit(std::vector<std::string> &units)
{
units = units_;
return true;
}
@@ -85,7 +121,7 @@ void CXmlOpr::copy_and_del(std::vector<Element_t*>& vec, std::vector<Element_t*>
{
out.clear();
// 先找到最后一个节点
Element_t* last_node = parent_node_->LastChildElement(opr_base_.the_node.c_str());
Element_t* last_node = parent_node_->LastChildElement(opr_base_.item_key.c_str());
Element_t* last_node_bk = last_node;
if (last_node == nullptr) {
return;
@@ -97,7 +133,7 @@ void CXmlOpr::copy_and_del(std::vector<Element_t*>& vec, std::vector<Element_t*>
last_node = n;
}
// 删除原有的节点
Element_t* fnode = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
Element_t* fnode = parent_node_->FirstChildElement(opr_base_.item_key.c_str());
Element_t* fnext = fnode->NextSiblingElement();
while (fnode != last_node_bk) {
parent_node_->DeleteChild(fnode);
@@ -120,7 +156,7 @@ Element_t* CXmlOpr::copy_element(Element_t* ele)
if (!ele) {
return nullptr;
}
Element_t* ret = doc_.NewElement(ele->Name());
Element_t* ret = doc_.NewElement(ele->Name());
const auto* attribute = ele->FirstAttribute();
while (attribute) {
ret->SetAttribute(attribute->Name(), attribute->Value());
@@ -141,7 +177,7 @@ bool CXmlOpr::check_valid_xml_data(const std::string& data)
bool CXmlOpr::check_same_struct(const std::string& data)
{
auto* own_ele = parent_node_->FirstChildElement(opr_base_.the_node.c_str());
auto* own_ele = parent_node_->FirstChildElement(opr_base_.item_key.c_str());
if (own_ele == nullptr) {
return true;
}
@@ -150,12 +186,12 @@ bool CXmlOpr::check_same_struct(const std::string& data)
if (doc.Error()) {
return false;
}
const auto* import_ele = doc.FirstChildElement(opr_base_.the_node.c_str());
const auto* import_ele = doc.FirstChildElement(opr_base_.item_key.c_str());
if (import_ele == nullptr) {
return false;
}
const auto* attribute = own_ele->FirstAttribute();
int own_cnt = 0;
int own_cnt = 0;
while (attribute) {
++own_cnt;
if (import_ele->FindAttribute(attribute->Name()) == nullptr) {
@@ -165,7 +201,7 @@ bool CXmlOpr::check_same_struct(const std::string& data)
}
const auto* attr_import = import_ele->FirstAttribute();
int import_cnt = 0;
int import_cnt = 0;
while (attr_import) {
++import_cnt;
attr_import = attr_import->Next();
@@ -183,7 +219,7 @@ bool CXmlOpr::check_same_struct(const std::string& data)
bool CXmlOpr::import_newer_data(const std::vector<std::string>& vec, std::size_t& success_count)
{
success_count = 0;
auto* last_item = parent_node_->LastChildElement(opr_base_.the_node.c_str());
auto* last_item = parent_node_->LastChildElement(opr_base_.item_key.c_str());
if (last_item == nullptr) {
return false;
}
@@ -191,7 +227,7 @@ bool CXmlOpr::import_newer_data(const std::vector<std::string>& vec, std::size_t
for (const auto& data : vec) {
tinyxml2::XMLDocument doc;
doc.Parse(data.c_str());
auto* item = doc.FirstChildElement(opr_base_.the_node.c_str());
auto* item = doc.FirstChildElement(opr_base_.item_key.c_str());
if (item == nullptr) {
continue;
}
@@ -224,7 +260,7 @@ 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_.item_key.c_str());
while (purpose_node) {
const char* value = purpose_node->Attribute(keys_[0].c_str());
if (key == std::string(value)) {

View File

@@ -1,10 +1,10 @@
#ifndef XML_OPERT_HEADER
#define XML_OPERT_HEADER
#include "config.h"
#include <string>
#include <tinyxml2.h>
#include <vector>
#include "../public_def.h"
struct SKeyValue {
SKeyValue(const char* pkey, const char* pvalue);
@@ -12,7 +12,7 @@ struct SKeyValue {
std::string value;
};
typedef tinyxml2::XMLElement Element_t;
typedef tinyxml2::XMLElement Element_t;
typedef std::vector<SKeyValue> Property_t;
class CXmlOpr
{
@@ -23,9 +23,10 @@ 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);
void set_baseinfo(const OneGroupIni& base);
bool parse_xml(std::vector<Element_t*>& vec);
bool get_all_elements(std::vector<Element_t*>& vec);
bool get_all_unit(std::vector<std::string>& units);
bool get_all_elements(std::vector<Element_t*>& vec, const std::string& unit = "");
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);
@@ -47,11 +48,12 @@ public:
void attributes_to_element(Element_t* ele, const Property_t& vec);
private:
tinyxml2::XMLDocument doc_{};
OprBase opr_base_{};
std::string xml_path_{};
Element_t* parent_node_{};
tinyxml2::XMLDocument doc_{};
OneGroupIni opr_base_{};
std::string xml_path_{};
Element_t* parent_node_{};
std::vector<std::string> keys_{};
std::vector<std::string> units_{};
};
#endif