2
import gtk.glade, gtk, gobject, pango, sys, os.path, time, os, string
3
import recipeManager, convert, reccard
4
from gtk_extras import WidgetSaver, mnemonic_manager
5
from gtk_extras import dialog_extras as de
6
from gtk_extras import treeview_extras as te
7
import exporters.printer as printer
10
from gettext import gettext as _
11
#from nutrition.nutritionLabel import NutritionLabel
12
#from nutrition.nutrition import NutritionInfoList
13
from gtk_extras.FauxActionGroups import ActionManager
16
class ShopGui (ActionManager):
17
"""A class to manage our shopping window."""
18
def __init__ (self, RecGui, conv=None):
19
debug("__init__ (self, RecGui):",5)
20
self.glade = gtk.glade.XML(os.path.join(gladebase,'shopList.glade'))
21
self.init_action_manager()
22
self.mm = mnemonic_manager.MnemonicManager()
23
self.mm.add_glade(self.glade)
24
self.mm.fix_conflicts_peacefully()
29
self.data,self.pantry=self.grabIngsFromRecs([])
31
self.create_slTree(self.data)
32
self.create_pTree(self.pantry)
34
## We need to keep track of including/excluding options...
35
## Here's our solution: we have a dictionary where we can lookg
36
## up ingredients by recipe by key
37
## {'recipe_id' : {'key1' : False
38
## 'key2 : True}} ... where true and false mean include/exclude
40
self.widget = self.glade.get_widget('shopList')
41
self.stat = self.glade.get_widget('statusbar1')
42
self.contid = self.stat.get_context_id('main')
43
self.conf = [] #WidgetSavers...
44
self.conf.append(WidgetSaver.WindowSaver(self.widget,
45
self.rg.prefs.get('shopGuiWin',{}),
47
panes = ['vpaned1','hpaned1']
49
w=self.glade.get_widget(p)
50
self.conf.append(WidgetSaver.WidgetSaver(
52
self.rg.prefs.get('shop%s'%p,{'position':w.get_position()})
54
self.setup_shop_dialog()
55
self.glade.signal_autoconnect({
56
'shopHide' : self.hide,
57
'shopSave' : self.save,
58
'shopPrint' : self.printList,
59
'shopClear' : self.clear,
60
'move_to_shopping' : self.rem_selection_from_pantry,
61
'move_to_pantry' : self.add_selection_to_pantry,
62
'show_help': lambda *args: de.show_faq(HELP_FILE,jump_to='Shopping'),
63
#'show_nutritional_info': self.show_nutritional_info,
66
def init_action_manager (self):
67
ActionManager.__init__(
69
{'shopGroup':[{'shopRemove':[{'tooltip':_('Move selected items from shopping list to "pantry" list. You can also move items by dragging and dropping.')},
71
['moveToPantryButton',
72
'remove_from_shopping_list_menuitem',
73
'add_to_pantry_popup_menuitem',
76
{'pantryRemove':[{'tooltip':_('Move selected items back to the shopping list. You can also move items by dragging and dropping.')},
78
['moveToShoppingListButton',
79
'add_to_sl_popup_menuitem',
80
'return_to_shopping_menuitem',
86
[('pantryRemove',self.rem_selection_from_pantry),
87
('shopRemove',self.add_selection_to_pantry),
90
def create_rtree (self):
91
debug("create_rtree (self):",5)
92
self.rmodel = self.create_rmodel()
93
#self.rectree = gtk.TreeView(self.rmodel)
94
self.rectree = self.glade.get_widget('shopRTree')
95
self.glade.signal_connect('ingmen_pantry',self.add_selection_to_pantry)
96
self.glade.signal_connect('panmen_remove',self.rem_selection_from_pantry)
97
self.rectree.set_model(self.rmodel)
98
renderer = gtk.CellRendererText()
100
#renderer.set_property('editable',True)
101
#renderer.connect('edited',tst)
102
titl = gtk.TreeViewColumn(_("Title"),renderer,text=1)
103
mult = gtk.TreeViewColumn(_("x"),renderer,text=2)
104
self.rectree.append_column(titl)
105
self.rectree.append_column(mult)
106
titl.set_resizable(True)
107
titl.set_clickable(True)
108
titl.set_reorderable(True)
109
mult.set_resizable(True)
110
mult.set_clickable(True)
111
mult.set_reorderable(True)
112
self.rectree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
115
def create_rmodel (self):
116
debug("create_rmodel (self):",5)
117
mod = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING)
118
for r,mult in self.recs.values():
119
iter = mod.append(None)
120
mod.set_value(iter,0,r)
121
mod.set_value(iter,1,r.title)
122
mod.set_value(iter,2,convert.float_to_frac(mult))
125
# def show_nutritional_info (self, *args):
126
# """Show nutritional information for this shopping list.
128
# nl = NutritionLabel(self.rg.prefs,
129
# custom_label=_('Nutritional Information for Shopping List')
132
# for d in [self.sh.dic,self.sh.mypantry]:
133
# for k,units in d.items():
135
# ings.append([k,a,u])
136
# nutinfo = NutritionInfoList(
137
# [self.nd.get_nutinfo_for_item(*i) for i in ings]
139
# nl.set_nutinfo(nutinfo)
140
# sw = gtk.ScrolledWindow()
141
# sw.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC)
142
# sw.add_with_viewport(nl)
143
# sw.show(); nl.show()
144
# md = de.ModalDialog(title=_("Nutritional Information for Shopping List"),modal=False)
145
# md.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
146
# md.vbox.pack_start(sw,fill=True,expand=True)
147
# md.set_default_size(600,500)
151
def save (self, *args):
152
debug("save (self, *args):",5)
153
self.message('Saving')
154
self.doSave(de.select_file(_("Save Shopping List As..."),
155
filename=os.path.join(os.path.expanduser("~"),
156
"%s %s"%(_('Shopping List'),
157
time.strftime("%x").replace("/","-"),
159
action=gtk.FILE_CHOOSER_ACTION_SAVE,
161
self.message(_('Saved!'))
163
def doSave (self, filename):
164
debug("doSave (self, filename):",5)
165
#of = open(filename,'w')
166
#self.writeHeader(of,)
167
#self.sh.pretty_print(of)
168
#self.doTextPrint(of)
170
import exporters.lprprinter
171
self._printList(exporters.lprprinter.SimpleWriter,file=filename,show_dialog=False)
173
def printList (self, *args):
174
debug("printList (self, *args):",0)
175
self._printList(printer.SimpleWriter,dialog_parent=self.widget)
177
def _printList (self, printer, *args, **kwargs):
178
w = printer(*args,**kwargs)
179
w.write_header(_("Shopping list for %s")%time.strftime("%x"))
180
w.write_subheader(_("For the following recipes:"))
181
for r,mult in self.recs.values():
184
itm += _(" x%s")%mult
185
w.write_paragraph(itm)
186
write_itm = lambda a,i: w.write_paragraph("%s %s"%(a,i))
187
self.sh.list_writer(w.write_subheader,write_itm)
190
def getSelectedRecs (self):
191
"""Return each recipe in list"""
192
def foreach(model,path,iter,recs):
193
debug("foreach(model,path,iter,recs):",5)
195
rec=model.get_value(iter,0)
198
debug("DEBUG: There was a problem with iter: %s path: %s"%(iter,path),1)
200
self.rectree.get_selection().selected_foreach(foreach,recs)
201
debug("%s selected recs: %s"%(len(recs),recs),3)
204
def clear (self, *args):
205
debug("clear (self, *args):",5)
206
selectedRecs=self.getSelectedRecs()
208
for t in selectedRecs:
209
self.recs.__delitem__(t.id)
210
debug("clear removed %s"%t,3)
212
elif de.getBoolean(label=_("No recipes selected. Do you want to clear the entire list?")):
217
debug("clear cancelled",2)
219
def addRec (self, rec, mult, includes={}):
220
debug("addRec (self, rec, mult, includes={}):",5)
221
"""Add recipe to our list, assuming it's not already there.
222
includes is a dictionary of optional items we want to include/exclude."""
223
self.recs[rec.id]=(rec,mult)
224
self.includes[rec.id]=includes
227
def commit_category_orders(self,tv,space_before=None,
229
"""Commit the order of categories to memory.
230
We allow for making room before or after a given
231
iter, in which case"""
233
iter=mod.get_iter_first()
236
cat=mod.get_value(iter,0)
237
if self.sh.catorder_dic.has_key(cat):
238
# positions are all integers -- this allows changing positions
239
# to be neatly dropped in as 0.5s
240
pos = int(self.sh.catorder_dic[cat])
245
self.sh.catorder_dic[cat]=pos
246
iter=mod.iter_next(iter)
250
debug("resetSL (self):",5)
251
self.data,self.pantry = self.grabIngsFromRecs(self.recs.values(),self.extras)
252
self.slMod = self.createIngModel(self.data)
253
self.pMod = self.createIngModel(self.pantry)
254
self.slTree.set_model(self.slMod)
255
self.pTree.set_model(self.pMod)
256
self.rectree.set_model(self.create_rmodel())
257
self.slTree.expand_all()
258
self.pTree.expand_all()
259
self.pTree_sel_changed_cb(self.pTree.get_selection())
260
self.slTree_sel_changed_cb(self.slTree.get_selection())
262
def create_slTree (self, data):
263
debug("create_slTree (self, data):",5)
264
self.slMod = self.createIngModel(data)
265
self.slTree = self.create_ingTree(self.glade.get_widget('shopITree'),
267
self.slTree.connect('popup-menu',self.popup_ing_menu)
268
def slTree_popup_cb (tv, event):
269
debug("slTree_popup_cb (tv, event):",5)
270
if event.button==3 or event.type == gtk.gdk._2BUTTON_PRESS:
271
self.popup_ing_menu(tv,event)
273
self.slTree.connect('button-press-event',slTree_popup_cb)
274
self.slTree.get_selection().connect('changed',self.slTree_sel_changed_cb)
275
# reset the first time
276
self.slTree_sel_changed_cb(self.slTree.get_selection())
278
def create_pTree (self, data):
279
debug("create_pTree (self, data):",5)
280
self.pMod = self.createIngModel(data)
281
self.pTree = self.create_ingTree(self.glade.get_widget('pantryTree'),
283
self.pTree.connect('popup-menu',self.popup_pan_menu)
284
self.pTree.get_selection().connect('changed',self.pTree_sel_changed_cb)
285
# reset the first time...
286
self.pTree_sel_changed_cb(self.pTree.get_selection())
287
def pTree_popup_cb (tv, event):
288
debug("pTree_popup_cb (tv, event):",5)
289
if event.button==3 or event.type == gtk.gdk._2BUTTON_PRESS:
290
self.popup_pan_menu(tv,event)
293
self.pTree.connect('button-press-event',pTree_popup_cb)
295
def create_ingTree (self, widget, model):
296
debug("create_ingTree (self, widget, model):",5)
297
#self.slTree = gtk.TreeView(self.slMod)
299
tree.set_model(self.slMod)
300
## add multiple selections
301
tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
302
## adding drag and drop functionality
303
targets = [('GOURMET_SHOPPER_SW', gtk.TARGET_SAME_WIDGET, 0),
304
('GOURMET_SHOPPER', gtk.TARGET_SAME_APP, 1),
308
('COMPOUND_TEXT',0,5),
309
('text/unicode',0,6),]
310
tree.drag_source_set(gtk.gdk.BUTTON1_MASK, targets,
311
gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
312
tree.enable_model_drag_dest(targets,
313
gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
314
tree.connect('drag_begin', self.on_drag_begin)
315
#tree.connect('drag_data_get', self.on_drag_data_get)
316
tree.connect('drag_data_received', self.on_drag_data_received)
317
#tree.connect('drag_motion', self.on_drag_motion)
318
#tree.connect('drag_drop', self.on_drag_drop)
319
renderer = gtk.CellRendererText()
320
for n,t in [[0,'Item'],[1,'Amount']]:
321
col = gtk.TreeViewColumn(t,renderer,text=n)
322
col.set_resizable(True)
323
tree.append_column(col)
328
def slTree_sel_changed_cb (self, selection):
329
"""Callback handler for selection change on shopping treeview."""
330
if selection.count_selected_rows()>0:
331
self.shopRemove.set_sensitive(True)
332
# if we have items selected, the pantry tree should not
333
# this makes these feel more like one control/list divided
335
self.pTree.get_selection().unselect_all()
337
self.shopRemove.set_sensitive(False)
339
def pTree_sel_changed_cb (self, selection):
340
"""Callback handler for selection change on pantry treeview"""
341
if selection.count_selected_rows()>0:
342
self.pantryRemove.set_sensitive(True)
343
# if we have items selected, the shopping tree should not.
344
# this makes these feel more like one control/list divided
346
self.slTree.get_selection().unselect_all()
348
self.pantryRemove.set_sensitive(False)
350
def on_drag_begin(self, tv, context):
351
debug("on_drag_begin(self, tv, context):",5)
353
self.ssave=te.selectionSaver(self.slTree,1)
354
self.pssave=te.selectionSaver(self.pTree,1)
356
def on_drag_motion (self, tv, context, x, y, time):
357
debug("on_drag_motion (self, tv, context, x, y, time):",5)
360
def on_drag_data_get (self, tv, context, selection, info, time):
361
debug("on_drag_data_get (self, tv, context, selection, info, time):",5)
362
debug('on_drag_data_get %s %s %s %s %s'%(tv,context,selection,info,time),5)
363
self.drag_selection=selection
364
debug("Selection data: %s %s %s %s"%(self.dragged,
365
self.drag_selection.data,
366
dir(self.drag_selection),
367
self.drag_selection.get_text()),5)
369
def ingSelection (self,return_iters=False):
370
"""A way to find out what's selected. By default, we simply return
371
the list of ingredient keys. If return_iters is True, we return the selected
372
iters themselves as well (returning a list of [key,iter]s)"""
373
debug("ingSelection (self):",5)
374
def foreach(model,path,iter,selected):
375
debug("foreach(model,path,iter,selected):",5)
376
selected.append(iter)
378
self.tv.get_selection().selected_foreach(foreach,selected)
379
debug("multiple selections = %s"%selected,3)
380
#ts,itera=self.tv.get_selection().get_selected()
382
for itera in selected:
383
key=self.tv.get_model().get_value(itera, 0)
385
selected_keys.append((key,itera))
387
selected_keys.append(key)
388
debug("ingSelection returns: %s"%selected_keys,3)
391
def popup_ing_menu (self, tv, event=None, *args):
392
debug("popup_ing_menu (self, tv, *args):",5)
395
event = gtk.get_current_event()
396
t = (event and hasattr(event,'time') and getattr(event,'time')
398
btn = (event and hasattr(event,'button') and getattr(event,'button')
400
print 'self.pop.popup(None,None,None,',btn,t,')'
401
self.pop.popup(None,None,None,btn,t)
404
def popup_pan_menu (self, tv, event=None, *args):
405
debug("popup_pan_menu (self, tv, *args):",5)
408
event = gtk.get_current_event()
409
t = (event and hasattr(event,'time') and getattr(event,'time')
411
btn = (event and hasattr(event,'button') and getattr(event,'button')
413
print 'self.panpop.popup(None,None,None,',btn,t,')'
414
self.panpop.popup(None,None,None,btn,t)
417
def setup_popup (self):
418
debug("setup_popup (self):",5)
419
def make_popup (pop):
420
debug("make_popup (pop):",5)
421
catitm = gtk.MenuItem("_Change Category")
423
catitm.set_submenu(popcats)
427
for i in self.sh.get_orgcats():
428
itm = gtk.MenuItem(i)
430
itm.connect('activate',self.popup_callback,i)
432
create = gtk.MenuItem('New Category')
433
popcats.append(create)
434
create.connect('activate',self.add_sel_to_newcat)
436
self.pop=self.glade.get_widget('ingmen')
438
self.panpop = self.glade.get_widget('panmen')
439
make_popup(self.panpop)
441
def popup_callback (self, menuitem, string):
442
debug("popup_callback (self, menuitem, string):",5)
443
kk=self.ingSelection()
444
if self.sh.get_orgcats().__contains__(string):
446
self.sh.orgdic[k]=string
448
debug("WARNING: orgcats %s does not contain %s" %(self.sh.get_orgcats(), string),4)
449
ssave=te.selectionSaver(self.slTree,1)
450
pssave=te.selectionSaver(self.pTree,1)
452
ssave.restore_selections(tv=self.slTree)
453
pssave.restore_selections(tv=self.slTree)
455
def add_sel_to_newcat (self, menuitem, *args):
456
debug("add_sel_to_newcat (self, menuitem, *args):",5)
457
kk=self.ingSelection()
458
sublab = ', '.join(kk)
459
cat = de.getEntry(label=_('Enter Category'),
460
sublabel=_("Category to add %s to") %sublab,
461
entryLabel=_('Category:'),
465
self.sh.orgdic[k]=cat
466
self.pop.get_children()[-1].hide()
467
self.panpop.get_children()[-1].hide()
469
ssave=te.selectionSaver(self.slTree,1)
470
pssave=te.selectionSaver(self.pTree,1)
472
ssave.restore_selections(tv=self.slTree)
473
pssave.restore_selections(tv=self.slTree)
475
def add_selection_to_pantry (self, *args):
476
"""Add selected items to pantry."""
477
debug("add_selection_to_pantry (self, *args):",5)
478
self.tv = self.slTree
479
self.ssave=te.selectionSaver(self.slTree,1)
480
self.pssave=te.selectionSaver(self.pTree,1)
481
kk = self.ingSelection()
483
self.sh.add_to_pantry(k)
485
self.ssave.restore_selections(tv=self.pTree)
487
def rem_selection_from_pantry (self, *args):
488
"""Add selected items to shopping list."""
489
debug("rem_selection_from_pantry (self, *args):",5)
491
self.ssave=te.selectionSaver(self.slTree,1)
492
self.pssave=te.selectionSaver(self.pTree,1)
493
for k in self.ingSelection():
494
self.sh.remove_from_pantry(k)
496
self.pssave.restore_selections(tv=self.slTree)
498
def on_drag_data_received(self, tv, context,x,y,selection,info,time):
499
debug("on_drag_data_received(self, tv,context,x,y,selection,info,time):",5)
500
if str(selection.target) == 'GOURMET_SHOPPER_SW':
501
## in this case, we're recategorizing
503
dest = tv.get_dest_row_at_pos(x,y)
505
path,drop_where = dest
506
iter=tv.get_model().get_iter((path[0])) #grab the category (outside of tree)
507
cat=tv.get_model().get_value(iter,0)
508
for sel,iter in self.ingSelection(return_iters=True):
509
path=tv.get_model().get_path(iter)
511
# if we're moving an entire category, then we
512
# need to reorder categories.
513
debug("Saving new category orders",0)
514
self.commit_category_orders(tv)
515
# and now we need to move our new category into place...
516
if drop_where==gtk.TREE_VIEW_DROP_AFTER or drop_where==gtk.TREE_VIEW_DROP_INTO_OR_AFTER:
517
new_pos=self.sh.catorder_dic[cat]+0.5
519
new_pos=self.sh.catorder_dic[cat]-0.5
520
self.sh.catorder_dic[sel] = new_pos
521
debug("%s moved to position %s"%(sel,self.sh.catorder_dic[sel]),0)
522
debug("The current order is: %s"%self.sh.catorder_dic)
524
self.sh.orgdic[sel]=cat
526
self.ssave.restore_selections(tv=self.slTree)
527
self.pssave.restore_selections(tv=self.pTree)
530
debug("Out of range!",0)
531
elif str(selection.target) == 'GOURMET_SHOPPER':
532
## in this case, we're moving
534
self.add_selection_to_pantry()
536
self.rem_selection_from_pantry()
538
def on_drag_drop (self, tv, context, x, y, time):
539
debug("on_drag_drop (self, tv, context, x, y, time):",5)
540
#model = tv.get_model()
541
otv,oselection=self.dragged
542
if otv==self.pTree and tv==self.slTree:
543
self.rem_selection_from_pantry()
544
elif otv==self.slTree and tv==self.pTree:
545
self.add_selection_to_pantry()
548
path,drop_where = tv.get_dest_row_at_pos(x,y)
549
iter=tv.get_model().get_iter((path[0])) #grab the category (outside of tree)
550
cat=tv.get_model().get_value(iter,0)
551
for sel in oselection:
552
self.sh.orgdic[sel]=cat
555
self.message("Out of range! %s")
558
def createIngModel (self, data):
559
debug("createIngModel (self, data):",5)
560
"""Data is a list of lists, where each item is [ing amt]"""
561
mod = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
563
catiter = mod.append(None)
564
mod.set_value(catiter, 0, c)
568
iter = mod.append(catiter)
569
mod.set_value(iter, 0, ing)
570
mod.set_value(iter, 1, amt)
573
def grabIngsFromRecs (self, recs, start=[]):
574
debug("grabIngsFromRecs (self, recs):",5)
575
"""Handed an array of (rec . mult)s, we combine their ingredients.
576
recs may be IDs or objects."""
578
for rec,mult in recs:
579
lst.extend(self.grabIngFromRec(rec,mult=mult))
580
self.sh = recipeManager.DatabaseShopper(lst, self.rg.rd, conv=self.conv)
581
data = self.sh.organize(self.sh.dic)
582
pantry = self.sh.organize(self.sh.mypantry)
583
debug("returning: data=%s pantry=%s"%(data,pantry),5)
586
def grabIngFromRec (self, rec, mult=1):
587
"""Get an ingredient from a recipe and return a list with our amt,unit,key"""
588
"""We will need [[amt,un,key],[amt,un,key]]"""
589
debug("grabIngFromRec (self, rec=%s, mult=%s):"%(rec,mult),5)
590
# Grab all of our ingredients
591
ings = self.rg.rd.get_ings(rec)
593
include_dic = self.includes.get(rec.id) or {}
595
if hasattr(i,'refid'): refid=i.refid
597
debug("adding ing %s, %s"%(i.item,refid),4)
599
# handle boolean includes value which applies to ALL ingredients
602
if type(include_dic) == dict :
603
# Then we have to look at the dictionary itself...
604
if ((not include_dic.has_key(i.ingkey))
606
not include_dic[i.ingkey]):
607
# we ignore our ingredient (don't add it)
609
if self.rg.rd.get_amount(i):
610
amount=self.rg.rd.get_amount(i,mult=mult)
613
## a reference tells us to get another recipe
614
## entirely. it has two parts: i.item (regular name),
615
## i.refid, i.refmult (amount we multiply recipe by)
616
## if we don't have the reference (i.refid), we just
617
## output the recipe name
618
debug("Grabbing recipe as ingredient!",2)
620
subrec = self.rg.rd.get_referenced_rec(i)
621
if subrec.id == rec.id:
623
label=_('Recipe calls for itself as an ingredient.'),
624
sublabel=_('Ingredient %s will be ignored.')%rec.title + _('Infinite recursion is not allowed in recipes!'))
627
# recipe refs need an amount. We'll
629
amt = self.rg.rd.get_amount_as_float(i)
630
if not amt: amount=amt
632
if not include_dic.has_key(subrec.id):
633
d = getOptionalIngDic(self.rg.rd.get_ings(subrec),
637
include_dic[subrec.id]=d
638
nested_list=self.grabIngFromRec(subrec,
640
lst.extend(nested_list)
643
# it appears we don't have this recipe
644
debug("We don't have recipe %s"%i.item,0)
649
lst.append([amount,i.unit,i.ingkey])
650
debug("grabIngFromRec returning %s"%lst,5)
653
def show (self, *args):
654
debug("show (self, *args):",5)
657
self.widget.present()
659
self.widget.grab_focus()
661
def hide (self, *args):
662
debug("hide (self, *args):",5)
669
def setup_shop_dialog (self):
670
self.orgdic = self.sh.orgdic
671
self.sie = ShopIngredientEditor(self.rg, self)
673
def message (self, txt):
674
debug("message (self, txt): %s"%txt,5)
675
self.stat.push(self.contid,txt)
678
class OptionalIngDialog (de.ModalDialog):
679
"""A dialog to query the user about whether to use optional ingredients."""
680
def __init__ (self,vw,prefs,rg,mult=1,default=False):
681
debug("__init__ (self,vw,default=False):",5)
683
de.ModalDialog.__init__(
685
label=_("Select optional ingredients."),
686
sublabel=_("Please specify which of the following optional ingredients you'd like to include on your shopping list."))
691
self.cb = gtk.CheckButton("Always use these settings")
692
self.cb.set_active(prefs.get('remember_optionals_by_default',False))
693
alignment = gtk.Alignment()
694
alignment.set_property('xalign',1.0)
695
alignment.add(self.cb)
696
self.vbox.add(alignment)
700
def create_model (self):
701
"""Create the TreeModel to show optional ingredients."""
702
debug("create_model (self):",5)
703
self.mod = gtk.TreeStore(gobject.TYPE_PYOBJECT, #the ingredient obj
704
gobject.TYPE_STRING, #amount
705
gobject.TYPE_STRING, #unit
706
gobject.TYPE_STRING, #item
707
gobject.TYPE_BOOLEAN) #include
709
iter=self.mod.append(None)
710
self.mod.set_value(iter,0,i)
712
self.mod.set_value(iter,1,
713
self.rg.rd.get_amount_as_string(i)
716
self.mod.set_value(iter,1,
717
self.rg.rd.get_amount_as_string(i,float(self.mult))
719
self.mod.set_value(iter,2,i.unit)
720
self.mod.set_value(iter,3,i.item)
721
self.mod.set_value(iter,4,self.default)
722
self.ret[i.ingkey]=self.default
724
def create_tree (self):
725
"""Create our TreeView and populate it with columns."""
726
debug("create_tree (self):",5)
728
self.tree = gtk.TreeView(self.mod)
729
txtr = gtk.CellRendererText()
730
togr = gtk.CellRendererToggle()
731
togr.set_property('activatable',True)
732
togr.connect('toggled',self.toggle_ing_cb)
733
#togr.start_editing()
734
for n,t in [[1,'Amount'],[2,'Unit'],[3,'Item']]:
735
col = gtk.TreeViewColumn(t,txtr,text=n)
736
col.set_resizable(True)
737
self.tree.append_column(col)
738
bcol = gtk.TreeViewColumn('Add to Shopping List',
740
self.tree.append_column(bcol)
741
self.vbox.add(self.tree)
744
def toggle_ing_cb (self, cellrenderertoggle, path, *args):
745
debug("toggle_ing_cb (self, cellrenderertoggle, path, *args):",5)
746
crt=cellrenderertoggle
747
iter=self.mod.get_iter(path)
748
val = self.mod.get_value(iter,4)
750
self.ret[self.mod.get_value(iter,0).ingkey]=newval
751
self.mod.set_value(iter,4,newval)
755
if self.modal: gtk.main()
756
if self.cb.get_active() and self.ret:
757
# if we are saving our settings permanently...
758
# we add ourselves to the shopoptional attribute
762
if ing_include: self.rg.rd.modify_ing(ing,{'shopoptional':2})
763
else: self.rg.rd.modify_ing(ing,{'shopoptional':1})
766
class ShopIngredientEditor (reccard.IngredientEditor):
767
def __init__ (self, RecGui, ShopGui):
770
reccard.IngredientEditor.__init__(self, RecGui, None)
771
#self.ingBox = self.keyBox
773
def init_dics (self):
774
self.orgdic = self.sg.sh.orgdic
775
self.shopcats = self.sg.sh.get_orgcats()
777
def setup_glade (self):
778
self.glade = self.sg.glade
779
#self.glade.signal_connect('ieApply', self.apply)
781
self.amountBox = self.glade.get_widget('sdAmount')
782
self.unitBox = self.glade.get_widget('sdUnit')
783
self.keyBox = self.glade.get_widget('sdKey')
784
self.shopBox = self.glade.get_widget('sdShopCat')
785
# add some of our own signals...
786
self.glade.signal_connect('sdAdd',self.add)
787
self.sdToggle = False
788
self.glade.signal_connect('shopAdd',self.showShopDialog)
789
self.glade.signal_connect('sdHide',self.hideShopDialog)
790
self.glade.signal_connect('sdAdd',self.add)
791
self.sdW = self.glade.get_widget('ShopDialog')
792
self.keyBox.get_children()[0].connect('changed',self.setKeyList)
794
def setKeyList (self, *args):
795
self.curkey = self.keyBox.entry.get_text()
796
if self.curkey == self.last_key:
799
x= m.get_value(iter,0)
800
if x.find(self.curkey) > -1:
803
self.keyBox.get_model().set_visible_func(vis)
804
self.keyBox.get_model().refilter()
805
self.last_key=self.curkey
807
def add (self, *args):
808
amt = self.amountBox.get_text()
811
amt=convert.frac_to_float(amt)
813
reccard.show_amount_error(amt)
815
unit = self.unitBox.entry.get_text()
817
shopcat = self.shopBox.child.get_text()
819
self.rg.sl.sh.add_org_itm(key,shopcat)
821
itm = [amt, unit, key]
822
self.sg.extras.append(itm)
826
def returned (self, *args):
828
self.amountBox.grab_focus()
830
def toggleShopDialog (self, *args):
831
if self.sdToggle: self.showShopDialog()
832
else: self.hideShopDialog()
834
def showShopDialog (self,*args):
838
def hideShopDialog (self,*args):
844
def getOptionalIngDic (ivw, mult, prefs, rg):
845
"""Return a dictionary of optional ingredients with a TRUE|FALSE value
847
Alternatively, we return a boolean value, in which case that is
848
the value for all ingredients.
850
The dictionary will tell us which ingredients to add to our shopping list.
851
We look at prefs to see if 'shop_always_add_optional' is set, in which case
852
we don't ask our user."""
853
debug("getOptionalIngDic (ivw):",5)
854
#vw = ivw.select(optional=True)
855
vw = filter(lambda r: r.optional==True, ivw)
856
# optional_mode: 0==ask, 1==add, -1==dont add
857
optional_mode=prefs.get('shop_handle_optional',0)
861
elif optional_mode==-1:
864
if not None in [i.shopoptional for i in vw]:
865
# in this case, we have a simple job -- load our saved
869
if i.shopoptional==2: dic[i.ingkey]=True
870
else: dic[i.ingkey]=False
872
# otherwise, we ask our user
873
print 'Run OID with ',vw,prefs,rg,mult
874
oid=OptionalIngDialog(vw, prefs, rg,mult )
879
raise "Option Dialog cancelled!"