#include "MainWidget.h" #include #include #include #include #include #include #include #include #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.16"); setWindowIcon(QIcon("://resource/xml.ico")); QScreen* primaryScreen = QGuiApplication::primaryScreen(); QRect screenGeometry = primaryScreen->geometry(); setMinimumWidth(screenGeometry.width() * 0.5); setMinimumHeight(screenGeometry.height() * 0.9); // setMinimumWidth(900); // setMinimumHeight(800); 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); ui->btnSearch->setFixedWidth(120); connect(ui->btnSelectFile, &QPushButton::clicked, this, [&]() { QString file = CUtil::select_file(this, u8"请选择xml文件", u8"XML(*.xml);;所有文件 (*)"); if (file.isEmpty()) { return; } read(file); //ui->edStatus->setText(file); }); connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(ui->edSearchKey->text()); }); 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 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(); if (base_.blank_width > 20) { blank_with_ = base_.blank_width; } 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(ui->edSearchKey->text()); 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) { menu_simple_->exec(QCursor::pos()); } else { menu_multi_->exec(QCursor::pos()); } } void MainWidget::generate_table_widget() { tab_widget_ = new QTableWidget(); metrics_ = std::make_shared(tab_widget_->font()); 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 = CUtil::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)); } col_with_.clear(); for (auto i = 0; i < keys_.size(); ++i) { col_with_[i] = 0; } 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, col_with_[i]); } QHBoxLayout* lay = new QHBoxLayout(); lay->addWidget(tab_widget_); ui->widget->setLayout(lay); } void MainWidget::push_content(const std::vector& 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); auto_add_ = true; 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(); auto_add_ = false; for (auto i = 0; i < keys_.size(); ++i) { tab_widget_->setColumnWidth(static_cast(i), col_with_[i]); } } 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) { base_.xml_path = file_path.toStdString(); if (!ini_.set_xml_path(base_.xml_path)) { CUtil::msg(this, u8"没有ini配置文件或者保存ini失败。"); return; } 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; } if (base_.allow_max_width < 0 || base_.allow_max_width > 1000) { allow_max_with_ = 100; } else { allow_max_with_ = base_.allow_max_width; } generate_table_widget(); push_content(vec_); current_ = vec_; 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(const QString& key) { QString bkey = key; if (bkey.isEmpty()) { current_ = vec_; push_content(current_); return; } if (tab_widget_ == nullptr) { return; } if (!ui->cbCaseSensitive->isChecked()) { bkey = bkey.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(bkey)) { 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().toStdString().c_str()); } 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::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(ui->edSearchKey->text()); } // 返回 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() { menu_simple_ = new QMenu(); menu_multi_ = 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"); menu_simple_->addAction(ac_edit_property_); menu_simple_->addAction(ac_copy_curline_); menu_simple_->addAction(ac_del_curline_); menu_simple_->addAction(ac_copy_key_); menu_multi_->addAction(ac_del_curline_); 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); } QString sda(data); int dwidth = metrics_->horizontalAdvance(sda) + blank_with_; int need_set_width = dwidth > allow_max_with_ ? allow_max_with_ : dwidth; col_with_[i] = col_with_[i] < need_set_width ? need_set_width : col_with_[i]; wgItem->setText(sda); tab_widget_->setItem(row, i, wgItem); } } void MainWidget::del_select_line() { if (!CUtil::affirm(this, u8"确认", u8"确认删除吗?")) { return; } QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows(); int size = indexList.size(); std::vector erase_row; for (auto i = size - 1; i > -1; --i) { Element_t* target = get_element_by_row(indexList[i].row()); if (target == nullptr) { continue; } xml_.del_element(target); tab_widget_->removeRow(indexList[i].row()); erase_row.push_back(indexList[i].row()); std::vector::iterator it; for (it = vec_.begin(); it != vec_.end(); ++it) { if (*it == target) { break; } } vec_.erase(it); } // std::sort(erase_row.begin(), erase_row.end(), std::greater()); // for (const auto& item : erase_row) { // tab_widget_->removeRow(item); // } search(ui->edSearchKey->text()); } 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 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& vec) { std::vector turn_vec{}; for (const auto& item : vec) { const char* str = item->Attribute(keys_[0].c_str()); std::string d(str); turn_vec.emplace_back(item, d); } 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; } std::vector vec; if (ui->rbAllPage->isChecked()) { get_related_elements(vec, AREA_ALL_PAGE); } else if (ui->rbReplaceSelect->isChecked()) { get_related_elements(vec, AREA_SELECT); } else if (ui->rbRepCurPage->isChecked()) { get_related_elements(vec, AREA_CUR_PAGE); } else { get_related_elements(vec, AREA_ALL); } if (vec.size() < 1) { CUtil::msg(this, u8"无选择数据"); return; } QString ret; for (auto& item : vec) { if (item == nullptr) { continue; } tinyxml2::XMLPrinter printer; item->element_->Accept(&printer); ret.append(printer.CStr()); delete item; } 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; } auto handle = [&](const std::vector& vec, bool is_search) { for (auto& item : vec) { if (is_common) { replace_str(key, after, item->element_); } else { replace_str(item->element_, key, after); } if (!is_search) { ele_update_gui(item->element_, item->row_); } delete item; } }; std::vector vec; if (ui->rbReplaceSelect->isChecked()) { QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows(); if (indexList.size() < 1) { CUtil::msg(this, u8"无选择数据"); return; } get_related_elements(vec, AREA_SELECT); handle(vec, false); } else if (ui->rbAllPage->isChecked()) { get_related_elements(vec, AREA_ALL_PAGE); handle(vec, false); xml_.get_all_elements(vec_); current_.clear(); current_ = vec_; search(ui->edRepAfter->text()); } else if (ui->rbRepCurPage->isChecked()) { get_related_elements(vec, AREA_CUR_PAGE); handle(vec, false); } else { if (!CUtil::affirm(this, u8"确认", u8"确认进行全局替换吗?")) { return; } get_related_elements(vec, AREA_ALL); handle(vec, true); xml_.get_all_elements(vec_); current_.clear(); current_ = vec_; search(ui->edSearchKey->text()); } } 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::get_related_elements(std::vector& out, ReplaceArea area) { 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_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; } } } 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"备份完成。"); } } OperElement::OperElement(Element_t* ele, int row) { element_ = ele; row_ = row; } SElement_t::SElement_t(Element_t* e, std::string& s) { ele = e; str = std::move(s); }