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

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

View File

@ -50,7 +50,10 @@ add_compile_options(/wd4267)
add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
endif()
add_executable(OneLevelXmlOpr ${PROJECT_SOURCES})
add_executable(OneLevelXmlOpr ${PROJECT_SOURCES}
conf_setting.h conf_setting.cpp conf_setting.ui
src/history.h src/history.cpp
src/uhistory.h src/uhistory.cpp src/uhistory.ui)
target_link_libraries(OneLevelXmlOpr PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
set_target_properties(OneLevelXmlOpr PROPERTIES
${BUNDLE_ID_OPTION}

View File

@ -1,5 +1,8 @@
#include "MainWidget.h"
#include "./ui_MainWidget.h"
#include "src/data_edit.h"
#include "public_def.h"
#include <QClipboard>
#include <QDateTime>
#include <QFile>
@ -8,10 +11,6 @@
#include <QScreen>
#include <QSettings>
#include <filesystem>
#include <regex>
#include "./ui_MainWidget.h"
#include "src/data_edit.h"
constexpr std::size_t g_OnePage = 100;
namespace fs = std::filesystem;
@ -19,7 +18,7 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
{
ui->setupUi(this);
setWindowTitle(u8"OneLevelXmlOpr v1.2.18");
setWindowTitle(u8"OneLevelXmlOpr v1.3.0");
setWindowIcon(QIcon("://resource/xml.ico"));
QScreen* primaryScreen = QGuiApplication::primaryScreen();
@ -30,7 +29,11 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
// setMinimumWidth(900);
// setMinimumHeight(800);
his_ = new CHistory();
attri_edit_ = new CAttributeEdit();
ini_oper_ = new CGroupIni();
ini_oper_->load_ini();
group_set_ = new CGroupSetting(this, ini_oper_);
ui->edStatus->setReadOnly(true);
ui->btnSave->setEnabled(false);
@ -50,8 +53,7 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
if (file.isEmpty()) {
return;
}
read(file);
// ui->edStatus->setText(file);
ui->edStatus->setText(file);
});
connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(ui->edSearchKey->text()); });
connect(ui->btnBackup, &QPushButton::clicked, this, [&]() { backup_file(); });
@ -61,6 +63,7 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
connect(ui->btnReset, &QPushButton::clicked, this, &MainWidget::reset);
connect(ui->btnReplace, &QPushButton::clicked, this, [&]() { replace_content(true); });
connect(ui->btnRxReplace, &QPushButton::clicked, this, [&]() { replace_content(false); });
connect(ui->cbUnit, &QComboBox::currentTextChanged, this, [&](const QString& content) { unit_change(); });
connect(ui->btnExport, &QPushButton::clicked, this, &MainWidget::copy_multi_data);
connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
unsigned int cur = ui->edCurPage->text().toUInt();
@ -80,6 +83,20 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
current_ = vec_;
push_content(current_);
});
connect(ui->btnSet, &QPushButton::clicked, this, [&]() {
group_set_->exec();
base_init();
});
connect(ui->btnHis, &QPushButton::clicked, this, [&]() {
CUIHistory his(this, his_);
his.exec();
if (his.cur_ != "") {
ui->edStatus->setText(his.cur_);
}
});
connect(ui->btnPageNext, &QPushButton::clicked, this, [&]() {
unsigned int cur = ui->edCurPage->text().toUInt();
push_content(current_, cur + 1);
@ -114,14 +131,11 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
init_menu();
ini_.set_work_exe(exe_path_);
base_ = ini_.get_config();
if (base_.blank_width > 20) {
blank_with_ = base_.blank_width;
if (cur_config_.max_blank_add > 20) {
blank_with_ = cur_config_.max_blank_add;
}
ui->edStatus->setText(QString::fromStdString(base_.xml_path));
// 基本处理
base_init();
}
void MainWidget::copy_key()
@ -147,19 +161,21 @@ void MainWidget::closeEvent(QCloseEvent* event)
void MainWidget::keyPressEvent(QKeyEvent* event)
{
switch (event->key()) {
case Qt::Key_Return:
search(ui->edSearchKey->text());
break;
default:
break;
case Qt::Key_Return:
search(ui->edSearchKey->text());
break;
default:
break;
}
QWidget::keyPressEvent(event);
}
MainWidget::~MainWidget()
{
delete attri_edit_;
delete ui;
delete attri_edit_;
delete ini_oper_;
delete his_;
}
void MainWidget::set_work_exe(char* path)
@ -190,8 +206,7 @@ void MainWidget::generate_table_widget()
connect(tab_widget_, &QTableWidget::itemChanged, this, [&](QTableWidgetItem* item) { item_changed_handle(item); });
connect(tab_widget_, &QTableWidget::customContextMenuRequested, this, &MainWidget::show_custom_menu);
auto config = ini_.get_config();
auto keys = CUtil::splitString(config.purpose, ",");
auto keys = CUtil::splitString(cur_config_.propertis, ",");
keys_.clear();
QStringList list;
@ -285,29 +300,48 @@ void MainWidget::judge_btn_page()
}
}
void MainWidget::read(const QString& file_path)
bool MainWidget::read(const QString& file_path)
{
base_.xml_path = file_path.toStdString();
if (!ini_.set_xml_path(base_.xml_path)) {
CUtil::msg(this, u8"没有ini配置文件或者保存ini失败。");
return;
// 获取配置
cur_config_.name = ui->cbConfig->currentText().toStdString();
if (!ini_oper_->get_item(cur_config_)) {
CUtil::msg(this, u8"获取配置失败。");
return false;
}
ui->edStatus->setText(file_path);
if (!xml_.open(base_.xml_path)) {
if (!xml_.open(file_path.toStdString())) {
CUtil::msg(this, u8"打开xml失败。");
return;
return false;
}
xml_.set_baseinfo(base_);
xml_.set_baseinfo(cur_config_);
if (!xml_.parse_xml(vec_)) {
CUtil::msg(this, u8"解析xml失败。");
return;
return false;
}
if (base_.allow_max_width < 0 || base_.allow_max_width > 1000) {
if (cur_config_.is_same) {
std::vector<std::string> units;
xml_.get_all_unit(units);
QStringList list;
for (const auto& unit : units) {
list.append(QString::fromStdString(unit));
}
u_ = true;
ui->cbUnit->clear();
if (!list.isEmpty()) {
ui->cbUnit->addItems(list);
ui->cbUnit->setCurrentIndex(0);
}
u_ = false;
}
else {
ui->cbUnit->setEnabled(false);
}
if (cur_config_.max_col_len < 0 || cur_config_.max_col_len > 1000) {
allow_max_with_ = 100;
} else {
allow_max_with_ = base_.allow_max_width;
allow_max_with_ = cur_config_.max_col_len;
}
generate_table_widget();
@ -321,6 +355,13 @@ void MainWidget::read(const QString& file_path)
ui->btnImport->setEnabled(true);
ui->btnExport->setEnabled(true);
ui->btnBackup->setEnabled(true);
ui->cbConfig->setEnabled(false);
ui->btnSet->setEnabled(false);
his_->push(ui->edStatus->text().toStdString());
return true;
}
void MainWidget::search(const QString& key)
@ -782,30 +823,30 @@ void MainWidget::get_related_elements(std::vector<OperElement*>& out, ReplaceAre
assert(tab_widget_);
out.clear();
switch (area) {
case AREA_ALL_PAGE: {
out.resize(current_.size());
std::transform(current_.begin(), current_.end(), out.begin(), [](Element_t* ele) { return new OperElement(ele, 0); });
break;
case AREA_ALL_PAGE: {
out.resize(current_.size());
std::transform(current_.begin(), current_.end(), out.begin(), [](Element_t* ele) { return new OperElement(ele, 0); });
break;
}
case AREA_CUR_PAGE: {
int rows = tab_widget_->rowCount();
for (int i = 0; i < rows; ++i) {
out.emplace_back(new OperElement(get_element_by_row(i), i));
}
case AREA_CUR_PAGE: {
int rows = tab_widget_->rowCount();
for (int i = 0; i < rows; ++i) {
out.emplace_back(new OperElement(get_element_by_row(i), i));
}
break;
}
case AREA_ALL: {
out.resize(vec_.size());
std::transform(vec_.begin(), vec_.end(), out.begin(), [](Element_t* ele) { return new OperElement(ele, 0); });
break;
}
default: {
QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
for (int i = 0; i < indexList.size(); ++i) {
out.emplace_back(new OperElement(get_element_by_row(indexList[i].row()), indexList[i].row()));
}
break;
break;
}
case AREA_ALL: {
out.resize(vec_.size());
std::transform(vec_.begin(), vec_.end(), out.begin(), [](Element_t* ele) { return new OperElement(ele, 0); });
break;
}
default: {
QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
for (int i = 0; i < indexList.size(); ++i) {
out.emplace_back(new OperElement(get_element_by_row(indexList[i].row()), indexList[i].row()));
}
break;
}
}
}
@ -823,6 +864,39 @@ void MainWidget::backup_file()
}
}
void MainWidget::base_init()
{
StrVec_t vec;
ini_oper_->get_all_node(vec);
QStringList list;
for (const auto& data : vec) {
list.append(QString::fromStdString(data));
}
ui->cbConfig->clear();
if (list.empty()) {
return;
}
ui->cbConfig->addItems(list);
ui->cbConfig->setCurrentIndex(0);
}
void MainWidget::unit_change()
{
if (u_) {
return;
}
std::string unit = ui->cbUnit->currentText().toStdString();
if (!xml_.get_all_elements(vec_, unit)) {
CUtil::msg(this, u8"获取单元信息失败:" + QString::fromStdString(unit));
return;
}
push_content(vec_);
current_ = vec_;
}
std::string MainWidget::extract_prefix(const std::string& name)
{
auto pos = name.find('.');

View File

@ -1,28 +1,36 @@
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include <QTableWidget>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <unordered_map>
#include "src/xml_opr.h"
#include "src/config.h"
#include "conf_setting.h"
#include "src/attribute_edit.h"
#include "src/config.h"
#include "src/xml_opr.h"
#include "src/history.h"
#include "src/uhistory.h"
#include <QAction>
#include <QMenu>
#include <QMessageBox>
#include <QTableWidget>
#include <QWidget>
#include <unordered_map>
struct SElement_t {
SElement_t(Element_t* e, std::string& s);
Element_t* ele;
Element_t* ele;
std::string str;
};
enum ReplaceArea { AREA_SELECT, AREA_ALL_PAGE, AREA_CUR_PAGE, AREA_ALL };
enum ReplaceArea {
AREA_SELECT,
AREA_ALL_PAGE,
AREA_CUR_PAGE,
AREA_ALL
};
struct OperElement {
OperElement(Element_t* ele, int row);
Element_t* element_{};
int row_{0};
int row_{0};
};
QT_BEGIN_NAMESPACE
@ -46,7 +54,7 @@ public:
void push_content(const std::vector<Element_t*>& eles, std::size_t page = 1);
private:
void read(const QString& file_path);
bool read(const QString& file_path);
void search(const QString& key);
void item_changed_handle(QTableWidgetItem* item);
void save();
@ -64,6 +72,8 @@ private:
void copy_multi_data();
void replace_content(bool is_common = true);
void backup_file();
void base_init();
void unit_change();
private:
std::string extract_prefix(const std::string& name);
@ -79,36 +89,39 @@ private:
void get_related_elements(std::vector<OperElement*>& out, ReplaceArea area);
private:
Element_t* get_element_by_key(const QString& key);
Element_t* get_element_by_row(int row);
Element_t* get_current_select_key();
Element_t* get_element_by_key(const QString& key);
Element_t* get_element_by_row(int row);
Element_t* get_current_select_key();
QTableWidgetItem* get_current_select_item();
private:
std::shared_ptr<QFontMetrics> metrics_;
std::shared_ptr<QFontMetrics> metrics_;
private:
QMenu* menu_simple_{};
QMenu* menu_multi_{};
QAction* ac_edit_property_{};
QAction* ac_copy_curline_{};
QAction* ac_del_curline_{};
QAction* ac_copy_key_{};
Ui::MainWidget* ui;
ConfigIni ini_{};
CXmlOpr xml_{};
std::string exe_path_{};
QTableWidget* tab_widget_{};
std::vector<Element_t*> vec_{};
std::vector<Element_t*> current_{};
QMenu* menu_simple_{};
QMenu* menu_multi_{};
QAction* ac_edit_property_{};
QAction* ac_copy_curline_{};
QAction* ac_del_curline_{};
QAction* ac_copy_key_{};
Ui::MainWidget* ui;
CXmlOpr xml_{};
std::string exe_path_{};
QTableWidget* tab_widget_{};
std::vector<Element_t*> vec_{};
std::vector<Element_t*> current_{};
std::vector<std::string> keys_{};
bool auto_add_{false};
std::size_t cur_page_{1};
std::size_t all_page_{1};
CAttributeEdit* attri_edit_{};
OprBase base_{};
long allow_max_with_{500};
long blank_with_{50};
ump_t col_with_{};
bool auto_add_{false};
std::size_t cur_page_{1};
std::size_t all_page_{1};
CAttributeEdit* attri_edit_{};
long allow_max_with_{500};
long blank_with_{50};
ump_t col_with_{};
CGroupSetting* group_set_{};
CGroupIni* ini_oper_{};
CHistory* his_{};
OneGroupIni cur_config_{};
bool u_{false};
};
#endif // MAINWIDGET_H

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1048</width>
<width>1056</width>
<height>682</height>
</rect>
</property>
@ -20,6 +20,13 @@
<string>1基本信息</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="btnHis">
<property name="text">
<string>历史</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSelectFile">
<property name="text">
@ -30,6 +37,9 @@
<item>
<widget class="QLineEdit" name="edStatus"/>
</item>
<item>
<widget class="QComboBox" name="cbConfig"/>
</item>
<item>
<widget class="QPushButton" name="btnRead">
<property name="text">
@ -70,7 +80,7 @@
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -108,14 +118,14 @@
<item>
<widget class="QPushButton" name="btnReplace">
<property name="text">
<string>一般替</string>
<string>一般替</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRxReplace">
<property name="text">
<string>正则替</string>
<string>正则替</string>
</property>
</widget>
</item>
@ -125,14 +135,14 @@
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbCaseSensitive">
<property name="text">
<string>区分大小</string>
<string>区分大小</string>
</property>
</widget>
</item>
@ -205,10 +215,33 @@
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbUnit"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<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="btnSet">
<property name="text">
<string>配置设置</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>

130
conf_setting.cpp Normal file
View File

@ -0,0 +1,130 @@
#include "conf_setting.h"
#include "public_def.h"
#include "ui_conf_setting.h"
CGroupSetting::CGroupSetting(QWidget* parent, CGroupIni* oper) : QDialog(parent), ui(new Ui::CGroupSetting)
{
ini_opr_ = oper;
ui->setupUi(this);
setWindowTitle(u8"配置编辑");
connect(ui->btnAddConfig, &QPushButton::clicked, this, [&]() { add_item(); });
connect(ui->btnDelConfig, &QPushButton::clicked, this, [&]() { del_item(); });
connect(ui->btnExit, &QPushButton::clicked, this, [&]() { close(); });
connect(ui->cbConfig, &QComboBox::currentTextChanged, this, [&](const QString& content) { change_ini(); });
}
CGroupSetting::~CGroupSetting()
{
delete ui;
}
void CGroupSetting::showEvent(QShowEvent* event)
{
update_ini();
QDialog::showEvent(event);
}
void CGroupSetting::add_item()
{
QString config_name = ui->edConfigName->text();
config_name = config_name.trimmed();
if (config_name.isEmpty()) {
CUtil::msg(this, u8"配置名为空");
return;
}
// 验证重名
// 添加
OneGroupIni gp;
gp.name = config_name.toStdString();
gp.item_key = ui->edItemKey->text().toStdString();
gp.main_nodes = ui->edMainPath->text().toStdString();
gp.relative_nodes = ui->edRelativePath->text().toStdString();
gp.max_col_len = ui->edMaxColLen->text().toLong();
gp.max_blank_add = ui->edMaxFillLen->text().toLong();
gp.propertis = ui->edProperties->text().toStdString();
gp.is_same = ui->chbIsSame->isChecked();
if (!ini_opr_->add_item(gp)) {
CUtil::msg(this, u8"失败");
return;
}
update_ini();
CUtil::msg(this, u8"成功");
}
void CGroupSetting::del_item()
{
std::string key = ui->cbConfig->currentText().toStdString();
if (!ini_opr_->del_item(key)) {
CUtil::msg(this, u8"失败");
return;
}
// 删除成功之后要更新 cb
update_ini();
CUtil::msg(this, u8"成功");
}
void CGroupSetting::set_ui(const OneGroupIni& gp)
{
ui->edConfigName->setText(QString::fromStdString(gp.name));
ui->edItemKey->setText(QString::fromStdString(gp.item_key));
ui->edMainPath->setText(QString::fromStdString(gp.main_nodes));
ui->edRelativePath->setText(QString::fromStdString(gp.relative_nodes));
ui->edMaxColLen->setText(QString::number(gp.max_col_len));
ui->edMaxFillLen->setText(QString::number(gp.max_blank_add));
ui->edProperties->setText(QString::fromStdString(gp.propertis));
if (gp.is_same) {
ui->chbIsSame->setChecked(true);
}
else {
ui->chbIsSame->setChecked(false);
}
}
void CGroupSetting::change_ini()
{
if (auto_add_) {
return;
}
QString name_key = ui->cbConfig->currentText();
OneGroupIni gp;
gp.name = name_key.toStdString();
if (!ini_opr_->get_item(gp)) {
CUtil::msg(this, u8"加载" + ui->cbConfig->currentText() + "失败");
} else {
set_ui(gp);
}
}
void CGroupSetting::update_ini()
{
StrVec_t vec;
ini_opr_->get_all_node(vec);
QStringList list;
for (const auto& data : vec) {
list.append(QString::fromStdString(data));
}
auto_add_ = true;
ui->cbConfig->clear();
if (!list.empty()) {
ui->cbConfig->addItems(list);
ui->cbConfig->setCurrentIndex(0);
OneGroupIni gp;
gp.name = ui->cbConfig->currentText().toStdString();
if (!ini_opr_->get_item(gp)) {
CUtil::msg(this, u8"加载" + ui->cbConfig->currentText() + "失败");
} else {
set_ui(gp);
}
}
auto_add_ = false;
}

35
conf_setting.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef CONF_SETTING_H
#define CONF_SETTING_H
#include <QDialog>
#include "src/config.h"
namespace Ui {
class CGroupSetting;
}
class CGroupSetting : public QDialog
{
Q_OBJECT
public:
explicit CGroupSetting(QWidget *parent, CGroupIni* oper);
~CGroupSetting();
protected:
void showEvent(QShowEvent* event) override;
private:
void add_item();
void del_item();
void set_ui(const OneGroupIni& gp);
void change_ini();
void update_ini();
private:
bool auto_add_{false};
Ui::CGroupSetting *ui;
CGroupIni* ini_opr_{};
};
#endif // CONF_SETTING_H

150
conf_setting.ui Normal file
View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CGroupSetting</class>
<widget class="QWidget" name="CGroupSetting">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>339</width>
<height>530</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>配置选择:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbConfig"/>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>名称:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edConfigName"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>主节点路径:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chbIsSame">
<property name="text">
<string>是否是相同结构</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="edMainPath"/>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>操作节点路径(相对主节点,没有不填写):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edRelativePath"/>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>子项头名称:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edItemKey"/>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>操作属性列表(半角逗号分隔)::</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edProperties"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>列最大宽度(默认1000):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edMaxColLen"/>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>单元右侧空白填充宽度(默认60):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edMaxFillLen"/>
</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="btnAddConfig">
<property name="text">
<string>新增/更新</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDelConfig">
<property name="text">
<string>删除</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnExit">
<property name="text">
<string>退出</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,6 +1,6 @@
#include "public_def.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QMessageBox>
#ifdef _WIN32
#include <windows.h>
@ -37,7 +37,7 @@ void CUtil::sort_by_repeat(std::vector<std::string>& vec)
std::size_t len1 = 0;
std::size_t len2 = 0;
std::size_t cur = 0;
auto compare = [&](const std::string& str1, const std::string& str2) {
auto compare = [&](const std::string& str1, const std::string& str2) {
len1 = str1.size();
len2 = str2.size();
if (cur >= len1 || cur >= len2) {
@ -84,13 +84,12 @@ std::string CUtil::utf8_to_gbk(const std::string& utf8_str)
}
#endif
std::vector<std::string> CUtil::splitString(const std::string& input, const std::string& delimiter)
{
std::vector<std::string> tokens;
size_t pos = 0;
std::string backup = input;
std::string token;
size_t pos = 0;
std::string backup = input;
std::string token;
while ((pos = backup.find(delimiter)) != std::string::npos) {
token = backup.substr(0, pos);
@ -102,4 +101,3 @@ std::vector<std::string> CUtil::splitString(const std::string& input, const std:
return tokens;
}

View File

@ -1,18 +1,9 @@
#ifndef PUBLIC_DEF_HEADER
#define PUBLIC_DEF_HEADER
#include <QWidget>
#include <string>
#include <vector>
#include <QWidget>
struct OprBase {
std::string node_path{};
std::string the_node{};
std::string purpose{};
std::string xml_path{};
long allow_max_width{500};
long blank_width{50};
};
class CUtil
{
@ -21,13 +12,13 @@ public:
~CUtil() = default;
public:
static void msg(QWidget* parent, const QString& content);
static bool affirm(QWidget* parent, const QString& titile, const QString& content);
static void msg(QWidget* parent, const QString& content);
static bool affirm(QWidget* parent, const QString& titile, const QString& content);
static QString select_file(QWidget* parent, const QString& info, const QString& filter);
static void sort_by_repeat(std::vector<std::string>& vec);
static void sort_by_repeat(std::vector<std::string>& vec);
public:
static std::string utf8_to_gbk(const std::string& utf8_str);
static std::string utf8_to_gbk(const std::string& utf8_str);
static std::vector<std::string> splitString(const std::string& input, const std::string& delimiter);
};

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