添加比对窗口雏形

This commit is contained in:
codeboss 2024-07-14 23:04:40 +08:00
parent d9231fa131
commit 81f27ccb4c
9 changed files with 272 additions and 24 deletions

View File

@ -5,6 +5,8 @@
</component>
<component name="ChangeListManager">
<list default="true" id="f609c0f2-cd0d-4eea-87f1-8caf02d3f04f" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/frame/CompareWindow.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/frame/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/entry.py" beforeDir="false" afterPath="$PROJECT_DIR$/entry.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/parse/ast_load.py" beforeDir="false" afterPath="$PROJECT_DIR$/parse/ast_load.py" afterDir="false" />
@ -24,9 +26,9 @@
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectColorInfo"><![CDATA[{
"associatedIndex": 1
}]]></component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 1
}</component>
<component name="ProjectId" id="2jEMCq2fbwwqDBeLk1htGPoMtzQ" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" />
@ -39,8 +41,10 @@
"keyToString": {
"Python.ast_load.executor": "Debug",
"Python.entry.executor": "Debug",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"git-widget-placeholder": "master"
"git-widget-placeholder": "master",
"last_opened_file_path": "D:/Projects/Python/StoryCheckTools"
}
}]]></component>
<component name="RunManager">
@ -75,7 +79,7 @@
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-python-sdk-5b207ade9991-746f403e7f0c-com.jetbrains.pycharm.community.sharedIndexes.bundled-PC-241.17890.14" />
<option value="bundled-python-sdk-50da183f06c8-d3b881c8e49f-com.jetbrains.pycharm.community.sharedIndexes.bundled-PC-233.13135.95" />
</set>
</attachedChunks>
</component>

View File

@ -1,8 +1,17 @@
from PyQt5.QtWidgets import QWidget, QApplication
from frame.CompareWindow import CompareWin
from sys import argv
from parse.ast_load import global_ast_path, AstParse
tool = AstParse(global_ast_path)
print(tool.generate_time())
tool.peak_storylines()
storys = tool.peak_storylines()
storys_2 = tool.peak_storylines()
defferent_list = tool.storylines_compare(storys, storys_2)
app = QApplication(argv)
win = CompareWin()
win.load_differents(defferent_list, storys, storys_2)
win.show()
app.exec()

56
frame/CompareWindow.py Normal file
View File

@ -0,0 +1,56 @@
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

