Not sure how many other folks want to import from iThoughts to OmniPlan, but I decided to post the scripts. Basically, it’s a two step process and, in addition to iThoughts and OmniPlan, you also need Pyto (I suspect it can be easily adapted to other iOS Python implementations, but that’s the one I used).
The Python script opens the iThoughts .itmz file (the format is undocumented, so how long this will work is anyone’s guess) and creates a .json file.
The Omni Automation plug-in loads data from the .json file into OmniPlan. The plug-in works, so far, under OmniPlan 3 and the Testflight version of OmniPlan 4.
The following information is copied from iThoughts:
- Topic name as task name (note that the main topic becomes the project name)
- Notes
- Start date as a Start at earliest constraint
- Due date as an End at latest constraint
- Effort
- Cost as Task Cost
- Progress as Completion
- Priority as Leveling Priority
- Resources
- A finish-start dependency is added for topics joined by a relationship
The Python script follows, since I can’t attach it. The Omni Automation plug-in is attached.iThoughtsJSON.omnijs (5.1 KB)
# This script extracts the overall map structure
# and project-related attributes from an
# iThoughts .itmz file in JSON format. The
# intended use is with a companion omnijs
# plugin that subsequently loads the JSON into OmniPlan.
# Note that the output file is named based on the root
# node of the map (so probably best to avoid any characters that
# doesn't work well in a file name) and it will appear
# in the pyto folder.
# While most of the code should be generic,
# the bookmarks module, which is basically an
# iOS file picker that remembers the last selection, is
# specific to pyto, as far as I know.
# The format of the .itmz file, which is actually a zip
# archive, and the mapdata.xml file contained
# within are undocumented and may very well change.
# There should be no expectation that this script is fit for any
# purpose. It may not even serve as a warning to others of the
# dangers of poor software development practice.
import zipfile
import bookmarks as bm
from lxml import etree
import json
resources = set()
def format_task(t, n, td, r):
topics = t.xpath('./topic')
if len(topics) == 0 :
return
td['topics'] = []
for topic in topics:
t_dict = {}
t_dict['uuid'] = topic.get('uuid')
t_dict['text'] = topic.get('text')
note = topic.get('note')
if note:
t_dict['note'] = note
progress = topic.get('task-progress')
if progress:
t_dict['progress'] = progress
effort = topic.get('task-effort')
if effort:
t_dict['effort'] = effort
start = topic.get('task-start')
if start:
t_dict['start'] = start
due = topic.get('task-due')
if due:
t_dict['due'] = due
resources = topic.get('resources')
if resources:
res = resources.split(',')
t_dict['resources'] = res
r.update(res)
priority = topic.get('task-priority')
if priority:
t_dict['priority'] = priority
cost = topic.get('cost')
costType = topic.get('cost-type')
if cost and costType and costType == '1':
t_dict['cost'] = cost
nn = n + 1
format_task(topic,nn,t_dict, r)
td['topics'].append(t_dict)
itmz_file = bm.FileBookmark("my_itmz_file").path
with zipfile.ZipFile(itmz_file) as myzip:
with myzip.open('mapdata.xml') as mydata:
content = {}
mapdata = etree.parse(mydata)
root = mapdata.getroot()
topics = root.xpath('//topics/topic')
topic_list = []
for topic in topics:
t_dict = {}
t_dict['uuid'] = topic.get('uuid')
top = topic.get('text')
t_dict['text'] = top
format_task(topic, 0, t_dict, resources)
topic_list.append(t_dict)
rels = root.xpath('//relationships/relationship')
rel_list = []
for rel in rels:
r_dict = {}
r_dict['uuid1'] = rel.get('end1-uuid')
r_dict['uuid2'] = rel.get('end2-uuid')
r_dict['style1'] = rel.get('end1-style')
r_dict['style2'] = rel.get('end2-style')
r_dict['type'] = rel.get('type')
rel_list.append(r_dict)
content['topics'] = topic_list
content['resources'] = sorted(resources)
content['relationships'] = rel_list
json_file = open(top + '.json', 'w')
json.dump(content, json_file)
json_file.close()
print('Done converting iThoughts file. Output in ' + top + '.json')
# We don't want to remember our file selection for next time
bm.FileBookmark("my_itmz_file").delete_from_disk()