OneLevelXmlOpr/MainWidget.cpp

743 lines
20 KiB
C++

#include "MainWidget.h"
#include <QClipboard>
#include <QSettings>
#include <QFile>
#include <QKeyEvent>
#include <QDateTime>
#include <QRegularExpression>
#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.9");
setWindowIcon(QIcon("://resource/xml.ico"));
setMinimumWidth(900);
setMinimumHeight(800);
width_.push_back(280);
for (int i = 0; i < 30; ++i) {
width_.push_back(160);
}
attri_edit_ = new CAttributeEdit();
ui->edStatus->setReadOnly(true);
ui->btnSave->setEnabled(false);
ui->edAllPage->setEnabled(false);
ui->cbCaseSensitive->setChecked(false);
ui->btnImport->setEnabled(false);
ui->btnExport->setEnabled(false);
ui->btnBackup->setEnabled(false);
ui->rbReplaceSelect->setChecked(true);
ui->btnRead->setFixedWidth(100);
ui->btnSave->setFixedWidth(100);
ui->btnExit->setFixedWidth(100);
connect(ui->btnSelectFile, &QPushButton::clicked, this, [&]() {
QString file = CUtil::select_file(this, u8"请选择xml文件", u8"XML(*.xml);;所有文件 (*)");
if (file.isEmpty()) {
return;
}
read(file);
});
connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(); });
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, [&]() { replace_content(true); });
connect(ui->btnRxReplace, &QPushButton::clicked, this, [&]() { replace_content(false); });
connect(ui->btnExport, &QPushButton::clicked, this, &MainWidget::copy_multi_data);
connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
unsigned int cur = ui->edCurPage->text().toUInt();
push_content(current_, cur - 1);
});
connect(ui->btnImport, &QPushButton::clicked, this, [&]() {
CDataEdit edit;
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();
push_content(current_, cur + 1);
});
connect(ui->btnJump, &QPushButton::clicked, this, [&]() {
unsigned int cur = ui->edCurPage->text().toUInt();
push_content(current_, cur);
});
connect(ui->btnResort, &QPushButton::clicked, this, [&]() {
if (tab_widget_ == nullptr) {
return;
}
sort_by_repeat(vec_);
std::vector<Element_t*> nvec{};
xml_.copy_and_del(vec_, nvec);
vec_.clear();
std::swap(vec_, nvec);
current_ = vec_;
push_content(current_);
});
QSettings settings;
settings.beginGroup("xmlopr");
restoreGeometry(settings.value("geometry").toByteArray());
settings.endGroup();
// QFile qss_file("://qss/lightblue.css");
// QFile qss_file("://qss/flatgray.css");
// if (qss_file.open(QFile::ReadOnly)) {
// qApp->setStyleSheet(qss_file.readAll());
// }
init_menu();
ini_.set_work_exe(exe_path_);
base_ = ini_.get_config();
ui->edStatus->setText(QString::fromStdString(base_.xml_path));
}
void MainWidget::copy_key()
{
Element_t* target = get_current_select_key();
if (target == nullptr) {
return;
}
QClipboard* clip = QApplication::clipboard();
clip->setText(QString(target->Attribute(keys_[0].c_str())));
// CUtil::msg(this, u8"已复制");
}
void MainWidget::closeEvent(QCloseEvent* event)
{
QSettings settings;
settings.beginGroup("xmlopr");
settings.setValue("geometry", saveGeometry());
settings.endGroup();
QWidget::closeEvent(event);
}
void MainWidget::keyPressEvent(QKeyEvent* event)
{
switch (event->key()) {
case Qt::Key_Return:
search();
break;
default:
break;
}
QWidget::keyPressEvent(event);
}
MainWidget::~MainWidget()
{
delete attri_edit_;
delete ui;
}
void MainWidget::set_work_exe(char* path)
{
exe_path_.clear();
exe_path_.append(path);
}
void MainWidget::show_custom_menu()
{
if (tab_widget_ == nullptr) {
return;
}
QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
if (indexList.size() == 1) {
context_menu_->exec(QCursor::pos());
}
}
void MainWidget::generate_table_widget()
{
tab_widget_ = new QTableWidget();
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);
auto config = ini_.get_config();
auto keys = splitString(config.purpose, ",");
keys_.clear();
QStringList list;
for (const auto& item : keys) {
if (item.empty()) {
continue;
}
keys_.push_back(item);
list.append(QString::fromStdString(item));
}
tab_widget_->setColumnCount(list.size());
tab_widget_->setHorizontalHeaderLabels(list);
tab_widget_->setSelectionBehavior(QAbstractItemView::SelectRows);
// tab_widget_->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
for (auto i = 0; i < keys.size(); ++i) {
tab_widget_->setColumnWidth(i, width_[i]);
}
QHBoxLayout* lay = new QHBoxLayout();
lay->addWidget(tab_widget_);
ui->widget->setLayout(lay);
}
void MainWidget::push_content(const std::vector<tinyxml2::XMLElement*>& eles, std::size_t page)
{
if (tab_widget_ == nullptr || page == 0) {
return;
}
std::size_t all_size = eles.size();
std::size_t max_show = g_OnePage * page;
all_page_ = all_size / 100;
if (all_size % 100 != 0) {
++all_page_;
}
if (page < 1 || page > all_page_) {
if (eles.size() > 0) {
CUtil::msg(this, u8"页码不在范围内");
return;
}
tab_widget_->clearContents();
tab_widget_->setRowCount(0);
cur_page_ = 0;
ui->edCurPage->setText(QString::number(cur_page_));
ui->edAllPage->setText(QString::number(all_page_));
return;
}
tab_widget_->clearContents();
tab_widget_->setRowCount(0);
for (auto p = (page - 1) * g_OnePage; p < all_size && p < max_show; ++p) {
int row_cnt = tab_widget_->rowCount();
tab_widget_->insertRow(row_cnt);
insert_one_line(eles[p], row_cnt);
}
ui->edCurPage->setText(QString::number(page));
cur_page_ = page;
ui->edAllPage->setText(QString::number(all_page_));
judge_btn_page();
}
void MainWidget::judge_btn_page()
{
int cur = ui->edCurPage->text().trimmed().toUInt();
if (cur <= 1) {
ui->btnPagePre->setEnabled(false);
} else {
ui->btnPagePre->setEnabled(true);
}
if (cur >= all_page_) {
ui->btnPageNext->setEnabled(false);
} else {
ui->btnPageNext->setEnabled(true);
}
}
void MainWidget::read(const QString& file_path)
{
ini_.set_xml_path(file_path.toStdString());
ui->edStatus->setText(file_path);
if (!xml_.open(base_.xml_path)) {
CUtil::msg(this, u8"打开xml失败。");
return;
}
xml_.set_baseinfo(base_);
if (!xml_.parse_xml(vec_)) {
CUtil::msg(this, u8"解析xml失败。");
return;
}
auto_add_ = true;
generate_table_widget();
push_content(vec_);
current_ = vec_;
auto_add_ = false;
ui->edStatus->setText(file_path);
ui->btnRead->setEnabled(false);
ui->btnSave->setEnabled(true);
ui->btnSelectFile->setEnabled(false);
ui->btnImport->setEnabled(true);
ui->btnExport->setEnabled(true);
ui->btnBackup->setEnabled(true);
}
void MainWidget::search()
{
QString key = ui->edSearchKey->text().trimmed();
if (key.isEmpty()) {
current_ = vec_;
push_content(current_);
return;
}
if (tab_widget_ == nullptr) {
return;
}
if (!ui->cbCaseSensitive->isChecked()) {
key = key.toUpper();
}
current_.clear();
for (const auto& item : vec_) {
for (auto i = 0; i < keys_.size(); ++i) {
const char* data = item->Attribute(keys_[i].c_str());
QString qdata(data);
if (!ui->cbCaseSensitive->isChecked()) {
qdata = qdata.toUpper();
}
if (!qdata.contains(key)) {
continue;
}
current_.push_back(item);
break;
}
}
push_content(current_);
}
void MainWidget::item_changed_handle(QTableWidgetItem* item)
{
if (auto_add_) {
return;
}
if (item == nullptr) {
return;
}
int row = item->row();
int col = item->column();
QString xml_key = tab_widget_->item(row, 0)->text();
Element_t* result = get_element_by_key(xml_key);
if (result == nullptr) {
return;
}
result->SetAttribute(keys_[col].c_str(), item->text().toLocal8Bit().constData());
}
void MainWidget::save()
{
if (xml_.save()) {
CUtil::msg(this, u8"保存成功");
} else {
CUtil::msg(this, u8"保存失败");
}
}
void MainWidget::copy_select_line()
{
// if (!CUtil::affirm(this, u8"确认", u8"确认复制吗?")) {
// return;
// }
QTableWidgetItem* cur_item = get_current_select_item();
if (cur_item == nullptr) {
return;
}
Element_t* target = get_element_by_key(cur_item->text());
if (target == nullptr) {
return;
}
Element_t* newer = xml_.copy_element(target);
if (!edit_property(newer, cur_item->row())) {
return;
}
xml_.insert_brother_node(target, newer);
tab_widget_->insertRow(cur_item->row() + 1);
insert_one_line(newer, cur_item->row() + 1);
std::vector<Element_t*>::iterator it;
for (it = vec_.begin(); it != vec_.end(); ++it) {
if (*it == target) {
break;
}
}
int df = it - vec_.begin() + 1;
vec_.insert(vec_.begin() + df, newer);
search();
}
// 返回 true 表示确认编辑了, false 表示取消编辑了。
bool MainWidget::edit_property(Element_t* target, int row)
{
if (target == nullptr) {
return false;
}
Property_t property;
xml_.get_attributes(target, property);
// 检测key值是否变化
std::string value_pre = property[0].value;
attri_edit_->set_attribute(property);
attri_edit_->exec();
if (!attri_edit_->is_ok_) {
return false;
}
attri_edit_->get_attribute(property);
if (property[0].value != value_pre) {
while (xml_.check_key_exists(property)) {
CUtil::msg(attri_edit_, u8"不能有相同的key,请检查。");
attri_edit_->exec();
attri_edit_->get_attribute(property);
if (!attri_edit_->is_ok_) {
return false;
}
}
}
xml_.attributes_to_element(target, property);
// 这里要同步到界面
ele_update_gui(target, row);
return true;
}
void MainWidget::ele_update_gui(Element_t* target, int row)
{
if (tab_widget_ == nullptr) {
return;
}
for (auto i = 0; i < keys_.size(); ++i) {
const char* v = target->Attribute(keys_[i].c_str());
auto* qitem = tab_widget_->item(row, i);
qitem->setText(QString(v));
}
}
void MainWidget::init_menu()
{
context_menu_ = new QMenu();
ac_edit_property_ = new QAction(u8"编辑");
ac_copy_curline_ = new QAction(u8"复制此项");
ac_del_curline_ = new QAction(u8"删除此项");
ac_copy_key_ = new QAction(u8"复制key");
context_menu_->addAction(ac_edit_property_);
context_menu_->addAction(ac_copy_curline_);
context_menu_->addAction(ac_del_curline_);
context_menu_->addAction(ac_copy_key_);
connect(ac_edit_property_, &QAction::triggered, this, [&]() {
QTableWidgetItem* cur_item = get_current_select_item();
if (cur_item == nullptr) {
return;
}
Element_t* target = get_element_by_key(cur_item->text());
if (target == nullptr) {
return;
}
edit_property(target, cur_item->row());
});
connect(ac_copy_curline_, &QAction::triggered, this, [&]() { copy_select_line(); });
connect(ac_del_curline_, &QAction::triggered, this, [&]() { del_select_line(); });
connect(ac_copy_key_, &QAction::triggered, this, [&]() { copy_key(); });
}
void MainWidget::insert_one_line(Element_t* ele, int row)
{
if (ele == nullptr) {
return;
}
for (auto i = 0; i < keys_.size(); ++i) {
const char* data = ele->Attribute(keys_[i].c_str());
QTableWidgetItem* wgItem = new QTableWidgetItem();
if (i == 0) {
wgItem->setFlags(wgItem->flags() & ~Qt::ItemIsEditable);
// wgItem->setFlags(wgItem->flags() | Qt::ItemIsUserCheckable);
// wgItem->setCheckState(Qt::Checked);
}
wgItem->setText(QString(data));
tab_widget_->setItem(row, i, wgItem);
}
}
void MainWidget::del_select_line()
{
if (!CUtil::affirm(this, u8"确认", u8"确认删除吗?")) {
return;
}
QTableWidgetItem* item = get_current_select_item();
if (item == nullptr) {
return;
}
Element_t* target = get_element_by_key(item->text());
if (target == nullptr) {
return;
}
xml_.del_element(target);
// TODO: 添加到界面
tab_widget_->removeRow(item->row());
std::vector<Element_t*>::iterator it;
for (it = vec_.begin(); it != vec_.end(); ++it) {
if (*it == target) {
break;
}
}
vec_.erase(it);
search();
}
Element_t* MainWidget::get_current_select_key()
{
Element_t* ret = nullptr;
QTableWidgetItem* item = get_current_select_item();
if (item == nullptr) {
return ret;
}
ret = get_element_by_key(item->text());
return ret;
}
QTableWidgetItem* MainWidget::get_current_select_item()
{
QTableWidgetItem* ret = nullptr;
if (tab_widget_ == nullptr) {
return ret;
}
QList<QTableWidgetItem*> selectedItems = tab_widget_->selectedItems();
if (selectedItems.size() < 1) {
CUtil::msg(this, u8"没有选中数据");
return ret;
}
ret = selectedItems[0];
return ret;
}
void MainWidget::reset()
{
current_.clear();
current_ = vec_;
push_content(current_);
}
tinyxml2::XMLElement* MainWidget::get_element_by_key(const QString& key)
{
Element_t* ret = nullptr;
for (const auto& ele : current_) {
const char* data = ele->Attribute(keys_[0].c_str());
QString qdata(data);
if (qdata != key) {
continue;
}
ret = ele;
break;
}
return ret;
}
Element_t* MainWidget::get_element_by_row(int row)
{
Element_t* ret = nullptr;
if (row < 0 || !tab_widget_ || row >= tab_widget_->rowCount()) {
return ret;
}
QTableWidgetItem* item = tab_widget_->item(row, 0);
ret = get_element_by_key(item->text());
return ret;
}
void MainWidget::sort_by_repeat(std::vector<Element_t*>& vec)
{
struct SElement_t {
SElement_t(Element_t* e, std::string& s)
{
ele = e;
str = std::move(s);
}
Element_t* ele{};
std::string str{};
};
std::vector<SElement_t> turn_vec{};
for (const auto& item : vec) {
const char* str = item->Attribute(keys_[0].c_str());
turn_vec.emplace_back(item, std::string(str));
}
auto compare = [&](const SElement_t& se1, const SElement_t& se2) {
std::size_t i = 0;
// 逐个字符比较,直到找到不同的字符或者某个字符串到达结尾
while (i < se1.str.length() && i < se2.str.length()) {
if (se1.str[i] != se2.str[i]) {
return se1.str[i] < se2.str[i];
}
++i;
}
// 如果有一个字符串到达结尾,而另一个还没有,则较短的字符串排在前面
return se1.str.length() < se2.str.length();
};
std::sort(turn_vec.begin(), turn_vec.end(), compare);
vec.clear();
for (const auto& item : turn_vec) {
vec.push_back(item.ele);
}
}
void MainWidget::copy_multi_data()
{
if (tab_widget_ == nullptr) {
return;
}
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;
}
tinyxml2::XMLPrinter printer;
e->Accept(&printer);
ret.append(printer.CStr());
}
CDataEdit edit;
edit.set_data(ret);
edit.exec();
}
void MainWidget::replace_content(bool is_common)
{
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->rbReplaceSelect->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;
}
if (is_common) {
replace_str(key, after, e);
} else {
replace_str(e, key, after);
}
ele_update_gui(e, indexList[i].row());
}
} else if (ui->rbRepCurPage->isChecked()) {
int row_count = tab_widget_->rowCount();
for (int i = 0; i < row_count; ++i) {
Element_t* e = get_element_by_row(i);
if (e == nullptr) {
continue;
}
if (is_common) {
replace_str(key, after, e);
} else {
replace_str(e, key, after);
}
ele_update_gui(e, i);
}
} else {
if (!CUtil::affirm(this, u8"确认", u8"确认进行全局替换吗?")) {
return;
}
for (auto& data : vec_) {
if (is_common) {
replace_str(key, after, data);
} else {
replace_str(data, key, after);
}
}
xml_.get_all_elements(vec_);
current_.clear();
current_ = vec_;
search();
}
}
void MainWidget::replace_str(const QString& pre, const QString& after, Element_t* ele)
{
if (ele == nullptr) {
return;
}
for (auto i = 0; i < keys_.size(); ++i) {
auto* value = ele->Attribute(keys_[i].c_str());
QString content(value);
if (content.contains(pre)) {
content.replace(pre, after);
ele->SetAttribute(keys_[i].c_str(), content.toStdString().c_str());
}
}
}
void MainWidget::replace_str(Element_t* ele, const QString& rg, const QString& after)
{
QRegularExpression rx(rg);
if (ele == nullptr) {
return;
}
for (auto i = 0; i < keys_.size(); ++i) {
auto* value = ele->Attribute(keys_[i].c_str());
QString content(value);
content.replace(rx, after);
ele->SetAttribute(keys_[i].c_str(), content.toStdString().c_str());
}
}
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"备份完成。");
}
}