StoryCheckTools/frame/CompareViews.py

206 lines
7.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
CompareViews
对比Storylines基线和最新Storylines编译结果差异对比
"""
import sys
import os
from typing import List, Dict, Tuple
from PyQt5.QtCore import QModelIndex
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QTableView, QSplitter, QApplication, QMainWindow
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from frame.MergeView import LinesMergeView, MergeDestination
from manage.MileStone import base_store_path, current_store_path
from parse.StoryMap import FragmentSlice, StoryMap, XAST_ParseTool, storyline_list2map
from parse.StorylineCmp import ModifyReason, CmpTool
class ResultList(QTableView):
def __init__(self, parent):
QTableView.__init__(self, parent)
self.model = QStandardItemModel(self)
self.model.setHorizontalHeaderLabels(["故事名称", "情节名称", "状态"])
self.setModel(self.model)
self.setSelectionMode(QTableView.SelectionMode.SingleSelection)
self.setSelectionBehavior(QTableView.SelectionBehavior.SelectRows)
pass
def present_affected_fragments(self, graph_new: Dict[str, StoryMap], cmp_result: Dict[ModifyReason, List[FragmentSlice]]):
"""
展示影响节点
:return:
"""
old_remove = cmp_result[ModifyReason.Removed]
affected_list = []
for node in old_remove:
affected_list = affected_list + self.__find_remove_affected_slice_within_new(graph_new, node)
pass
fragm_items = self.__filter_and_related_defines_seek(affected_list)
self.__append_fragments_list(fragm_items, "REMOVE")
curr_append = cmp_result[ModifyReason.Append]
affected_list = self.__find_append_and_changed_affected_slice(curr_append)
fragm_items = self.__filter_and_related_defines_seek(affected_list)
self.__append_fragments_list(fragm_items, "APPEND")
curr_changed = cmp_result[ModifyReason.Changed]
affected_list = self.__find_append_and_changed_affected_slice(curr_changed)
fragm_items = self.__filter_and_related_defines_seek(affected_list)
self.__append_fragments_list(fragm_items, "UPDATE")
pass
def __find_remove_affected_slice_within_new(self, graph_new: Dict[str, StoryMap], peers_old: FragmentSlice) -> List[FragmentSlice]:
"""
获取受到移除节点直接影响的节点
:param graph_new: 新图
:param peers_old: 旧图节点
:return:
"""
retvs = []
story_name = peers_old.parent_story
# 移除了情节定义
if peers_old.is_define_node[0]:
refer_list = peers_old.refers_slice
for refer_slice_prev in refer_list.values():
retvs = retvs + self.__find_remove_affect_within_new(graph_new, refer_slice_prev)
pass
story_curr = graph_new[story_name]
# 新图内故事线存在,非最后一个节点,计算影响
if story_curr is not None and peers_old.next_node is not None:
o_frag_def = peers_old.next_node
frag_curr_def = story_curr.get_fragment_defined(o_frag_def.is_define_node[1])
if frag_curr_def is not None:
retvs.append(frag_curr_def)
pass
pass
else:
refer_story_new = graph_new[story_name]
slice_affected = peers_old.next_node
# 非最后一个,需要计算影响,新图中的故事线存在,计算影响
if slice_affected is not None and refer_story_new is not None:
v_s_name = slice_affected.story_refer
v_f_name = slice_affected.fragm_refer
# 获取收到影响的情节片段
slice_refer_now = CmpTool.__locate_fragment_refer__(refer_story_new.slice_list[0], v_s_name, v_f_name)
if slice_refer_now is not None:
retvs.append(slice_refer_now)
pass
pass
return retvs
def __find_append_and_changed_affected_slice(self, peers_new: List[FragmentSlice]) -> List[FragmentSlice]:
retvs = []
for curr_node in peers_new:
next_slice = curr_node.next_node
if next_slice is not None:
retvs.append(next_slice)
return retvs
def __filter_and_related_defines_seek(self, affect_directed: List[FragmentSlice]) -> List[Tuple[str, str]]:
story_fragment_names: Dict[str, Tuple[str, str]] = {}
for node in affect_directed:
# 情节定义节点
if node.is_define_node[0]:
fragm_key = f"{node.parent_story}#{node.is_define_node[1]}"
story_fragment_names[fragm_key] = (node.parent_story, node.is_define_node[1])
# 情节引用节点
else:
fragm_key = f"{node.story_refer}#{node.fragm_refer}"
story_fragment_names[fragm_key] = (node.story_refer, node.fragm_refer)
pass
pass
return list(story_fragment_names.values())
def __append_fragments_list(self, fragment_keys: List[Tuple[str, str]], comp_type: str) -> None:
for key_def in fragment_keys:
row = [
QStandardItem(key_def[0]),
QStandardItem(key_def[1]),
QStandardItem(comp_type)
]
for cell in row:
cell.setEditable(False)
self.model.appendRow(row)
pass
pass
pass
class CompareWindow(QWidget):
def __init__(self, graph_new: Dict[str, StoryMap], cmp_result: Dict[ModifyReason, List[FragmentSlice]], parent):
QWidget.__init__(self, parent)
self.graph_new_refer = graph_new
layout = QVBoxLayout(self)
self.splitter = QSplitter(self)
layout.addWidget(self.splitter)
self.result_list = ResultList(self)
self.splitter.addWidget(self.result_list)
self.splitter.addWidget(QWidget(self))
self.result_list.present_affected_fragments(graph_new, cmp_result)
self.result_list.clicked.connect(self.present_fragment_merge_content)
pass
def present_fragment_merge_content(self, index: QModelIndex):
if not index.isValid():
return
story_name = self.result_list.model.item(index.row(), 0).text()
fragm_name = self.result_list.model.item(index.row(), 1).text()
story_node = self.graph_new_refer[story_name]
fragm_node = story_node.get_fragment_defined(fragm_name)
main_point = MergeDestination(story_name, fragm_node.prev_node, fragm_node)
elist = []
for refstory in fragm_node.refers_slice.keys():
refslice = fragm_node.refers_slice[refstory]
elist.append(MergeDestination(refstory, refslice.prev_node, refslice))
new_view = LinesMergeView(main_point, elist, self)
new_view.load_from_mem()
self.splitter.replaceWidget(1, new_view)
pass
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
win = QMainWindow()
ast_old = XAST_ParseTool(base_store_path)
ast_new = XAST_ParseTool(current_store_path)
map_old = storyline_list2map(ast_old.story_list)
map_new = storyline_list2map(ast_new.story_list)
ast_old.storylines_plait(map_old)
ast_new.storylines_plait(map_new)
cmp_tool = CmpTool()
all_changed = cmp_tool.graph_compare(map_new, map_old)
view = CompareWindow(map_new, all_changed, win)
win.setCentralWidget(view)
win.show()
app.exec()