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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# Copyright 2005-2008 Nanorex, Inc. See LICENSE file for details.
"""
prefsTree.py -- experimental code related to showing
user preferences in the model tree
(not presently used as of 050612, but works; very incomplete)
@author: Bruce
@version: $Id$
@copyright: 2005-2008 Nanorex, Inc. See LICENSE file for details.
History:
bruce 050613 started this.
Module classification: [bruce 071215]
Tentatively, "model", though arguably it also contains ui code.
Used by model_tree but also in assembly (which is in "model").
Perhaps ought to be split into two files?
"""
import os
from foundation.Utility import Node
from foundation.Group import Group
from model.part import Part
from utilities.constants import noop, dispLabel, default_display_mode
import foundation.env as env
_debug_prefstree = True # safe for commit even when True
class PrefNode(Node):
"""
Leaf node for storing a local change to a single preference attribute
"""
#e or is PrefsGroup the same class? not sure...
## no_selgroup_is_ok = True
def __init__(self, assy, name = "prefnode"):
Node.__init__(self, assy, name)
return
def __CM_Add_Node(self):
self.addsibling( PrefNode(self.assy, "prefnode") )
pass
class PrefChoiceNode(PrefNode):
"""
A PrefNode which lets the user choose one of a small finite set of choices
using its cmenu (or maybe in other ways too?)
"""
def __init__(self, assy, name, choices = None, default_name = None, defaultValue = None, typename = None ):
PrefNode.__init__(self, assy, name)
self.choices = choices or [('No choices!', None)]
self.choicedict = {}
self.typename = typename #k not used?
for name, val in self.choices:
self.choicedict[name] = val
if default_name is not None:
self.default_name = default_name
self.defaultValue = self.choicedict[default_name] # it better be in there!
elif defaultValue is not None or None in self.choicedict.values():
for name, val in self.choices:
if val == defaultValue:
self.default_name = name
self.defaultValue = val
break
else:
self.default_name, self.defaultValue = self.choices[0]
return
def __cmenu_items(self): ###IMPLEM a call of this
submenu = []
for choice in self.choicelist:
submenu.append((choice, noop)) ###noop -> lambda
res = []
res.append(("choices",submenu))
return res
pass
# these exprs are of the form [ class, opts( opt1 = val1, ... ) ]
def opts(**kws):
return dict(kws)
bool_choice = [ PrefChoiceNode, opts(
typename = "boolean", #??
choices = [('True', True), ('False', False)],
default_name = 'False'
)]
# not very useful, better to use checkmark presence or not on the pref item itself, not this submenu from it
# (that requires using the QListViewItem subclass with a checkmark)
# or alternatively, having a submenu with some boolean toggle items in it (our menu_spec could offer that option)
dispmode_choice = [ PrefChoiceNode, opts(
typename = "display mode",
choices = zip( dispLabel, range(len(dispLabel)) ),
defaultValue = default_display_mode
)]
# ==
class PrefsGroup(Group):
"""
Group node for storing a set of local changes to preference attributes
"""
## no_selgroup_is_ok = True
def __init__(self, assy, name): # arg order is like Node, not like Group
dad = None
Group.__init__(self, name, assy, dad)
# dad arg is required (#e should not be) and arg order is inconsistent (should not be)
def __CM_Add_Node(self):
self.addchild( PrefNode(self.assy, "prefnode") )
self.assy.w.mt.mt_update() #k why needed? (and does it help?)
pass
# ==
# print _node._MainPrefsGroup__CM_Save_Prefs()
def prefsPath(assy):
return os.path.join( assy.w.tmpFilePath, "Preferences", "prefs.mmp" ) #e use common code for the dir
class MainPrefsGroup(PrefsGroup): # kind of like PartGroup; where do we say it's immortal? in the part, not the node.
def is_top_of_selection_group(self): return True
def rename_enabled(self): return False
def drag_move_ok(self): return False
def permits_ungrouping(self): return False
def description_for_history(self):
"""
[overridden from Group method]
"""
return "Preferences"
def __CM_Save_Prefs(self):
"""
[temporary kluge, should autosave whenever changed, or from dialog buttons]
save this node's part into a constant-named mmp file in prefs dir
(for now -- details of where/how it saves them is private and might change)
"""
path = prefsPath(self.assy)
self.part.writemmpfile( path) ####@@@@ need options? their defaults were changed on 051209 w/o reviewing this code.
env.history.message( "saved Preferences Group" )
# kluge: zap some useless cmenu items for this kind of node (activates special kluge in mtree cmenu maker)
__CM_Hide = None
__CM_Group = None
__CM_Ungroup = None
pass
class MainPrefsGroupPart(Part):
"""
[public, meant to be imported and used by code in assembly.py]
"""
def immortal(self): return True
def glpane_label_text(self):
return "(preferences area; not in the mmp file)"
def location_name(self):
return "prefs tree" #k used??
def movie_suffix(self):
"""
what suffix should we use in movie filenames? None means don't permit making them.
"""
None #k does this still work?
pass
def prefsTree(assy):
"""
Make or return the prefsTree object for the given assy
"""
#e really there should be a single one per session, but this should work
try:
## assert isinstance(assy.prefsTree, prefsTree_class) # multiple ways this can fail, and that's normal
# above messes up reloading, so do this instead:
assert assy.prefsTree.__class__.__name__ == "prefsTree_class"
return assy.prefsTree
except:
if _debug_prefstree:
print "remaking prefsTree object for", assy # this is normal
pass
assy.prefsTree = prefsTree_class(assy)
assy.prefs_node = assy.prefsTree.topnode #e might be better for assy to look it up this way itself
assy.update_parts()
# this will set assy.prefs_node.part to a MainPrefsGroupPart instance, if it has no .part yet (as we expect)
return assy.prefsTree
class prefsTree_class:
topnode = None
def __init__(self, assy):
self.assy = assy
self.topnode = MainPrefsGroup(assy, "Preferences")
path = prefsPath(self.assy)
stuff = read_mmp_single_part( assy, path) # a list of one ordinary group named Preferences
(prefsgroup,) = stuff
mems = prefsgroup.steal_members()
for mem in mems:
self.topnode.addchild( mem)
pass
def read_mmp_single_part(assy, filename):
from files.mmp.files_mmp import readmmp
# start incredible kluge block
history = env.history
#bruce 050901 revised this.
# It depends on there being only one active history object at a time.
# (Before 050913, that object was stored as both env.history and win.history.)
oldmessage = history.message
from utilities.constants import noop
history.message = noop # don't bother user with this file being nonstd (bad, should pass a flag, so other errors seen)
try:
ok, grouplist = readmmp(assy, filename, isInsert = True)
finally:
history.message = oldmessage
if grouplist:
viewdata, mainpart, shelf = grouplist
return mainpart.steal_members() # a python list of whatever toplevel stuff was in the mmp file
return None
# need object to describe available state in the program, and its structure as a tree
# (eg list of modes available; widget layout; rendering loop -- this is partly user-mutable and partly not)
# and then the prefsnodes are an interface to that object,
# and can load their state from it or save their state to it.
# it might also be nodes, not sure
# ==
# remaking nodes destroys any renames I did for them, would mess up DND results too --
# need to keep them around and update them instead (ok if I remake the owner object, though)
# or perhaps let them be proxies for other state (harder, but might be needed anyway, to save that state)
# end
|