章节节点引用视图构建完成
This commit is contained in:
parent
d4bf6b186c
commit
9b59b0a458
|
@ -5,14 +5,10 @@
|
|||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="f609c0f2-cd0d-4eea-87f1-8caf02d3f04f" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/graph/undirected_graph/UDGLayout.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/graph/undirected_graph/UDGPresent.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/graph/undirected_graph/__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$/frame/ContentView.py" beforeDir="false" afterPath="$PROJECT_DIR$/frame/ContentView.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/graph/DataType.py" beforeDir="false" afterPath="$PROJECT_DIR$/graph/DataType.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/graph/directed_acyclic_graph/DAGPresent.py" beforeDir="false" afterPath="$PROJECT_DIR$/graph/directed_acyclic_graph/DAGPresent.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/graph/undirected_graph/UDGPresent.py" beforeDir="false" afterPath="$PROJECT_DIR$/graph/undirected_graph/UDGPresent.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/parse/StoryMap.py" beforeDir="false" afterPath="$PROJECT_DIR$/parse/StoryMap.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
|
@ -40,40 +36,40 @@
|
|||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"Python.CompareViews.executor": "Run",
|
||||
"Python.CompareWindow.executor": "Run",
|
||||
"Python.ContentView.executor": "Run",
|
||||
"Python.DAGGraph (1).executor": "Run",
|
||||
"Python.DAGGraph.executor": "Run",
|
||||
"Python.DAGLayout (1).executor": "Run",
|
||||
"Python.DAGLayout.executor": "Run",
|
||||
"Python.DAGPresent.executor": "Run",
|
||||
"Python.MergeView.executor": "Run",
|
||||
"Python.MileStone.executor": "Run",
|
||||
"Python.NovelManage.executor": "Debug",
|
||||
"Python.ReferView.executor": "Run",
|
||||
"Python.StoryMap.executor": "Run",
|
||||
"Python.UDGLayout.executor": "Run",
|
||||
"Python.UDGPresent.executor": "Run",
|
||||
"Python.ast_load.executor": "Debug",
|
||||
"Python.entry.executor": "Run",
|
||||
"Python.test.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"git-widget-placeholder": "master",
|
||||
"last_opened_file_path": "D:/Projects/Python/StoryTools",
|
||||
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"Python.CompareViews.executor": "Run",
|
||||
"Python.CompareWindow.executor": "Run",
|
||||
"Python.ContentView.executor": "Debug",
|
||||
"Python.DAGGraph (1).executor": "Run",
|
||||
"Python.DAGGraph.executor": "Run",
|
||||
"Python.DAGLayout (1).executor": "Run",
|
||||
"Python.DAGLayout.executor": "Run",
|
||||
"Python.DAGPresent.executor": "Run",
|
||||
"Python.MergeView.executor": "Run",
|
||||
"Python.MileStone.executor": "Run",
|
||||
"Python.NovelManage.executor": "Debug",
|
||||
"Python.ReferView.executor": "Run",
|
||||
"Python.StoryMap.executor": "Run",
|
||||
"Python.UDGLayout.executor": "Run",
|
||||
"Python.UDGPresent.executor": "Run",
|
||||
"Python.ast_load.executor": "Debug",
|
||||
"Python.entry.executor": "Run",
|
||||
"Python.test.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"git-widget-placeholder": "master",
|
||||
"last_opened_file_path": "D:/Projects/Python/StoryTools",
|
||||
"settings.editor.selected.configurable": "debugger.dataViews"
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="PyDebuggerOptionsProvider">
|
||||
<option name="mySaveCallSignatures" value="true" />
|
||||
<option name="mySupportGeventDebugging" value="true" />
|
||||
<option name="myDropIntoDebuggerOnFailedTests" value="true" />
|
||||
<option name="myPyQtBackend" value="pyqt5" />
|
||||
</component>
|
||||
<component name="RunManager" selected="Python.UDGPresent">
|
||||
<component name="RunManager" selected="Python.ContentView">
|
||||
<configuration name="ContentView" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="StoryTools" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
|
@ -193,8 +189,8 @@
|
|||
</list>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python.UDGPresent" />
|
||||
<item itemvalue="Python.ContentView" />
|
||||
<item itemvalue="Python.UDGPresent" />
|
||||
<item itemvalue="Python.test" />
|
||||
<item itemvalue="Python.UDGLayout" />
|
||||
<item itemvalue="Python.DAGPresent" />
|
||||
|
@ -222,4 +218,15 @@
|
|||
<component name="UnknownFeatures">
|
||||
<option featureType="com.intellij.fileTypeFactory" implementationName="*.bat" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/graph/undirected_graph/UDGPresent.py</url>
|
||||
<line>239</line>
|
||||
<option name="timeStamp" value="2" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
|
@ -1,13 +1,16 @@
|
|||
import sys
|
||||
import sys, os
|
||||
from typing import Dict, List
|
||||
|
||||
from PyQt5.QtCore import QPoint
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
|
||||
from PyQt5.QtWidgets import QMenu
|
||||
from PyQt5.QtCore import QPoint, Qt
|
||||
from PyQt5.QtGui import QTransform
|
||||
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QSlider, QDoubleSpinBox
|
||||
from PyQt5.QtWidgets import QMenu, QHBoxLayout
|
||||
|
||||
from graph.DataType import Arrow, Point
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
from graph.DataType import Arrow, Point, Line
|
||||
from graph.directed_acyclic_graph.DAGPresent import DAGActiveView
|
||||
from parse.StoryMap import StoryMap, XAST_ParseTool
|
||||
from graph.undirected_graph.UDGPresent import UDGPresent
|
||||
from parse.StoryMap import StoryMap, XAST_ParseTool, ArticleSlice
|
||||
from parse.ast_load import global_ast_path
|
||||
|
||||
|
||||
|
@ -24,7 +27,7 @@ class StorylinesView(QWidget):
|
|||
self.fragment_view = DAGActiveView(self)
|
||||
layout.setContentsMargins(0,0,0,0)
|
||||
layout.addWidget(self.fragment_view)
|
||||
self.fragment_view.nodes_clicked.connect(self.highlisth_node_path)
|
||||
self.fragment_view.nodes_clicked.connect(self.highlight_node_path)
|
||||
self.present_graph: Dict[str, StoryMap] = {}
|
||||
pass
|
||||
pass
|
||||
|
@ -58,7 +61,7 @@ class StorylinesView(QWidget):
|
|||
self.fragment_view.update_with_edges(arrows)
|
||||
pass
|
||||
|
||||
def highlisth_node_path(self, xpos, ypos, list):
|
||||
def highlight_node_path(self, xpos, ypos, list):
|
||||
if len(list) == 0:
|
||||
return
|
||||
|
||||
|
@ -92,12 +95,12 @@ class StorylinesView(QWidget):
|
|||
pass
|
||||
|
||||
if len(story_list) == 1:
|
||||
self.highlisth_node_path(xpos, ypos, [("node", story_list[0])])
|
||||
self.highlight_node_path(xpos, ypos, [("node", story_list[0])])
|
||||
elif len(story_list) > 1:
|
||||
menu = QMenu()
|
||||
for story in story_list:
|
||||
def trigger(story_name:str):
|
||||
return lambda : self.highlisth_node_path(xpos, ypos, [("node", story_name)])
|
||||
return lambda : self.highlight_node_path(xpos, ypos, [("node", story_name)])
|
||||
|
||||
menu.addAction(f"story/{story}", trigger(story))
|
||||
pass
|
||||
|
@ -116,16 +119,70 @@ class StorylinesView(QWidget):
|
|||
class ArticleRefsView(QWidget):
|
||||
def __init__(self, parent):
|
||||
QWidget.__init__(self, parent)
|
||||
self.refer_view = UDGPresent(self)
|
||||
layout = QGridLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
layout.addWidget(self.refer_view)
|
||||
|
||||
self.ppu_slider = QSlider(Qt.Orientation.Horizontal, self)
|
||||
self.scala_slider = QSlider(Qt.Orientation.Vertical, self)
|
||||
self.scala_slider.setRange(0, 1000)
|
||||
self.scala_slider.setValue(100)
|
||||
layout.addWidget(self.scala_slider, 0, 1)
|
||||
|
||||
slide_panel = QWidget(self)
|
||||
layout.addWidget(slide_panel, 1, 0, 1, 2)
|
||||
bottom_layout = QHBoxLayout(slide_panel)
|
||||
bottom_layout.setSpacing(0)
|
||||
bottom_layout.setContentsMargins(0, 0, 0, 0)
|
||||
bottom_layout.addWidget(self.ppu_slider)
|
||||
|
||||
self.ppu_max = QDoubleSpinBox(self)
|
||||
self.ppu_max.setRange(0, 2**31)
|
||||
self.ppu_max.setValue(10000)
|
||||
self.ppu_slider.setRange(0, 10000)
|
||||
self.ppu_slider.setValue(int(self.refer_view.pixel_per_unit))
|
||||
bottom_layout.addWidget(self.ppu_max)
|
||||
|
||||
self.refer_view.node_clicked.connect(self.highlight_sibling_nodes)
|
||||
|
||||
def scala_view(times:float):
|
||||
tm = QTransform()
|
||||
tm.scale(times, times)
|
||||
return tm
|
||||
|
||||
self.scala_slider.valueChanged.connect(lambda iproc: self.refer_view.setTransform(scala_view(iproc/100.0)))
|
||||
self.ppu_slider.valueChanged.connect(lambda ppu:self.refer_view.refresh_with_ppu(ppu))
|
||||
self.ppu_slider.sliderReleased.connect(lambda : self.refer_view.update_scene_rect())
|
||||
pass
|
||||
|
||||
def present_volumes_graph(self, ref_graph: List[ArticleSlice]):
|
||||
node_edges = []
|
||||
|
||||
for line in ref_graph:
|
||||
for target in line.refer_target:
|
||||
node_edges.append(Line(Point(line.article_fullname), Point(target)))
|
||||
pass
|
||||
pass
|
||||
|
||||
self.refer_view.rebuild_from_edges(node_edges)
|
||||
pass
|
||||
|
||||
def highlight_sibling_nodes(self, nodename: str):
|
||||
self.refer_view.highlight_sibling_nodes(nodename)
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
view = StorylinesView(None)
|
||||
#view = StorylinesView(None)
|
||||
view = ArticleRefsView(None)
|
||||
view.show()
|
||||
|
||||
tool = XAST_ParseTool(global_ast_path)
|
||||
view.present_stories_graph(tool.get_story_graph())
|
||||
# view.present_stories_graph(tool.get_story_graph())
|
||||
view.present_volumes_graph(tool.get_article_nodes())
|
||||
|
||||
# view.fragment_view.highlight_graph_link(["血脉的源头", "血脉的源头&待续"])
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import sys
|
||||
import sys, os
|
||||
from abc import abstractmethod
|
||||
from enum import Enum
|
||||
from typing import List, Dict, Tuple
|
||||
|
@ -7,7 +7,9 @@ import networkx as nx
|
|||
from PyQt5.QtCore import QPointF, QRectF, Qt, pyqtSignal
|
||||
from PyQt5.QtGui import QFont, QPainterPath, QPen, QPainter, QMouseEvent
|
||||
from PyQt5.QtWidgets import QGraphicsItem, QGraphicsView, QApplication, QGraphicsScene
|
||||
from PyQt5.QtWidgets import QSplitter, QHBoxLayout
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||
from graph.DataType import Point, Line
|
||||
|
||||
|
||||
|
@ -36,15 +38,20 @@ class GraphNode:
|
|||
@abstractmethod
|
||||
def pos(self) -> QPointF:
|
||||
raise NotImplementedError("pos")
|
||||
|
||||
@abstractmethod
|
||||
def relayout_exec(self, ppu: float = 1):
|
||||
raise NotImplementedError("relayout_exec")
|
||||
|
||||
|
||||
class PresentNode(QGraphicsItem, GraphNode):
|
||||
def __init__(self, name: str, font: QFont, parent):
|
||||
def __init__(self, name: str, font: QFont, prim_x:float, prim_y:float, parent):
|
||||
QGraphicsItem.__init__(self, parent)
|
||||
self.node_name = name
|
||||
self.__is_highlight_mark = False
|
||||
self.__font_bind = font
|
||||
self.__sibling_list = []
|
||||
self.__prim_pos: Tuple[float, float] = (prim_x, prim_y)
|
||||
self.setZValue(10)
|
||||
pass
|
||||
|
||||
|
@ -85,7 +92,7 @@ class PresentNode(QGraphicsItem, GraphNode):
|
|||
|
||||
painter.save()
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
painter.drawRect(outline)
|
||||
#painter.drawRect(outline)
|
||||
|
||||
if self.__is_highlight_mark:
|
||||
brush = Qt.red
|
||||
|
@ -102,6 +109,13 @@ class PresentNode(QGraphicsItem, GraphNode):
|
|||
painter.restore()
|
||||
pass
|
||||
|
||||
def relayout_exec(self, ppu: float = 1):
|
||||
pos_x = ppu * self.__prim_pos[0]
|
||||
pos_y = ppu * self.__prim_pos[1]
|
||||
self.setPos(pos_x, pos_y)
|
||||
self.update()
|
||||
pass
|
||||
|
||||
|
||||
class ConnectionNode(QGraphicsItem, GraphNode):
|
||||
def __init__(self, p0: GraphNode, p1: GraphNode, parent):
|
||||
|
@ -124,7 +138,7 @@ class ConnectionNode(QGraphicsItem, GraphNode):
|
|||
return self.__highlight_mark
|
||||
pass
|
||||
|
||||
def relayout_exec(self):
|
||||
def relayout_exec(self, ppi: float = 1):
|
||||
start_pos = self.__point0.pos()
|
||||
end_pos = self.__point1.pos()
|
||||
|
||||
|
@ -135,6 +149,7 @@ class ConnectionNode(QGraphicsItem, GraphNode):
|
|||
|
||||
self.setPos(QPointF(start_x, start_y))
|
||||
self.__outline = QRectF(0, 0, end_x - start_x, end_y - start_y)
|
||||
self.update()
|
||||
pass
|
||||
|
||||
def boundingRect(self):
|
||||
|
@ -176,6 +191,8 @@ class UDGPresent(QGraphicsView):
|
|||
|
||||
def __init__(self, parent):
|
||||
QGraphicsView.__init__(self, parent)
|
||||
self.pixel_per_unit = 5000
|
||||
|
||||
self.__highlight_nodes: List[GraphNode] = []
|
||||
self.node_set: Dict[str, GraphNode] = {}
|
||||
self.__layout_graph = nx.Graph()
|
||||
|
@ -190,69 +207,38 @@ class UDGPresent(QGraphicsView):
|
|||
def rebuild_from_edges(self, line_set: List[Line]):
|
||||
self.node_set.clear()
|
||||
|
||||
edge_set: Dict[str, Tuple[GraphNode, GraphNode]] = {}
|
||||
|
||||
for line in line_set:
|
||||
start_node = line.points()[0]
|
||||
if start_node.point_name not in self.node_set:
|
||||
self.node_set[start_node.point_name] = PresentNode(start_node.point_name, self.font(), None)
|
||||
pass
|
||||
|
||||
self.__layout_graph.add_node(start_node.point_name)
|
||||
|
||||
end_node = line.points()[1]
|
||||
if start_node.point_name == end_node.point_name:
|
||||
continue
|
||||
if end_node.point_name not in self.node_set:
|
||||
self.node_set[end_node.point_name] = PresentNode(end_node.point_name, self.font(), None)
|
||||
pass
|
||||
|
||||
self.__layout_graph.add_node(end_node.point_name)
|
||||
|
||||
self.__layout_graph.add_edge(start_node.point_name, end_node.point_name)
|
||||
|
||||
start_force_point: PresentNode = self.node_set[start_node.point_name]
|
||||
other_force_point: PresentNode = self.node_set[end_node.point_name]
|
||||
|
||||
if other_force_point not in start_force_point.sibling_nodes():
|
||||
start_force_point.sibling_append(other_force_point)
|
||||
if start_force_point not in other_force_point.sibling_nodes():
|
||||
other_force_point.sibling_append(start_force_point)
|
||||
|
||||
pass
|
||||
|
||||
|
||||
pos_map = nx.spring_layout(self.__layout_graph)
|
||||
scala_value:float = 0
|
||||
for name in pos_map:
|
||||
primitive_pos = pos_map[name]
|
||||
target_gnode: PresentNode = self.node_set[name]
|
||||
for node_name in pos_map:
|
||||
node_prim_pos = pos_map[node_name]
|
||||
targetx_node = PresentNode(node_name, self.font(), node_prim_pos[0], node_prim_pos[1], None)
|
||||
self.node_set[node_name] = targetx_node
|
||||
|
||||
sibling_nodes = target_gnode.sibling_nodes()
|
||||
for sib in sibling_nodes:
|
||||
sib_primitive_pos = pos_map[sib.node_name]
|
||||
prim_x_span = primitive_pos[0] - sib_primitive_pos[0]
|
||||
prim_y_span = primitive_pos[1] - sib_primitive_pos[1]
|
||||
|
||||
target_rect = target_gnode.boundingRect()
|
||||
scala_value = max(scala_value, target_rect.width()/prim_x_span)
|
||||
scala_value = max(scala_value, target_rect.height()/prim_y_span)
|
||||
pass
|
||||
pass
|
||||
|
||||
for name in pos_map:
|
||||
primitive_pos = pos_map[name]
|
||||
target_gnode: PresentNode = self.node_set[name]
|
||||
target_gnode.setPos(primitive_pos[0] * scala_value, primitive_pos[1] * scala_value)
|
||||
self.__scene_bind.addItem(target_gnode)
|
||||
self.scene().addItem(targetx_node)
|
||||
targetx_node.relayout_exec(self.pixel_per_unit)
|
||||
pass
|
||||
|
||||
for edge in nx.edges(self.__layout_graph):
|
||||
edge_start = edge[0]
|
||||
edge_end = edge[1]
|
||||
node_one = self.node_set[edge_start]
|
||||
node_two = self.node_set[edge_end]
|
||||
node_one: PresentNode = self.node_set[edge_start]
|
||||
node_two: PresentNode = self.node_set[edge_end]
|
||||
node_one.sibling_append(node_two)
|
||||
node_two.sibling_append(node_one)
|
||||
|
||||
connection = ConnectionNode(node_one, node_two, None)
|
||||
self.scene().addItem(connection)
|
||||
connection.relayout_exec()
|
||||
connection.relayout_exec(self.pixel_per_unit)
|
||||
self.node_set[f"conn::{edge_start}&{edge_end}"] = connection
|
||||
pass
|
||||
pass
|
||||
|
||||
|
@ -260,7 +246,7 @@ class UDGPresent(QGraphicsView):
|
|||
QGraphicsView.mousePressEvent(self, event)
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
item: GraphNode = self.itemAt(event.pos())
|
||||
if item.node_type() == PresentNodeType.PresentNode:
|
||||
if item is not None and item.node_type() == PresentNodeType.PresentNode:
|
||||
vnode: PresentNode = item
|
||||
self.node_clicked.emit(vnode.node_name)
|
||||
print(vnode.node_name)
|
||||
|
@ -268,6 +254,74 @@ class UDGPresent(QGraphicsView):
|
|||
pass
|
||||
pass
|
||||
|
||||
def refresh_with_ppu(self, ppu: float):
|
||||
self.pixel_per_unit = ppu
|
||||
|
||||
for node in self.node_set.values():
|
||||
if node.node_type() == PresentNodeType.PresentNode:
|
||||
node.relayout_exec(ppu)
|
||||
pass
|
||||
pass
|
||||
|
||||
for node in self.node_set.values():
|
||||
if node.node_type() == PresentNodeType.ConnectionNode:
|
||||
node.relayout_exec(ppu)
|
||||
pass
|
||||
pass
|
||||
|
||||
self.scene().update()
|
||||
self.update()
|
||||
pass
|
||||
|
||||
def update_scene_rect(self):
|
||||
minx = 2*64
|
||||
miny = 2*64
|
||||
maxx = -2**64
|
||||
maxy = -2**64
|
||||
for item in self.node_set.values():
|
||||
minx = min(item.pos().x(), minx)
|
||||
miny = min(item.pos().y(), miny)
|
||||
maxx = max(item.pos().x() + item.boundingRect().width(), maxx)
|
||||
maxy = max(item.pos().y() + item.boundingRect().height(), maxy)
|
||||
pass
|
||||
|
||||
self.scene().setSceneRect(minx, miny, maxx - minx, maxy - miny)
|
||||
pass
|
||||
|
||||
def highlight_sibling_nodes(self, center_node: str):
|
||||
for node in self.__highlight_nodes:
|
||||
node.highlight(False)
|
||||
pass
|
||||
self.__highlight_nodes.clear()
|
||||
|
||||
target_node: PresentNode = self.node_set[center_node]
|
||||
if target_node is None:
|
||||
return
|
||||
|
||||
target_node.highlight(True)
|
||||
self.__highlight_nodes.append(target_node)
|
||||
for sib_node in target_node.sibling_nodes():
|
||||
sib_node.highlight(True)
|
||||
self.__highlight_nodes.append(sib_node)
|
||||
|
||||
sib_name = sib_node.node_name
|
||||
constr1 = f"conn::{center_node}&{sib_name}"
|
||||
constr2 = f"conn::{sib_name}&{center_node}"
|
||||
if constr1 in self.node_set:
|
||||
self.node_set[constr1].highlight(True)
|
||||
self.__highlight_nodes.append(self.node_set[constr1])
|
||||
elif constr2 in self.node_set:
|
||||
self.node_set[constr2].highlight(True)
|
||||
self.__highlight_nodes.append(self.node_set[constr2])
|
||||
pass
|
||||
pass
|
||||
|
||||
self.scene().update()
|
||||
self.update()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -27,6 +27,24 @@ class FragmentSlice(EmptyNode):
|
|||
pass
|
||||
|
||||
|
||||
class ArticleSlice(EmptyNode):
|
||||
def __init__(self, a_name: str, v_name: str):
|
||||
self.article_name = a_name
|
||||
self.volume_blongs = v_name
|
||||
self.article_fullname = f"{v_name}@{a_name}"
|
||||
|
||||
self.refer_target: List[str] = [] # 引用切面
|
||||
self.text_sections: List[str] = [] # 文本段落
|
||||
pass
|
||||
|
||||
def get_from_memory(self) -> str:
|
||||
return "\n".join(self.text_sections)
|
||||
|
||||
def set_to_memory(self, content: str):
|
||||
self.text_sections = content.split("\n")
|
||||
pass
|
||||
|
||||
|
||||
class StoryMap:
|
||||
def __init__(self, name: str):
|
||||
self.story_name = name
|
||||
|
@ -44,7 +62,7 @@ class StoryMap:
|
|||
self.slice_list.append(node)
|
||||
pass
|
||||
|
||||
def get_fragment_defined(self, name: str) -> FragmentSlice:
|
||||
def get_fragment_defined(self, name: str) -> FragmentSlice|None:
|
||||
for fit in self.slice_list:
|
||||
if fit.is_define_node[0]:
|
||||
if fit.is_define_node[1] == name:
|
||||
|
@ -140,6 +158,58 @@ class XAST_ParseTool:
|
|||
self.storylines_plait(story_dict)
|
||||
return story_dict
|
||||
|
||||
def get_article_nodes(self) -> List[ArticleSlice]:
|
||||
retvalues = []
|
||||
|
||||
hangout_nodes = ArticleSlice("悬空节点", "")
|
||||
retvalues.append(hangout_nodes)
|
||||
|
||||
fragments = self.__get_all_fragment_names()
|
||||
volumes = self.dom_tree.getElementsByTagName("volume")
|
||||
for vnode in volumes:
|
||||
child_articles = self.__volume_node_parse(vnode)
|
||||
retvalues.extend(child_articles)
|
||||
for child in child_articles:
|
||||
for refn in child.refer_target:
|
||||
if refn in fragments:
|
||||
fragments.remove(refn)
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
|
||||
hangout_nodes.refer_target.extend(fragments)
|
||||
return retvalues
|
||||
|
||||
def __get_all_fragment_names(self) -> List[str]:
|
||||
values = []
|
||||
|
||||
frags = self.dom_tree.getElementsByTagName("fragment")
|
||||
for frag in frags:
|
||||
story: mdom.Element = frag.parentNode
|
||||
values.append(f"{story.getAttribute("name")}&{frag.getAttribute("name")}")
|
||||
pass
|
||||
|
||||
return values
|
||||
|
||||
def __volume_node_parse(self, vnode: mdom.Element)-> List[ArticleSlice]:
|
||||
retvalues = []
|
||||
|
||||
vname = vnode.getAttribute("name")
|
||||
articles = vnode.getElementsByTagName("article")
|
||||
for anode in articles:
|
||||
aname = anode.getAttribute("name")
|
||||
node_inst = ArticleSlice(aname, vname)
|
||||
retvalues.append(node_inst)
|
||||
refsnode = anode.getElementsByTagName("refer")
|
||||
for refnode in refsnode:
|
||||
ref_story = refnode.getAttribute("story")
|
||||
ref_fragment = refnode.getAttribute("fragment")
|
||||
node_inst.refer_target.append(f"{ref_story}&{ref_fragment}")
|
||||
pass
|
||||
pass
|
||||
|
||||
return retvalues
|
||||
pass
|
||||
|
||||
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue