-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathomni_interface.py
More file actions
203 lines (170 loc) · 7.37 KB
/
omni_interface.py
File metadata and controls
203 lines (170 loc) · 7.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import appscript
from data_structures import *
class OmniGraffleInterface(object):
"""
Abstracts OmniGraffle specific parsing and editing.
"""
# OmniGraffle appscript instance
og = None
def __init__(self, name=None):
try:
if name:
self.og = appscript.app(name)
else:
try:
self.og = appscript.app('OmniGraffle.app')
except:
self.og = appscript.app('OmniGraffle Professional 5.app')
except:
raise "Could not find OmniGraffle application"
def create_graffle(self, AObjects, write_fields_in_object=True):
"""
Writes AObjects to OmniGraffle file via appscript
1. First pass writes object shapes
2. Second pass writes arrows
3. Does layout
"""
self.og.make(new=appscript.k.document)
main_doc = self.og.windows.first.get()
# AObject -> omni node
nodes = {}
""" write OmniGraffle file """
for aobject in AObjects:
n = self._write_node(main_doc, aobject, write_fields_in_object=write_fields_in_object)
nodes[aobject] = n
for aobject in AObjects:
for afield in aobject.fields:
if afield.dest:
if afield.dest in nodes:
self._write_edge(nodes[aobject], nodes[afield.dest], afield.dest.color)
# adjust pages automatically based on node layout
main_doc.adjusts_pages.set(True)
# set automatic layout
main_doc.layout_info.get().type.set(appscript.k.force_directed)
#main_doc.layout_info.get().automatic_layout.set(True)
self.og.layout(main_doc.graphics)
def update_graffle(self, AObjects, filename):
"""
Updates OmniGraffle file based on AObjects
First Pass:
1. Iterate through existing OG nodes
-> If there is a matching AObject
remove existing fields, relations
2. Create nodes for AObjects without matches
Second Pass:
1. Iterate through OG node/AObject pairs from first pass
-> add fields and relations
"""
self.og.open(filename)
main_doc = self.og.windows.first.get()
#todo
def load_aobjects(self, filename=None):
"""
Loads OmniGraffle file into AObjects
1. Iterate over groups to construct AObjects with dest-less fields
2. Iterate over AObjects, reconstruct field types and dest links as appropriate
@return: list of AObjects
"""
if filename:
self.og.open(filename)
main_doc = self.og.windows.first.get()
# group -> AObject
group_aobj_dict = {}
#### 1. Construct AObject for each graphic
for group in main_doc.groups.get():
n0 = group.graphics.get()[0]
n1 = group.graphics.get()[1]
if ':' in n0.text.get():
fields = n0
name = n1
else:
fields = n1
name = n0
# retrieve AObject name
ao = AObject(name.text.get())
# retrieve AObject fields
for fullfield in fields.text.get().split('\n'):
name = fullfield.split(':')[0].strip()
type = fullfield.split(':')[1].strip()
if type[:-1] == 'F': # CharF, IntegerF
type = "%sield" % type # CharField, IntegerField
# do this in second pass
#elif type[:2] == '->':
# type = "ForeignKey"
# dest = AObject with name == type[2:]
ao.add_field(name=name, type=type)
group_aobj_dict[group] = ao
#### 2. Recreate AField destination links
for group, ao in group_aobj_dict.items():
for field in ao.fields:
if field.type[:2] == '->':
dest_name = field.type[2:]
# find destination AObject
for line in group.outgoing_lines.get():
dest_ao = group_aobj_dict[line.destination.get()]
# check if this is the right line for the field type
if dest_ao.name == dest_name:
field.dest = dest_ao
field.type = 'ForeignKey'
return group_aobj_dict.values()
def _write_node(self, document, aobject, write_fields_in_object=True):
"""
creates two nodes, one for name, one for list of fields,
and assembles them into a single node group
@return: group
"""
properties = {appscript.k.text: aobject.name,
appscript.k.autosizing: appscript.k.full,
appscript.k.draws_shadow: True,
#appscript.k.color: (1, 0, 0),
appscript.k.fill_color: aobject.color,
#appscript.k.text_color: (0, 0, 1),
appscript.k.name: aobject.shape}
n_name = document.make(new=appscript.k.shape,
#at=document.graphics.first,
with_properties=properties)
field_names = []
for f in aobject.fields:
# this needs to be reversible
if f.type[:-5] == 'Field': # CharField, IntegerField
type = f.type[:-4] # CharF, IntegerF
elif f.type == 'ForeignKey' and f.dest: # ForeignKey (to AObject named User)
type = "->%s" % f.dest.name # eg ->User, ->Post
else:
type = f.type
field_names.append("%s: %s" % (f.name, type))
#field_names = ["%s: %s" % (f.name, type) for f in aobject.fields]
properties2 = {appscript.k.text: '\n'.join(field_names),
appscript.k.autosizing: appscript.k.full,
appscript.k.draws_shadow: True}
if write_fields_in_object:
n_fields = document.make(new=appscript.k.shape,
#at=document.graphics.first,
with_properties=properties2)
# set widths to be the same
max_width = max(n_fields.size.get()[0], n_name.size.get()[0])
n_name.size.set([max_width, n_name.size.get()[1]])
n_fields.size.set([max_width, n_fields.size.get()[1]])
# position field node beneath name node
# same x as name, add height to y
n_fields.origin.set([n_name.origin.get()[0],
n_name.origin.get()[1] + n_name.size.get()[1]])
# assemble
return document.assemble([n_name, n_fields])
else:
return n_name
def _write_edge(self, og_src, og_dest, color):
if color == (1, 1, 1):
color = (0, 0, 0)
properties = {appscript.k.line_type: appscript.k.curved,
appscript.k.tail_type: 0,
appscript.k.head_type:"FilledArrow",
appscript.k.stroke_color: color,
appscript.k.thickness: 5}
#print "og_src", og_src
#print " dest", og_dest
#print dir(og_src)
self.og.connect(og_src,
to=og_dest,
with_properties=properties)
# og.layout(doc.document.pages.first)