195 lines
7.4 KiB
Python
195 lines
7.4 KiB
Python
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QTableView, QSplitter, QApplication, QMainWindow
|
||
|
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||
|
from typing import List, Dict, Tuple
|
||
|
from manage.MileStone import base_store_path, current_store_path
|
||
|
from parse.StorylineCmp import ModifyReason, CmpTool
|
||
|
from parse.StoryMap import FragmentSlice, StoryMap, XAST_ParseTool, storyline_list2map
|
||
|
import sys
|
||
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QModelIndex
|
||
|
from frame.MergeView import LinesMergeView,MergeDestination
|
||
|
|
||
|
|
||
|
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]], type: str) -> None:
|
||
|
for key_def in fragment_keys:
|
||
|
row = []
|
||
|
row.append(QStandardItem(key_def[0]))
|
||
|
row.append(QStandardItem(key_def[1]))
|
||
|
row.append(QStandardItem(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()
|