mindmap.mindmap module¶
- class mindmap.mindmap.MindmapDocument(charttype: str = 'auto', turbo_mode: bool = False, inline_editing_mode: bool = False, mermaid_mode: bool = True, macos_access: str = 'appscript')¶
Bases:
object- __init__(charttype: str = 'auto', turbo_mode: bool = False, inline_editing_mode: bool = False, mermaid_mode: bool = True, macos_access: str = 'appscript')¶
Initialize a MindmapDocument instance which automates MindManager operations.
- Parameters:
charttype (str) – The type of chart to be used (orgchart, radial, auto).
turbo_mode (bool) – Flag for enabling turbo mode -> use only text.
inline_editing_mode (bool) – Flag for enabling inline editing mode.
mermaid_mode (bool) – Flag for enabling mermaid mode.
macos_access (str) – Method for accessing macOS features (default is ‘appscript’, alternative is ‘applescript’).
- check_parent_exists(topic_guid, this_guid, visited=None)¶
Recursively check if a parent-child relationship exists between topics.
- Parameters:
topic_guid (str) – The GUID of the topic to check.
this_guid (str) – The GUID that might be a parent of the topic.
visited (set, optional) – Set of visited GUIDs to avoid infinite recursion.
- Returns:
True if the parent-child relationship exists, False otherwise.
- Return type:
bool
- clone_mindmap_topic(mindmap_topic, subtopics: list[MindmapTopic] = None, parent=None)¶
Clone a MindmapTopic instance including its subtopics.
- Parameters:
mindmap_topic (MindmapTopic) – The topic to clone.
subtopics (list[MindmapTopic], optional) – A list of subtopics to clone.
parent – The parent for the cloned topic.
- Returns:
A new instance that is a clone of the given topic.
- Return type:
- count_parent_and_child_occurrences(mindmap_topic, guid_counts, visited=None)¶
Recursively count the occurrences of parent and child relationships for each topic.
- Parameters:
mindmap_topic (MindmapTopic) – The current topic in the mindmap.
guid_counts (dict) – Dictionary to store counts with topic GUID as keys.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- create_mindmap(verbose=False)¶
Create a MindManager mindmap document from the internal MindmapTopic structure. This includes counting occurrences, extracting tags/icons, and setting up relationships and links.
- Parameters:
verbose (bool) – (Optional) Enable verbose output.
- create_mindmap_and_finalize()¶
Create the mindmap document and finalize it.
- finalize()¶
Finalize the mindmap document by ensuring the maximum topic level is set, then calling MindManager’s finalize.
- get_grounding_information()¶
Extract grounding information from the mindmap, including the central topic and selected subtopics.
- Returns:
- (top_most_topic, subtopics) where top_most_topic is the central topic or a concatenated string
of non-selected topics, and subtopics is a comma-separated string of selected subtopics.
- Return type:
tuple
- get_library_folder()¶
Get the library folder used by MindManager.
- Returns:
The path to the library folder.
- get_map_icons_and_fix_refs_from_mindmap(mindmap, map_icons: list[MindmapIcon], visited=None)¶
Extract icons from mindmap topics and fix their references if needed.
- Parameters:
mindmap (MindmapTopic) – The current topic in the mindmap.
map_icons (list[MindmapIcon]) – List to collect unique icons.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- get_max_topic_level(mindmap_topic, max_topic_level=0, visited=None)¶
Recursively compute the maximum topic level within the mind map.
- Parameters:
mindmap_topic (MindmapTopic) – The current topic to evaluate.
max_topic_level (int) – The current maximum level found.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- Returns:
The highest topic level found in the mindmap.
- Return type:
int
- get_mindmap(topic=None, mode='full')¶
Retrieve the mind map structure from the currently open MindManager document.
- Parameters:
topic – (Optional) A specific topic from which to start building the mindmap. If not provided, the central topic is used.
mode (str) – The mode to use to gather attributes (full=all attributes, content=text+rtf+notes, text=text only).
- Returns:
True if the mind map was successfully retrieved, otherwise False.
- Return type:
bool
- get_mindmap_topic_from_topic(topic, parent_topic=None, mode='full')¶
Recursively convert a MindManager topic into a MindmapTopic object.
- Parameters:
topic – The current MindManager topic to convert.
parent_topic (MindmapTopic) – The parent MindmapTopic, if any.
mode (str) – The mode to use to gather attributes (full=all attributes, content=text+rtf+notes, text=text only).
- Returns:
The converted topic with its subtopics.
- Return type:
- get_parent_topic(topic, visited=None)¶
Retrieve the parent topic for a given MindManager topic.
- Parameters:
topic – The current topic from which to get the parent.
visited (set, optional) – Track visited GUIDs to avoid cycles.
- Returns:
The parent topic wrapped as a MindmapTopic, or None if at the root.
- Return type:
MindmapTopic or None
- get_parents_from_mindmap(mindmap, parents, visited=None)¶
Build a dictionary mapping subtopic GUIDs to their parent’s GUID.
- Parameters:
mindmap (MindmapTopic) – The current topic in the mindmap.
parents (dict) – Dictionary to store parent-child GUID mappings.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- get_relationships_from_mindmap(mindmap, references, visited=None)¶
Recursively extract relationships (references) from the mindmap.
- Parameters:
mindmap (MindmapTopic) – The current topic in the mindmap.
references (list[MindmapReference]) – List to collect the relationships.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- get_selection()¶
Retrieve the currently selected topics in the MindManager document.
- Returns:
A list of MindmapTopic instances representing the selection.
- Return type:
list[MindmapTopic]
- get_tags_from_mindmap(mindmap, tags, visited=None)¶
Recursively collect unique tags from the mindmap.
- Parameters:
mindmap (MindmapTopic) – The current topic in the mindmap.
tags (list[str]) – List to collect tag texts.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- get_topic_links_from_mindmap(mindmap, links, visited=None)¶
Recursively extract topic links from the mindmap.
- Parameters:
mindmap (MindmapTopic) – The current topic in the mindmap.
links (list[MindmapReference]) – List to collect topic links as MindmapReference objects.
visited (set) – Set of visited topic GUIDs to avoid infinite recursion.
- get_topic_texts_from_selection(mindmap_topics)¶
Extract topic texts, levels, and GUIDs from selected topics.
- Parameters:
mindmap_topics (list[MindmapTopic]) – List of topics to process.
- set_background_image(image_path)¶
Set the background image for the MindManager document.
- Parameters:
image_path (str) – The file path to the background image.
- set_topic_from_mindmap_topic(topic, mindmap_topic, map_icons, done=None, done_global=None, level=0)¶
Create or update a MindManager topic from a MindmapTopic instance recursively.
- Parameters:
topic – The current MindManager topic to update.
mindmap_topic (MindmapTopic) – The source MindmapTopic data.
map_icons (list[MindmapIcon]) – List of map icons to use.
done (dict, optional) – Dictionary tracking processed topics at current level.
done_global (dict, optional) – Global dictionary for tracking duplicate processing.
level (int) – Current hierarchical level.
- Returns:
The processed MindmapTopic.
- Return type:
- update_done(topic_guid, mindmap_topic, level, done, done_global)¶
Update tracking dictionaries for processed topics and create duplicate links/tags.
- Parameters:
topic_guid (str) – The GUID of the current topic in MindManager.
mindmap_topic (MindmapTopic) – The MindmapTopic being processed.
level (int) – The current level in the topic hierarchy.
done (dict) – Dictionary tracking topics processed at a given level.
done_global (dict) – Global dictionary tracking processed topics for duplicate detection.
- class mindmap.mindmap.MindmapIcon(text: str = '', is_stock_icon=True, index: int = 1, signature: str = '', path: str = '', group: str = '')¶
Bases:
object- __init__(text: str = '', is_stock_icon=True, index: int = 1, signature: str = '', path: str = '', group: str = '')¶
Initialize a MindmapIcon instance.
- Parameters:
text (str) – The display text for the icon.
is_stock_icon (bool) – Flag indicating if the icon is a stock icon.
index (int) – The index of a stock icon.
signature (str) – A unique signature for the icon.
path (str) – File path to the icon if it is custom.
group (str) – The group/category of the icon.
- class mindmap.mindmap.MindmapImage(text: str = '')¶
Bases:
object- __init__(text: str = '')¶
Initialize a MindmapImage instance.
- Parameters:
text (str) – Path to the image.
- class mindmap.mindmap.MindmapLink(text: str = '', url: str = '', guid: str = '')¶
Bases:
object- __init__(text: str = '', url: str = '', guid: str = '')¶
Initialize a MindmapLink instance.
- Parameters:
text (str) – The display text for the link.
url (str) – The URL that the link points to.
guid (str) – A unique identifier for the link.
- class mindmap.mindmap.MindmapNotes(text: str = '', xhtml: str = '', rtf: str = '')¶
Bases:
object- __init__(text: str = '', xhtml: str = '', rtf: str = '')¶
Initialize a MindmapNotes instance.
- Parameters:
text (str) – Plain text version of the notes.
xhtml (str) – XHTML formatted notes.
rtf (str) – RTF formatted notes.
- class mindmap.mindmap.MindmapReference(guid_1: str = '', guid_2: str = '', direction: int = 1, label: str = '')¶
Bases:
object- __init__(guid_1: str = '', guid_2: str = '', direction: int = 1, label: str = '')¶
Initialize a MindmapReference (relationship) instance.
- Parameters:
guid_1 (str) – The GUID of the first topic.
guid_2 (str) – The GUID of the second topic.
direction (int) – The direction of the reference (1 indicates a standard direction).
label (str) – A label for the relationship.
- class mindmap.mindmap.MindmapTag(text: str = '')¶
Bases:
object- __init__(text: str = '')¶
Initialize a MindmapTag instance.
- Parameters:
text (str) – The text representing the tag.
- class mindmap.mindmap.MindmapTopic(guid: str = '', text: str = '', rtf: str = '', level: int = 0, selected: bool = False, parent: MindmapTopic = None, subtopics: list[MindmapTopic] = None, links: list[MindmapLink] = None, image: MindmapImage = None, icons: list[MindmapIcon] = None, notes: MindmapNotes = None, tags: list[MindmapTag] = None, references: list[MindmapReference] = None)¶
Bases:
object- __init__(guid: str = '', text: str = '', rtf: str = '', level: int = 0, selected: bool = False, parent: MindmapTopic = None, subtopics: list[MindmapTopic] = None, links: list[MindmapLink] = None, image: MindmapImage = None, icons: list[MindmapIcon] = None, notes: MindmapNotes = None, tags: list[MindmapTag] = None, references: list[MindmapReference] = None)¶
Initialize a MindmapTopic instance.
- Parameters:
guid (str) – Unique identifier for the topic.
text (str) – The text content of the topic.
rtf (str) – RTF formatted text for the topic.
level (int) – The hierarchical level of the topic.
selected (bool) – Flag to indicate if the topic is selected.
parent (MindmapTopic) – The parent topic if any.
subtopics (list[MindmapTopic]) – List of subtopics.
links (list[MindmapLink]) – List of associated links.
image (MindmapImage) – Associated image object.
icons (list[MindmapIcon]) – List of associated icons.
notes (MindmapNotes) – Associated notes.
tags (list[MindmapTag]) – List of associated tags.
references (list[MindmapReference]) – List of associated relationships.
1import uuid
2
3import mindm.mindmanager as mm
4
5DUPLICATED_TAG = 'Duplicated'
6DUPLICATE_LABEL = 'DUPLICATE'
7
8class MindmapLink:
9 def __init__(self, text: str = '', url: str = '', guid: str = ''):
10 """
11 Initialize a MindmapLink instance.
12
13 Args:
14 text (str): The display text for the link.
15 url (str): The URL that the link points to.
16 guid (str): A unique identifier for the link.
17 """
18 self.text = text
19 self.url = url
20 self.guid = guid
21
22class MindmapImage:
23 def __init__(self, text: str = ''):
24 """
25 Initialize a MindmapImage instance.
26
27 Args:
28 text (str): Path to the image.
29 """
30 self.text = text
31
32class MindmapNotes:
33 def __init__(self, text: str = '', xhtml: str = '', rtf: str = ''):
34 """
35 Initialize a MindmapNotes instance.
36
37 Args:
38 text (str): Plain text version of the notes.
39 xhtml (str): XHTML formatted notes.
40 rtf (str): RTF formatted notes.
41 """
42 self.text = text
43 self.xhtml = xhtml
44 self.rtf = rtf
45
46class MindmapIcon:
47 def __init__(self,
48 text: str = '',
49 is_stock_icon=True,
50 index: int = 1,
51 signature: str = '',
52 path: str = '',
53 group: str = ''):
54 """
55 Initialize a MindmapIcon instance.
56
57 Args:
58 text (str): The display text for the icon.
59 is_stock_icon (bool): Flag indicating if the icon is a stock icon.
60 index (int): The index of a stock icon.
61 signature (str): A unique signature for the icon.
62 path (str): File path to the icon if it is custom.
63 group (str): The group/category of the icon.
64 """
65 self.text = text
66 self.is_stock_icon = is_stock_icon
67 self.index = index
68 self.signature = signature
69 self.path = path
70 self.group = group
71
72class MindmapTag:
73 def __init__(self, text: str = ''):
74 """
75 Initialize a MindmapTag instance.
76
77 Args:
78 text (str): The text representing the tag.
79 """
80 self.text = text
81
82class MindmapReference:
83 def __init__(self,
84 guid_1: str = '',
85 guid_2: str = '',
86 direction: int = 1,
87 label: str = ''):
88 """
89 Initialize a MindmapReference (relationship) instance.
90
91 Args:
92 guid_1 (str): The GUID of the first topic.
93 guid_2 (str): The GUID of the second topic.
94 direction (int): The direction of the reference (1 indicates a standard direction).
95 label (str): A label for the relationship.
96 """
97 self.guid_1 = guid_1
98 self.guid_2 = guid_2
99 self.direction = direction
100 self.label = label
101
102class MindmapTopic:
103 def __init__(self,
104 guid: str = '',
105 text: str = '',
106 rtf: str = '',
107 level: int = 0,
108 selected: bool = False,
109 parent: 'MindmapTopic' = None,
110 subtopics: list['MindmapTopic'] = None,
111 links: list['MindmapLink'] = None,
112 image: 'MindmapImage' = None,
113 icons: list['MindmapIcon'] = None,
114 notes: 'MindmapNotes' = None,
115 tags: list['MindmapTag'] = None,
116 references: list['MindmapReference'] = None):
117 """
118 Initialize a MindmapTopic instance.
119
120 Args:
121 guid (str): Unique identifier for the topic.
122 text (str): The text content of the topic.
123 rtf (str): RTF formatted text for the topic.
124 level (int): The hierarchical level of the topic.
125 selected (bool): Flag to indicate if the topic is selected.
126 parent (MindmapTopic): The parent topic if any.
127 subtopics (list[MindmapTopic]): List of subtopics.
128 links (list[MindmapLink]): List of associated links.
129 image (MindmapImage): Associated image object.
130 icons (list[MindmapIcon]): List of associated icons.
131 notes (MindmapNotes): Associated notes.
132 tags (list[MindmapTag]): List of associated tags.
133 references (list[MindmapReference]): List of associated relationships.
134 """
135 self.guid = guid
136 self.text = text.replace('"', '`').replace("'", "`").replace("\r", "").replace("\n", "")
137 self.rtf = rtf
138 self.level = level
139 self.selected = selected
140 self.parent = parent
141 self.links = links if links is not None else []
142 self.image = image
143 self.icons = icons if icons is not None else []
144 self.notes = notes
145 self.tags = tags if tags is not None else []
146 self.references = references if references is not None else []
147 self.subtopics = subtopics if subtopics is not None else []
148
149
150class MindmapDocument:
151 def __init__(self, charttype: str = 'auto', turbo_mode: bool = False, inline_editing_mode: bool = False, mermaid_mode: bool = True, macos_access: str = 'appscript'):
152 """
153 Initialize a MindmapDocument instance which automates MindManager operations.
154
155 Args:
156 charttype (str): The type of chart to be used (orgchart, radial, auto).
157 turbo_mode (bool): Flag for enabling turbo mode -> use only text.
158 inline_editing_mode (bool): Flag for enabling inline editing mode.
159 mermaid_mode (bool): Flag for enabling mermaid mode.
160 macos_access (str): Method for accessing macOS features (default is 'appscript', alternative is 'applescript').
161 """
162 self.charttype: str = charttype
163 self.turbo_mode: bool = turbo_mode
164 self.inline_editing_mode: bool = inline_editing_mode
165 self.mermaid_mode: bool = mermaid_mode
166 self.macos_access: str = macos_access
167 self.mindmap: 'MindmapTopic' = None
168 self.central_topic_selected: bool = False
169 self.selected_topic_texts: list[str] = []
170 self.selected_topic_levels: list[int] = []
171 self.selected_topic_ids: list[str] = []
172 self.max_topic_level: int = 0
173 self.macos_access = macos_access
174 self.mindm = mm.Mindmanager(charttype, macos_access)
175
176 def get_mindmap(self, topic=None, mode='full'):
177 """
178 Retrieve the mind map structure from the currently open MindManager document.
179
180 Args:
181 topic: (Optional) A specific topic from which to start building the mindmap.
182 If not provided, the central topic is used.
183 mode (str): The mode to use to gather attributes (full=all attributes, content=text+rtf+notes, text=text only).
184
185 Returns:
186 bool: True if the mind map was successfully retrieved, otherwise False.
187 """
188 if self.macos_access == 'applescript' and self.mindm.platform == 'darwin':
189 # get whole mindmap
190 mindmap = self.mindm.get_central_topic()
191 else:
192 if topic is None:
193 topic = self.mindm.get_central_topic()
194
195 mindmap = self.get_mindmap_topic_from_topic(self.mindm.get_topic_by_id(topic.guid), mode=mode)
196
197 self.max_topic_level = self.get_max_topic_level(mindmap)
198 self.mindmap = mindmap
199 return True
200
201 def get_max_topic_level(self, mindmap_topic, max_topic_level=0, visited=None):
202 """
203 Recursively compute the maximum topic level within the mind map.
204
205 Args:
206 mindmap_topic (MindmapTopic): The current topic to evaluate.
207 max_topic_level (int): The current maximum level found.
208 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
209
210 Returns:
211 int: The highest topic level found in the mindmap.
212 """
213 if visited is None:
214 visited = set()
215 if mindmap_topic.guid in visited:
216 return max_topic_level
217 visited.add(mindmap_topic.guid)
218 for subtopic in mindmap_topic.subtopics:
219 if subtopic.level > max_topic_level:
220 max_topic_level = subtopic.level
221 max_topic_level = self.get_max_topic_level(subtopic, max_topic_level, visited)
222 return max_topic_level
223
224 def get_parent_topic(self, topic, visited=None):
225 """
226 Retrieve the parent topic for a given MindManager topic.
227
228 Args:
229 topic: The current topic from which to get the parent.
230 visited (set, optional): Track visited GUIDs to avoid cycles.
231
232 Returns:
233 MindmapTopic or None: The parent topic wrapped as a MindmapTopic, or None if at the root.
234 """
235 if visited is None:
236 visited = set()
237 topic_guid = self.mindm.get_guid_from_topic(topic)
238 if topic_guid in visited:
239 return None
240 visited.add(topic_guid)
241 topic_level = self.mindm.get_level_from_topic(topic)
242 if topic_level == 0:
243 return None
244 parent_topic = self.mindm.get_parent_from_topic(topic)
245 if parent_topic is None:
246 return None
247 parent_guid = self.mindm.get_guid_from_topic(parent_topic)
248 if parent_guid == topic_guid:
249 return None
250 parent_mindmap_topic = MindmapTopic(
251 guid=parent_guid,
252 text=self.mindm.get_text_from_topic(parent_topic),
253 level=self.mindm.get_level_from_topic(parent_topic),
254 parent=self.get_parent_topic(parent_topic, visited),
255 )
256 return parent_mindmap_topic
257
258 def get_selection(self):
259 """
260 Retrieve the currently selected topics in the MindManager document.
261
262 Returns:
263 list[MindmapTopic]: A list of MindmapTopic instances representing the selection.
264 """
265 selection = self.mindm.get_selection()
266 mindmap_topics = []
267 for topic in selection:
268 level = self.mindm.get_level_from_topic(topic)
269 mindmap_topic = MindmapTopic(
270 guid=self.mindm.get_guid_from_topic(topic),
271 text=self.mindm.get_text_from_topic(topic),
272 level=level,
273 parent=self.get_parent_topic(topic),
274 selected=True,
275 )
276 mindmap_topics.append(mindmap_topic)
277 self.get_topic_texts_from_selection(mindmap_topics)
278 return mindmap_topics
279
280 def get_mindmap_topic_from_topic(self, topic, parent_topic=None, mode='full'):
281 """
282 Recursively convert a MindManager topic into a MindmapTopic object.
283
284 Args:
285 topic: The current MindManager topic to convert.
286 parent_topic (MindmapTopic): The parent MindmapTopic, if any.
287 mode (str): The mode to use to gather attributes (full=all attributes, content=text+rtf+notes, text=text only).
288
289 Returns:
290 MindmapTopic: The converted topic with its subtopics.
291 """
292 if mode == 'full':
293 mindmap_topic = self.mindm.get_mindmaptopic_from_topic_full(topic)
294 mindmap_topic.parent = parent_topic
295 elif mode == 'content':
296 mindmap_topic = self.mindm.get_mindmaptopic_from_topic_content(topic)
297 else:
298 mindmap_topic = self.mindm.get_mindmaptopic_from_topic(topic)
299
300 subtopics = self.mindm.get_subtopics_from_topic(topic)
301 mindmap_subtopics = []
302 for subtopic in subtopics:
303 child = self.get_mindmap_topic_from_topic(subtopic, parent_topic=mindmap_topic, mode=mode)
304 mindmap_subtopics.append(child)
305 mindmap_topic.subtopics = mindmap_subtopics
306 return mindmap_topic
307
308 def get_relationships_from_mindmap(self, mindmap, references, visited=None):
309 """
310 Recursively extract relationships (references) from the mindmap.
311
312 Args:
313 mindmap (MindmapTopic): The current topic in the mindmap.
314 references (list[MindmapReference]): List to collect the relationships.
315 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
316 """
317 if visited is None:
318 visited = set()
319 if mindmap.guid in visited:
320 return
321 visited.add(mindmap.guid)
322 for reference in mindmap.references:
323 if reference.direction == 1:
324 references.append(MindmapReference(
325 guid_1=reference.guid_1,
326 guid_2=reference.guid_2,
327 direction=reference.direction,
328 label=reference.label
329 ))
330 for subtopic in mindmap.subtopics:
331 self.get_relationships_from_mindmap(subtopic, references, visited)
332
333 def get_topic_links_from_mindmap(self, mindmap, links, visited=None):
334 """
335 Recursively extract topic links from the mindmap.
336
337 Args:
338 mindmap (MindmapTopic): The current topic in the mindmap.
339 links (list[MindmapReference]): List to collect topic links as MindmapReference objects.
340 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
341 """
342 if visited is None:
343 visited = set()
344 if mindmap.guid in visited:
345 return
346 visited.add(mindmap.guid)
347 for link in mindmap.links:
348 if link.guid != '':
349 links.append(MindmapReference(
350 guid_1=mindmap.guid,
351 guid_2=link.guid,
352 direction=1,
353 label=link.text
354 ))
355 for subtopic in mindmap.subtopics:
356 self.get_topic_links_from_mindmap(subtopic, links, visited)
357
358 def get_tags_from_mindmap(self, mindmap, tags, visited=None):
359 """
360 Recursively collect unique tags from the mindmap.
361
362 Args:
363 mindmap (MindmapTopic): The current topic in the mindmap.
364 tags (list[str]): List to collect tag texts.
365 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
366 """
367 if visited is None:
368 visited = set()
369 if mindmap.guid in visited:
370 return
371 visited.add(mindmap.guid)
372 for tag in mindmap.tags:
373 if tag.text != '' and tag.text not in tags:
374 tags.append(tag.text)
375 for subtopic in mindmap.subtopics:
376 self.get_tags_from_mindmap(subtopic, tags, visited)
377
378 def get_parents_from_mindmap(self, mindmap, parents, visited=None):
379 """
380 Build a dictionary mapping subtopic GUIDs to their parent's GUID.
381
382 Args:
383 mindmap (MindmapTopic): The current topic in the mindmap.
384 parents (dict): Dictionary to store parent-child GUID mappings.
385 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
386 """
387 if visited is None:
388 visited = set()
389 if mindmap.guid in visited:
390 return
391 visited.add(mindmap.guid)
392 for subtopic in mindmap.subtopics:
393 if subtopic.guid not in parents:
394 parents[subtopic.guid] = mindmap.guid
395 self.get_parents_from_mindmap(subtopic, parents, visited)
396 return
397
398 def get_map_icons_and_fix_refs_from_mindmap(self, mindmap, map_icons: list['MindmapIcon'], visited=None):
399 """
400 Extract icons from mindmap topics and fix their references if needed.
401
402 Args:
403 mindmap (MindmapTopic): The current topic in the mindmap.
404 map_icons (list[MindmapIcon]): List to collect unique icons.
405 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
406 """
407 if visited is None:
408 visited = set()
409 if mindmap.guid in visited:
410 return
411 visited.add(mindmap.guid)
412
413 for i, topic_icon_ref in enumerate(mindmap.icons):
414 # Only process non-stock icons belonging to the 'Types' group
415 if not topic_icon_ref.is_stock_icon and topic_icon_ref.group == 'Types':
416 found = False
417 for map_icon in map_icons:
418 if map_icon.signature == topic_icon_ref.signature:
419 found = True
420 new_icon = map_icon
421 break
422 if not found:
423 new_icon = MindmapIcon(
424 text=topic_icon_ref.text,
425 index=topic_icon_ref.index,
426 is_stock_icon=topic_icon_ref.is_stock_icon,
427 path=topic_icon_ref.path,
428 signature=topic_icon_ref.signature,
429 group=topic_icon_ref.group)
430 map_icons.append(new_icon)
431 mindmap.icons[i] = new_icon
432 for subtopic in mindmap.subtopics:
433 self.get_map_icons_and_fix_refs_from_mindmap(subtopic, map_icons, visited)
434
435 def count_parent_and_child_occurrences(self, mindmap_topic, guid_counts, visited=None):
436 """
437 Recursively count the occurrences of parent and child relationships for each topic.
438
439 Args:
440 mindmap_topic (MindmapTopic): The current topic in the mindmap.
441 guid_counts (dict): Dictionary to store counts with topic GUID as keys.
442 visited (set): Set of visited topic GUIDs to avoid infinite recursion.
443 """
444 if visited is None:
445 visited = set()
446 if str(mindmap_topic.guid) == '':
447 mindmap_topic.guid = str(uuid.uuid4())
448 if mindmap_topic.guid not in visited:
449 visited.add(mindmap_topic.guid)
450 if mindmap_topic.guid not in guid_counts:
451 guid_counts[mindmap_topic.guid] = {'parent': 0, 'child': 0}
452 for subtopic in mindmap_topic.subtopics:
453 if mindmap_topic.guid:
454 guid_counts[mindmap_topic.guid]['parent'] += 1
455 if subtopic.guid:
456 if subtopic.guid not in guid_counts:
457 guid_counts[subtopic.guid] = {'parent': 0, 'child': 0}
458 guid_counts[subtopic.guid]['child'] += 1
459 self.count_parent_and_child_occurrences(subtopic, guid_counts, visited)
460
461 def get_topic_texts_from_selection(self, mindmap_topics):
462 """
463 Extract topic texts, levels, and GUIDs from selected topics.
464
465 Args:
466 mindmap_topics (list[MindmapTopic]): List of topics to process.
467 """
468 topic_texts = []
469 topic_levels = []
470 topic_ids = []
471 central_topic_selected = False
472 for topic in mindmap_topics:
473 if topic.selected:
474 if topic.level > 0:
475 topic_texts.append(topic.text)
476 topic_levels.append(topic.level)
477 topic_ids.append(topic.guid)
478 else:
479 central_topic_selected = True
480
481 self.central_topic_selected = central_topic_selected
482 self.selected_topic_texts = topic_texts
483 self.selected_topic_levels = topic_levels
484 self.selected_topic_ids = topic_ids
485
486 def clone_mindmap_topic(self, mindmap_topic, subtopics: list['MindmapTopic'] = None, parent=None):
487 """
488 Clone a MindmapTopic instance including its subtopics.
489
490 Args:
491 mindmap_topic (MindmapTopic): The topic to clone.
492 subtopics (list[MindmapTopic], optional): A list of subtopics to clone.
493 parent: The parent for the cloned topic.
494
495 Returns:
496 MindmapTopic: A new instance that is a clone of the given topic.
497 """
498 cloned_subtopics = []
499 if subtopics is not None:
500 for subtopic in subtopics:
501 cloned_subtopic = self.clone_mindmap_topic(subtopic)
502 cloned_subtopics.append(cloned_subtopic)
503 return MindmapTopic(
504 guid=mindmap_topic.guid,
505 text=mindmap_topic.text,
506 rtf=mindmap_topic.rtf,
507 level=mindmap_topic.level,
508 parent=parent,
509 links=mindmap_topic.links,
510 image=mindmap_topic.image,
511 icons=mindmap_topic.icons,
512 notes=mindmap_topic.notes,
513 tags=mindmap_topic.tags,
514 subtopics=cloned_subtopics
515 )
516
517 def update_done(self, topic_guid, mindmap_topic, level, done, done_global):
518 """
519 Update tracking dictionaries for processed topics and create duplicate links/tags.
520
521 Args:
522 topic_guid (str): The GUID of the current topic in MindManager.
523 mindmap_topic (MindmapTopic): The MindmapTopic being processed.
524 level (int): The current level in the topic hierarchy.
525 done (dict): Dictionary tracking topics processed at a given level.
526 done_global (dict): Global dictionary tracking processed topics for duplicate detection.
527 """
528 if mindmap_topic.guid == '':
529 return
530 if level <= 1:
531 done = {}
532 elif level >= 2:
533 done[mindmap_topic.guid] = [topic_guid] if mindmap_topic.guid not in done else done[mindmap_topic.guid] + [topic_guid]
534 if mindmap_topic.guid in done_global:
535 # Check for duplicate relationships and add links/tags accordingly.
536 if self.guid_counts[mindmap_topic.guid]['child'] < 11 and self.guid_counts[mindmap_topic.guid]['parent'] >= 0:
537 for i in range(len(done_global[mindmap_topic.guid])):
538 link_from = topic_guid
539 link_to = done_global[mindmap_topic.guid][i]
540 self.mindm.add_topic_link(link_from, link_to, DUPLICATE_LABEL)
541 self.mindm.add_topic_link(link_to, link_from, DUPLICATE_LABEL)
542 if len(done_global[mindmap_topic.guid]) == 1:
543 self.mindm.add_tag_to_topic(topic=None, tag_text=DUPLICATED_TAG, topic_guid=done_global[mindmap_topic.guid][0])
544 self.mindm.add_tag_to_topic(topic=None, tag_text=DUPLICATED_TAG, topic_guid=topic_guid)
545 done_global[mindmap_topic.guid] = done_global[mindmap_topic.guid] + [topic_guid]
546 else:
547 done_global[mindmap_topic.guid] = [topic_guid]
548
549 def set_topic_from_mindmap_topic(self, topic, mindmap_topic, map_icons, done=None, done_global=None, level=0):
550 """
551 Create or update a MindManager topic from a MindmapTopic instance recursively.
552
553 Args:
554 topic: The current MindManager topic to update.
555 mindmap_topic (MindmapTopic): The source MindmapTopic data.
556 map_icons (list[MindmapIcon]): List of map icons to use.
557 done (dict, optional): Dictionary tracking processed topics at current level.
558 done_global (dict, optional): Global dictionary for tracking duplicate processing.
559 level (int): Current hierarchical level.
560
561 Returns:
562 MindmapTopic: The processed MindmapTopic.
563 """
564 if done is None:
565 done = {}
566 if done_global is None:
567 done_global = {}
568 try:
569 if self.turbo_mode:
570 topic_guid = self.mindm.get_guid_from_topic(topic)
571 self.update_done(topic_guid, mindmap_topic, level, done, done_global)
572 for subtopic in mindmap_topic.subtopics:
573 try:
574 sub = self.mindm.add_subtopic_to_topic(topic, subtopic.text)
575 self.set_topic_from_mindmap_topic(sub, subtopic, map_icons, done, done_global, level + 1)
576 except Exception as e:
577 print(f"Error(1) processing topic/subtopic {mindmap_topic.guid}/{subtopic.guid}: {e}")
578 else:
579 topic, topic_guid = self.mindm.set_topic_from_mindmap_topic(topic, mindmap_topic, map_icons)
580 self.update_done(topic_guid, mindmap_topic, level, done, done_global)
581
582 if mindmap_topic.subtopics and len(mindmap_topic.subtopics) > 0:
583 # Sort subtopics alphabetically by text
584 mindmap_topic.subtopics.sort(key=lambda sub: sub.text)
585
586 for subtopic in mindmap_topic.subtopics:
587 try:
588 if subtopic.guid in done:
589 this_guid_as_parent_exists = self.check_parent_exists(topic_guid, subtopic.guid)
590 if not this_guid_as_parent_exists:
591 cloned_subtopic = self.clone_mindmap_topic(subtopic)
592 sub = self.mindm.add_subtopic_to_topic(topic, cloned_subtopic.text)
593 self.set_topic_from_mindmap_topic(sub, cloned_subtopic, map_icons, done, done_global, level + 1)
594 else:
595 sub = self.mindm.add_subtopic_to_topic(topic, subtopic.text)
596 self.set_topic_from_mindmap_topic(sub, subtopic, map_icons, done, done_global, level + 1)
597 except Exception as e:
598 print(f"Error(2) processing topic/subtopic {mindmap_topic.guid}/{subtopic.guid}: {e}")
599 return mindmap_topic
600 except Exception as e:
601 print(f"Error in set_topic_from_mindmap_topic at level {level} with topic {mindmap_topic.guid}: {e}")
602
603 def check_parent_exists(self, topic_guid, this_guid, visited=None):
604 """
605 Recursively check if a parent-child relationship exists between topics.
606
607 Args:
608 topic_guid (str): The GUID of the topic to check.
609 this_guid (str): The GUID that might be a parent of the topic.
610 visited (set, optional): Set of visited GUIDs to avoid infinite recursion.
611
612 Returns:
613 bool: True if the parent-child relationship exists, False otherwise.
614 """
615 if visited is None:
616 visited = set()
617 if topic_guid in visited:
618 return False
619 visited.add(topic_guid)
620
621 check = False
622 if topic_guid in self.parents:
623 parent_guid = self.parents[topic_guid]
624 if parent_guid == this_guid:
625 check = True
626 else:
627 check = self.check_parent_exists(parent_guid, this_guid, visited)
628 return check
629
630 def create_mindmap(self, verbose=False):
631 """
632 Create a MindManager mindmap document from the internal MindmapTopic structure.
633 This includes counting occurrences, extracting tags/icons, and setting up relationships and links.
634
635 Args:
636 verbose (bool): (Optional) Enable verbose output.
637 """
638 tags = []
639 map_icons = []
640 relationships = []
641 links = []
642
643 self.parents = {}
644 self.guid_counts = {}
645 self.count_parent_and_child_occurrences(self.mindmap, self.guid_counts)
646 self.get_parents_from_mindmap(self.mindmap, self.parents)
647
648 self.get_tags_from_mindmap(self.mindmap, tags)
649 self.get_map_icons_and_fix_refs_from_mindmap(self.mindmap, map_icons)
650 self.get_relationships_from_mindmap(self.mindmap, relationships)
651 self.get_topic_links_from_mindmap(self.mindmap, links)
652
653 self.mindm.add_document(0)
654 self.mindm.create_map_icons(map_icons)
655 self.mindm.create_tags(tags, DUPLICATED_TAG)
656
657 if self.mindm.platform == 'darwin' and self.macos_access == 'applescript':
658 self.mindm.set_topic_from_mindmap_topic(None, self.mindmap, map_icons)
659 self.get_mindmap()
660 else:
661 central_topic = self.mindm.get_central_topic()
662 self.mindm.set_text_to_topic(self.mindm.get_topic_by_id(central_topic.guid), self.mindmap.text)
663
664 done_global = {}
665 self.set_topic_from_mindmap_topic(
666 topic=self.mindm.get_topic_by_id(central_topic.guid),
667 mindmap_topic=self.mindmap,
668 map_icons=map_icons,
669 done={},
670 done_global=done_global)
671
672 # Create relationships between topics
673 for reference in relationships:
674 object1_guids = done_global[reference.guid_1]
675 object2_guids = done_global[reference.guid_2]
676 for object1_guid in object1_guids:
677 for object2_guid in object2_guids:
678 self.mindm.add_relationship(object1_guid, object2_guid, reference.label)
679
680 # Create topic links
681 for link in links:
682 object1_guids = done_global[link.guid_1]
683 object2_guids = done_global[link.guid_2]
684 for object1_guid in object1_guids:
685 for object2_guid in object2_guids:
686 self.mindm.add_topic_link(object1_guid, object2_guid, link.label)
687
688 def create_mindmap_and_finalize(self):
689 """
690 Create the mindmap document and finalize it.
691 """
692 self.create_mindmap()
693 self.finalize()
694
695 def finalize(self):
696 """
697 Finalize the mindmap document by ensuring the maximum topic level is set, then calling MindManager's finalize.
698 """
699 if self.max_topic_level == 0:
700 self.max_topic_level = self.get_max_topic_level(self.mindmap)
701 self.mindm.finalize(self.max_topic_level)
702
703 def set_background_image(self, image_path):
704 """
705 Set the background image for the MindManager document.
706
707 Args:
708 image_path (str): The file path to the background image.
709 """
710 self.mindm.set_document_background_image(image_path)
711
712 def get_library_folder(self):
713 """
714 Get the library folder used by MindManager.
715
716 Returns:
717 The path to the library folder.
718 """
719 return self.mindm.get_library_folder()
720
721 def get_grounding_information(self):
722 """
723 Extract grounding information from the mindmap, including the central topic and selected subtopics.
724
725 Returns:
726 tuple: (top_most_topic, subtopics) where top_most_topic is the central topic or a concatenated string
727 of non-selected topics, and subtopics is a comma-separated string of selected subtopics.
728 """
729 central_topic_text = self.mindmap.text
730 self.get_selection()
731 subtopics = ""
732 if len(self.selected_topic_texts) == 0:
733 top_most_topic = central_topic_text
734 else:
735 if self.central_topic_selected:
736 top_most_topic = central_topic_text
737 subtopics = ",".join(self.selected_topic_texts)
738 else:
739 min_level = min(self.selected_topic_levels)
740 max_level = max(self.selected_topic_levels)
741 if (min_level == max_level):
742 top_most_topic = central_topic_text
743 subtopics = ",".join(self.selected_topic_texts)
744 else:
745 top_most_topic = ""
746 for i in range(len(self.selected_topic_levels)):
747 if self.selected_topic_levels[i] != max_level:
748 top_most_topic += self.selected_topic_texts[i] + "/"
749 else:
750 subtopics += self.selected_topic_texts[i] + ","
751
752 if top_most_topic.endswith("/"):
753 top_most_topic = top_most_topic[:-1]
754 if subtopics.endswith(","):
755 subtopics = subtopics[:-1]
756 return top_most_topic, subtopics