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

Source Code for Module today

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2005 Joe Pham <djpham@bitpim.org> 
  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: today.py 4601 2008-03-04 22:37:48Z djpham $ 
  9   
 10  """ 
 11  Code to handle BitPim Today tab. 
 12   
 13  """ 
 14   
 15  # standard modules 
 16   
 17  # wx modules 
 18  import wx 
 19  import wx.lib.scrolledpanel as scrolled 
 20  import wx.lib.hyperlink as hl 
 21   
 22  # BitPim modules 
 23  import aggregatedisplay as aggr 
 24  import pubsub 
 25  import widgets 
 26   
 27   
 28  # Today REQUEST_TAB_CHANGED keys, types, and constants 
 29  Tab_Today=0 
 30  Tab_PhoneBook=1 
 31  Tab_Wallpaper=2 
 32  Tab_Ringers=3 
 33  Tab_Calendar=4 
 34  Tab_Memo=5 
 35  Tab_Todo=6 
 36  Tab_SMS=7 
 37  Tab_CallHistory=8 
 38  # TODAY_DATA keys, types, and constants 
 39  Today_Section='section' 
 40  Today_Groups='groups' 
 41  Today_Group_Tab='tab_index' 
 42  Today_Items='items' 
 43  Today_Item_Name='name' 
 44  Today_Item_Data='item_data' 
 45  # Sections 
 46  Today_Section_Today='Today' 
 47  Today_Section_ThisWeek='This Week' 
 48  # Groups 
 49  Today_Group_Calendar='Calendar:' 
 50  Today_Group_Todo='Todo List:' 
 51  Today_Group_Memo='Memo:' 
 52  Today_Group_IncomingSMS='SMS Inbox:' 
 53  Today_Group_IncomingCalls='Incoming Calls:' 
 54  Today_Group_MissedCalls='Missed Calls:' 
 55   
 56  dow_initials=('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', '   ') 
 57   
 58  EVT_TODAY_ITEM_SELECTED=wx.NewEventType() 
