#include "cmp_present.h" #include #include #include #include using namespace views; using namespace xast_parse; using namespace std; using namespace compare; StoryChangePresent::StoryChangePresent( const QHash>& g_base, const QHash>& g_old, QWidget* parent) : QWidget(parent), base_compare(Compare(g_base)), g_old(g_old), _type_appoint(new QToolBox(this)), _fragment_summary(new QTableView(this)), _upstream_summary(new QTableView(this)), _change_model(new QStandardItemModel(this)), _story_appoint(new QComboBox(this)), _edit_splitter(new QSplitter(this)), _define_view(new QListView(this)), _refer_view(new QListView(this)), _defn_fragment(new StorylineModel), _curr_refslice(new StorylineModel) { _type_appoint->layout()->setMargin(1); _type_appoint->layout()->setSpacing(1); auto _base_layout = new QVBoxLayout(this); _base_layout->setMargin(0); _base_layout->setSpacing(0); // 功能区域左右分割 auto area_splitter = new QSplitter(this); _base_layout->addWidget(area_splitter); area_splitter->addWidget(_type_appoint); // 编辑区域 auto edit_area = new QWidget(this); area_splitter->addWidget(edit_area); auto edit_layout = new QVBoxLayout(edit_area); edit_layout->setMargin(0); edit_layout->addWidget(_story_appoint); edit_layout->addWidget(_edit_splitter, 1); _edit_splitter->addWidget(_refer_view); _edit_splitter->addWidget(_define_view); // ============================ _type_appoint->addItem(_upstream_summary, u8"上游修改"); _type_appoint->addItem(_fragment_summary, u8"情节修改"); auto font_default = this->font(); font_default.setPointSize(16); this->setFont(font_default); _define_view->setModel(_defn_fragment); _refer_view->setModel(_curr_refslice); _fragment_summary->setModel(_change_model); _upstream_summary->setModel(_change_model); // =========================== connect(_type_appoint, &QToolBox::currentChanged, this, &StoryChangePresent::type_change); type_change(0); _define_view->setWordWrap(true); _define_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); _define_view->setItemDelegate(new StorylineDelegate(_define_view)); _refer_view->setWordWrap(true); _refer_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); _refer_view->setItemDelegate(new StorylineDelegate(_refer_view)); } Compare& StoryChangePresent::compareTool() { return this->base_compare; } void StoryChangePresent::type_change(int idx) { disconnect(_story_appoint, QOverload::of(&QComboBox::currentIndexChanged), nullptr, nullptr); disconnect(_upstream_summary, &QTableView::pressed, nullptr, nullptr); disconnect(_fragment_summary, &QTableView::pressed, nullptr, nullptr); _story_appoint->clear(); _story_appoint->setEnabled(false); _defn_fragment->loadCurrentSlice(nullptr); _curr_refslice->loadCurrentSlice(nullptr); _change_model->clear(); QList> fragms; if (!idx) { fragms = base_compare.changeCompare(Type::UpstreamAlter, g_old); } else { fragms = base_compare.changeCompare(Type::FragmentAlter, g_old); } _change_model->setHorizontalHeaderLabels(QStringList() << u8"故事名称" << u8"情节名称"); for (auto fragm : fragms) { auto story = dynamic_pointer_cast(fragm->parentSlice().lock()); QList row; row << new QStandardItem(story->name()); row << new QStandardItem(fragm->name()); _change_model->appendRow(row); } _upstream_summary->resizeColumnsToContents(); _fragment_summary->resizeColumnsToContents(); connect(_upstream_summary, &QTableView::pressed, this, &StoryChangePresent::fragment_selected); connect(_fragment_summary, &QTableView::pressed, this, &StoryChangePresent::fragment_selected); } pair combine_with(const QList& sections) { if (sections.isEmpty()) return pair(); auto head_rst = combine_with(sections.mid(0, sections.size() - 1)); auto target_str = sections.last(); auto final_rst = make_pair( head_rst.first + "/" + target_str, head_rst.second << 8 + target_str.size() ); return final_rst; } void StoryChangePresent::fragment_selected(const QModelIndex& item) { if (!item.isValid()) return; disconnect(_story_appoint, QOverload::of(&QComboBox::currentIndexChanged), nullptr, nullptr); _story_appoint->clear(); _story_appoint->setEnabled(true); auto story_index = item.sibling(item.row(), 0); auto fragm_index = item.sibling(item.row(), 1); auto story_item = this->_change_model->itemFromIndex(story_index); auto fragm_item = this->_change_model->itemFromIndex(fragm_index); auto story_inst = this->base_compare.graphBind()[story_item->text()]; auto fragm_slice = story_inst->getFragment(fragm_item->text()); auto fragm_def = dynamic_pointer_cast(fragm_slice); _defn_fragment->loadCurrentSlice(fragm_def); connect(_story_appoint, QOverload::of(&QComboBox::currentIndexChanged), this, &StoryChangePresent::storyline_selected); for (auto refer : fragm_def->referSlices()) { auto def_v = combine_with(refer->nameSet()); _story_appoint->addItem(def_v.first, def_v.second); } } void StoryChangePresent::storyline_selected(const QString& line) { auto def_fragm = dynamic_pointer_cast(_defn_fragment->currentSlice()); auto flag = _story_appoint->currentData(); for (auto slice : def_fragm->referSlices()) { auto defv = combine_with(slice->nameSet()); if (flag == defv.second && line == defv.first) { _curr_refslice->loadCurrentSlice(slice); break; } } } void StorylineModel::loadCurrentSlice(shared_ptr target_node) { this->beginResetModel(); this->_current_slice = target_node; _nodes_temp.clear(); if (this->_current_slice) { auto pslice = this->_current_slice->parentSlice().lock(); auto conn = dynamic_pointer_cast(pslice); auto temp_node = conn->firstChild(); while (temp_node) { _nodes_temp << temp_node; temp_node = temp_node->nextSlice(); } } this->endResetModel(); } shared_ptr StorylineModel::currentSlice() { return this->_current_slice; } QModelIndex StorylineModel::index(int row, int column, const QModelIndex& parent) const { return createIndex(row, column); } QModelIndex StorylineModel::parent(const QModelIndex& child) const { return QModelIndex(); } int StorylineModel::rowCount(const QModelIndex& parent) const { return _nodes_temp.size(); } int StorylineModel::columnCount(const QModelIndex& parent) const { return 1; } QVariant StorylineModel::data(const QModelIndex& index, int role) const { switch (role) { case Qt::EditRole: case Qt::DisplayRole: { auto curr_node = _nodes_temp.at(index.row()); switch (curr_node->type()) { case SliceType::TextPragraph: { auto node = dynamic_pointer_cast(curr_node); return node->getLines(); } case SliceType::FragmentDefines: { auto node = dynamic_pointer_cast(curr_node); return node->getTextNode()->getLines(); } case SliceType::PointRefers: { auto node = dynamic_pointer_cast(curr_node); return node->getTextNode()->getLines(); } } } case Qt::BackgroundRole: { auto curr_node = _nodes_temp.at(index.row()); if (curr_node == _current_slice) { return QColor(Qt::lightGray); } return QColor(Qt::white); } default: return QVariant(); } } Qt::ItemFlags StorylineModel::flags(const QModelIndex& idx) const { auto flags = QAbstractItemModel::flags(idx); auto curr_node = _nodes_temp.at(idx.row()); if (curr_node == _current_slice) return flags | Qt::ItemIsEditable; return flags; } bool StorylineModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (role == Qt::EditRole) { auto curr_node = _nodes_temp.at(index.row()); switch (curr_node->type()) { case SliceType::TextPragraph: { auto tnode = dynamic_pointer_cast(curr_node); tnode->setLines(value.toString()); }break; case SliceType::FragmentDefines: { auto defnode = dynamic_pointer_cast(curr_node); defnode->getTextNode()->setLines(value.toString()); }break; case SliceType::PointRefers: { auto refnode = dynamic_pointer_cast(curr_node); refnode->getTextNode()->setLines(value.toString()); }break; default: return false; } this->dataChanged(index, index, QVector() << Qt::EditRole << Qt::DisplayRole); return true; } else { return QAbstractItemModel::setData(index, value, role); } } #include StorylineDelegate::StorylineDelegate(QAbstractItemView* pwidget) :QStyledItemDelegate(pwidget), bind_view(pwidget) { } QWidget* StorylineDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { return new QTextEdit(bind_view); } void StorylineDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { static_cast(editor)->setText(index.data(Qt::EditRole).toString()); } void StorylineDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { auto ned = static_cast(editor); model->setData(index, ned->toPlainText(), Qt::EditRole); } void StorylineDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const { editor->setGeometry(option.rect); } QSize StorylineDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { return QStyledItemDelegate::sizeHint(option, index) + QSize(0, 20); } #include #include #include CompareWindow::CompareWindow(QFileInfo filebase, QFileInfo fileold) :_graph_base(XAST_Parser(filebase.canonicalFilePath())), _graph_old(XAST_Parser(fileold.canonicalFilePath())), _cmp_widget(new StoryChangePresent(_graph_base.storyGraph(), _graph_old.storyGraph())) { auto mbar = menuBar(); auto file = mbar->addMenu(u8"文件"); file->addAction(u8"另存为", [=]() { auto target = QFileDialog::getExistingDirectory(this, "获取目标文件夹", QDir::homePath()); if (target == u8"") return; this->_graph_base.output(QDir(target)); }); this->setCentralWidget(_cmp_widget); }