mindm.mindmanager_mac_as module¶
MacOS-specific implementation of the Mindmanager interface. This class implementation uses the native AppleScript approach.
This module provides MacOS platform-specific implementation for interacting with MindManager application, including functionality for manipulating topics, properties, relationships, and document structure.
- class mindm.mindmanager_mac_as.Mindmanager(charttype)¶
Bases:
object- MACOS_LIBRARY_FOLDER = 'C:\\Users\\runneradmin\\Library\\Application Support\\Mindjet\\MindManager\\XX\\English\\Library'¶
- MACOS_MERGE_ALL_WINDOWS = False¶
- __init__(charttype)¶
- add_document(max_topic_level)¶
Opens the correct template based on charttype and subtopic counts.
- add_relationship(guid1, guid2, label='')¶
- add_subtopic_to_topic(topic_id, topic_text)¶
Create a new subtopic under topic_id with topic_text. Return the new subtopic’s ID or None on failure.
- add_tag_to_topic(topic_id, tag_text, topic_guid)¶
- add_topic_link(guid1, guid2, label='')¶
- create_map_icons(map_icons)¶
- create_tags(tags: list[str], DUPLICATED_TAG: str)¶
- document_exists()¶
Returns True if there’s at least one open document in MindManager.
- finalize(max_topic_level)¶
Balance the map, activate MindManager, optionally merge windows, and clean up.
- get_active_document_object()¶
Return ‘document 1’ if a document is open, else None.
- get_central_topic() MindmapTopic¶
Return the central topic’s ID or None if not found.
- get_guid_from_topic(topic_id) str¶
- get_icons_from_topic(topic_id) list[MindmapIcon]¶
- get_image_from_topic(topic_id) MindmapImage¶
- get_level_from_topic(topic_id)¶
- get_library_folder()¶
- get_links_from_topic(topic_id) list[MindmapLink]¶
- get_mindmanager_object()¶
- get_mindmaptopic_from_topic(topic_id) MindmapTopic¶
Returns a MindmapTopic with guid, text, rtf and level, all retrieved via a single AppleScript call.
- get_mindmaptopic_from_topic_content(topic_id) MindmapTopic¶
Returns a MindmapTopic with guid, text, rtf, level, and notes, all retrieved via a single AppleScript call.
- get_mindmaptopic_from_topic_full(topic_id) MindmapTopic¶
Returns a MindmapTopic with guid, text, rtf, level, notes, and references, all via one AppleScript call. (links/icons/tags/image remain unimplemented.)
- get_notes_from_topic(topic_id) MindmapNotes¶
Return MindmapNotes or None.
- get_parent_from_topic(topic_id)¶
Return the parent’s ID or None if there is no parent or the topic doesn’t exist.
- get_references_from_topic(topic_id) list[MindmapReference]¶
Return a list of MindmapReference objects for the given topic.
- get_selection()¶
Return a list of topic IDs in the current selection.
- get_subtopics_from_topic(topic_id)¶
Return a list of subtopic IDs.
- get_tags_from_topic(topic_id) list[MindmapTag]¶
- get_text_from_topic(topic_id)¶
- get_title_from_topic(topic_id)¶
- get_topic_by_id(topic_id)¶
- get_version()¶
- set_document_background_image(path)¶
- set_text_to_topic(topic_id, topic_text)¶
Set the topic’s text (equivalent to topic.name.set).
- set_title_to_topic(topic_id, topic_rtf)¶
Set the topic’s title (equivalent to topic.title.set).
- set_topic_from_mindmap_topic(topic_id, mindmap_topic, map_icons)¶
Updates the topic’s text, RTF title, and notes from mindmap_topic via a single AppleScript call. Returns (refreshed_topic_id, original_topic_id).
1"""
2MacOS-specific implementation of the Mindmanager interface.
3This class implementation uses the native AppleScript approach.
4
5This module provides MacOS platform-specific implementation for interacting
6with MindManager application, including functionality for manipulating topics,
7properties, relationships, and document structure.
8"""
9
10import os
11import sys
12import json
13import subprocess
14
15from mindmap.mindmap import (
16 MindmapLink,
17 MindmapImage,
18 MindmapNotes,
19 MindmapIcon,
20 MindmapTag,
21 MindmapReference,
22 MindmapTopic,
23)
24import mindmap.serialization as mms
25
26APPLESCRIPT_READ = os.path.join(os.path.dirname(__file__), "as", "read.scpt")
27APPLESCRIPT_WRITE = os.path.join(os.path.dirname(__file__), "as", "write.scpt")
28
29def _run_applescript(script: str, args: list = None) -> str:
30 if args is None:
31 args = []
32
33 command = ["osascript", "-e", script] + args
34 try:
35 result = subprocess.run(
36 command,
37 capture_output=True,
38 text=True,
39 check=True
40 )
41 return result.stdout.strip()
42 except subprocess.CalledProcessError as e:
43 print(f"AppleScript error: {e.stderr}")
44 return ""
45
46def _run_compiled_applescript(script_path: str, args: list = None) -> str:
47 if args is None:
48 args = []
49
50 command = ["osascript", script_path] + (args or [])
51
52 try:
53 result = subprocess.run(
54 command,
55 capture_output=True,
56 text=True,
57 check=True
58 )
59 return result.stdout.strip()
60 except subprocess.CalledProcessError as e:
61 print("osascript returned", e.returncode)
62 print("--- stdout ---\n", e.stdout)
63 print("--- stderr ---\n", e.stderr)
64 return ""
65
66class Mindmanager:
67
68 MACOS_MERGE_ALL_WINDOWS = False
69 MACOS_LIBRARY_FOLDER = os.path.join(
70 os.path.expanduser("~"),
71 "Library",
72 "Application Support",
73 "Mindjet",
74 "MindManager",
75 "XX",
76 "English",
77 "Library"
78 )
79
80 def __init__(self, charttype):
81 self._charttype = charttype
82
83 # Get version from MindManager
84 script = 'tell application "MindManager" to return version'
85 version_str = _run_applescript(script)
86 if version_str:
87 self._version = version_str.split('.')[0]
88 else:
89 self._version = "0"
90
91 self._library_folder = self.MACOS_LIBRARY_FOLDER.replace("XX", self._version)
92 if self._version == '24':
93 orgchart_template_path = os.path.join(self._library_folder, "Templates", "Blank Templates", "Organization Chart.mmat")
94 else:
95 orgchart_template_path = os.path.join(self._library_folder, "Templates", "Blank Templates", "Org-Chart Map.mmat")
96 self._orgchart_template = orgchart_template_path
97 self._radial_template = os.path.join(self._library_folder, "Templates", "Blank Templates", "Radial Map.mmat")
98
99 def _read(self, modus, arguments = None) -> list['MindmapTopic']:
100 if arguments:
101 script_args = [modus] + arguments
102 else:
103 script_args = [modus]
104
105 json_string = _run_compiled_applescript(APPLESCRIPT_READ, script_args)
106
107 if not json_string:
108 return None # no data returned
109 try:
110 jsonObject = json.loads(json_string)
111 if isinstance(jsonObject, dict):
112 # It's a single tree structure
113 topic = self._dict_to_mindmap_topic(jsonObject)
114 return [topic] if topic else None
115 elif isinstance(jsonObject, list):
116 # It's a list of topic structures
117 topics = []
118 for item in jsonObject:
119 if isinstance(item, dict):
120 topic = self._dict_to_mindmap_topic(item)
121 if topic:
122 topics.append(topic)
123 return topics
124 else:
125 # Unexpected format
126 print(f"Unexpected JSON format received: {type(jsonObject)}")
127 return None
128 except json.JSONDecodeError as e:
129 print(f"Error parsing JSON from AppleScript: {e}")
130 return None
131
132 def _write(self, modus, mindmap_topic):
133 json_string = json.dumps(mms.serialize_object_simple(mindmap_topic))
134 script_args = [modus] + [json_string]
135 result = _run_compiled_applescript(APPLESCRIPT_WRITE, script_args)
136 return result
137
138 def _dict_to_mindmap_topic(self, node_dict: dict) -> 'MindmapTopic':
139 """
140 Helper to recursively convert a dict of the form:
141 { "guid": ..., "text": ..., "level": ..., "notes": ..., "subtopics": [ ... ] }
142 into a MindmapTopic object with subtopics.
143 """
144 notes_obj = None
145 if node_dict.get("notes"):
146 notes_obj = MindmapNotes(text=node_dict["notes"])
147 references = []
148 for ref in node_dict.get("references", []) or []:
149 if not isinstance(ref, dict):
150 continue
151 direction = 0
152 try:
153 direction = int(ref.get("direction", 0) or 0)
154 except (TypeError, ValueError):
155 direction = 0
156 references.append(
157 MindmapReference(
158 direction=direction,
159 guid_1=ref.get("guid_1", ""),
160 guid_2=ref.get("guid_2", ""),
161 )
162 )
163 tags = []
164 for tag in node_dict.get("tags", []) or []:
165 if isinstance(tag, dict):
166 text_val = tag.get("text", "")
167 else:
168 text_val = tag
169 if text_val:
170 tags.append(MindmapTag(text=text_val))
171 topic = MindmapTopic(
172 guid=node_dict.get("guid", ""),
173 text=node_dict.get("text", ""),
174 level=int(node_dict.get("level", 0)),
175 notes=notes_obj,
176 tags=tags,
177 references=references,
178 )
179 subtopics = node_dict.get("subtopics", [])
180 for child_dict in subtopics:
181 child_topic = self._dict_to_mindmap_topic(child_dict)
182 if child_topic:
183 topic.subtopics.append(child_topic)
184 child_topic.parent = topic
185
186 return topic
187
188 def get_mindmanager_object(self):
189 return None
190
191 def get_active_document_object(self):
192 """
193 Return 'document 1' if a document is open, else None.
194 """
195 return "document 1" if self.document_exists() else None
196
197 def get_library_folder(self):
198 return self._library_folder
199
200 def get_version(self):
201 return self._version
202
203 def set_document_background_image(self, path):
204 pass
205
206 def document_exists(self):
207 """
208 Returns True if there's at least one open document in MindManager.
209 """
210 script = '''
211 tell application "MindManager"
212 if (count of documents) > 0 then
213 return "true"
214 else
215 return "false"
216 end if
217 end tell
218 '''
219 result = _run_applescript(script)
220 return (result == "true")
221
222 def get_central_topic(self) -> 'MindmapTopic':
223 """
224 Return the central topic's ID or None if not found.
225 """
226 result = self._read("getTree")
227 return result[0] if result else None
228
229 def get_mindmaptopic_from_topic(self, topic_id) -> 'MindmapTopic':
230 """
231 Returns a MindmapTopic with guid, text, rtf and level,
232 all retrieved via a single AppleScript call.
233 """
234 if not topic_id:
235 return None
236
237 # Single AppleScript to grab all basic properties at once:
238 script = f'''
239 tell application "MindManager"
240 try
241 set theTopic to first topic of document 1 whose id is "{topic_id}"
242 set theGUID to id of theTopic
243 set theName to name of theTopic
244 set theTitle to title of theTopic
245 set theLevel to level of theTopic
246 return theGUID & "%%" & theName & "%%" & theTitle & "%%" & (theLevel as text)
247 on error
248 return ""
249 end try
250 end tell
251 '''
252 result = _run_applescript(script)
253 if not result:
254 return None # topic not found or error
255
256 parts = result.split("%%", 3) # we expect exactly 4 parts
257 if len(parts) < 4:
258 return None
259
260 theGUID, theName, theTitle, theLevelStr = parts
261
262 # Convert level to integer if possible
263 try:
264 theLevel = int(theLevelStr)
265 except ValueError:
266 theLevel = None
267
268 # Clean up the text property so it mimics your old replacements
269 theName = theName.replace('"', '`').replace("'", "`").replace("\r", "").replace("\n", "")
270
271 # Construct and return the MindmapTopic
272 return MindmapTopic(
273 guid=theGUID,
274 text=theName,
275 rtf=theTitle,
276 level=theLevel,
277 )
278
279 def get_mindmaptopic_from_topic_content(self, topic_id) -> 'MindmapTopic':
280 """
281 Returns a MindmapTopic with guid, text, rtf, level, and notes,
282 all retrieved via a single AppleScript call.
283 """
284 if not topic_id:
285 return None
286
287 # Single AppleScript to grab all basic properties at once:
288 script = f'''
289 tell application "MindManager"
290 try
291 set theTopic to first topic of document 1 whose id is "{topic_id}"
292 set theGUID to id of theTopic
293 set theName to name of theTopic
294 set theTitle to title of theTopic
295 set theLevel to level of theTopic
296 set theNotes to notes of theTopic
297 return theGUID & "%%" & theName & "%%" & theTitle & "%%" & (theLevel as text) & "%%" & theNotes
298 on error
299 return ""
300 end try
301 end tell
302 '''
303 result = _run_applescript(script)
304 if not result:
305 return None # topic not found or error
306
307 parts = result.split("%%", 4) # we expect exactly 5 parts
308 if len(parts) < 5:
309 return None
310
311 theGUID, theName, theTitle, theLevelStr, theNotes = parts
312
313 # Convert level to integer if possible
314 try:
315 theLevel = int(theLevelStr)
316 except ValueError:
317 theLevel = None
318
319 # Clean up the text property so it mimics your old replacements
320 theName = theName.replace('"', '`').replace("'", "`").replace("\r", "").replace("\n", "")
321
322 # Build the MindmapNotes object if notes are non-empty
323 notes_obj = MindmapNotes(text=theNotes) if theNotes else None
324
325 # Construct and return the MindmapTopic
326 return MindmapTopic(
327 guid=theGUID,
328 text=theName,
329 rtf=theTitle,
330 level=theLevel,
331 notes=notes_obj,
332 )
333
334 def get_mindmaptopic_from_topic_full(self, topic_id) -> 'MindmapTopic':
335 """
336 Returns a MindmapTopic with guid, text, rtf, level, notes, and references,
337 all via one AppleScript call. (links/icons/tags/image remain unimplemented.)
338 """
339 if not topic_id:
340 return None
341
342 # Single AppleScript to grab all properties + references
343 script = f'''
344 tell application "MindManager"
345 try
346 set theTopic to first topic of document 1 whose id is "{topic_id}"
347 set theGUID to id of theTopic
348 set theName to name of theTopic
349 set theTitle to title of theTopic
350 set theLevel to level of theTopic
351 set theNotes to notes of theTopic
352 set rels to relationships of theTopic
353 set referencesString to ""
354 repeat with r in rels
355 set sLoc to id of (starting location of r)
356 set eLoc to id of (ending location of r)
357 set referencesString to referencesString & sLoc & "||" & eLoc & "||--||"
358 end repeat
359 return theGUID & "%%" & theName & "%%" & theTitle & "%%" & (theLevel as text) & "%%" & theNotes & "%%" & referencesString
360 on error
361 return ""
362 end try
363 end tell
364 '''
365 result = _run_applescript(script)
366 if not result:
367 return None
368
369 # We expect 6 parts: guid, name, title, level, notes, referencesString
370 parts = result.split("%%", 5)
371 if len(parts) < 6:
372 return None
373
374 theGUID, theName, theTitle, theLevelStr, theNotes, referencesRaw = parts
375
376 # Convert level to integer if possible
377 try:
378 theLevel = int(theLevelStr)
379 except ValueError:
380 theLevel = None
381
382 # Clean up the text property
383 theName = theName.replace('"', '`').replace("'", "`").replace("\r", "").replace("\n", "")
384
385 # Build the MindmapNotes object if notes are non-empty
386 notes_obj = MindmapNotes(text=theNotes) if theNotes else None
387
388 # Parse references:
389 # referencesRaw might look like "GUID1||GUID2||--||GUID3||GUID4||--||"
390 references = []
391 if referencesRaw:
392 rel_chunks = referencesRaw.split("||--||")
393 for chunk in rel_chunks:
394 chunk = chunk.strip()
395 if not chunk:
396 continue
397 pair = chunk.split("||")
398 if len(pair) == 2:
399 sLoc, eLoc = pair
400 if sLoc == theGUID: # If it matches the old pattern
401 references.append(
402 MindmapReference(direction=1, guid_1=sLoc, guid_2=eLoc)
403 )
404 else:
405 # Or handle direction=2 or other logic if needed
406 pass
407
408 # For now, links, icons, tags, image remain unimplemented => empty
409 links = []
410 icons = []
411 tags = []
412 image = None
413
414 return MindmapTopic(
415 guid=theGUID,
416 text=theName,
417 rtf=theTitle,
418 level=theLevel,
419 notes=notes_obj,
420 links=links,
421 image=image,
422 icons=icons,
423 tags=tags,
424 references=references,
425 )
426
427 def get_topic_by_id(self, topic_id):
428 return topic_id
429
430 def get_selection(self):
431 """
432 Return a list of topic IDs in the current selection.
433 """
434 result = self._read("getSelection")
435 return result
436
437 def get_level_from_topic(self, topic_id):
438 if not topic_id:
439 return None
440 script = f'''
441 tell application "MindManager"
442 try
443 set theTopic to first topic of document 1 whose id is "{topic_id}"
444 return level of theTopic
445 on error
446 return ""
447 end try
448 end tell
449 '''
450 level_str = _run_applescript(script)
451 return int(level_str) if level_str.isdigit() else None
452
453 def get_text_from_topic(self, topic_id):
454 if not topic_id:
455 return ""
456 script = f'''
457 tell application "MindManager"
458 try
459 set theTopic to first topic of document 1 whose id is "{topic_id}"
460 return name of theTopic
461 on error
462 return ""
463 end try
464 end tell
465 '''
466 text = _run_applescript(script)
467 # Replace certain characters (as in original code)
468 text = text.replace('"', '`').replace("'", "`").replace("\r", "").replace("\n", "")
469 return text
470
471 def get_title_from_topic(self, topic_id):
472 if not topic_id:
473 return ""
474 script = f'''
475 tell application "MindManager"
476 try
477 set theTopic to first topic of document 1 whose id is "{topic_id}"
478 return title of theTopic
479 on error
480 return ""
481 end try
482 end tell
483 '''
484 return _run_applescript(script)
485
486 def get_subtopics_from_topic(self, topic_id):
487 """
488 Return a list of subtopic IDs.
489 """
490 if not topic_id:
491 return []
492 script = f'''
493 tell application "MindManager"
494 try
495 set theTopic to first topic of document 1 whose id is "{topic_id}"
496 set subTs to subtopics of theTopic
497 set output to ""
498 repeat with t in subTs
499 set output to output & (id of t) & linefeed
500 end repeat
501 return output
502 on error
503 return ""
504 end try
505 end tell
506 '''
507 raw = _run_applescript(script)
508 return [x.strip() for x in raw.splitlines() if x.strip()]
509
510 def get_links_from_topic(self, topic_id) -> list[MindmapLink]:
511 return []
512
513 def get_image_from_topic(self, topic_id) -> MindmapImage:
514 return None
515
516 def get_icons_from_topic(self, topic_id) -> list[MindmapIcon]:
517 return []
518
519 def get_notes_from_topic(self, topic_id) -> MindmapNotes:
520 """
521 Return MindmapNotes or None.
522 """
523 if not topic_id:
524 return None
525 script = f'''
526 tell application "MindManager"
527 try
528 set theTopic to first topic of document 1 whose id is "{topic_id}"
529 return notes of theTopic
530 on error
531 return ""
532 end try
533 end tell
534 '''
535 notes_text = _run_applescript(script)
536 if notes_text:
537 return MindmapNotes(text=notes_text)
538 return None
539
540 def get_tags_from_topic(self, topic_id) -> list[MindmapTag]:
541 return []
542
543 def get_references_from_topic(self, topic_id) -> list[MindmapReference]:
544 """
545 Return a list of MindmapReference objects for the given topic.
546 """
547 references = []
548 if not topic_id:
549 return references
550
551 script = f'''
552 tell application "MindManager"
553 try
554 set theTopic to first topic of document 1 whose id is "{topic_id}"
555 set rels to relationships of theTopic
556 if (count of rels) = 0 then
557 return ""
558 end if
559 set outList to ""
560 repeat with r in rels
561 set sLoc to id of (starting location of r)
562 set eLoc to id of (ending location of r)
563 set outList to outList & sLoc & "||" & eLoc & linefeed
564 end repeat
565 return outList
566 on error
567 return ""
568 end try
569 end tell
570 '''
571 raw = _run_applescript(script)
572 for line in raw.splitlines():
573 parts = line.split("||")
574 if len(parts) == 2:
575 sLoc, eLoc = parts
576 if sLoc == topic_id:
577 references.append(
578 MindmapReference(
579 direction=1,
580 guid_1=sLoc,
581 guid_2=eLoc
582 )
583 )
584 return references
585
586 def get_guid_from_topic(self, topic_id) -> str:
587 return topic_id if topic_id else ""
588
589 def add_subtopic_to_topic(self, topic_id, topic_text):
590 """
591 Create a new subtopic under `topic_id` with `topic_text`.
592 Return the new subtopic's ID or None on failure.
593 """
594 if not topic_id:
595 return None
596 safe_text = topic_text.replace('"', '\\"')
597 script = f'''
598 tell application "MindManager"
599 try
600 set parentTopic to first topic of document 1 whose id is "{topic_id}"
601 set newT to make new topic at end of subtopics of parentTopic with properties {{name:"{safe_text}"}}
602 return id of newT
603 on error
604 return ""
605 end try
606 end tell
607 '''
608 new_id = _run_applescript(script)
609 return new_id if new_id else None
610
611 def get_parent_from_topic(self, topic_id):
612 """
613 Return the parent's ID or None if there is no parent or the topic doesn't exist.
614 """
615 if not topic_id:
616 return None
617 script = f'''
618 tell application "MindManager"
619 try
620 set theTopic to first topic of document 1 whose id is "{topic_id}"
621 set p to parent of theTopic
622 if p is not missing value then
623 return id of p
624 else
625 return ""
626 end if
627 on error
628 return ""
629 end try
630 end tell
631 '''
632 result = _run_applescript(script)
633 return result if result else None
634
635 def set_text_to_topic(self, topic_id, topic_text):
636 """
637 Set the topic's text (equivalent to topic.name.set).
638 """
639 if not topic_id:
640 return
641 safe_text = topic_text.replace('"', '\\"')
642 script = f'''
643 tell application "MindManager"
644 try
645 set theTopic to first topic of document 1 whose id is "{topic_id}"
646 set name of theTopic to "{safe_text}"
647 end try
648 end tell
649 '''
650 _run_applescript(script)
651
652 def set_title_to_topic(self, topic_id, topic_rtf):
653 """
654 Set the topic's title (equivalent to topic.title.set).
655 """
656 if not topic_id:
657 return
658 safe_text = topic_rtf.replace('"', '\\"')
659 script = f'''
660 tell application "MindManager"
661 try
662 set theTopic to first topic of document 1 whose id is "{topic_id}"
663 set title of theTopic to "{safe_text}"
664 end try
665 end tell
666 '''
667 _run_applescript(script)
668
669 def add_tag_to_topic(self, topic_id, tag_text, topic_guid):
670 pass
671
672 def set_topic_from_mindmap_topic(self, topic_id, mindmap_topic, map_icons):
673 """
674 Updates the topic's text, RTF title, and notes from `mindmap_topic`
675 via a single AppleScript call.
676 Returns (refreshed_topic_id, original_topic_id).
677 """
678 if not topic_id and not mindmap_topic:
679 return None, None
680
681 if not topic_id:
682 try:
683 self._write("writeTree", mindmap_topic)
684 return None, None
685
686 except Exception as e:
687 print(f"Error in set_topic_from_mindmap_topic: {e}")
688 return None, None
689 else:
690 try:
691 script_lines = []
692 script_lines.append('tell application "MindManager"')
693 script_lines.append(' try')
694 script_lines.append(f' set theTopic to first topic of document 1 whose id is "{topic_id}"')
695 safe_text = (mindmap_topic.text or "").replace('"', '\\"')
696 script_lines.append(f' set name of theTopic to "{safe_text}"')
697 if mindmap_topic.rtf:
698 safe_rtf = mindmap_topic.rtf.replace('"', '\\"')
699 script_lines.append(f' set title of theTopic to "{safe_rtf}"')
700 if mindmap_topic.notes:
701 safe_notes = (mindmap_topic.notes.text or "").replace('"', '\\"')
702 script_lines.append(f' set notes of theTopic to "{safe_notes}"')
703 script_lines.append(' return id of theTopic')
704 script_lines.append(' on error errMsg')
705 script_lines.append(' return ""')
706 script_lines.append(' end try')
707 script_lines.append('end tell')
708 full_script = "\n".join(script_lines)
709 refreshed_id = _run_applescript(full_script)
710 if not refreshed_id:
711 return None, None
712 return refreshed_id, topic_id
713
714 except Exception as e:
715 print(f"Error in set_topic_from_mindmap_topic: {e}")
716 return None, None
717
718 def create_map_icons(self, map_icons):
719 pass
720
721 def create_tags(self, tags: list[str], DUPLICATED_TAG: str):
722 pass
723
724 def add_relationship(self, guid1, guid2, label=''):
725 if not guid1 or not guid2:
726 print("Error in add_relationship: One or both topic IDs missing.")
727 return
728 script = f'''
729 tell application "MindManager"
730 try
731 set t1 to first topic of document 1 whose id is "{guid1}"
732 set t2 to first topic of document 1 whose id is "{guid2}"
733 if t1 is not missing value and t2 is not missing value then
734 make new relationship with properties {{starting location:t1, ending location:t2}}
735 end if
736 on error errMsg
737 return ""
738 end try
739 end tell
740 '''
741 _run_applescript(script)
742
743 def add_topic_link(self, guid1, guid2, label=''):
744 pass
745
746 def add_document(self, max_topic_level):
747 """
748 Opens the correct template based on charttype and subtopic counts.
749 """
750 if not self.document_exists():
751 cnt_subtopics = 0
752 else:
753 script_count = '''
754 tell application "MindManager"
755 set c to count of subtopics of central topic of document 1
756 return c
757 end tell
758 '''
759 res = _run_applescript(script_count)
760 try:
761 cnt_subtopics = int(res)
762 except:
763 cnt_subtopics = 0
764
765 if self._charttype == "orgchart":
766 template_alias = self._orgchart_template
767 elif self._charttype == "radial":
768 template_alias = self._radial_template
769 else:
770 # "auto"
771 if max_topic_level > 2 and cnt_subtopics > 4:
772 template_alias = self._orgchart_template
773 else:
774 template_alias = self._radial_template
775
776 safe_path = template_alias.replace('"', '\\"')
777 script_open = f'''
778 tell application "MindManager"
779 open POSIX file "{safe_path}"
780 end tell
781 '''
782 _run_applescript(script_open)
783
784 def finalize(self, max_topic_level):
785 """
786 Balance the map, activate MindManager, optionally merge windows, and clean up.
787 """
788 if not self.document_exists():
789 return
790
791 # Balance map
792 script_balance = '''
793 tell application "MindManager"
794 try
795 balance map of document 1
796 end try
797 end tell
798 '''
799 _run_applescript(script_balance)
800
801 # Activate MindManager
802 script_activate = '''
803 tell application "MindManager"
804 activate
805 end tell
806 '''
807 _run_applescript(script_activate)
808
809 # Optionally merge all windows
810 if self.MACOS_MERGE_ALL_WINDOWS:
811 self.merge_windows()
812
813 # No persistent object references to clear
814 pass