59 60 #------------------------------------------------------------------------------- 61 -class NotificationEvent(object):
62 - def __init__(self, evt_handler, client_data=None):
63 self._evt_handler=evt_handler 64 self.client_data=client_data 65 self.data=None
66 - def send(self):
67 self._evt_handler(self)
68
69 #------------------------------------------------------------------------------- 70 -class NotificationEventHandler(object):
71 - def __init__(self):
72 self._evt_table={}
73
74 - def append(self, evt_handler, group, client_data=None):
75 evt=NotificationEvent(evt_handler, client_data) 76 self._evt_table.setdefault(group, []).append(evt)
77
78 - def process(self, group, evt):
79 for e in self._evt_table.get(group, []): 80 e.data=evt 81 e.send()
82
83 #------------------------------------------------------------------------------- 84 evt_handler=None 85 -def bind_notification_event(_evt_handler, group, client_data=None):
86 global evt_handler 87 if evt_handler is None: 88 evt_handler=NotificationEventHandler() 89 evt_handler.append(_evt_handler, group, client_data)
90
91 #------------------------------------------------------------------------------- 92 -class BaseEvent(object):
93 - def __init__(self, section, group):
94 self.section=section 95 self.group=group 96 self._items=[]
97
98 - def append(self, item_name, item_data=None):
99 # append a data item to this event 100 self._items.append({ Today_Item_Name: item_name, 101 Today_Item_Data: item_data })
102
103 - def _set_names(self, names):
104 self._items=[{ Today_Item_Name: x, Today_Item_Data: None } \ 105 for x in names]
106 - def _get_names(self):
107 return [x[Today_Item_Name] for x in self._items]
108 names=property(fget=_get_names, fset=_set_names) 109
110 - def _get_items(self):
111 return self._items
112 items=property(fget=_get_items) 113
114 - def broadcast(self):
115 # broadcast this event 116 pubsub.publish(pubsub.NEW_DATA_AVAILABLE, data=self)
117 @classmethod
118 - def bind(_, func):
120
121 #------------------------------------------------------------------------------- 122 -class TodayCalendarEvent(BaseEvent):
123 - def __init__(self):
126 -class ThisWeekCalendarEvent(BaseEvent):
127 - def __init__(self):
130 -class TodayTodoEvent(BaseEvent):
131 - def __init__(self):
134 -class ThisWeekTodoEvent(BaseEvent):
135 - def __init__(self):
138 -class TodayMemoEvent(BaseEvent):
139 - def __init__(self):
142 -class TodaySMSEvent(BaseEvent):
143 - def __init__(self):
146 -class TodayIncomingCallsEvent(BaseEvent):
147 - def __init__(self):
150 -class TodayMissedCallsEvent(BaseEvent):
151 - def __init__(self):
154
155 # Request Today Event----------------------------------------------------------- 156 -def bind_request_event(evt_handler):
157 pubsub.subscribe(evt_handler, pubsub.REQUEST_TODAY_DATA)
158 -def send_request_event():
159 pubsub.publish(pubsub.REQUEST_TODAY_DATA)
160
161 #------------------------------------------------------------------------------- 162 EVT_HYPERLINK_LEFT=hl.EVT_HYPERLINK_LEFT 163 -class HyperLinkCtrl(hl.HyperLinkCtrl):
164 - def __init__(self, *args, **kargs):
165 super(HyperLinkCtrl, self).__init__(*args, **kargs) 166 self.AutoBrowse(False) 167 self.DoPopup(False) 168 self.client_data=None
169
170 - def SetToolTip(self, tip):
171 if isinstance(tip, (str, unicode)): 172 super(HyperLinkCtrl, self).SetToolTip(wx.ToolTip(tip)) 173 else: 174 super(HyperLinkCtrl, self).SetToolTip(tip)
175
176 - def SetLabel(self, label):
177 super(HyperLinkCtrl, self).SetLabel(label) 178 self.SetToolTip(label)
179
180 #------------------------------------------------------------------------------- 181 -class StaticText(wx.StaticText):
182 _max_item_len=30 183 _postfix='...' 184 _max_client_len=_max_item_len-len(_postfix)
185 - def __init__(self, *args, **kargs):
186 super(StaticText, self).__init__(*args, **kargs)
187 - def SetLabel(self, label):
188 if len(label)>self._max_item_len: 189 label=label[:self._max_client_len]+self._postfix 190 super(StaticText, self).SetLabel(label)
191 208
209 #------------------------------------------------------------------------------- 210 -class GroupWidget(wx.Panel, widgets.BitPimWidget):
211 max_total_items=10 212 max_items=9 213 _title_font=None 214 _item_font=None 215 _last_item={ Today_Item_Name: '... more ...', 216 Today_Item_Data: None }
217 - def __init__(self, parent, _name):
218 super(GroupWidget, self).__init__(parent, wx.NewId()) 219 self.name=_name.get('name', '') 220 self.tab_index=_name.get('tab_index', None) 221 self._data=[] 222 self._widgets=[] 223 if not self._title_font: 224 self._title_font=wx.Font(12, wx.FONTFAMILY_DEFAULT, 225 wx.FONTSTYLE_NORMAL, 226 wx.FONTWEIGHT_BOLD) 227 self._item_font=wx.Font(10, wx.FONTFAMILY_MODERN, 228 wx.FONTSTYLE_NORMAL, 229 wx.FONTWEIGHT_NORMAL) 230 bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, ''), wx.VERTICAL) 231 title=HyperLinkCtrl(self, -1, self.name) 232 if self._title_font.Ok(): 233 title.SetFont(self._title_font) 234 hl.EVT_HYPERLINK_LEFT(self, title.GetId(), self.OnItemSelected) 235 bs.Add(title, 0, wx.ALL, 5) 236 vbs=wx.BoxSizer(wx.VERTICAL) 237 for i in range(self.max_total_items): 238 w=ItemHyperLink(self, -1, '') 239 if self._item_font.Ok(): 240 w.SetFont(self._item_font) 241 hl.EVT_HYPERLINK_LEFT(self, w.GetId(), self.OnItemSelected) 242 vbs.Add(w, 0, wx.RIGHT|wx.LEFT, 5) 243 vbs.Hide(i) 244 self._widgets.append(w) 245 bs.Add(vbs, 1, wx.LEFT, 10) 246 self._vbs=vbs 247 bs.Fit(self) 248 self.SetSizer(bs) 249 self.SetAutoLayout(True)
250
251 - def Draw(self, dc, width, height, selected):
252 x=dc.pos[0]-dc.view_start[0] 253 y=dc.pos[1]-dc.view_start[1] 254 self.SetDimensions(x, y, width, height)
255
256 - def OnHyperlinkLeft(self, evt):
257 if self.tab_index: 258 pubsub.publish(pubsub.REQUEST_TAB_CHANGED, 259 data=self.tab_index)
260
261 - def OnItemSelected(self, evt):
262 if evt_handler: 263 self.OnHyperlinkLeft(evt) 264 evt_handler.process(self.name, evt.GetEventObject().client_data)
265
266 - def Set(self, data):
267 data_len=len(data) 268 if data_len>self.max_total_items: 269 self._data=data[:self.max_items] 270 self._data.append(self._last_item) 271 data_len=self.max_total_items 272 else: 273 self._data=data 274 for i in range(data_len): 275 self._widgets[i].SetLabel(self._data[i].get(Today_Item_Name, ''), 276 self._data[i].get(Today_Item_Data, None)) 277 self._vbs.Show(i) 278 for i in range(data_len, self.max_total_items): 279 self._vbs.Hide(i) 280 self._vbs.Layout() 281 self.Fit() 282 self.Refresh()
283
284 - def not_empty(self):
285 return self._data
286
287 #------------------------------------------------------------------------------- 288 -class SectionHeader(aggr.SectionHeader):
289 default_width=10 290 default_height=10
291 - def __init__(self, label):
292 super(SectionHeader, self).__init__(label) 293 self._items=[]
294 - def Add(self, item):
295 self._items.append(item)
296 - def GetAllItems(self):
297 return self._items
298 - def GetItems(self):
299 l=[] 300 for x in self._items: 301 if x.not_empty(): 302 l.append(x) 303 x.Show() 304 else: 305 x.Hide() 306 return l
307 - def GetItemSize(self):
308 w=self.default_width 309 h=self.default_height 310 for e in self._items: 311 w1,h1=e.GetSizeTuple() 312 w=max(w, w1) 313 h=max(h,h1) 314 return (w,h)
315
316 - def not_empty(self):
317 return self.GetItems()
318
319 320 #------------------------------------------------------------------------------- 321 -class TodayWidget(aggr.Display, widgets.BitPimWidget):
322 _section_names=('Today','This Week') 323 _item_names=(({ 'name': Today_Group_Calendar, 'tab_index': Tab_Calendar }, 324 { 'name': Today_Group_Todo, 'tab_index': Tab_Todo }, 325 { 'name': Today_Group_Memo, 'tab_index': Tab_Memo }, 326 { 'name': Today_Group_IncomingSMS, 'tab_index': Tab_SMS }, 327 { 'name': Today_Group_IncomingCalls, 'tab_index': Tab_CallHistory }, 328 { 'name': Today_Group_MissedCalls, 'tab_index': Tab_CallHistory }), 329 ({ 'name': Today_Group_Calendar, 'tab_index': Tab_Calendar }, 330 { 'name': Today_Group_Todo, 'tab_index': Tab_Todo } )) 331
332 - def __init__(self, mainwindow, parent):
333 self._sections=[] 334 super(TodayWidget, self).__init__(parent, self) 335 self._main_window=mainwindow 336 # sections & items info 337 self._sections=[SectionHeader(s) for s in self._section_names] 338 for i,group in enumerate(self._item_names): 339 for name in group: 340 w=GroupWidget(self, name) 341 self._sections[i].Add(w) 342 # all done 343 # populate data 344 self.UpdateItems() 345 # register for pubsub events 346 BaseEvent.bind(self.OnNewData) 347 pubsub.subscribe(self._OnMidnight, pubsub.MIDNIGHT)
348
349 - def GetSections(self):
350 "Return a list of section headers" 351 return [x for x in self._sections if x.not_empty()]
352
353 - def GetItemSize(self, sectionnumber, sectionheader):
354 "Return (width, height of each item)" 355 return sectionheader.GetItemSize()
356
357 - def GetItemsFromSection(self,sectionnumber,sectionheader):
358 return sectionheader.GetItems()
359
360 - def _populate(self, data):
361 section_name=data.section 362 group_name=data.group 363 for s in self._sections: 364 if s.label!=section_name: 365 continue 366 for group in s.GetAllItems(): 367 if group.name==group_name: 368 group.Set(data.items) 369 break 370 break 371 self.UpdateItems() 372 self.Refresh()
373
374 - def OnNewData(self, msg=None):
375 if msg is None: 376 return 377 self._populate(msg.data)
378
379 - def _OnMidnight(self, _):
381