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

Source Code for Module common_calendar

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2004 Joe Pham <djpham@netzero.com> 
  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: common_calendar.py 4711 2008-09-27 21:04:32Z djpham $ 
  9   
 10  "Common stuff for the Calendar Import functions" 
 11   
 12  # system modules 
 13  from __future__ import with_statement 
 14  import calendar 
 15  import copy 
 16  import datetime 
 17  import sys 
 18   
 19  # wxPython modules 
 20  import wx 
 21  import wx.calendar 
 22  import wx.lib.mixins.listctrl as listmix 
 23   
 24  # local modules 
 25  import database 
 26  import guihelper 
 27  import guiwidgets 
 28  import pubsub 
 29   
 30  no_end_date=(4000, 1, 1, 0, 0) 
 31   
32 -def bp_repeat_str(dict, v):
33 if v is None: 34 return '' 35 return v
36
37 -def bp_date_str(dict, v):
38 try: 39 if v[0]>=no_end_date[0]: 40 # no-end date, don't display it 41 if dict.get('allday', False): 42 return '' 43 else: 44 return '%02d:%02d'%v[3:] 45 46 if dict.get('allday', False): 47 return '%04d-%02d-%02d'%v[:3] 48 else: 49 return '%04d-%02d-%02d %02d:%02d'% v 50 except (ValueError, TypeError): 51 return '' 52 except: 53 if __debug__: raise 54 return ''
55
56 -def bp_alarm_str(dict, v):
57 try: 58 if dict.get('alarm', False): 59 v=dict.get('alarm_value', 0) 60 if v: 61 return '-%d min'%v 62 else: 63 return 'Ontime' 64 else: 65 return '' 66 except (ValueError, TypeError): 67 return '' 68 except: 69 if __debug__: raise 70 return ''
71
72 -def category_str(dict, v):
73 try: 74 s='' 75 for d in v: 76 if len(d): 77 if len(s): 78 s+=', '+d 79 else: 80 s=d 81 return s 82 except (ValueError, TypeError): 83 return '' 84 except: 85 if __debug__: raise 86 return ''
87 88 #-------------------------------------------------------------------------------
89 -class ImportDataSource(object):
90 # how to define, and retrieve calendar import data source 91 92 # subclass might want to set these 93 message_str='Select the source' 94 wildcard='*.*' 95
96 - def __init__(self):
97 self._source=None
98
99 - def browse(self, parent=None):
100 # how to select a source, default to select a file 101 with guihelper.WXDialogWrapper(wx.FileDialog(parent, self.message_str, wildcard=self.wildcard), 102 True) as (dlg, retcode): 103 if retcode==wx.ID_OK: 104 self._source=dlg.GetPath()
105
106 - def get(self):
107 # return a source suitable for importing data 108 return self._source
109
110 - def name(self):
111 # return a string name for the source, default is the source itself 112 return self._source or ''
113
114 - def _get_id(self):
115 # return the ID string of this source (mainly for Outlook), 116 # by default, just return the name 117 return self.name()
118 - def _set_id(self, id):
119 # set the ID of this source (mainly for Outlook), 120 # by default, just set the source to it 121 self._source=id
122 id=property(fget=_get_id, fset=_set_id)
123 124 #-------------------------------------------------------------------------------
125 -class PreviewDialog(wx.Dialog, listmix.ColumnSorterMixin):
126 ID_ADD=wx.NewId() 127 ID_MERGE=wx.NewId() 128
129 - def __init__(self, parent, id, title, col_labels, data={}, 130 config_name=None, 131 style=wx.CAPTION|wx.MAXIMIZE_BOX| \ 132 wx.SYSTEM_MENU|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
133 134 wx.Dialog.__init__(self, parent, id=id, title=title, style=style) 135 136 self.__col_labels=col_labels 137 self.__config_name=config_name 138 self.itemDataMap={} 139 # main boxsizer 140 main_bs=wx.BoxSizer(wx.VERTICAL) 141 # add custom controls here 142 self.getcontrols(main_bs) 143 # create a data preview list with supplied column labels 144 self.__list=wx.ListView(self, wx.NewId()) 145 self.__image_list=wx.ImageList(16, 16) 146 self.__ig_up=self.__image_list.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, 147 wx.ART_OTHER, 148 (16, 16))) 149 self.__ig_dn=self.__image_list.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, 150 wx.ART_OTHER, 151 (16, 16))) 152 self.__list.SetImageList(self.__image_list, wx.IMAGE_LIST_SMALL) 153 li=wx.ListItem() 154 li.m_mask=wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE 155 li.m_image=-1 156 for i, d in enumerate(self.__col_labels): 157 # insert a column with specified name and width 158 li.m_text=d[1] 159 self.__list.InsertColumnInfo(i, li) 160 self.__list.SetColumnWidth(i, d[2]) 161 main_bs.Add(self.__list, 1, wx.EXPAND, 0) 162 self.populate(data) 163 # the Mixin sorter 164 listmix.ColumnSorterMixin.__init__(self, len(col_labels)) 165 # now the buttons 166 self.getpostcontrols(main_bs) 167 # handle events 168 # all done 169 self.SetSizer(main_bs) 170 self.SetAutoLayout(True) 171 main_bs.Fit(self) 172 # save my own size, if specified 173 if config_name is not None: 174 guiwidgets.set_size(config_name, self) 175 wx.EVT_SIZE(self, self.__save_size)
176
177 - def getcontrols(self, main_bs):
178 # controls to be placed above the preview pane 179 # by default, put nothing. 180 pass
181
182 - def getpostcontrols(self, main_bs):
183 # control to be placed below the preview pane 184 # by default, just add the OK & CANCEL button 185 main_bs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 186 main_bs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
187
188 - def populate(self, data):
189 self.__list.DeleteAllItems() 190 m={} 191 m_count=0 192 for k in data: 193 try: 194 d=data[k] 195 col_idx=None 196 mm={} 197 for i, l in enumerate(self.__col_labels): 198 entry=d.get(l[0], None) 199 s='' 200 if l[3] is None: 201 s=str(entry) 202 else: 203 s=l[3](d, entry) 204 mm[i]=s 205 if i: 206 self.__list.SetStringItem(col_idx, i, s) 207 else: 208 col_idx=self.__list.InsertImageStringItem(sys.maxint, s, -1) 209 self.__list.SetItemData(col_idx, m_count) 210 m[m_count]=mm 211 m_count += 1 212 except: 213 # something wrong happened, drop this event 214 if __debug__: raise 215 self.itemDataMap=m
216
217 - def GetListCtrl(self):
218 return self.__list
219
220 - def GetSortImages(self):
221 return (self.__ig_dn, self.__ig_up)
222
223 - def __save_size(self, evt):
224 if self.__config_name is not None: 225 guiwidgets.save_size(self.__config_name, self.GetRect()) 226 evt.Skip()
227 228 #-------------------------------------------------------------------------------
229 -class FilterDataObject(database.basedataobject):
230 _knownproperties=['rpt_events', 'no_alarm', 'alarm_override', 231 'ringtone', 'vibrate', 'alarm_value', 232 'preset_date' ] 233 _knownlistproperties=database.basedataobject._knownlistproperties.copy() 234 _knownlistproperties.update( {'categories': ['category'], 235 'start': ['year', 'month', 'day'], 236 'end': ['year', 'month', 'day'] })
237 - def __init__(self, data=None):
238 if data: 239 self.update(data)
240 241 filterobjectfactory=database.dataobjectfactory(FilterDataObject) 242 #-------------------------------------------------------------------------------
243 -class FilterDialogBase(wx.Dialog):
244 unnamed="Select:"
245 - def __init__(self, parent, id, caption, categories, style=wx.DEFAULT_DIALOG_STYLE):
246 wx.Dialog.__init__(self, parent, id, 247 title=caption, style=style) 248 # the main box sizer 249 bs=wx.BoxSizer(wx.VERTICAL) 250 # the flex grid sizers for the editable items 251 main_fgs=wx.FlexGridSizer(0, 1, 0, 0) 252 fgs=wx.FlexGridSizer(3, 2, 0, 5) 253 fgs1=wx.FlexGridSizer(0, 1, 0, 0) 254 fgs2=wx.FlexGridSizer(0, 2, 0, 5) 255 # set the date options 256 self.SetDateControls(fgs, fgs1) 257 # new repeat to single events option 258 self._rpt_chkbox=wx.CheckBox(self, id=wx.NewId(), label='Repeat Events:', 259 style=wx.ALIGN_RIGHT) 260 self._rpt_chkbox.Disable() 261 fgs.Add(self._rpt_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 262 self._rpt_chkbox_text=wx.StaticText(self, -1, 'Import as multi-single events.') 263 fgs.Add(self._rpt_chkbox_text, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTRE, 0) 264 self._rpt_chkbox_text.Disable() 265 # alarm option 266 choices=('Disable All Alarms', 'Use Alarm Settings From Calender', 267 'Set Alarm On All Events') 268 self.__alarm_setting = wx.RadioBox(self, id=wx.NewId(), 269 label="Select Alarm Settings For Imported Events", 270 choices=choices, 271 majorDimension=1, 272 size=(280,-1)) 273 fgs1.Add(self.__alarm_setting, 0, wx.ALIGN_CENTRE|wx.TOP|wx.BOTTOM, 5) 274 #alarm vibrate 275 self.__vibrate=wx.CheckBox(self, id=wx.NewId(), label='Alarm Vibrate:', 276 style=wx.ALIGN_RIGHT) 277 fgs2.Add(self.__vibrate, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 278 self.__vibrate_text=wx.StaticText(self, -1, 'Enable vibrate for alarms.') 279 fgs2.Add(self.__vibrate_text, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 5) 280 # alarm settings 281 self.__ringtone_text=wx.StaticText(self, -1, 'Alarm Ringtone:') 282 fgs2.Add(self.__ringtone_text, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 283 self.__ringtone=wx.ComboBox(self, id=wx.NewId(), 284 style=wx.CB_DROPDOWN|wx.CB_READONLY, 285 choices=[self.unnamed], size=(160,-1)) 286 fgs2.Add(self.__ringtone, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 287 # alarm value 288 self.__alarm_value_text=wx.StaticText(self, -1, 'Alert before (mins):') 289 fgs2.Add(self.__alarm_value_text, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 290 self.__alarm_value=wx.lib.intctrl.IntCtrl(self, id=wx.NewId(), size=(50,-1), 291 value=0, min=0, max=1000) 292 fgs2.Add( self.__alarm_value, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 293 # category option 294 self.__cat_chkbox=wx.CheckBox(self, id=wx.NewId(), label='Categories:', 295 style=wx.ALIGN_RIGHT) 296 fgs2.Add(self.__cat_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 297 for i,c in enumerate(categories): 298 if not len(c): 299 categories[i]='<None>' 300 self.__cats=wx.CheckListBox(self, choices=categories, size=(160, 50)) 301 self.__cats.Disable() 302 fgs2.Add(self.__cats, 0, wx.ALIGN_LEFT, 0) 303 main_fgs.Add(fgs, 1, wx.EXPAND|wx.ALL, 0) 304 main_fgs.Add(fgs1, 1, wx.EXPAND|wx.ALL, 0) 305 main_fgs.Add(fgs2, 1, wx.EXPAND|wx.ALL, 0) 306 bs.Add(main_fgs, 1, wx.EXPAND|wx.ALL, 5) 307 # the buttons 308 bs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 309 bs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 310 # event handles 311 wx.EVT_CHECKBOX(self, self._start_date_chkbox.GetId(), self.OnCheckBox) 312 wx.EVT_CHECKBOX(self, self._end_date_chkbox.GetId(), self.OnCheckBox) 313 wx.EVT_CHECKBOX(self, self.__cat_chkbox.GetId(), self.OnCheckBox) 314 wx.EVT_RADIOBOX(self, self.__alarm_setting.GetId(), self.OnAlarmSetting) 315 # Listen to changes in ringtones list 316 pubsub.subscribe(self.OnRingtoneUpdates, pubsub.ALL_RINGTONES) 317 # all done 318 self.SetSizer(bs) 319 self.SetAutoLayout(True) 320 bs.Fit(self)
321
322 - def __del__(self):
324
325 - def ShowModal(self):
326 # request ringtones from 327 wx.CallAfter(pubsub.publish, pubsub.REQUEST_RINGTONES) # make the call once we are onscreen 328 return wx.Dialog.ShowModal(self)
329
330 - def OnRingtoneUpdates(self, msg):
331 "Receives pubsub message with ringtone list" 332 tones=msg.data[:] 333 #cur=self.Get() 334 try: 335 self.__ringtone.Clear() 336 self.__ringtone.Append(self.unnamed) 337 for p in tones: 338 self.__ringtone.Append(p) 339 rt=self.__ringtone.SetStringSelection(self.ringtone) 340 except: 341 self.ringtone=self.unnamed
342
343 - def __set_cats(self, chk_box, c, data):
344 if data is None: 345 chk_box.SetValue(False) 346 c.Disable() 347 else: 348 chk_box.SetValue(True) 349 c.Enable() 350 for i,d in enumerate(data): 351 if not len(d): 352 data[i]='<None>' 353 for i in range(c.GetCount()): 354 c.Check(i, c.GetString(i) in data)
355
356 - def __set_rpt(self, data):
357 if self._start_date_chkbox.GetValue() and\ 358 self._end_date_chkbox.GetValue(): 359 self._rpt_chkbox.Enable() 360 self._rpt_chkbox_text.Enable() 361 self._rpt_chkbox.SetValue(data) 362 else: 363 self._rpt_chkbox.SetValue(False) 364 self._rpt_chkbox.Disable() 365 self._rpt_chkbox_text.Disable()
366
367 - def __set_alarm_fields(self, value):
368 if value==0: 369 self.__vibrate.Disable() 370 self.__alarm_value.Disable() 371 self.__ringtone.Disable() 372 self.__vibrate_text.Disable() 373 self.__alarm_value_text.Disable() 374 self.__ringtone_text.Disable() 375 elif value==1: 376 self.__vibrate.Enable() 377 self.__alarm_value.Disable() 378 self.__ringtone.Enable() 379 self.__vibrate_text.Enable() 380 self.__alarm_value_text.Disable() 381 self.__ringtone_text.Enable() 382 else: 383 self.__vibrate.Enable() 384 self.__alarm_value.Enable() 385 self.__ringtone.Enable() 386 self.__vibrate_text.Enable() 387 self.__alarm_value_text.Enable() 388 self.__ringtone_text.Enable()
389
390 - def set_base(self, data):
391 self.__set_rpt(data.get('rpt_events', False)) 392 no_alarm=data.get('no_alarm', False) 393 alarm_override=data.get('alarm_override', False) 394 if no_alarm: 395 value=0 396 elif alarm_override: 397 value=2 398 else: 399 value=1 400 self.__set_alarm_fields(value) 401 self.__alarm_setting.SetSelection(value) 402 self.ringtone=data.get('ringtone', self.unnamed) 403 try: 404 self.__ringtone.SetStringSelection(ringtone) 405 except: 406 self.__ringtone.SetStringSelection(self.unnamed) 407 value=data.get('vibrate', False); 408 self.__vibrate.SetValue(value) 409 self.__alarm_value.SetValue(int(data.get('alarm_value', 0))) 410 self.__set_cats(self.__cat_chkbox, self.__cats, data.get('categories', None))
411
412 - def get_base(self, r):
413 r['rpt_events']=self._rpt_chkbox.GetValue() 414 value=self.__alarm_setting.GetSelection() 415 if value==0: 416 r['no_alarm']=True 417 r['alarm_override']=False 418 elif value==1: 419 r['no_alarm']=False 420 r['alarm_override']=False 421 else: 422 r['no_alarm']=False 423 r['alarm_override']=True 424 r['ringtone']=self.__ringtone.GetStringSelection() 425 r['vibrate']=self.__vibrate.GetValue() 426 r['alarm_value']=self.__alarm_value.GetValue() 427 if self.__cat_chkbox.GetValue(): 428 c=[] 429 for i in range(self.__cats.GetCount()): 430 if self.__cats.IsChecked(i): 431 s=self.__cats.GetString(i) 432 if s=='<None>': 433 c.append('') 434 else: 435 c.append(s) 436 r['categories']=c 437 else: 438 r['categories']=None 439 return
440
441 - def OnAlarmSetting(self, _):
442 self.__set_alarm_fields(self.__alarm_setting.GetSelection())
443
444 - def _repeat_option(self, on=True):
445 if on: 446 self._rpt_chkbox.Enable() 447 self._rpt_chkbox_text.Enable() 448 else: 449 self._rpt_chkbox.SetValue(False) 450 self._rpt_chkbox.Disable() 451 self._rpt_chkbox_text.Disable()
452
453 - def OnCheckBox(self, evt):
454 evt_id=evt.GetId() 455 if evt_id==self._start_date_chkbox.GetId(): 456 w1,w2=self._start_date_chkbox, self._start_date 457 elif evt_id==self._end_date_chkbox.GetId(): 458 w1,w2=self._end_date_chkbox, self._end_date 459 else: 460 w1,w2=self.__cat_chkbox, self.__cats 461 if w1.GetValue(): 462 w2.Enable() 463 else: 464 w2.Disable() 465 # turn on the repeat event option of both start date and end date 466 # are specified. 467 self._repeat_option(self._start_date_chkbox.GetValue() and \ 468 self._end_date_chkbox.GetValue())
469 470 #-------------------------------------------------------------------------------
471 -class FilterDialog(FilterDialogBase):
472 - def __init__(self, parent, id, caption, categories, style=wx.DEFAULT_DIALOG_STYLE):
473 FilterDialogBase.__init__(self, parent, id, caption, categories, style) 474 self._get_from_fs()
475
476 - def _get_from_fs(self):
477 _db_data=self.GetParent().GetParent().GetActiveDatabase().getmajordictvalues('calendar_filter', 478 filterobjectfactory) 479 _data={} 480 _data.update(_db_data.get('filter', {})) 481 if _data.has_key('categories'): 482 _cat=[x['category'] for x in _data['categories']] 483 del _data['categories'] 484 _data['categories']=_cat 485 if _data.has_key('start'): 486 _d0=_data['start'][0] 487 _date=(_d0['year'], _d0['month'], _d0['day']) 488 del _data['start'] 489 _data['start']=_date 490 if _data.has_key('end'): 491 _d0=_data['end'][0] 492 _date=(_d0['year'], _d0['month'], _d0['day']) 493 del _data['end'] 494 _data['end']=_date 495 self.set(_data)
496
497 - def _save_to_fs(self, data):
498 _data=copy.deepcopy(data, {}) 499 del _data['categories'] 500 if data.has_key('categories') and data['categories']: 501 _cat=[{'category': x} for x in data['categories'] ] 502 _data['categories']=_cat 503 del _data['start'] 504 if data.has_key('start') and data['start']: 505 _date=[{'year': data['start'][0], 'month': data['start'][1], 506 'day': data['start'][2] }] 507 _data['start']=_date 508 del _data['end'] 509 if data.has_key('end') and data['end']: 510 _date=[{'year': data['end'][0], 'month': data['end'][1], 511 'day': data['end'][2] }] 512 _data['end']=_date 513 _dict={ 'filter': _data } 514 database.ensurerecordtype(_dict, filterobjectfactory) 515 self.GetParent().GetParent().GetActiveDatabase().savemajordict('calendar_filter', 516 _dict)
517
518 - def SetDateControls(self, fgs, fgs1):
519 self._start_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 520 label='Start Date:', 521 style=wx.ALIGN_RIGHT) 522 fgs.Add(self._start_date_chkbox, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL, 0) 523 self._start_date=wx.calendar.CalendarCtrl(self, -1, wx.DateTime_Now(), 524 style = wx.calendar.CAL_SUNDAY_FIRST 525 | wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION) 526 self._start_date.Disable() 527 fgs.Add(self._start_date, 1, wx.ALIGN_LEFT, 5) 528 self._end_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 529 label='End Date:', 530 style=wx.ALIGN_RIGHT) 531 fgs.Add(self._end_date_chkbox, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL, 0) 532 self._end_date=wx.calendar.CalendarCtrl(self, -1, wx.DateTime_Now(), 533 style = wx.calendar.CAL_SUNDAY_FIRST 534 | wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION) 535 self._end_date.Disable() 536 fgs.Add(self._end_date, 1, wx.ALIGN_LEFT, 5) 537 self._preset_date_chkbox=wx.CheckBox(self, -1, label='Preset Duration', 538 style=wx.ALIGN_RIGHT) 539 fgs.Add(self._preset_date_chkbox, 0, 540 wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL, 0) 541 self._preset_date=wx.Choice(self, -1, choices=('This Week', 542 'This Month', 543 'This Year', 544 'Next 7 Days',)) 545 self._preset_date.SetSelection(1) 546 self._preset_date.Disable() 547 fgs.Add(self._preset_date, 0, wx.ALIGN_LEFT, 5) 548 wx.EVT_CHECKBOX(self, self._preset_date_chkbox.GetId(), 549 self.OnCheckBox)
550
551 - def OnCheckBox(self, evt):
552 super(FilterDialog, self).OnCheckBox(evt) 553 self._repeat_option(self._start_date_chkbox.GetValue() and \ 554 self._end_date_chkbox.GetValue() or \ 555 self._preset_date_chkbox.GetValue()) 556 if evt.GetId()==self._preset_date_chkbox.GetId(): 557 if self._preset_date_chkbox.GetValue(): 558 self._preset_date.Enable() 559 else: 560 self._preset_date.Disable()
561
562 - def __set_date(self, chk_box, cal, d):
563 if d is None: 564 chk_box.SetValue(False) 565 cal.Disable() 566 else: 567 chk_box.SetValue(True) 568 cal.Enable() 569 dt=wx.DateTime() 570 dt.Set(d[2], year=d[0], month=d[1]-1) 571 cal.SetDate(dt)
572
573 - def set_base(self, data):
574 super(FilterDialog, self).set_base(data) 575 self._rpt_chkbox.SetValue(data.get('rpt_events', False))
576
577 - def set(self, data):
578 self.__set_date(self._start_date_chkbox, self._start_date, 579 data.get('start', None)) 580 self.__set_date(self._end_date_chkbox, self._end_date, 581 data.get('end', None)) 582 self.set_base(data) 583 if data.get('preset_date', None) is not None: 584 self._preset_date_chkbox.SetValue(True) 585 self._preset_date.Enable() 586 self._preset_date.SetSelection(data['preset_date']) 587 self._repeat_option(True) 588 else: 589 self._preset_date_chkbox.SetValue(False) 590 self._preset_date.Disable()
591
592 - def _get_preset_thisweek(self):
593 # return the dates of (today, Sat) 594 _today=datetime.date.today() 595 _dow=_today.isoweekday()%7 #Sun=0, Sat=6 596 _end=_today+datetime.timedelta(6-_dow) 597 return ((_today.year, _today.month, _today.day), 598 (_end.year, _end.month, _end.day))
599
600 - def _get_preset_thismonth(self):
601 # return the dates of (today, end-of-month) 602 _today=datetime.date.today() 603 _end=_today.replace(day=calendar.monthrange(_today.year,_today.month)[1]) 604 return ((_today.year, _today.month, _today.day), 605 (_end.year, _end.month, _end.day))
606
607 - def _get_preset_thisyear(self):
608 # return the dates of (today, end-of-year) 609 _today=datetime.date.today() 610 _end=_today.replace(month=12, day=31) 611 return ((_today.year, _today.month, _today.day), 612 (_end.year, _end.month, _end.day))
613
614 - def _get_preset_next7(self):
615 # return the dates of (today, today+6) 616 _today=datetime.date.today() 617 _end=_today+datetime.timedelta(days=6) 618 return ((_today.year, _today.month, _today.day), 619 (_end.year, _end.month, _end.day))
620
621 - def _get_preset_date(self):
622 _choice=self._preset_date.GetSelection() 623 if _choice==wx.NOT_FOUND: 624 return None, None 625 if _choice==0: 626 return self._get_preset_thisweek() 627 elif _choice==1: 628 return self._get_preset_thismonth() 629 elif _choice==2: 630 return self._get_preset_thisyear() 631 else: 632 return self._get_preset_next7()
633
634 - def get(self):
635 r={} 636 if self._preset_date_chkbox.GetValue(): 637 r['start'],r['end']=self._get_preset_date() 638 r['preset_date']=self._preset_date.GetSelection() 639 else: 640 r['preset_date']=None 641 if self._start_date_chkbox.GetValue(): 642 dt=self._start_date.GetDate() 643 r['start']=(dt.GetYear(), dt.GetMonth()+1, dt.GetDay()) 644 else: 645 r['start']=None 646 if self._end_date_chkbox.GetValue(): 647 dt=self._end_date.GetDate() 648 r['end']=(dt.GetYear(), dt.GetMonth()+1, dt.GetDay()) 649 else: 650 r['end']=None 651 self.get_base(r) 652 self._save_to_fs(r) 653 return r
654 655 #-------------------------------------------------------------------------------
656 -class AutoSyncFilterDialog(FilterDialogBase):
657 - def __init__(self, parent, id, caption, categories, style=wx.DEFAULT_DIALOG_STYLE):
658 FilterDialogBase.__init__(self, parent, id, caption, categories, style)
659
660 - def SetDateControls(self, fgs, fgs1):
661 #start_offset 662 self._start_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 663 label='Start Offset (days):', 664 style=wx.ALIGN_RIGHT) 665 fgs.Add(self._start_date_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 666 self._start_date=wx.lib.intctrl.IntCtrl(self, id=wx.NewId(), size=(50,-1), 667 value=0, min=0, max=1000) 668 self._start_date.Disable() 669 fgs.Add( self._start_date, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 670 #end_offset 671 self._end_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 672 label='End Offset (days):', 673 style=wx.ALIGN_RIGHT) 674 fgs.Add(self._end_date_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 675 self._end_date=wx.lib.intctrl.IntCtrl(self, id=wx.NewId(), size=(50,-1), 676 value=0, min=0, max=1000) 677 self._end_date.Disable() 678 fgs.Add( self._end_date, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 679 fgs1.Add(wx.StaticText(self, -1, 'Note: The start offset is the number of days' + 680 ' in the past, and the end offset is the number of days' + 681 ' in the future imported from the calender into your phone. If' + 682 ' disabled, all past and/or future events are imported.', 683 size=(270,55)), 684 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 5)
685 686
687 - def __set_start_date(self, d):
688 if d is None: 689 self._start_date_chkbox.SetValue(False) 690 self._start_date.Disable() 691 else: 692 self._start_date_chkbox.SetValue(True) 693 self._start_date.Enable() 694 self._start_date.SetValue(d)
695
696 - def __set_end_date(self, d):
697 if d is None: 698 self._end_date_chkbox.SetValue(False) 699 self._end_date.Disable() 700 else: 701 self._end_date_chkbox.SetValue(True) 702 self._end_date.Enable() 703 self._end_date.SetValue(d)
704
705 - def set(self, data):
706 self.__set_start_date(data.get('start_offset', None)) 707 self.__set_end_date(data.get('end_offset', None)) 708 self.set_base(data)
709
710 - def get(self):
711 r={} 712 if self._start_date_chkbox.GetValue(): 713 r['start_offset']=self._start_date.GetValue() 714 else: 715 r['start_offset']=None 716 if self._end_date_chkbox.GetValue(): 717 r['end_offset']=self._end_date.GetValue() 718 else: 719 r['end_offset']=None 720 self.get_base(r) 721 return r
722 723 #-------------------------------------------------------------------------------
724 -class ExportCalendarDialog(wx.Dialog):
725 # subclass should override these 726 _default_file_name="" 727 _wildcards="All files|*.*" 728
729 - def __init__(self, parent, title):
730 super(ExportCalendarDialog, self).__init__(parent, -1, title) 731 # make the ui 732 vbs=wx.BoxSizer(wx.VERTICAL) 733 hbs=wx.BoxSizer(wx.HORIZONTAL) 734 hbs.Add(wx.StaticText(self, -1, "File"), 0, wx.ALL|wx.ALIGN_CENTRE, 5) 735 self.filenamectrl=wx.TextCtrl(self, -1, self._default_file_name) 736 hbs.Add(self.filenamectrl, 1, wx.ALL|wx.EXPAND, 5) 737 self.browsectrl=wx.Button(self, wx.NewId(), "Browse...") 738 hbs.Add(self.browsectrl, 0, wx.ALL|wx.EXPAND, 5) 739 vbs.Add(hbs, 0, wx.EXPAND|wx.ALL, 5) 740 # selection GUI 741 vbs.Add(self.GetSelectionGui(self), 5, wx.EXPAND|wx.ALL, 5) 742 # the buttons 743 vbs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL,5) 744 vbs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTER|wx.ALL, 5) 745 # event handlers 746 wx.EVT_BUTTON(self, self.browsectrl.GetId(), self.OnBrowse) 747 wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk) 748 # all done 749 self.SetSizer(vbs) 750 self.SetAutoLayout(True) 751 vbs.Fit(self)
752
753 - def GetSelectionGui(self, parent):
754 hbs=wx.BoxSizer(wx.HORIZONTAL) 755 self._selection=wx.RadioBox(parent, wx.NewId(), 'Events Selection', 756 choices=['All', 'Date Range'], 757 style=wx.RA_SPECIFY_ROWS) 758 hbs.Add(self._selection, 0, wx.EXPAND|wx.ALL, 5) 759 sbs=wx.StaticBoxSizer(wx.StaticBox(parent, -1, 'Date Range'), wx.VERTICAL) 760 gs=wx.FlexGridSizer(-1, 2, 5, 5) 761 gs.AddGrowableCol(1) 762 gs.Add(wx.StaticText(self, -1, 'Start:'), 0, wx.ALL, 0) 763 self._start_date=wx.DatePickerCtrl(self, style=wx.DP_DROPDOWN | wx.DP_SHOWCENTURY) 764 gs.Add(self._start_date, 0, wx.ALL, 0) 765 gs.Add(wx.StaticText(self, -1, 'End:'), 0, wx.ALL, 0) 766 self._end_date=wx.DatePickerCtrl(self, style=wx.DP_DROPDOWN | wx.DP_SHOWCENTURY) 767 gs.Add(self._end_date, 0, wx.ALL, 0) 768 sbs.Add(gs, 1, wx.EXPAND|wx.ALL, 5) 769 hbs.Add(sbs, 0, wx.EXPAND|wx.ALL, 5) 770 return hbs
771
772 - def OnBrowse(self, _):
773 with guihelper.WXDialogWrapper(wx.FileDialog(self, defaultFile=self.filenamectrl.GetValue(), 774 wildcard=self._wildcards, style=wx.SAVE|wx.CHANGE_DIR), 775 True) as (dlg, retcode): 776 if retcode==wx.ID_OK: 777 self.filenamectrl.SetValue(dlg.GetPath())
778
779 - def _export(self):
780 # perform the actual caledar data import, subclass MUST override 781 raise NotImplementedError
782
783 - def OnOk(self, _):
784 # do export 785 self._export() 786 self.EndModal(wx.ID_OK)
787