Module todo
[hide private]
[frames] | no frames]

Source Code for Module todo

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2005 Joe Pham <djpham@netzero.net> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: todo.py 4459 2007-11-24 07:55:33Z djpham $ 
  9   
 10  """ 
 11  Code to handle Todo Items 
 12   
 13  The format for the Todo items is standardized.  It is a dict with the following 
 14  fields: 
 15   
 16  TodoEntry properties: 
 17  summary - 'string subject' 
 18  note - 'string note' 
 19  due_date - 'YYYYMMDD' 
 20  status - (None, NotStarted, InProgress, NeedActions, Completed, Cancelled) 
 21  percent_complete - None, range(101) 
 22  completion_date - 'YYYYMMDD' 
 23  categories - [{ 'category': string }] 
 24  private - True/<False|None> 
 25  priority - range(1, 11) 1=Highest, 5=Normal, 10=Lowest 
 26   
 27  TodoEntry Methods: 
 28  get() - return a copy of the internal dict 
 29  set(dict) - set the internal dict 
 30  check_completion() - check the task for completion and if so set appropriate 
 31                       values 
 32  completion() - set the task as completed and set appropriate values 
 33   
 34  To implement Todo read/write for a phone module: 
 35   Add 2 entries into Profile._supportedsyncs: 
 36          ... 
 37          ('todo', 'read', None),     # all todo reading 
 38          ('todo', 'write', 'OVERWRITE')  # all todo writing 
 39   
 40  implement the following 2 methods in your Phone class: 
 41      def gettodo(self, result): 
 42          ... 
 43          return result 
 44   
 45      def savetodo(self, result, merge): 
 46          ... 
 47          return result 
 48   
 49  The result dict key is 'todo'. 
 50   
 51  """ 
 52   
 53  # standard modules 
 54  from __future__ import with_statement 
 55  import copy 
 56  import datetime 
 57  import time 
 58   
 59  # wx modules 
 60  import wx 
 61  import wx.lib.calendar 
 62  import wx.calendar as cal 
 63  import wx.lib.scrolledpanel as scrolled 
 64   
 65  # BitPim modules 
 66  import calendarentryeditor as cal_editor 
 67  import database 
 68  import guihelper 
 69  import helpids 
 70  import field_color 
 71  import phonebookentryeditor as pb_editor 
 72  import pubsub 
 73  import today 
 74  import guihelper 
 75  import widgets 
 76   
 77  widgets_list=[] 
 78   
 79  #------------------------------------------------------------------------------- 
