def __init__( self, template_path, options=None, styles=None, stencils=tuple()): """ :param str template_path: Path where graph HTML templates are located. :param GraphOptions options: Options of graph drawing widget, uses default if not given. :param GraphStyles styles: Styles available in graph drawing widget, uses default if not given. :param iterable[str] stencils: Stencils available in graph drawing widget. """ self.template_path = template_path from qmxgraph.configuration import GraphStyles from qmxgraph.configuration import GraphOptions if options is None: options = GraphOptions() if styles is None: styles = GraphStyles() self.options = options self.styles = styles self.stencils = stencils
def __init__(self): QMainWindow.__init__(self) self.setMinimumSize(QSize(640, 480)) self.setWindowTitle("Qmx Styles") styles_cfg = { 'round_node': { 'shape': 'ellipse', 'fill_color': '#D88', 'vertical_label_position': 'bottom', 'vertical_align': 'top', }, 'bold_edge': { 'end_arrow': 'classic', 'shape': 'connector', 'stroke_width': 5.0, }, } self.graph_widget = QmxGraph(styles=GraphStyles(styles_cfg), parent=self) # Only operate with the qmx's api after the widget has been loaded. self.graph_widget.loadFinished.connect(self.graph_load_handler) self.setCentralWidget(self.graph_widget)
def test_custom_shapes(selenium, port, tmpdir, wait_graph_page_ready): """ :type selenium: selenium.webdriver.remote.webdriver.WebDriver :type port: qmxgraph.tests.conftest.Port """ # Shape found in by https://www.draw.io/stencils/basic.xml custom_stencil = '''\ <shapes> <shape name="Moon" h="103.05" w="77.05" aspect="variable" strokewidth="inherit"> <connections> <constraint x="0.48" y="0" perimeter="0" name="N"/> <constraint x="1" y="0.89" perimeter="0" name="SE"/> </connections> <background> <path> <move x="37.05" y="0"/> <arc rx="48" ry="48" x-axis-rotation="0" large-arc-flag="1" sweep-flag="0" x="77.05" y="92"/> <arc rx="60" ry="60" x-axis-rotation="0" large-arc-flag="0" sweep-flag="1" x="37.05" y="0"/> <close/> </path> </background> <foreground> <fillstroke/> </foreground> </shape> </shapes>''' # noqa stencil_file = tmpdir.mkdir("stencils").join("custom.xml") stencil_file.write(custom_stencil) stencils = [str(stencil_file)] styles = GraphStyles({ 'moon': { 'shape': 'Moon', 'fill_color': '#ffff00', }, }) def has_custom_shape(): return bool( selenium.find_elements_by_css_selector('g>g>path[fill="#ffff00"]')) with server.host(port=port.get(), styles=styles, stencils=stencils) as host: wait_graph_page_ready(host=host) assert not has_custom_shape() selenium.execute_script( "api.insertVertex(10, 10, 20, 20, 'custom', 'moon')") assert has_custom_shape()
def test_edge_with_style(port, mode, graph_cases_factory): """ :type port: qmxgraph.tests.conftest.Port :type mode: str :type graph_cases_factory: callable """ styles = GraphStyles({ 'edge': { 'stroke_color': '#000000', }, }) with server.host(port=port.get(), styles=styles) as host: cases = graph_cases_factory(host) graph = cases('2v_1e' if mode == 'by_code' else '2v_1eDD') assert graph.get_edge( *graph.get_vertices()).get_attribute('stroke') == '#000000'
def host(port): """ Hosts a graph page, with a series of simple default options and styles. :type port: Port :rtype: qmxgraph.host_graph.Host :return: Object with details about hosted graph page. """ from qmxgraph.configuration import GraphStyles styles = GraphStyles({ 'group': { 'shape': 'rectangle', 'fill_color': '#ff93ba', 'dashed': True, }, 'table': { 'fill_color': '#ffffff', 'stroke_opacity': 0, 'fill_opacity': 0, }, 'yellow': { 'fill_color': '#ffff00', }, 'purple': { 'fill_color': '#ff00ff', }, }) from qmxgraph.configuration import GraphOptions options = GraphOptions( # Highlight disabled for this kind of test as interferes a lot with # some mouse events, preventing Selenium from clicking desired # HTML elements. show_highlight=False, ) from qmxgraph import server with server.host(port=port.get(), styles=styles, options=options) as host_: yield host_
def __init__( self, options=None, styles=None, stencils=tuple(), auto_load=True, parent=None, ): """ :param qmxgraph.configuration.GraphOptions|None options: Features enabled in graph drawing widget. If none given, uses defaults. :param qmxgraph.configuration.GraphStyles|None styles: Additional styles made available for graph drawing widget besides mxGraph's default ones. If none given only mxGraph defaults are available. :param iterable[str] stencils: A sequence of XMLs available in Qt resource collections. Each XML must respect format defined by mxGraph (see https://jgraph.github.io/mxgraph/docs/js-api/files/shape/mxStencil-js.html#mxStencil and https://jgraph.github.io/mxgraph/javascript/examples/stencils.xml for reference). :param bool auto_load: If should load page as soon as widget is initialized. :param QWidget|None parent: Parent widget. """ QWidget.__init__(self, parent) self._own_path = ':/qmxgraph' self._mxgraph_path = ':/mxgraph' if options is None: options = GraphOptions() self._options = options if styles is None: styles = GraphStyles(styles={}) self._styles = styles self._stencils = stencils # Web view fills whole widget area self._layout = QGridLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) # no margin to web view self._web_view = QWebViewWithDragDrop() self._web_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Starts disabled, only enable once finished loading page (as user # interaction before that would be unsafe) # TODO: widget remain with disabled appearance even after enabled # self.setEnabled(False) self._layout.addWidget(self._web_view, 0, 0, 1, 1) self._error_bridge = None self._events_bridge = None self._drag_drop_handler = None # Similar to a browser, QmxGraph widget is going to allow inspection by # typing F12 self._inspector_dialog = None inspector_shortcut = QShortcut(self) inspector_shortcut.setKey("F12") inspector_shortcut.activated.connect(self.toggle_inspector) self._execute_on_load_finished() self._api = QmxGraphApi(graph=self) self._web_view.on_drag_enter_event.connect(self._on_drag_enter) self._web_view.on_drag_move_event.connect(self._on_drag_move) self._web_view.on_drop_event.connect(self._on_drop) self._double_click_bridge = _DoubleClickBridge() self._popup_menu_bridge = _PopupMenuBridge() if auto_load: self._load_graph_page()