0
frame/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
from lxml import etree
from typing import List
from typing import List, Dict
global_ast_path = r"E:\storyline.xast"
@ -15,35 +15,151 @@ def items_filter(items, proc):
return values
def items_map(items: List['StoryLine']) -> Dict[str, 'StoryLine']:
map: Dict[str, 'StoryLine'] = {}
for inst in items:
map[inst.signature] = inst
pass
return map
class FragmentSlice():
def __init__(self, signature: str):
"""
故事情节片段
"""
def __init__(self, signature: str, file_path: str):
self.signature = signature
self.file_path = file_path
self.text_sections = []
self.refer_items: 'FragmentSlice' = []
pass
def append_text_section(self, section: str):
"""
添加描述文本段落
:param section: 文本段落
:return: None
"""
self.text_sections.append(section)
pass
def append_refer_slice(self, refer:'FragmentSlice'):
"""
添加引用描述段落内容
class StorySlice():
def __init__(self, signature: str):
:param refer: 引用段落
:return: None
"""
self.refer_items.append(refer)
pass
def content_equal(self, other: 'FragmentSlice') -> bool:
"""
内容比较
:param other: 其他片段
:return: 比较结果
"""
if self.signature != other.signature:
return False
if len(self.text_sections) != len(other.text_sections):
return False
for line0 in self.text_sections:
if not line0 in other.text_sections:
return False
pass
if len(self.refer_items) != len(other.refer_items):
return False
for slice in self.refer_items:
find: bool = False
for slice_1 in other.refer_items:
if slice.content_equal(slice_1):
find = True
pass
pass
if not find:
return False
pass
return True
class StoryLine():
"""
故事线结果
"""
def __init__(self, signature: str, file_path: str):
self.signature = signature
self.file_path = file_path
self.text_sections = []
self.fragment_slices = []
pass
def append_text_section(self, section: str):
"""
添加文本描述
:param section: 文本段落
:return: None
"""
self.text_sections.append(section)
pass
def append_fragment_slice(self, slice: FragmentSlice):
"""
添加情节
:param slice: 情节实例
:return: None
"""
self.fragment_slices.append(slice)
pass
def content_equal(self, other: "StoryLine") -> bool:
"""
内容比较
:param other: 其他实例
:return: 比较结果
"""
if self.signature != other.signature:
return False
if len(self.text_sections) != len(other.text_sections):
return False
for line in self.text_sections:
if not line in other.text_sections:
return False
pass
if len(self.fragment_slices) != len(other.fragment_slices):
return False
for slice0 in self.fragment_slices:
find: bool = False
for slice1 in other.fragment_slices:
if slice0.content_equal(slice1):
find = True
pass
pass
if not find:
return False
pass
return True
class AstParse():
"""
Ast解析器
"""
def __init__(self, ast_path: str):
self.ast_path = ast_path
ast_file = open(ast_path, "rb")
@ -52,27 +168,42 @@ class AstParse():
pass
def generate_time(self) -> str:
"""
获取生成时间
:return: 生成时间字符串
"""
attr_time = self.ast_inst.xpath("/ast[1]/@time")[0]
return str(attr_time)
def peak_storylines(self) -> List[StorySlice]:
def peak_storylines(self) -> List[StoryLine]:
"""
提取所有故事线
:return: 故事线列表
"""
story_list = self.ast_inst.xpath("/ast/story") # 获取所有故事节点
story_items = []
fragm_map: Dict[str, FragmentSlice] = {}
for story in story_list:
story_name = story.xpath("@name")[0]
story_slice = StorySlice("story:"+story_name)
story_file = story.xpath("@file-path")[0]
story_slice = StoryLine("story:" + story_name, story_file)
story_items.append(story_slice)
story_text_lines = story.xpath("text-section/@text") # 获取所有描述
story_text_lines = story.xpath("text-section/@text") #获取所有描述
for line in story_text_lines:
story_slice.append_text_section(line)
pass
fragment_items = story.xpath("fragment") # 获取所有情节定义
fragment_items = story.xpath("fragment") #获取所有情节定义
for fragm in fragment_items:
fragment_name = fragm.xpath("@name")
fragm_slice = FragmentSlice("fragment:"+story_name+"#"+fragment_name)
fragment_name = fragm.xpath("@name")[0]
fragm_slice = FragmentSlice(f"fragment:{story_name}#{fragment_name}", story_file)
story_slice.append_fragment_slice(fragm_slice)
fragm_map[fragm_slice.signature] = fragm_slice
fragm_text_lines = fragm.xpath("text-section/@text")
for line in fragm_text_lines:
fragm_slice.append_text_section(line)
@ -80,14 +211,62 @@ class AstParse():
pass
pass
fragm_refers = self.ast_inst.xpath("//refer")
for refer in fragm_refers:
story_name = refer.xpath("@story")
fragm_name = refer.xpath("@fragment")
story_refers = items_filter(story_items, lambda x:x.signature == f"story:{story_name}")
if(len(story_refers) > 0):
story_refer = story_refers[0]
fragm_refer_items = self.ast_inst.xpath("//refer")
for refer_item in fragm_refer_items:
story_name_refer = refer_item.xpath("@story")[0]
fragm_name_refer = refer_item.xpath("@fragment")[0]
fragm_file = refer_item.xpath("@file-path")[0]
fragm_signature = f"fragment:{story_name_refer}#{fragm_name_refer}"
fragment_target = fragm_map[fragm_signature]
fragm_pnode = refer_item.xpath("..")[0]
if fragm_pnode.xpath("name()") == "story":
this_story_name = fragm_pnode.xpath("@name")[0]
refer_slice = FragmentSlice(f"refer:<{this_story_name}>{story_name_refer}#{fragm_name_refer}", fragm_file)
fragment_target.append_refer_slice(refer_slice)
refer_lines = refer_item.xpath("text-section/@text")
for line in refer_lines:
refer_slice.append_text_section(line)
pass
pass
if fragm_pnode.xpath("name()") == "article":
this_article_name = fragm_pnode.xpath("@name")[0]
this_volume_node = fragm_pnode.xpath("..")[0]
this_volume_name = this_volume_node.xpath("@name")[0]
refer_slice = FragmentSlice(f"refer-article<{this_volume_name}#{this_article_name}>{story_name_refer}#{fragm_name_refer}", fragm_file)
fragment_target.append_refer_slice(refer_slice)
refer_lines = refer_item.xpath("text-section/@text")
for line in refer_lines:
refer_slice.append_text_section(line)
pass
pass
return story_items
def storylines_compare(self, base_list: List[StoryLine], other_list: List[StoryLine]) -> List[str]:
changed_list: List[str] = []
base_map = items_map(base_list)
for other_item in other_list:
if not other_item.signature in base_map:
changed_list.append(other_item.signature)
continue
base_item = base_map[other_item.signature]
if not other_item.content_equal(base_item):
changed_list.append(other_item.signature)
pass
base_map.pop(other_item.signature)
pass
for addit in base_map.values():
changed_list.append(addit.signature)
pass
return changed_list