324 lines
10 KiB
C++
324 lines
10 KiB
C++
#include "cmp_present.h"
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QSplitter>
|
|
#include <QDebug>
|
|
|
|
using namespace views;
|
|
using namespace xast_parse;
|
|
using namespace std;
|
|
using namespace compare;
|
|
|
|
|
|
StoryChangePresent::StoryChangePresent(
|
|
const QHash<QString, shared_ptr<StoryDefine>>& g_base,
|
|
const QHash<QString, shared_ptr<StoryDefine>>& 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<const QString&>::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<shared_ptr<PointDefines>> 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<StoryDefine>(fragm->parentSlice().lock());
|
|
QList<QStandardItem*> 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<QString, qlonglong> combine_with(const QList<QString>& sections) {
|
|
if (sections.isEmpty())
|
|
return pair<QString, qlonglong>();
|
|
|
|
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<const QString&>::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<PointDefines>(fragm_slice);
|
|
_defn_fragment->loadCurrentSlice(fragm_def);
|
|
|
|
connect(_story_appoint, QOverload<const QString&>::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<PointDefines>(_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<IElementSlice> 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<ICollection>(pslice);
|
|
|
|
auto temp_node = conn->firstChild();
|
|
while (temp_node) {
|
|
_nodes_temp << temp_node;
|
|
temp_node = temp_node->nextSlice();
|
|
}
|
|
}
|
|
this->endResetModel();
|
|
}
|
|
|
|
shared_ptr<IElementSlice> 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<TextParagraph>(curr_node);
|
|
return node->getLines();
|
|
}
|
|
case SliceType::FragmentDefines:
|
|
{
|
|
auto node = dynamic_pointer_cast<PointDefines>(curr_node);
|
|
return node->getTextNode()->getLines();
|
|
}
|
|
case SliceType::PointRefers:
|
|
{
|
|
auto node = dynamic_pointer_cast<FragmentRefer>(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<TextParagraph>(curr_node);
|
|
tnode->setLines(value.toString());
|
|
}break;
|
|
case SliceType::FragmentDefines:
|
|
{
|
|
auto defnode = dynamic_pointer_cast<PointDefines>(curr_node);
|
|
defnode->getTextNode()->setLines(value.toString());
|
|
}break;
|
|
case SliceType::PointRefers:
|
|
{
|
|
auto refnode = dynamic_pointer_cast<FragmentRefer>(curr_node);
|
|
refnode->getTextNode()->setLines(value.toString());
|
|
}break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
this->dataChanged(index, index, QVector<int>() << Qt::EditRole << Qt::DisplayRole);
|
|
return true;
|
|
}
|
|
else {
|
|
return QAbstractItemModel::setData(index, value, role);
|
|
}
|
|
}
|
|
|
|
#include <QTextEdit>
|
|
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<QTextEdit*>(editor)->setText(index.data(Qt::EditRole).toString());
|
|
}
|
|
|
|
void StorylineDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
|
|
auto ned = static_cast<QTextEdit*>(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 <QMenu>
|
|
#include <QMenuBar>
|
|
#include <QFileDialog>
|
|
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);
|
|
}
|