diff-view
This commit is contained in:
parent
4279bcea32
commit
cec7faf053
|
@ -5,7 +5,12 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="f609c0f2-cd0d-4eea-87f1-8caf02d3f04f" name="Changes" comment="">
|
<list default="true" id="f609c0f2-cd0d-4eea-87f1-8caf02d3f04f" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/manage/NovelManage.py" beforeDir="false" afterPath="$PROJECT_DIR$/manage/NovelManage.py" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/frame/CompareViews.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/frame/CompareWindow.py" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/frame/MergeView.py" beforeDir="false" afterPath="$PROJECT_DIR$/frame/MergeView.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/parse/StoryMap.py" beforeDir="false" afterPath="$PROJECT_DIR$/parse/StoryMap.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/parse/StorylineCmp.py" beforeDir="false" afterPath="$PROJECT_DIR$/parse/StorylineCmp.py" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
@ -35,6 +40,7 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent"><![CDATA[{
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
|
"Python.CompareViews.executor": "Run",
|
||||||
"Python.CompareWindow.executor": "Run",
|
"Python.CompareWindow.executor": "Run",
|
||||||
"Python.MergeView.executor": "Run",
|
"Python.MergeView.executor": "Run",
|
||||||
"Python.MileStone.executor": "Run",
|
"Python.MileStone.executor": "Run",
|
||||||
|
@ -49,7 +55,29 @@
|
||||||
"last_opened_file_path": "D:/Projects/Python/StoryCheckTools"
|
"last_opened_file_path": "D:/Projects/Python/StoryCheckTools"
|
||||||
}
|
}
|
||||||
}]]></component>
|
}]]></component>
|
||||||
<component name="RunManager" selected="Python.NovelManage">
|
<component name="RunManager" selected="Python.CompareViews">
|
||||||
|
<configuration name="CompareViews" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="StoryTools" />
|
||||||
|
<option name="ENV_FILES" value="" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/frame" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/frame/CompareViews.py" />
|
||||||
|
<option name="PARAMETERS" value="" />
|
||||||
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
|
<option name="EMULATE_TERMINAL" value="false" />
|
||||||
|
<option name="MODULE_MODE" value="false" />
|
||||||
|
<option name="REDIRECT_INPUT" value="false" />
|
||||||
|
<option name="INPUT_FILE" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
<configuration name="MileStone" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
<configuration name="MileStone" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
<module name="StoryTools" />
|
<module name="StoryTools" />
|
||||||
<option name="ENV_FILES" value="" />
|
<option name="ENV_FILES" value="" />
|
||||||
|
@ -94,28 +122,6 @@
|
||||||
<option name="INPUT_FILE" value="" />
|
<option name="INPUT_FILE" value="" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="ReferView" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
|
||||||
<module name="StoryTools" />
|
|
||||||
<option name="ENV_FILES" value="" />
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/frame" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/frame/ReferView.py" />
|
|
||||||
<option name="PARAMETERS" value="" />
|
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
||||||
<option name="EMULATE_TERMINAL" value="false" />
|
|
||||||
<option name="MODULE_MODE" value="false" />
|
|
||||||
<option name="REDIRECT_INPUT" value="false" />
|
|
||||||
<option name="INPUT_FILE" value="" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<configuration name="StoryMap" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
<configuration name="StoryMap" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
<module name="StoryTools" />
|
<module name="StoryTools" />
|
||||||
<option name="ENV_FILES" value="" />
|
<option name="ENV_FILES" value="" />
|
||||||
|
@ -161,19 +167,19 @@
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<list>
|
<list>
|
||||||
|
<item itemvalue="Python.CompareViews" />
|
||||||
<item itemvalue="Python.NovelManage" />
|
<item itemvalue="Python.NovelManage" />
|
||||||
<item itemvalue="Python.entry" />
|
<item itemvalue="Python.entry" />
|
||||||
<item itemvalue="Python.MileStone" />
|
<item itemvalue="Python.MileStone" />
|
||||||
<item itemvalue="Python.ReferView" />
|
|
||||||
<item itemvalue="Python.StoryMap" />
|
<item itemvalue="Python.StoryMap" />
|
||||||
</list>
|
</list>
|
||||||
<recent_temporary>
|
<recent_temporary>
|
||||||
<list>
|
<list>
|
||||||
|
<item itemvalue="Python.CompareViews" />
|
||||||
<item itemvalue="Python.NovelManage" />
|
<item itemvalue="Python.NovelManage" />
|
||||||
<item itemvalue="Python.MileStone" />
|
<item itemvalue="Python.MileStone" />
|
||||||
<item itemvalue="Python.entry" />
|
<item itemvalue="Python.entry" />
|
||||||
<item itemvalue="Python.StoryMap" />
|
<item itemvalue="Python.StoryMap" />
|
||||||
<item itemvalue="Python.ReferView" />
|
|
||||||
</list>
|
</list>
|
||||||
</recent_temporary>
|
</recent_temporary>
|
||||||
</component>
|
</component>
|
||||||
|
@ -199,9 +205,14 @@
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
<breakpoints>
|
<breakpoints>
|
||||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||||
<url>file://$PROJECT_DIR$/manage/NovelManage.py</url>
|
<url>file://$PROJECT_DIR$/frame/CompareViews.py</url>
|
||||||
<line>4</line>
|
<line>167</line>
|
||||||
<option name="timeStamp" value="14" />
|
<option name="timeStamp" value="1" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||||
|
<url>file://$PROJECT_DIR$/frame/CompareViews.py</url>
|
||||||
|
<line>164</line>
|
||||||
|
<option name="timeStamp" value="2" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
</breakpoints>
|
</breakpoints>
|
||||||
</breakpoint-manager>
|
</breakpoint-manager>
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
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()
|
|
@ -1,56 +0,0 @@
|
||||||
from PyQt5.QtWidgets import QWidget, QTreeView, QVBoxLayout
|
|
||||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
|
||||||
from typing import List
|
|
||||||
from parse.ast_load import StoryLine, FragmentSlice, items_map
|
|
||||||
|
|
||||||
|
|
||||||
class CompareWin(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
QWidget.__init__(self)
|
|
||||||
self.setWindowTitle("故事线比较")
|
|
||||||
|
|
||||||
self.__compare_model = QStandardItemModel(self)
|
|
||||||
self.__compare_view = QTreeView(self)
|
|
||||||
self.__compare_model.setHorizontalHeaderLabels(["节点名称", "比对参数"])
|
|
||||||
self.__compare_view.setModel(self.__compare_model)
|
|
||||||
|
|
||||||
layout = QVBoxLayout(self)
|
|
||||||
layout.addWidget(self.__compare_view)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def load_differents(self, changed: List[str], base_list: List[StoryLine], other_list: List[StoryLine]):
|
|
||||||
base_map = items_map(base_list)
|
|
||||||
other_map = items_map(other_list)
|
|
||||||
|
|
||||||
for changed_item in changed:
|
|
||||||
item = QStandardItem(changed_item)
|
|
||||||
item2 = QStandardItem()
|
|
||||||
item.setEditable(False)
|
|
||||||
item2.setEditable(False)
|
|
||||||
self.__compare_model.appendRow([item, item2])
|
|
||||||
|
|
||||||
if changed_item in other_map:
|
|
||||||
story_origin = other_map[changed_item]
|
|
||||||
item_o = QStandardItem(story_origin.signature)
|
|
||||||
if not changed_item in base_map:
|
|
||||||
item2.setText("append")
|
|
||||||
else:
|
|
||||||
item2.setText("modify")
|
|
||||||
item_o2 = QStandardItem(story_origin.file_path)
|
|
||||||
item_o.setEditable(False)
|
|
||||||
item_o2.setEditable(False)
|
|
||||||
item.appendRow([item_o, item_o2])
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if changed_item in base_map:
|
|
||||||
story_modif = base_map[changed_item]
|
|
||||||
item_ext = QStandardItem(story_modif.signature)
|
|
||||||
item2.setText("remove")
|
|
||||||
item_ext2 = QStandardItem(story_modif.file_path)
|
|
||||||
item_ext.setEditable(False)
|
|
||||||
item_ext2.setEditable(False)
|
|
||||||
item.appendRow([item_ext, item_ext2])
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
pass
|
|
|
@ -21,6 +21,7 @@ class LinesMergeView(QWidget, MemorySkin):
|
||||||
self.refers_line = refdefs
|
self.refers_line = refdefs
|
||||||
|
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
splitter = QSplitter(Qt.Orientation.Vertical, self)
|
splitter = QSplitter(Qt.Orientation.Vertical, self)
|
||||||
layout.addWidget(splitter)
|
layout.addWidget(splitter)
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -7,6 +7,7 @@ from frame.ReferView import EmptyNode, MemoryNode
|
||||||
class FragmentSlice(EmptyNode):
|
class FragmentSlice(EmptyNode):
|
||||||
def __init__(self, def_mark: bool = False, name: str= ""):
|
def __init__(self, def_mark: bool = False, name: str= ""):
|
||||||
self.is_define_node = (def_mark, name)
|
self.is_define_node = (def_mark, name)
|
||||||
|
self.parent_story = ""
|
||||||
self.story_refer = ""
|
self.story_refer = ""
|
||||||
self.fragm_refer = ""
|
self.fragm_refer = ""
|
||||||
self.fragm_sort_i = 0
|
self.fragm_sort_i = 0
|
||||||
|
@ -19,11 +20,11 @@ class FragmentSlice(EmptyNode):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_from_memory(self) -> str:
|
def get_from_memory(self) -> str:
|
||||||
return r"\n".join(self.text_sections)
|
return "\n".join(self.text_sections)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_to_memory(self, content: str):
|
def set_to_memory(self, content: str):
|
||||||
self.text_sections = content.split(r"\n")
|
self.text_sections = content.split("\n")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ class StoryMap:
|
||||||
|
|
||||||
def append_fragment_slice(self, node: FragmentSlice):
|
def append_fragment_slice(self, node: FragmentSlice):
|
||||||
self.slice_list[-1].next_node = node
|
self.slice_list[-1].next_node = node
|
||||||
|
node.parent_story = self.story_name
|
||||||
node.prev_node = self.slice_list[-1]
|
node.prev_node = self.slice_list[-1]
|
||||||
node.fragm_sort_i = len(self.slice_list)
|
node.fragm_sort_i = len(self.slice_list)
|
||||||
self.slice_list.append(node)
|
self.slice_list.append(node)
|
||||||
|
|
|
@ -14,20 +14,20 @@ class CmpTool:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def graph_compare(self, graph_new: Dict[str, StoryMap], graph_old: Dict[str, StoryMap]) -> Dict[ModifyReason, FragmentSlice]:
|
def graph_compare(self, graph_new: Dict[str, StoryMap], graph_old: Dict[str, StoryMap]) -> Dict[ModifyReason, List[FragmentSlice]]:
|
||||||
fragments_has_removed = []
|
fragments_has_removed = []
|
||||||
for story in graph_old.values():
|
for story in graph_old.values():
|
||||||
fragments_has_removed = fragments_has_removed + self.__event_remove_check(graph_new, story)
|
fragments_has_removed = fragments_has_removed + self.__slice_remove_check(graph_new, story)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
fragments_has_appended = []
|
fragments_has_appended = []
|
||||||
for story in graph_new.values():
|
for story in graph_new.values():
|
||||||
fragments_has_appended = fragments_has_appended + self.__event_append_check(graph_old, story)
|
fragments_has_appended = fragments_has_appended + self.__slice_append_check(graph_old, story)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
fragments_has_changed = []
|
fragments_has_changed = []
|
||||||
for story in graph_new.values():
|
for story in graph_new.values():
|
||||||
fragments_has_changed = fragments_has_changed + self.__event_changed_check(graph_old, story)
|
fragments_has_changed = fragments_has_changed + self.__slice_changed_check(graph_old, story)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -36,35 +36,78 @@ class CmpTool:
|
||||||
ModifyReason.Changed: fragments_has_changed,
|
ModifyReason.Changed: fragments_has_changed,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __event_remove_check(self, graph_new: Dict[str, StoryMap], story_old: StoryMap) -> List[FragmentSlice]:
|
def __slice_remove_check(self, graph_new: Dict[str, StoryMap], story_old: StoryMap) -> List[FragmentSlice]:
|
||||||
list_retv = []
|
list_retv = []
|
||||||
for slice in story_old.slice_list[1:]:
|
|
||||||
if slice.is_define_node[0]:
|
|
||||||
s_name = story_old.story_name
|
s_name = story_old.story_name
|
||||||
f_name = slice.is_define_node[1]
|
story_curr = graph_new[s_name]
|
||||||
story_findout = graph_new[s_name]
|
|
||||||
if story_findout is None or story_findout.get_fragment_defined(f_name) is None:
|
|
||||||
list_retv.append(slice)
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
return list_retv
|
|
||||||
|
|
||||||
def __event_append_check(self, graph_old: Dict[str, StoryMap], story_new: StoryMap) -> List[FragmentSlice]:
|
for slice in story_old.slice_list[1:]:
|
||||||
list_retv = []
|
if story_curr is None:
|
||||||
for slice in story_new.slice_list[1:]:
|
list_retv.append(slice)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 确定情节定义节点
|
||||||
if slice.is_define_node[0]:
|
if slice.is_define_node[0]:
|
||||||
s_name = story_new.story_name
|
|
||||||
f_name = slice.is_define_node[1]
|
f_name = slice.is_define_node[1]
|
||||||
story_findout = graph_old[s_name]
|
if story_curr.get_fragment_defined(f_name) is None:
|
||||||
if story_findout is None or story_findout.get_fragment_defined(f_name) is None:
|
list_retv.append(slice)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
# 确定情节引用节点
|
||||||
|
else:
|
||||||
|
s_refer_name = slice.story_refer
|
||||||
|
f_refer_name = slice.fragm_refer
|
||||||
|
refer_curr = CmpTool.__locate_fragment_refer__(story_curr.slice_list[0], s_refer_name, f_refer_name)
|
||||||
|
if refer_curr is None:
|
||||||
list_retv.append(slice)
|
list_retv.append(slice)
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
return list_retv
|
return list_retv
|
||||||
|
|
||||||
def __event_changed_check(self, graph_old: Dict[str, StoryMap], story_new: StoryMap) -> List[FragmentSlice]:
|
def __slice_append_check(self, graph_old: Dict[str, StoryMap], story_new: StoryMap) -> List[FragmentSlice]:
|
||||||
|
list_retv = []
|
||||||
|
s_name = story_new.story_name
|
||||||
|
story_prev = graph_old[s_name]
|
||||||
|
|
||||||
|
for slice in story_new.slice_list[1:]:
|
||||||
|
if story_prev is None:
|
||||||
|
list_retv.append(slice)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 确定情节定义节点
|
||||||
|
if slice.is_define_node[0]:
|
||||||
|
f_name = slice.is_define_node[1]
|
||||||
|
if story_prev.get_fragment_defined(f_name) is None:
|
||||||
|
list_retv.append(slice)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
# 确定情节引用节点
|
||||||
|
else:
|
||||||
|
s_refer_name = slice.story_refer
|
||||||
|
f_refer_name = slice.fragm_refer
|
||||||
|
refer_prev = CmpTool.__locate_fragment_refer__(story_prev.slice_list[0], s_refer_name, f_refer_name)
|
||||||
|
if refer_prev is None:
|
||||||
|
list_retv.append(slice)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
return list_retv
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __locate_fragment_refer__(cls, ref_story_head: FragmentSlice, story_self: str, fragm_self: str) -> FragmentSlice:
|
||||||
|
if ref_story_head is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 确定属于引用节点
|
||||||
|
if not ref_story_head.is_define_node[0]:
|
||||||
|
if ref_story_head.story_refer == story_self and ref_story_head.fragm_refer == fragm_self:
|
||||||
|
return ref_story_head
|
||||||
|
|
||||||
|
return cls.__locate_fragment_refer__(ref_story_head.next_node, story_self, fragm_self)
|
||||||
|
|
||||||
|
def __slice_changed_check(self, graph_old: Dict[str, StoryMap], story_new: StoryMap) -> List[FragmentSlice]:
|
||||||
story_old = graph_old[story_new.story_name]
|
story_old = graph_old[story_new.story_name]
|
||||||
if story_old is not None:
|
if story_old is not None:
|
||||||
return self.__event_changed_chack_for(story_old, story_new)
|
return self.__event_changed_chack_for(story_old, story_new)
|
||||||
|
@ -73,19 +116,34 @@ class CmpTool:
|
||||||
def __event_changed_chack_for(self, story_old: StoryMap, story_new: StoryMap) -> List[FragmentSlice]:
|
def __event_changed_chack_for(self, story_old: StoryMap, story_new: StoryMap) -> List[FragmentSlice]:
|
||||||
list_retv = []
|
list_retv = []
|
||||||
for fragm_curr in story_new.slice_list[1:]:
|
for fragm_curr in story_new.slice_list[1:]:
|
||||||
|
# 情节定义只比较定义节点本身
|
||||||
if fragm_curr.is_define_node[0]:
|
if fragm_curr.is_define_node[0]:
|
||||||
fragm_prev = story_old.get_fragment_defined(fragm_curr.is_define_node[1])
|
fragm_prev = story_old.get_fragment_defined(fragm_curr.is_define_node[1])
|
||||||
|
# 确定新旧图都定义了该情节
|
||||||
if fragm_prev is not None:
|
if fragm_prev is not None:
|
||||||
if fragm_curr.fragm_sort_i != fragm_prev.fragm_sort_i:
|
if fragm_curr.fragm_sort_i != fragm_prev.fragm_sort_i:
|
||||||
list_retv.append(fragm_curr)
|
list_retv.append(fragm_curr)
|
||||||
pass
|
elif len(fragm_curr.text_sections) != len(fragm_prev.text_sections):
|
||||||
|
|
||||||
if len(fragm_curr.text_sections) != len(fragm_prev.text_sections):
|
|
||||||
list_retv.append(fragm_curr)
|
list_retv.append(fragm_curr)
|
||||||
elif fragm_curr.text_sections != fragm_prev.text_sections:
|
elif fragm_curr.text_sections != fragm_prev.text_sections:
|
||||||
list_retv.append(fragm_curr)
|
list_retv.append(fragm_curr)
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
|
refer_curr = fragm_curr
|
||||||
|
refer_prev = CmpTool.__locate_fragment_refer__(story_old.slice_list[0], refer_curr.story_refer, refer_curr.fragm_refer)
|
||||||
|
# 确定新旧图都定义了该引用节点
|
||||||
|
if refer_prev is not None:
|
||||||
|
if refer_prev.fragm_sort_i != refer_curr.fragm_sort_i:
|
||||||
|
list_retv.append(refer_curr)
|
||||||
|
elif len(refer_prev.text_sections) != len(refer_curr.text_sections):
|
||||||
|
list_retv.append(refer_curr)
|
||||||
|
elif refer_prev.text_sections != refer_curr.text_sections:
|
||||||
|
list_retv.append(refer_curr)
|
||||||
pass
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
return list_retv
|
return list_retv
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue