Skip to content

Commit d18b8e9

Browse files
authored
Adding support for object and Userobject xml for diagram elements with (#125)
1 parent 894b693 commit d18b8e9

File tree

7 files changed

+434
-52
lines changed

7 files changed

+434
-52
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from pathlib import Path
2+
3+
import drawpyo
4+
from drawpyo import load_diagram
5+
6+
# Load Draw.io diagram
7+
relative_path = Path("..") / "reference drawio charts" / "object.drawio"
8+
file_path = (Path(__file__).parent / relative_path).resolve()
9+
10+
diagram = load_diagram(file_path)
11+
12+
# Create file & page
13+
file = drawpyo.File()
14+
file.file_path = str(Path.home() / "Test Drawpyo Charts")
15+
file.file_name = "Test_object.drawio"
16+
17+
page = drawpyo.Page(file=file)
18+
19+
diagram.add_to(page)
20+
# Write the file
21+
file.write()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<mxfile host="Drawpyo">
2+
<diagram name="Page-1" id="hyHWzmBswkbCvm2kR1NW">
3+
<mxGraphModel dx="2037" dy="830" grid="1">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<object label="" test="test" id="2xg5nJA0Zl71o69cM8dW-4">
8+
<mxCell
9+
edge="1"
10+
parent="1"
11+
source="2xg5nJA0Zl71o69cM8dW-1"
12+
style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;"
13+
target="2xg5nJA0Zl71o69cM8dW-2"
14+
>
15+
<mxGeometry relative="1" as="geometry" />
16+
</mxCell>
17+
</object>
18+
<object label="" test="test" id="2xg5nJA0Zl71o69cM8dW-1">
19+
<mxCell parent="1" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1">
20+
<mxGeometry height="60" width="120" x="350" y="370" as="geometry" />
21+
</mxCell>
22+
</object>
23+
<mxCell
24+
id="2xg5nJA0Zl71o69cM8dW-5"
25+
edge="1"
26+
parent="1"
27+
source="2xg5nJA0Zl71o69cM8dW-2"
28+
style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;"
29+
target="2xg5nJA0Zl71o69cM8dW-1"
30+
>
31+
<mxGeometry relative="1" as="geometry" />
32+
</mxCell>
33+
<UserObject
34+
label="%name%"
35+
name="Name"
36+
placeholders="1"
37+
link="data:page/id,hyHWzmBswkbCvm2kR1NW"
38+
id="2xg5nJA0Zl71o69cM8dW-2"
39+
>
40+
<mxCell parent="1" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1">
41+
<mxGeometry height="60" width="120" x="150" y="280" as="geometry" />
42+
</mxCell>
43+
</UserObject>
44+
</root>
45+
</mxGraphModel>
46+
</diagram>
47+
</mxfile>

src/drawpyo/diagram/edges.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ def __init__(self, **kwargs: Any) -> None:
9292
super().__init__(**kwargs)
9393
self.xml_class: str = "mxCell"
9494

95+
self.object_attributes: Dict[str, str] = dict(
96+
kwargs.get("object_attributes", {})
97+
)
98+
self.user_object_attributes: Dict[str, str] = dict(
99+
kwargs.get("user_object_attributes", {})
100+
)
101+
95102
# Style
96103
self.color_scheme: Optional[ColorScheme] = kwargs.get("color_scheme", None)
97104
self.text_format: Optional[TextFormat] = kwargs.get("text_format", TextFormat())
@@ -210,15 +217,20 @@ def attributes(self) -> Dict[str, Any]:
210217
Returns:
211218
dict: Dictionary of object attributes and their values
212219
"""
220+
id_value = self.id
221+
if self.object_attributes or self.user_object_attributes:
222+
id_value = None
213223
base_attr_dict: Dict[str, Any] = {
214-
"id": self.id,
224+
"id": id_value,
215225
"style": self.style,
216226
"edge": self.edge,
217227
"parent": self.xml_parent_id,
218228
"source": self.source_id,
219229
"target": self.target_id,
220230
}
221-
if self.value is not None:
231+
if self.value is not None and not (
232+
self.object_attributes or self.user_object_attributes
233+
):
222234
base_attr_dict["value"] = self.value
223235
return base_attr_dict
224236

@@ -591,8 +603,36 @@ def xml(self) -> str:
591603
tag: str = (
592604
self.xml_open_tag + "\n " + self.geometry.xml + "\n" + self.xml_close_tag
593605
)
606+
wrapper_tag = None
607+
wrapper_attrs = None
608+
if self.user_object_attributes:
609+
wrapper_tag = "UserObject"
610+
wrapper_attrs = self.user_object_attributes
611+
elif self.object_attributes:
612+
wrapper_tag = "object"
613+
wrapper_attrs = self.object_attributes
614+
if wrapper_tag and wrapper_attrs is not None:
615+
return (
616+
self._wrapper_open_tag(wrapper_tag, wrapper_attrs)
617+
+ "\n "
618+
+ tag.replace("\n", "\n ")
619+
+ f"\n</{wrapper_tag}>"
620+
)
594621
return tag
595622

623+
def _wrapper_open_tag(self, tag: str, attrs: Dict[str, str]) -> str:
624+
attrs = {k: v for k, v in attrs.items() if v is not None}
625+
if "label" not in attrs and self.value is not None:
626+
attrs["label"] = self.value
627+
if "id" not in attrs:
628+
attrs["id"] = self.id
629+
630+
open_tag = f"<{tag}"
631+
for att, value in attrs.items():
632+
xml_parameter = self.xml_ify(str(value))
633+
open_tag = open_tag + " " + att + '="' + xml_parameter + '"'
634+
return open_tag + ">"
635+
596636

597637
class BasicEdge(Edge):
598638
pass

src/drawpyo/diagram/objects.py

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
from os import path
2-
from typing import Optional, Dict, Any, List, Union, Tuple
3-
from ..utils.logger import logger
2+
from typing import Any, Dict, List, Optional, Tuple, Union
43

4+
from ..utils.color_scheme import ColorScheme
5+
from ..utils.logger import logger
6+
from ..utils.standard_colors import StandardColor
57
from .base_diagram import (
68
DiagramBase,
79
Geometry,
810
import_shape_database,
911
)
1012
from .text_format import TextFormat
11-
from ..utils.color_scheme import ColorScheme
12-
from ..utils.standard_colors import StandardColor
1313

1414
__all__ = ["Object", "BasicObject", "Group", "object_from_library"]
1515

@@ -144,6 +144,12 @@ def __init__(
144144
self.autosize_to_children: bool = kwargs.get("autosize_to_children", False)
145145
self.autocontract: bool = kwargs.get("autocontract", False)
146146
self.autosize_margin: int = kwargs.get("autosize_margin", 20)
147+
self.object_attributes: Dict[str, str] = dict(
148+
kwargs.get("object_attributes", {})
149+
)
150+
self.user_object_attributes: Dict[str, str] = dict(
151+
kwargs.get("user_object_attributes", {})
152+
)
147153

148154
# Geometry
149155
self.position: Optional[tuple] = position
@@ -355,9 +361,16 @@ def format_as_library_object(
355361

356362
@property
357363
def attributes(self) -> Dict[str, Any]:
364+
id_value = self.id
365+
value_value = self.value
366+
if not (self.tag or self.tooltip) and (
367+
self.object_attributes or self.user_object_attributes
368+
):
369+
id_value = None
370+
value_value = None
358371
return {
359-
"id": self.id,
360-
"value": self.value,
372+
"id": id_value,
373+
"value": value_value,
361374
"style": self.style,
362375
"vertex": self.vertex,
363376
"parent": self.xml_parent_id,
@@ -711,8 +724,38 @@ def xml(self) -> str:
711724
tag: str = (
712725
self.xml_open_tag + "\n " + self.geometry.xml + "\n" + self.xml_close_tag
713726
)
727+
if self.tag or self.tooltip:
728+
return tag
729+
wrapper_tag = None
730+
wrapper_attrs = None
731+
if self.user_object_attributes:
732+
wrapper_tag = "UserObject"
733+
wrapper_attrs = self.user_object_attributes
734+
elif self.object_attributes:
735+
wrapper_tag = "object"
736+
wrapper_attrs = self.object_attributes
737+
if wrapper_tag and wrapper_attrs is not None:
738+
return (
739+
self._wrapper_open_tag(wrapper_tag, wrapper_attrs)
740+
+ "\n "
741+
+ tag.replace("\n", "\n ")
742+
+ f"\n</{wrapper_tag}>"
743+
)
714744
return tag
715745

746+
def _wrapper_open_tag(self, tag: str, attrs: Dict[str, str]) -> str:
747+
attrs = {k: v for k, v in attrs.items() if v is not None}
748+
if "label" not in attrs and self.value is not None:
749+
attrs["label"] = self.value
750+
if "id" not in attrs:
751+
attrs["id"] = self.id
752+
753+
open_tag = f"<{tag}"
754+
for att, value in attrs.items():
755+
xml_parameter = self.xml_ify(str(value))
756+
open_tag = open_tag + " " + att + '="' + xml_parameter + '"'
757+
return open_tag + ">"
758+
716759

717760
class BasicObject(Object):
718761
pass

0 commit comments

Comments
 (0)