PyScore

001: # -*- python -*-
002: # finishescon.py # python package PyScore.timesheet module finishes.controller #
003: 
004: # PyScore
005: # a race scoring programme
006: # written by Matt Draisey
007: # 2004 April 6
008: 
009: reloadable=True
010: reloadables=[]
011: 
012: # finishescon.py # python package PyScore.timesheet module finishes.controller #
013: 
014: import gtk,pango
015: from treemodel import filttab,filttime
016: from utility import utils,guiutils
017: from timesheet import entriesmod as modeller
018: from timesheet import finishesview as view
019: 
020: # the initial model and model constants
021: 
022: view.listview[0].set_model(
023:     filttab.FiltChainTable(rows=("","DNC","DNS","OCS","DNF","RAF"))
024: )
025: view.listview[1].set_model(
026:     filttime.FiltTimeTable(proto=(20,00,00))
027: )
028: 
029: # the entry interface
030: 
031: def entry_open(protostring="20:0:0",insertionfield=None,*f):
032:     proto=tuple([utils.safe_int(t) for t in protostring.split(":",2)])
033:     assert len(proto)==3
034:     model0=filttab.FiltChainTable(rows=("","DNC","DNS","OCS","DNF","RAF"))
035:     model1=filttime.FiltTimeTable(proto=proto)
036:     bits=f[2:]
037:     s=":".join(utils.whittle(*f[:2]))
038:     if insertionfield==0:
039:         insertionpoint=len(f[0])
040:     else:
041:         insertionpoint=None
042:     reset_entry(model0,model1,s,bits,insertionpoint)
043: 
044: def entry_is_open():
045:     return is_entry()
046: 
047: def entry_tweak(protostring):
048:     proto=tuple([utils.safe_int(t) for t in protostring.split(":",2)])
049:     assert len(proto)==3
050:     tweakmodel=filttime.FiltTimeTable(proto=proto)
051:     # get old selection
052:     hstring=tweak_hysteresis()
053:     if hstring:
054:         h=tuple([utils.safe_int(t) for t in hstring.split(":",2)])
055:         assert len(h)==3
056:     else:
057:         h=None
058:     # pass on old selection to new model
059:     tweak_entry(tweakmodel,hysteresis=h)
060: 
061: def entry_close():
062:     clear_entry()
063: 
064: # constants and finishes globals # (re)initialization interface
065: 
066: basecolour=view.listview[0].get_style().base[gtk.STATE_NORMAL]
067: colcolour=gtk.gdk.color_parse("#ffcc99")
068: view.renderer[0].set_property("cell-background-gdk",colcolour)
069: 
070: class Finishes(object):
071:     model=[view.listview[i].get_model() for i in [0,1]]
072:     activecol=0
073:     currentf=["",""]
074: 
075: for i in [0,1]:
076:     if Finishes.model[i].filter_nonempty():
077:         view.listview[i].set_cursor((0,))
078: 
079: # more complex than necessary to avoid sending null default data to gui
080: #   wouldn't matter except that TreeSortModel uses an unstable sort
081: #   so you can't send it excess data without unpleasant side-effects
082: def reset_entry(model0,model1,text,bits,insertionpoint=None):
083:     view.box.set_text(text)
084:     insertionpoint=None
085:     Finishes.model[0],Finishes.model[1]=model0,model1
086:     chain=Finishes.model[0].filter_comprehend(text,insertionpoint)
087:     if len(chain)>1:
088:         chainfilter=chain[1]
089:     else:
090:         chainfilter=""
091:     if insertionpoint<>None:
092:         insertionpoint-=len(chainfilter)
093:     Finishes.model[1].filter_comprehend(chainfilter,insertionpoint)
094:     newcol=len(chain)-1
095:     assert 0<=newcol<=1
096:     # pretty background colour
097:     view.renderer[newcol].set_property("cell-background-gdk",colcolour)
098:     Finishes.activecol=newcol
099:     # set cursor
100:     for i in [0,1]:
101:         view.listview[i].set_model(Finishes.model[i])
102:         bestfit=Finishes.model[i].best_fit()
103:         view.listview[i].queue_draw()
104:         if bestfit<>None:
105:             view.listview[i].set_cursor(bestfit)
106:         else:
107:             modeller.set_finish_subentry(i,"")
108:     Finishes.currentf[0]=chain[0]
109:     Finishes.currentf[1]=chainfilter
110:     for i,b in enumerate(bits):
111:         view.toggle[i].set_active(b)
112: 
113: def is_entry():
114:     return Finishes.model[1]<>None
115: 
116: def tweak_hysteresis():
117:     if Finishes.model[1]:
118:         (r,c)=view.listview[1].get_cursor()
119:         if r:
120:             return Finishes.model[1].get_row(r)[0]
121:     return ""
122: 
123: def tweak_entry(tweakmodel,hysteresis=None):
124:     if not Finishes.model[1]: return
125:     tweakmodel.filter_comprehend(Finishes.currentf[1])
126:     if hysteresis:
127:         bestfit=tweakmodel.hysteresis_completion(hysteresis)
128:     else:
129:         bestfit=tweakmodel.best_fit()
130:     tweakrow=tweakmodel.get_row(bestfit)
131:     view.listview[1].set_model(tweakmodel)
132:     Finishes.model[1]=tweakmodel
133:     if bestfit<>None:
134:         view.listview[1].set_cursor(bestfit)
135:     else:
136:         modeller.set_finish_subentry(i,"")
137: 
138: def clear_entry():
139:     for i in [0,1]:
140:         view.listview[i].set_model(None)
141:         Finishes.model[i]=None
142:     if 0<=Finishes.activecol<=1:
143:         oldrenderer=view.renderer[Finishes.activecol]
144:         oldrenderer.set_property("cell-background-gdk",basecolour)
145:     Finishes.activecol=0
146:     Finishes.currentf=["",""]
147:     view.box.set_text("")
148: 
149: # gui callbacks
150: 
151: def on_box_changed(box):
152:     assert box==view.box
153:     if not Finishes.model[1]: return
154:     insertionpoint=None #insertionpoint=box.get_position()
155:     chain=Finishes.model[0].filter_comprehend(box.get_text(),insertionpoint)
156:     if len(chain)>1:
157:         chainfilter=chain[1]
158:     else:
159:         chainfilter=""
160:     insertionpoint=None #insertionpoint-=len(chainfilter)
161:     Finishes.model[1].filter_comprehend(chainfilter,insertionpoint)
162:     newcol=len(chain)-1
163:     assert 0<=newcol<=1
164:     # pretty background colour
165:     if newcol<>Finishes.activecol:
166:         oldrenderer=view.renderer[Finishes.activecol]
167:         oldrenderer.set_property("cell-background-gdk",basecolour)
168:         view.renderer[newcol].set_property("cell-background-gdk",colcolour)
169:         for i in [0,1]:
170:             view.listview[i].queue_draw()
171:         Finishes.activecol=newcol
172:     # set cursor
173:     # avoid unnecessarily touching fields as we want user
174:     # selected row to remain stably selected
175:     if Finishes.currentf[0]<>chain[0]:
176:         bestfit=Finishes.model[0].best_fit()
177:         if bestfit<>None:
178:             view.listview[0].set_cursor(bestfit)
179:         else:
180:             modeller.set_finish_subentry(0,"")
181:         Finishes.currentf[0]=chain[0]
182:     if Finishes.currentf[1]<>chainfilter:
183:         bestfit=Finishes.model[1].best_fit()
184:         if bestfit<>None:
185:             view.listview[1].set_cursor(bestfit)
186:         else:
187:             modeller.set_finish_subentry(1,"")
188:         Finishes.currentf[1]=chainfilter
189: 
190: def on_box_key_press(widget,event):
191:     assert widget==view.box
192:     if not Finishes.model[1]: return
193:     k=event.keyval
194:     if k in guiutils.cursor_mover:
195:         view_move_cursor(
196:             view.listview[Finishes.activecol],*guiutils.cursor_mover[k]
197:         )
198:         return 1
199: 
200: def view_move_cursor(tree,*mover):
201:     active=Finishes.activecol
202:     assert tree==view.listview[active]
203:     if not Finishes.model[1]: return
204:     if Finishes.model[active].filter_nonempty():
205:         rsize=Finishes.model[active].filtered_size()
206:         (r,c)=view.listview[active].get_cursor()
207:         r=guiutils.page_cursor_move(r,rsize,*mover)
208:         view.listview[active].set_cursor(r,c)
209:     return 1
210: 
211: def on_view_cursor_changed(tree,i):
212:     assert tree==view.listview[i]
213:     (r,c)=view.listview[i].get_cursor()
214:     row=Finishes.model[i].get_row(r)
215:     modeller.set_finish_subentry(i,*row)
216: 
217: def on_toggle(checkbutton,i):
218:     assert checkbutton==view.toggle[i]
219:     b=view.toggle[i].get_active()
220:     modeller.set_finish_toggle(i,b)
221: 
222: ######## register reloadables ########
223: 
224: reloadables+=[guiutils]
225: reloadables+=[filttab,filttime,utils]
226: 
227: # finishescon.py # python package PyScore.timesheet module finishes.controller #