80 -class TodoDataObject(database.basedataobject):
81 _knownproperties=['summary', 'note', 'due_date', 'status', 82 'percent_complete', 'completion_date', 'priority' ] 83 _knownlistproperties=database.basedataobject._knownlistproperties.copy() 84 _knownlistproperties.update( {'categories': ['category'], 85 'flags': ['secret'] }) 86
87 - def __init__(self, data=None):
88 if data is None or not isinstance(data, TodoEntry): 89 return; 90 self.update(data.get_db_dict())
91 todoobjectfactory=database.dataobjectfactory(TodoDataObject) 92 93 #-------------------------------------------------------------------------------
94 -class TodoEntry(object):
95 ST_NotStarted=1 96 ST_InProgress=2 97 ST_NeedActions=3 98 ST_Completed=4 99 ST_Cancelled=5 100 ST_Last=6 101 ST_Range=xrange(ST_NotStarted, ST_Last) 102 ST_Names=( 103 '<None>', 'Not Started', 'In Progess', 'Need Actions', 104 'Completed', 'Cancelled', 'LAST') 105 PC_Range=xrange(101) # % Complete: 0-100% 106 PR_Range=xrange(1, 11) 107 _id_index=0 108 _max_id_index=999 109
110 - def __init__(self):
111 self._data={ 'serials': [] } 112 self._create_id()
113
114 - def get(self):
115 return copy.deepcopy(self._data, {})
116 - def set(self, d):
117 self._data={} 118 self._data.update(d)
119
120 - def get_db_dict(self):
121 return self.get()
122 - def set_db_dict(self, d):
123 self.set(d)
124
125 - def complete(self):
126 # complete this task: set relevant values to indicate so 127 if self.status != self.ST_Completed: 128 self.status=self.ST_Completed 129 if self.percent_complete != 100: 130 self.percent_complete=100 131 if not len(self.completion_date): 132 self.completion_date=datetime.date.today().strftime('%Y%m%d')
133
134 - def check_completion(self):
135 if self.status==self.ST_Completed or self.percent_complete==100 or \ 136 len(self.completion_date): 137 self.complete()
138
139 - def _set_or_del(self, key, v, v_list=[]):
140 if v is None or v in v_list: 141 if self._data.has_key(key): 142 del self._data[key] 143 else: 144 self._data[key]=v
145
146 - def _create_id(self):
147 "Create a BitPim serial for this entry" 148 self._data.setdefault("serials", []).append(\ 149 {"sourcetype": "bitpim", 150 "id": '%.3f%03d'%(time.time(), TodoEntry._id_index) }) 151 if TodoEntry._id_index<TodoEntry._max_id_index: 152 TodoEntry._id_index+=1 153 else: 154 TodoEntry._id_index=0
155 - def _get_id(self):
156 s=self._data.get('serials', []) 157 for n in s: 158 if n.get('sourcetype', None)=='bitpim': 159 return n.get('id', None) 160 return None
161 id=property(fget=_get_id) 162
163 - def _get_summary(self):
164 return self._data.get('summary', '')
165 - def _set_summary(self, v):
166 self._set_or_del('summary', v, [''])
167 summary=property(fget=_get_summary, fset=_set_summary) 168
169 - def _get_note(self):
170 return self._data.get('note', '')
171 - def _set_note(self, v):
172 self._set_or_del('note', v, [''])
173 note=property(fget=_get_note, fset=_set_note) 174
175 - def _get_due_date(self):
176 return self._data.get('due_date', '')
177 - def _set_due_date(self, v):
178 self._set_or_del('due_date', v, [''])
179 due_date=property(fget=_get_due_date, fset=_set_due_date) 180
181 - def _get_status(self):
182 return self._data.get('status', None)
183 - def _set_status(self, v):
184 if v is not None and v not in self.ST_Range: 185 raise ValueError, 'Illegal Status Value' 186 self._set_or_del('status', v, []) 187 if v==self.ST_Completed: 188 self.complete()
189 status=property(fget=_get_status, fset=_set_status)
190 - def is_active(self):
191 _status=self.status 192 return _status!=self.ST_Completed and _status!=self.ST_Cancelled
193
194 - def _get_percent_complete(self):
195 return self._data.get('percent_complete', None)
196 - def _set_percent_complete(self, v):
197 if v is not None and v not in self.PC_Range: 198 raise ValueError, 'Illegal Percent Complete Value' 199 self._set_or_del('percent_complete', v, []) 200 if v==100: 201 self.complete()
202 percent_complete=property(fget=_get_percent_complete, 203 fset=_set_percent_complete) 204
205 - def _get_completion_date(self):
206 return self._data.get('completion_date', '')
207 - def _set_completion_date(self, v):
208 self._set_or_del('completion_date', v, ['']) 209 if v is not None and len(v): 210 self.complete()
211 completion_date=property(fget=_get_completion_date, 212 fset=_set_completion_date) 213
214 - def _get_priority(self):
215 return self._data.get('priority', None)
216 - def _set_priority(self, v):
217 if v is not None and v not in self.PR_Range: 218 raise ValueError, 'Illegal priority value' 219 self._set_or_del('priority', v, [])
220 priority=property(fget=_get_priority, fset=_set_priority) 221
222 - def _get_categories(self):
223 return self._data.get('categories', [])
224 - def _set_categories(self, s):
225 self._set_or_del('categories', s,[]) 226 if not s and self._data.has_key('categories'): 227 del self._data['categories']
228 categories=property(fget=_get_categories, fset=_set_categories) 229
230 - def _get_secret(self):
231 f=self._data.get('flags', []) 232 for n in f: 233 if n.has_key('secret'): 234 return n['secret'] 235 return False
236 - def _set_secret(self, v):
237 f=self._data.get('flags', []) 238 for i, n in enumerate(f): 239 if n.has_key('secret'): 240 if v is None or not v: 241 del f[i] 242 if not self._data['flags']: 243 del self._data['flags'] 244 else: 245 n['secret']=v 246 return 247 if v is not None and v: 248 self._data.setdefault('flags', []).append({'secret': v})
249 private=property(fget=_get_secret, fset=_set_secret)
250 251 #-------------------------------------------------------------------------------
252 -class StatusComboBox(wx.ComboBox):
253 - def __init__(self, parent, _=None):
254 self._choices=[TodoEntry.ST_Names[x] for x in range(TodoEntry.ST_Last)] 255 super(StatusComboBox, self).__init__(parent, -1, 256 self._choices[0], 257 (-1, -1), (-1, -1), 258 self._choices, wx.CB_READONLY) 259 wx.EVT_COMBOBOX(self, self.GetId(), parent.OnMakeDirty)
260 - def GetValue(self):
261 s=super(StatusComboBox, self).GetValue() 262 for v,n in enumerate(self._choices): 263 if n==s: 264 break; 265 if v: 266 return v 267 else: 268 return None
269 - def SetValue(self, v):
270 if v is None: 271 v=0 272 super(StatusComboBox, self).SetValue(self._choices[v])
273 274 #-------------------------------------------------------------------------------
275 -class PercentCompleteBox(wx.ComboBox):
276 - def __init__(self, parent, _=None):
277 self. _choices=['<None>', '0%', '10%', '20%', '30%', '40%', 278 '50%', '60%', '70%', '80%', '90%', '100%'] 279 super(PercentCompleteBox, self).__init__(parent, -1, self._choices[0], 280 (-1,-1), (-1,-1), 281 self._choices, wx.CB_READONLY) 282 wx.EVT_COMBOBOX(self, self.GetId(), parent.OnMakeDirty)
283 - def GetValue(self):
284 s=super(PercentCompleteBox, self).GetValue() 285 for v,n in enumerate(self._choices): 286 if n==s: 287 break 288 if v: 289 return (v-1)*10 290 else: 291 return None
292 - def SetValue(self, v):
293 if v is None: 294 v=0 295 else: 296 v=(v/10)+1 297 super(PercentCompleteBox, self).SetValue(self._choices[v])
298 299 #-------------------------------------------------------------------------------
300 -class PriorityBox(wx.ComboBox):
301 - def __init__(self, parent, _= None):
302 self._choices=['<None>', '1 - Highest', '2', '3', '4', '5 - Normal', 303 '6', '7', '8', '9', '10 - Lowest'] 304 super(PriorityBox, self).__init__(parent, -1, self._choices[0], 305 (-1, -1), (-1, -1), 306 self._choices, wx.CB_READONLY) 307 wx.EVT_COMBOBOX(self, self.GetId(), parent.OnMakeDirty)
308 - def GetValue(self):
309 s=super(PriorityBox, self).GetValue() 310 for v,n in enumerate(self._choices): 311 if n==s: 312 break 313 if v: 314 return v 315 else: 316 return None
317 - def SetValue(self, v):
318 if v is None: 319 v=0 320 super(PriorityBox, self).SetValue(self._choices[v])
321 322 #-------------------------------------------------------------------------------
323 -class DateControl(wx.Panel, widgets.BitPimWidget):
324 - def __init__(self, parent, _=None):
325 super(DateControl, self).__init__(parent, -1) 326 self._dt=None 327 # main box sizer, a label, and a button 328 self._hs=wx.BoxSizer(wx.HORIZONTAL) 329 self._date_str=wx.StaticText(self, -1, '<None>') 330 self._date_btn=wx.Button(self, -1, 'Set Date') 331 self._hs.Add(self._date_str, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) 332 self._hs.Add(self._date_btn, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) 333 # events 334 wx.EVT_BUTTON(self, self._date_btn.GetId(), self._OnSetDate) 335 # all done 336 self.SetSizer(self._hs) 337 self.SetAutoLayout(True)
338 - def _refresh(self):
339 if self._dt is None: 340 s='<None>' 341 else : 342 s=self._dt.strftime('%Y-%m-%d') 343 self._date_str.SetLabel(s) 344 self._hs.Layout() 345 self.GetParent().OnMakeDirty(None)
346 - def _OnSetDate(self, _):
347 # bring up a calendar dlg 348 if self._dt is None: 349 dt=datetime.date.today() 350 else: 351 dt=self._dt 352 with guihelper.WXDialogWrapper(wx.lib.calendar.CalenDlg(self, 353 month=dt.month, 354 day=dt.day, 355 year=dt.year)) as dlg: 356 dlg.Centre() 357 if dlg.ShowModal() == wx.ID_OK: 358 self._dt=datetime.date(dlg.calend.GetYear(), 359 dlg.calend.GetMonth(), 360 dlg.calend.GetDay()) 361 self._refresh()
362 - def SetValue(self, v):
363 # set a date string from the dict 364 if v is None or not len(v): 365 self._dt=None 366 else: 367 self._dt=datetime.date(int(v[:4]), int(v[4:6]), int(v[6:])) 368 self._refresh()
369 - def GetValue(self):
370 # return a date string YYYYMMDD 371 if self._dt is None: 372 return '' 373 return self._dt.strftime('%Y%m%d')
374 375 #-------------------------------------------------------------------------------
376 -class DirtyCheckBox(wx.CheckBox):
377 - def __init__(self, parent, _=None):
378 super(DirtyCheckBox, self).__init__(parent, -1) 379 wx.EVT_CHECKBOX(self, self.GetId(), parent.OnMakeDirty)
380 381 #-------------------------------------------------------------------------------
382 -class GeneralEditor(pb_editor.DirtyUIBase):
383 _dict_key_index=0 384 _label_index=1 385 _class_index=2 386 _get_index=3 387 _set_index=4 388 _w_index=5 389 _flg_index=6 390
391 - def __init__(self, parent, _=None):
392 global widgets_list 393 394 super(GeneralEditor, self).__init__(parent) 395 self._fields=[ 396 ['summary', 'Summary:', cal_editor.DVTextControl, None, None, None, wx.EXPAND], 397 ['status', 'Status:', StatusComboBox, None, None, None, 0], 398 ['due_date', 'Due Date:', DateControl, None, None, None, wx.EXPAND], 399 ['percent_complete', '% Complete:', PercentCompleteBox, None, None, None, 0], 400 ['completion_date', 'Completion Date:', DateControl, None, None, None, wx.EXPAND], 401 ['private', 'Private:', DirtyCheckBox, None, None, None, 0], 402 ['priority', 'Priority:', PriorityBox, None, None, None, 0] 403 ] 404 gs=wx.FlexGridSizer(-1, 2, 5, 5) 405 gs.AddGrowableCol(1) 406 for n in self._fields: 407 _txt=wx.StaticText(self, -1, n[self._label_index], 408 style=wx.ALIGN_LEFT) 409 widgets_list.append((_txt, n[self._dict_key_index])) 410 gs.Add(_txt, 0, wx.EXPAND|wx.BOTTOM, 0) 411 w=n[self._class_index](self, -1) 412 gs.Add(w, 0, n[self._flg_index]|wx.BOTTOM, 5) 413 n[self._w_index]=w 414 # event handlers 415 # all done 416 self.SetSizer(gs) 417 self.SetAutoLayout(True) 418 gs.Fit(self)
419
420 - def OnMakeDirty(self, evt):
421 self.OnDirtyUI(evt)
422
423 - def Set(self, data):
424 self.ignore_dirty=True 425 if data is None: 426 for n in self._fields: 427 n[self._w_index].Enable(False) 428 else: 429 for n in self._fields: 430 w=n[self._w_index] 431 w.Enable(True) 432 w.SetValue(getattr(data, n[self._dict_key_index])) 433 self.ignore_dirty=self.dirty=False
434
435 - def Get(self, data):
436 self.ignore_dirty=self.dirty=False 437 if data is None: 438 return 439 for n in self._fields: 440 w=n[self._w_index] 441 v=w.GetValue() 442 ## if v is not None: 443 setattr(data, n[self._dict_key_index], v)
444 445 #-------------------------------------------------------------------------------
446 -class TodoWidget(wx.Panel, widgets.BitPimWidget):
447 color_field_name='todo' 448
449 - def __init__(self, mainwindow, parent):
450 global widgets_list 451 452 super(TodoWidget, self).__init__(parent, -1) 453 self._main_window=mainwindow 454 self._data=self._data_map={} 455 # main box sizer 456 vbs=wx.BoxSizer(wx.VERTICAL) 457 # horizontal sizer for the listbox and tabs 458 hbs=wx.BoxSizer(wx.HORIZONTAL) 459 # the list box 460 self._item_list=wx.ListBox(self, wx.NewId(), 461 style=wx.LB_SINGLE|wx.LB_HSCROLL|wx.LB_NEEDED_SB) 462 hbs.Add(self._item_list, 1, wx.EXPAND|wx.BOTTOM, border=5) 463 # the detailed info pane as a scrolled panel 464 scrolled_panel=scrolled.ScrolledPanel(self, -1) 465 vbs1=wx.BoxSizer(wx.VERTICAL) 466 self._items=( 467 (GeneralEditor, 0, None), 468 (cal_editor.CategoryEditor, 1, 'category'), 469 (pb_editor.MemoEditor, 1, 'memo') 470 ) 471 self._w=[] 472 for n in self._items: 473 w=n[0](scrolled_panel, -1) 474 vbs1.Add(w, n[1], wx.EXPAND|wx.ALL, 5) 475 self._w.append(w) 476 if n[2]: 477 widgets_list.append((w.static_box, n[2])) 478 scrolled_panel.SetSizer(vbs1) 479 scrolled_panel.SetAutoLayout(True) 480 vbs1.Fit(scrolled_panel) 481 scrolled_panel.SetupScrolling() 482 hbs.Add(scrolled_panel, 3, wx.EXPAND|wx.ALL, border=5) 483 # save references to the widgets 484 self._general_editor_w=self._w[0] 485 self._cat_editor_w=self._w[1] 486 self._memo_editor_w=self._w[2] 487 # the bottom buttons 488 hbs1=wx.BoxSizer(wx.HORIZONTAL) 489 self._save_btn=wx.Button(self, wx.ID_SAVE) 490 self._revert_btn=wx.Button(self, wx.ID_REVERT_TO_SAVED) 491 help_btn=wx.Button(self, wx.ID_HELP) 492 hbs1.Add(self._save_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 493 hbs1.Add(help_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 494 hbs1.Add(self._revert_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 495 # all done 496 vbs.Add(hbs, 1, wx.EXPAND|wx.ALL, 5) 497 vbs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 498 vbs.Add(hbs1, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 499 self.SetSizer(vbs) 500 self.SetAutoLayout(True) 501 vbs.Fit(self) 502 # event handlers 503 wx.EVT_LISTBOX(self, self._item_list.GetId(), self._OnListBoxItem) 504 wx.EVT_BUTTON(self, self._save_btn.GetId(), self._OnSave) 505 wx.EVT_BUTTON(self, self._revert_btn.GetId(), self._OnRevert) 506 wx.EVT_BUTTON(self, wx.ID_HELP, 507 lambda _: wx.GetApp().displayhelpid(helpids.ID_TAB_TODO)) 508 # DIRTY UI Event handlers 509 for w in self._w: 510 pb_editor.EVT_DIRTY_UI(self, w.GetId(), self.OnMakeDirty) 511 # populate data 512 self._populate() 513 # turn on dirty flag 514 self.ignoredirty=False 515 self.setdirty(False) 516 # register for Today selection 517 today.bind_notification_event(self.OnTodaySelection, 518 today.Today_Group_Todo) 519 today.bind_request_event(self.OnTodayRequest) 520 # color coded labels 521 field_color.reload_color_info(self, widgets_list) 522 pubsub.subscribe(self.OnPhoneChanged, pubsub.PHONE_MODEL_CHANGED)
523
524 - def OnPhoneChanged(self, _):
525 # just reload the color info based on the new phone 526 field_color.reload_color_info(self, widgets_list) 527 self.Refresh()
528
529 - def _clear(self):
530 self._item_list.Clear() 531 self._clear_each()
532
533 - def _clear_each(self):
534 for w in self._w: 535 w.Set(None) 536 w.Enable(False) 537 self.Refresh()
538
539 - def _publish_today_events(self):
540 now=datetime.datetime.now() 541 _today='%04d%02d%02d'%(now.year, now.month, now.day) 542 keys=self._data.keys() 543 keys.sort() 544 today_event=today.TodayTodoEvent() 545 for k in keys: 546 if self._data[k].is_active() and \ 547 (not self._data[k].due_date or \ 548 self._data[k].due_date<=_today): 549 today_event.append(self._data[k].summary, 550 { 'key': k, 551 'index': self._data_map[k] }) 552 today_event.broadcast()
553
554 - def _publish_thisweek_events(self):
555 now=datetime.datetime.now() 556 _today='%04d%02d%02d'%(now.year, now.month, now.day) 557 s=now+datetime.timedelta(7-now.isoweekday()%7) 558 _sun='%04d%02d%02d'%(s.year, s.month, s.day) 559 keys=self._data.keys() 560 keys.sort() 561 today_event=today.ThisWeekTodoEvent() 562 dow_flg=[False]*7 563 for k in keys: 564 due_date=self._data[k].due_date 565 if due_date>_today and due_date<_sun: 566 dt=datetime.datetime(int(due_date[:4]), int(due_date[4:6]), 567 int(due_date[6:8])) 568 _dow=dt.isoweekday()%7 569 if dow_flg[_dow]: 570 _name=today.dow_initials[-1]+' '+self._data[k].summary 571 else: 572 dow_flg[_dow]=True 573 _name=today.dow_initials[_dow]+' - '+self._data[k].summary 574 today_event.append(_name, { 'key': k, 575 'index': self._data_map[k] }) 576 today_event.broadcast()
577
578 - def OnTodayRequest(self, _):
581
582 - def OnTodaySelection(self, evt):
583 self.ActivateSelf() 584 if evt.data: 585 self._item_list.SetSelection(evt.data.get('index', wx.NOT_FOUND)) 586 self._populate_each(evt.data.get('key', None))
587
588 - def _populate(self):
589 # populate new data 590 self._clear() 591 self._data_map={} 592 # populate the list with data 593 keys=self._data.keys() 594 keys.sort() 595 for k in keys: 596 n=self._data[k] 597 i=self._item_list.Append(n.summary) 598 self._item_list.SetClientData(i, k) 599 self._data_map[k]=i 600 self._publish_today_events() 601 self._publish_thisweek_events()
602
603 - def _populate_each(self, k):
604 # populate the detailed info of the item keyed k 605 if k is None: 606 # clear out all the subfields 607 self._clear_each() 608 return 609 # there're data, first enable the widgets 610 self.ignoredirty=True 611 for w in self._w: 612 w.Enable(True) 613 entry=self._data[k] 614 # set the general detail 615 self._general_editor_w.Set(entry) 616 self._cat_editor_w.Set(entry.categories) 617 self._memo_editor_w.Set({ 'memo': entry.note }) 618 self.ignoredirty=False 619 self.setdirty(False)
620 621 # called from various widget update callbacks
622 - def OnMakeDirty(self, _=None):
623 """A public function you can call that will set the dirty flag""" 624 if self.dirty or self.ignoredirty or not self.IsShown(): 625 # already dirty, no need to make it worse 626 return 627 self.setdirty(True)
628
629 - def setdirty(self, val):
630 """Set the dirty flag""" 631 if self.ignoredirty: 632 return 633 self.dirty=val 634 self._item_list.Enable(not self.dirty) 635 self._save_btn.Enable(self.dirty) 636 self._revert_btn.Enable(self.dirty)
637
638 - def GetDeleteInfo(self):
639 return guihelper.ART_DEL_TODO, "Delete Todo Item"
640
641 - def GetAddInfo(self):
642 return guihelper.ART_ADD_TODO, "Add Todo Item"
643
644 - def CanAdd(self):
645 if self.dirty: 646 return False 647 return True
648
649 - def OnAdd(self, _):
650 # add a new memo item 651 if self.dirty: 652 # busy editing, cannot add now, just return 653 return 654 m=TodoEntry() 655 m.summary='New Task' 656 self._data[m.id]=m 657 self._populate() 658 self._save_to_db(self._data) 659 self._item_list.Select(self._data_map[m.id]) 660 self._populate_each(m.id)
661
662 - def CanDelete(self):
663 sel_idx=self._item_list.GetSelection() 664 if sel_idx is None or sel_idx==-1: 665 # none selected 666 return False 667 return True
668
669 - def OnDelete(self, _):
670 # delete the current selected item 671 sel_idx=self._item_list.GetSelection() 672 if sel_idx is None or sel_idx==-1: 673 # none selected 674 return 675 self.ignoredirty=True 676 k=self._item_list.GetClientData(sel_idx) 677 self._item_list.Delete(sel_idx) 678 self._clear_each() 679 del self._data[k] 680 del self._data_map[k] 681 self._save_to_db(self._data) 682 self.ignoredirty=False 683 self.setdirty(False)
684
685 - def getdata(self,dict,want=None):
686 dict['todo']=copy.deepcopy(self._data) 687 return dict
688
689 - def populate(self, dict):
690 self._data=dict.get('todo', {}) 691 self._populate()
692
693 - def _save_to_db(self, todo_dict):
694 db_rr={} 695 for k, e in todo_dict.items(): 696 db_rr[k]=TodoDataObject(e) 697 database.ensurerecordtype(db_rr, todoobjectfactory) 698 self._main_window.database.savemajordict('todo', db_rr) 699 self._publish_today_events() 700 self._publish_thisweek_events()
701
702 - def populatefs(self, dict):
703 self._save_to_db(dict.get('todo', {})) 704 return dict
705
706 - def getfromfs(self, result):
707 # read data from the database 708 todo_dict=self._main_window.database.\ 709 getmajordictvalues('todo',todoobjectfactory) 710 r={} 711 for k,e in todo_dict.items(): 712 ce=TodoEntry() 713 ce.set_db_dict(e) 714 r[ce.id]=ce 715 result.update({ 'todo': r }) 716 return result
717
718 - def _OnListBoxItem(self, evt):
719 # an item was clicked on/selected 720 self._populate_each(self._item_list.GetClientData(evt.GetInt())) 721 self.Refresh()
722
723 - def _OnSave(self, evt):
724 # save the current changes 725 self.ignoredirty=True 726 sel_idx=self._item_list.GetSelection() 727 k=self._item_list.GetClientData(sel_idx) 728 entry=self._data[k] 729 self._general_editor_w.Get(entry) 730 entry.note=self._memo_editor_w.Get().get('memo', None) 731 entry.categories=self._cat_editor_w.Get() 732 entry.check_completion() 733 self._general_editor_w.Set(entry) 734 self._item_list.SetString(sel_idx, entry.summary) 735 self._save_to_db(self._data) 736 self.ignoredirty=False 737 self.setdirty(False)
738
739 - def _OnRevert(self, evt):
740 self.ignoredirty=True 741 self._item_list.Enable() 742 sel_idx=self._item_list.GetSelection() 743 if sel_idx!=wx.NOT_FOUND: 744 k=self._item_list.GetClientData(sel_idx) 745 self._populate_each(k) 746 self.ignoredirty=False 747 self.setdirty(False)
748 749 #------------------------------------------------------------------------------- 750