0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2004 Joe Pham <djpham@netzero.com> 0004 ### 0005 ### This program is free software; you can redistribute it and/or modify 0006 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0007 ### 0008 ### $Id: common_calendar.py 4675 2008-08-12 21:52:12Z djpham $ 0009 0010 "Common stuff for the Calendar Import functions" 0011 0012 # system modules 0013 from __future__ import with_statement 0014 import calendar 0015 import copy 0016 import datetime 0017 import sys 0018 0019 # wxPython modules 0020 import wx 0021 import wx.calendar 0022 import wx.lib.mixins.listctrl as listmix 0023 0024 # local modules 0025 import database 0026 import guihelper 0027 import guiwidgets 0028 import pubsub 0029 0030 no_end_date=(4000, 1, 1, 0, 0) 0031 0032 def bp_repeat_str(dict, v): 0033 if v is None: 0034 return '' 0035 return v 0036 0037 def bp_date_str(dict, v): 0038 try: 0039 if v[0]>=no_end_date[0]: 0040 # no-end date, don't display it 0041 if dict.get('allday', False): 0042 return '' 0043 else: 0044 return '%02d:%02d'%v[3:] 0045 0046 if dict.get('allday', False): 0047 return '%04d-%02d-%02d'%v[:3] 0048 else: 0049 return '%04d-%02d-%02d %02d:%02d'% v 0050 except (ValueError, TypeError): 0051 return '' 0052 except: 0053 if __debug__: raise 0054 return '' 0055 0056 def bp_alarm_str(dict, v): 0057 try: 0058 if dict.get('alarm', False): 0059 v=dict.get('alarm_value', 0) 0060 if v: 0061 return '-%d min'%v 0062 else: 0063 return 'Ontime' 0064 else: 0065 return '' 0066 except (ValueError, TypeError): 0067 return '' 0068 except: 0069 if __debug__: raise 0070 return '' 0071 0072 def category_str(dict, v): 0073 try: 0074 s='' 0075 for d in v: 0076 if len(d): 0077 if len(s): 0078 s+=', '+d 0079 else: 0080 s=d 0081 return s 0082 except (ValueError, TypeError): 0083 return '' 0084 except: 0085 if __debug__: raise 0086 return '' 0087 0088 #------------------------------------------------------------------------------- 0089 class ImportDataSource(object): 0090 # how to define, and retrieve calendar import data source 0091 0092 # subclass might want to set these 0093 message_str='Select the source' 0094 wildcard='*.*' 0095 0096 def __init__(self): 0097 self._source=None 0098 0099 def browse(self, parent=None): 0100 # how to select a source, default to select a file 0101 with guihelper.WXDialogWrapper(wx.FileDialog(parent, self.message_str, wildcard=self.wildcard), 0102 True) as (dlg, retcode): 0103 if retcode==wx.ID_OK: 0104 self._source=dlg.GetPath() 0105 0106 def get(self): 0107 # return a source suitable for importing data 0108 return self._source 0109 0110 def name(self): 0111 # return a string name for the source, default is the source itself 0112 return self._source or '' 0113 0114 def _get_id(self): 0115 # return the ID string of this source (mainly for Outlook), 0116 # by default, just return the name 0117 return self.name() 0118 def _set_id(self, id): 0119 # set the ID of this source (mainly for Outlook), 0120 # by default, just set the source to it 0121 self._source=id 0122 id=property(fget=_get_id, fset=_set_id) 0123 0124 #------------------------------------------------------------------------------- 0125 class PreviewDialog(wx.Dialog, listmix.ColumnSorterMixin): 0126 ID_ADD=wx.NewId() 0127 ID_MERGE=wx.NewId() 0128 0129 def __init__(self, parent, id, title, col_labels, data={}, 0130 config_name=None, 0131 style=wx.CAPTION|wx.MAXIMIZE_BOX| \ 0132 wx.SYSTEM_MENU|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER): 0133 0134 wx.Dialog.__init__(self, parent, id=id, title=title, style=style) 0135 0136 self.__col_labels=col_labels 0137 self.__config_name=config_name 0138 self.itemDataMap={} 0139 # main boxsizer 0140 main_bs=wx.BoxSizer(wx.VERTICAL) 0141 # add custom controls here 0142 self.getcontrols(main_bs) 0143 # create a data preview list with supplied column labels 0144 self.__list=wx.ListView(self, wx.NewId()) 0145 self.__image_list=wx.ImageList(16, 16) 0146 self.__ig_up=self.__image_list.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, 0147 wx.ART_OTHER, 0148 (16, 16))) 0149 self.__ig_dn=self.__image_list.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, 0150 wx.ART_OTHER, 0151 (16, 16))) 0152 self.__list.SetImageList(self.__image_list, wx.IMAGE_LIST_SMALL) 0153 li=wx.ListItem() 0154 li.m_mask=wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE 0155 li.m_image=-1 0156 for i, d in enumerate(self.__col_labels): 0157 # insert a column with specified name and width 0158 li.m_text=d[1] 0159 self.__list.InsertColumnInfo(i, li) 0160 self.__list.SetColumnWidth(i, d[2]) 0161 main_bs.Add(self.__list, 1, wx.EXPAND, 0) 0162 self.populate(data) 0163 # the Mixin sorter 0164 listmix.ColumnSorterMixin.__init__(self, len(col_labels)) 0165 # now the buttons 0166 self.getpostcontrols(main_bs) 0167 # handle events 0168 # all done 0169 self.SetSizer(main_bs) 0170 self.SetAutoLayout(True) 0171 main_bs.Fit(self) 0172 # save my own size, if specified 0173 if config_name is not None: 0174 guiwidgets.set_size(config_name, self) 0175 wx.EVT_SIZE(self, self.__save_size) 0176 0177 def getcontrols(self, main_bs): 0178 # controls to be placed above the preview pane 0179 # by default, put nothing. 0180 pass 0181 0182 def getpostcontrols(self, main_bs): 0183 # control to be placed below the preview pane 0184 # by default, just add the OK & CANCEL button 0185 main_bs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 0186 main_bs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 0187 0188 def populate(self, data): 0189 self.__list.DeleteAllItems() 0190 m={} 0191 m_count=0 0192 for k in data: 0193 try: 0194 d=data[k] 0195 col_idx=None 0196 mm={} 0197 for i, l in enumerate(self.__col_labels): 0198 entry=d.get(l[0], None) 0199 s='' 0200 if l[3] is None: 0201 s=str(entry) 0202 else: 0203 s=l[3](d, entry) 0204 mm[i]=s 0205 if i: 0206 self.__list.SetStringItem(col_idx, i, s) 0207 else: 0208 col_idx=self.__list.InsertImageStringItem(sys.maxint, s, -1) 0209 self.__list.SetItemData(col_idx, m_count) 0210 m[m_count]=mm 0211 m_count += 1 0212 except: 0213 # something wrong happened, drop this event 0214 if __debug__: raise 0215 self.itemDataMap=m 0216 0217 def GetListCtrl(self): 0218 return self.__list 0219 0220 def GetSortImages(self): 0221 return (self.__ig_dn, self.__ig_up) 0222 0223 def __save_size(self, evt): 0224 if self.__config_name is not None: 0225 guiwidgets.save_size(self.__config_name, self.GetRect()) 0226 evt.Skip() 0227 0228 #------------------------------------------------------------------------------- 0229 class FilterDataObject(database.basedataobject): 0230 _knownproperties=['rpt_events', 'no_alarm', 'alarm_override', 0231 'ringtone', 'vibrate', 'alarm_value', 0232 'preset_date' ] 0233 _knownlistproperties=database.basedataobject._knownlistproperties.copy() 0234 _knownlistproperties.update( {'categories': ['category'], 0235 'start': ['year', 'month', 'day'], 0236 'end': ['year', 'month', 'day'] }) 0237 def __init__(self, data=None): 0238 if data: 0239 self.update(data) 0240 0241 filterobjectfactory=database.dataobjectfactory(FilterDataObject) 0242 #------------------------------------------------------------------------------- 0243 class FilterDialogBase(wx.Dialog): 0244 unnamed="Select:" 0245 def __init__(self, parent, id, caption, categories, style=wx.DEFAULT_DIALOG_STYLE): 0246 wx.Dialog.__init__(self, parent, id, 0247 title=caption, style=style) 0248 # the main box sizer 0249 bs=wx.BoxSizer(wx.VERTICAL) 0250 # the flex grid sizers for the editable items 0251 main_fgs=wx.FlexGridSizer(0, 1, 0, 0) 0252 fgs=wx.FlexGridSizer(3, 2, 0, 5) 0253 fgs1=wx.FlexGridSizer(0, 1, 0, 0) 0254 fgs2=wx.FlexGridSizer(0, 2, 0, 5) 0255 # set the date options 0256 self.SetDateControls(fgs, fgs1) 0257 # new repeat to single events option 0258 self._rpt_chkbox=wx.CheckBox(self, id=wx.NewId(), label='Repeat Events:', 0259 style=wx.ALIGN_RIGHT) 0260 self._rpt_chkbox.Disable() 0261 fgs.Add(self._rpt_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0262 self._rpt_chkbox_text=wx.StaticText(self, -1, 'Import as multi-single events.') 0263 fgs.Add(self._rpt_chkbox_text, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTRE, 0) 0264 self._rpt_chkbox_text.Disable() 0265 # alarm option 0266 choices=('Disable All Alarms', 'Use Alarm Settings From Calender', 0267 'Set Alarm On All Events') 0268 self.__alarm_setting = wx.RadioBox(self, id=wx.NewId(), 0269 label="Select Alarm Settings For Imported Events", 0270 choices=choices, 0271 majorDimension=1, 0272 size=(280,-1)) 0273 fgs1.Add(self.__alarm_setting, 0, wx.ALIGN_CENTRE|wx.TOP|wx.BOTTOM, 5) 0274 #alarm vibrate 0275 self.__vibrate=wx.CheckBox(self, id=wx.NewId(), label='Alarm Vibrate:', 0276 style=wx.ALIGN_RIGHT) 0277 fgs2.Add(self.__vibrate, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0278 self.__vibrate_text=wx.StaticText(self, -1, 'Enable vibrate for alarms.') 0279 fgs2.Add(self.__vibrate_text, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 5) 0280 # alarm settings 0281 self.__ringtone_text=wx.StaticText(self, -1, 'Alarm Ringtone:') 0282 fgs2.Add(self.__ringtone_text, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0283 self.__ringtone=wx.ComboBox(self, id=wx.NewId(), 0284 style=wx.CB_DROPDOWN|wx.CB_READONLY, 0285 choices=[self.unnamed], size=(160,-1)) 0286 fgs2.Add(self.__ringtone, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 0287 # alarm value 0288 self.__alarm_value_text=wx.StaticText(self, -1, 'Alert before (mins):') 0289 fgs2.Add(self.__alarm_value_text, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0290 self.__alarm_value=wx.lib.intctrl.IntCtrl(self, id=wx.NewId(), size=(50,-1), 0291 value=0, min=0, max=1000) 0292 fgs2.Add( self.__alarm_value, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 0293 # category option 0294 self.__cat_chkbox=wx.CheckBox(self, id=wx.NewId(), label='Categories:', 0295 style=wx.ALIGN_RIGHT) 0296 fgs2.Add(self.__cat_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0297 for i,c in enumerate(categories): 0298 if not len(c): 0299 categories[i]='<None>' 0300 self.__cats=wx.CheckListBox(self, choices=categories, size=(160, 50)) 0301 self.__cats.Disable() 0302 fgs2.Add(self.__cats, 0, wx.ALIGN_LEFT, 0) 0303 main_fgs.Add(fgs, 1, wx.EXPAND|wx.ALL, 0) 0304 main_fgs.Add(fgs1, 1, wx.EXPAND|wx.ALL, 0) 0305 main_fgs.Add(fgs2, 1, wx.EXPAND|wx.ALL, 0) 0306 bs.Add(main_fgs, 1, wx.EXPAND|wx.ALL, 5) 0307 # the buttons 0308 bs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 0309 bs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 0310 # event handles 0311 wx.EVT_CHECKBOX(self, self._start_date_chkbox.GetId(), self.OnCheckBox) 0312 wx.EVT_CHECKBOX(self, self._end_date_chkbox.GetId(), self.OnCheckBox) 0313 wx.EVT_CHECKBOX(self, self.__cat_chkbox.GetId(), self.OnCheckBox) 0314 wx.EVT_RADIOBOX(self, self.__alarm_setting.GetId(), self.OnAlarmSetting) 0315 # Listen to changes in ringtones list 0316 pubsub.subscribe(self.OnRingtoneUpdates, pubsub.ALL_RINGTONES) 0317 # all done 0318 self.SetSizer(bs) 0319 self.SetAutoLayout(True) 0320 bs.Fit(self) 0321 0322 def __del__(self): 0323 pubsub.unsubscribe(self.OnRingtoneUpdates) 0324 0325 def ShowModal(self): 0326 # request ringtones from 0327 wx.CallAfter(pubsub.publish, pubsub.REQUEST_RINGTONES) # make the call once we are onscreen 0328 return wx.Dialog.ShowModal(self) 0329 0330 def OnRingtoneUpdates(self, msg): 0331 "Receives pubsub message with ringtone list" 0332 tones=msg.data[:] 0333 #cur=self.Get() 0334 try: 0335 self.__ringtone.Clear() 0336 self.__ringtone.Append(self.unnamed) 0337 for p in tones: 0338 self.__ringtone.Append(p) 0339 rt=self.__ringtone.SetStringSelection(self.ringtone) 0340 except: 0341 self.ringtone=self.unnamed 0342 0343 def __set_cats(self, chk_box, c, data): 0344 if data is None: 0345 chk_box.SetValue(False) 0346 c.Disable() 0347 else: 0348 chk_box.SetValue(True) 0349 c.Enable() 0350 for i,d in enumerate(data): 0351 if not len(d): 0352 data[i]='<None>' 0353 for i in range(c.GetCount()): 0354 c.Check(i, c.GetString(i) in data) 0355 0356 def __set_rpt(self, data): 0357 if self._start_date_chkbox.GetValue() and\ 0358 self._end_date_chkbox.GetValue(): 0359 self._rpt_chkbox.Enable() 0360 self._rpt_chkbox_text.Enable() 0361 self._rpt_chkbox.SetValue(data) 0362 else: 0363 self._rpt_chkbox.SetValue(False) 0364 self._rpt_chkbox.Disable() 0365 self._rpt_chkbox_text.Disable() 0366 0367 def __set_alarm_fields(self, value): 0368 if value==0: 0369 self.__vibrate.Disable() 0370 self.__alarm_value.Disable() 0371 self.__ringtone.Disable() 0372 self.__vibrate_text.Disable() 0373 self.__alarm_value_text.Disable() 0374 self.__ringtone_text.Disable() 0375 elif value==1: 0376 self.__vibrate.Enable() 0377 self.__alarm_value.Disable() 0378 self.__ringtone.Enable() 0379 self.__vibrate_text.Enable() 0380 self.__alarm_value_text.Disable() 0381 self.__ringtone_text.Enable() 0382 else: 0383 self.__vibrate.Enable() 0384 self.__alarm_value.Enable() 0385 self.__ringtone.Enable() 0386 self.__vibrate_text.Enable() 0387 self.__alarm_value_text.Enable() 0388 self.__ringtone_text.Enable() 0389 0390 def set_base(self, data): 0391 self.__set_rpt(data.get('rpt_events', False)) 0392 no_alarm=data.get('no_alarm', False) 0393 alarm_override=data.get('alarm_override', False) 0394 if no_alarm: 0395 value=0 0396 elif alarm_override: 0397 value=2 0398 else: 0399 value=1 0400 self.__set_alarm_fields(value) 0401 self.__alarm_setting.SetSelection(value) 0402 self.ringtone=data.get('ringtone', self.unnamed) 0403 try: 0404 self.__ringtone.SetStringSelection(ringtone) 0405 except: 0406 self.__ringtone.SetStringSelection(self.unnamed) 0407 value=data.get('vibrate', False); 0408 self.__vibrate.SetValue(value) 0409 self.__alarm_value.SetValue(data.get('alarm_value', 0)) 0410 self.__set_cats(self.__cat_chkbox, self.__cats, data.get('categories', None)) 0411 0412 def get_base(self, r): 0413 r['rpt_events']=self._rpt_chkbox.GetValue() 0414 value=self.__alarm_setting.GetSelection() 0415 if value==0: 0416 r['no_alarm']=True 0417 r['alarm_override']=False 0418 elif value==1: 0419 r['no_alarm']=False 0420 r['alarm_override']=False 0421 else: 0422 r['no_alarm']=False 0423 r['alarm_override']=True 0424 r['ringtone']=self.__ringtone.GetStringSelection() 0425 r['vibrate']=self.__vibrate.GetValue() 0426 r['alarm_value']=self.__alarm_value.GetValue() 0427 if self.__cat_chkbox.GetValue(): 0428 c=[] 0429 for i in range(self.__cats.GetCount()): 0430 if self.__cats.IsChecked(i): 0431 s=self.__cats.GetString(i) 0432 if s=='<None>': 0433 c.append('') 0434 else: 0435 c.append(s) 0436 r['categories']=c 0437 else: 0438 r['categories']=None 0439 return 0440 0441 def OnAlarmSetting(self, _): 0442 self.__set_alarm_fields(self.__alarm_setting.GetSelection()) 0443 0444 def _repeat_option(self, on=True): 0445 if on: 0446 self._rpt_chkbox.Enable() 0447 self._rpt_chkbox_text.Enable() 0448 else: 0449 self._rpt_chkbox.SetValue(False) 0450 self._rpt_chkbox.Disable() 0451 self._rpt_chkbox_text.Disable() 0452 0453 def OnCheckBox(self, evt): 0454 evt_id=evt.GetId() 0455 if evt_id==self._start_date_chkbox.GetId(): 0456 w1,w2=self._start_date_chkbox, self._start_date 0457 elif evt_id==self._end_date_chkbox.GetId(): 0458 w1,w2=self._end_date_chkbox, self._end_date 0459 else: 0460 w1,w2=self.__cat_chkbox, self.__cats 0461 if w1.GetValue(): 0462 w2.Enable() 0463 else: 0464 w2.Disable() 0465 # turn on the repeat event option of both start date and end date 0466 # are specified. 0467 self._repeat_option(self._start_date_chkbox.GetValue() and \ 0468 self._end_date_chkbox.GetValue()) 0469 0470 #------------------------------------------------------------------------------- 0471 class FilterDialog(FilterDialogBase): 0472 def __init__(self, parent, id, caption, categories, style=wx.DEFAULT_DIALOG_STYLE): 0473 FilterDialogBase.__init__(self, parent, id, caption, categories, style) 0474 self._get_from_fs() 0475 0476 def _get_from_fs(self): 0477 _db_data=self.GetParent().GetParent().GetActiveDatabase().getmajordictvalues('calendar_filter', 0478 filterobjectfactory) 0479 _data={} 0480 _data.update(_db_data.get('filter', {})) 0481 if _data.has_key('categories'): 0482 _cat=[x['category'] for x in _data['categories']] 0483 del _data['categories'] 0484 _data['categories']=_cat 0485 if _data.has_key('start'): 0486 _d0=_data['start'][0] 0487 _date=(_d0['year'], _d0['month'], _d0['day']) 0488 del _data['start'] 0489 _data['start']=_date 0490 if _data.has_key('end'): 0491 _d0=_data['end'][0] 0492 _date=(_d0['year'], _d0['month'], _d0['day']) 0493 del _data['end'] 0494 _data['end']=_date 0495 self.set(_data) 0496 0497 def _save_to_fs(self, data): 0498 _data=copy.deepcopy(data, {}) 0499 del _data['categories'] 0500 if data.has_key('categories') and data['categories']: 0501 _cat=[{'category': x} for x in data['categories'] ] 0502 _data['categories']=_cat 0503 del _data['start'] 0504 if data.has_key('start') and data['start']: 0505 _date=[{'year': data['start'][0], 'month': data['start'][1], 0506 'day': data['start'][2] }] 0507 _data['start']=_date 0508 del _data['end'] 0509 if data.has_key('end') and data['end']: 0510 _date=[{'year': data['end'][0], 'month': data['end'][1], 0511 'day': data['end'][2] }] 0512 _data['end']=_date 0513 _dict={ 'filter': _data } 0514 database.ensurerecordtype(_dict, filterobjectfactory) 0515 self.GetParent().GetParent().GetActiveDatabase().savemajordict('calendar_filter', 0516 _dict) 0517 0518 def SetDateControls(self, fgs, fgs1): 0519 self._start_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 0520 label='Start Date:', 0521 style=wx.ALIGN_RIGHT) 0522 fgs.Add(self._start_date_chkbox, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL, 0) 0523 self._start_date=wx.calendar.CalendarCtrl(self, -1, wx.DateTime_Now(), 0524 style = wx.calendar.CAL_SUNDAY_FIRST 0525 | wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION) 0526 self._start_date.Disable() 0527 fgs.Add(self._start_date, 1, wx.ALIGN_LEFT, 5) 0528 self._end_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 0529 label='End Date:', 0530 style=wx.ALIGN_RIGHT) 0531 fgs.Add(self._end_date_chkbox, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL, 0) 0532 self._end_date=wx.calendar.CalendarCtrl(self, -1, wx.DateTime_Now(), 0533 style = wx.calendar.CAL_SUNDAY_FIRST 0534 | wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION) 0535 self._end_date.Disable() 0536 fgs.Add(self._end_date, 1, wx.ALIGN_LEFT, 5) 0537 self._preset_date_chkbox=wx.CheckBox(self, -1, label='Preset Duration', 0538 style=wx.ALIGN_RIGHT) 0539 fgs.Add(self._preset_date_chkbox, 0, 0540 wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL, 0) 0541 self._preset_date=wx.Choice(self, -1, choices=('This Week', 0542 'This Month', 0543 'This Year', 0544 'Next 7 Days',)) 0545 self._preset_date.SetSelection(1) 0546 self._preset_date.Disable() 0547 fgs.Add(self._preset_date, 0, wx.ALIGN_LEFT, 5) 0548 wx.EVT_CHECKBOX(self, self._preset_date_chkbox.GetId(), 0549 self.OnCheckBox) 0550 0551 def OnCheckBox(self, evt): 0552 super(FilterDialog, self).OnCheckBox(evt) 0553 self._repeat_option(self._start_date_chkbox.GetValue() and \ 0554 self._end_date_chkbox.GetValue() or \ 0555 self._preset_date_chkbox.GetValue()) 0556 if evt.GetId()==self._preset_date_chkbox.GetId(): 0557 if self._preset_date_chkbox.GetValue(): 0558 self._preset_date.Enable() 0559 else: 0560 self._preset_date.Disable() 0561 0562 def __set_date(self, chk_box, cal, d): 0563 if d is None: 0564 chk_box.SetValue(False) 0565 cal.Disable() 0566 else: 0567 chk_box.SetValue(True) 0568 cal.Enable() 0569 dt=wx.DateTime() 0570 dt.Set(d[2], year=d[0], month=d[1]-1) 0571 cal.SetDate(dt) 0572 0573 def set_base(self, data): 0574 super(FilterDialog, self).set_base(data) 0575 self._rpt_chkbox.SetValue(data.get('rpt_events', False)) 0576 0577 def set(self, data): 0578 self.__set_date(self._start_date_chkbox, self._start_date, 0579 data.get('start', None)) 0580 self.__set_date(self._end_date_chkbox, self._end_date, 0581 data.get('end', None)) 0582 self.set_base(data) 0583 if data.get('preset_date', None) is not None: 0584 self._preset_date_chkbox.SetValue(True) 0585 self._preset_date.Enable() 0586 self._preset_date.SetSelection(data['preset_date']) 0587 self._repeat_option(True) 0588 else: 0589 self._preset_date_chkbox.SetValue(False) 0590 self._preset_date.Disable() 0591 0592 def _get_preset_thisweek(self): 0593 # return the dates of (today, Sat) 0594 _today=datetime.date.today() 0595 _dow=_today.isoweekday()%7 #Sun=0, Sat=6 0596 _end=_today+datetime.timedelta(6-_dow) 0597 return ((_today.year, _today.month, _today.day), 0598 (_end.year, _end.month, _end.day)) 0599 0600 def _get_preset_thismonth(self): 0601 # return the dates of (today, end-of-month) 0602 _today=datetime.date.today() 0603 _end=_today.replace(day=calendar.monthrange(_today.year,_today.month)[1]) 0604 return ((_today.year, _today.month, _today.day), 0605 (_end.year, _end.month, _end.day)) 0606 0607 def _get_preset_thisyear(self): 0608 # return the dates of (today, end-of-year) 0609 _today=datetime.date.today() 0610 _end=_today.replace(month=12, day=31) 0611 return ((_today.year, _today.month, _today.day), 0612 (_end.year, _end.month, _end.day)) 0613 0614 def _get_preset_next7(self): 0615 # return the dates of (today, today+6) 0616 _today=datetime.date.today() 0617 _end=_today+datetime.timedelta(days=6) 0618 return ((_today.year, _today.month, _today.day), 0619 (_end.year, _end.month, _end.day)) 0620 0621 def _get_preset_date(self): 0622 _choice=self._preset_date.GetSelection() 0623 if _choice==wx.NOT_FOUND: 0624 return None, None 0625 if _choice==0: 0626 return self._get_preset_thisweek() 0627 elif _choice==1: 0628 return self._get_preset_thismonth() 0629 elif _choice==2: 0630 return self._get_preset_thisyear() 0631 else: 0632 return self._get_preset_next7() 0633 0634 def get(self): 0635 r={} 0636 if self._preset_date_chkbox.GetValue(): 0637 r['start'],r['end']=self._get_preset_date() 0638 r['preset_date']=self._preset_date.GetSelection() 0639 else: 0640 r['preset_date']=None 0641 if self._start_date_chkbox.GetValue(): 0642 dt=self._start_date.GetDate() 0643 r['start']=(dt.GetYear(), dt.GetMonth()+1, dt.GetDay()) 0644 else: 0645 r['start']=None 0646 if self._end_date_chkbox.GetValue(): 0647 dt=self._end_date.GetDate() 0648 r['end']=(dt.GetYear(), dt.GetMonth()+1, dt.GetDay()) 0649 else: 0650 r['end']=None 0651 self.get_base(r) 0652 self._save_to_fs(r) 0653 return r 0654 0655 #------------------------------------------------------------------------------- 0656 class AutoSyncFilterDialog(FilterDialogBase): 0657 def __init__(self, parent, id, caption, categories, style=wx.DEFAULT_DIALOG_STYLE): 0658 FilterDialogBase.__init__(self, parent, id, caption, categories, style) 0659 0660 def SetDateControls(self, fgs, fgs1): 0661 #start_offset 0662 self._start_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 0663 label='Start Offset (days):', 0664 style=wx.ALIGN_RIGHT) 0665 fgs.Add(self._start_date_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0666 self._start_date=wx.lib.intctrl.IntCtrl(self, id=wx.NewId(), size=(50,-1), 0667 value=0, min=0, max=1000) 0668 self._start_date.Disable() 0669 fgs.Add( self._start_date, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 0670 #end_offset 0671 self._end_date_chkbox=wx.CheckBox(self, id=wx.NewId(), 0672 label='End Offset (days):', 0673 style=wx.ALIGN_RIGHT) 0674 fgs.Add(self._end_date_chkbox, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 5) 0675 self._end_date=wx.lib.intctrl.IntCtrl(self, id=wx.NewId(), size=(50,-1), 0676 value=0, min=0, max=1000) 0677 self._end_date.Disable() 0678 fgs.Add( self._end_date, 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 2) 0679 fgs1.Add(wx.StaticText(self, -1, 'Note: The start offset is the number of days' + 0680 ' in the past, and the end offset is the number of days' + 0681 ' in the future imported from the calender into your phone. If' + 0682 ' disabled, all past and/or future events are imported.', 0683 size=(270,55)), 0684 0, wx.ALIGN_LEFT|wx.TOP|wx.BOTTOM, 5) 0685 0686 0687 def __set_start_date(self, d): 0688 if d is None: 0689 self._start_date_chkbox.SetValue(False) 0690 self._start_date.Disable() 0691 else: 0692 self._start_date_chkbox.SetValue(True) 0693 self._start_date.Enable() 0694 self._start_date.SetValue(d) 0695 0696 def __set_end_date(self, d): 0697 if d is None: 0698 self._end_date_chkbox.SetValue(False) 0699 self._end_date.Disable() 0700 else: 0701 self._end_date_chkbox.SetValue(True) 0702 self._end_date.Enable() 0703 self._end_date.SetValue(d) 0704 0705 def set(self, data): 0706 self.__set_start_date(data.get('start_offset', None)) 0707 self.__set_end_date(data.get('end_offset', None)) 0708 self.set_base(data) 0709 0710 def get(self): 0711 r={} 0712 if self._start_date_chkbox.GetValue(): 0713 r['start_offset']=self._start_date.GetValue() 0714 else: 0715 r['start_offset']=None 0716 if self._end_date_chkbox.GetValue(): 0717 r['end_offset']=self._end_date.GetValue() 0718 else: 0719 r['end_offset']=None 0720 self.get_base(r) 0721 return r 0722 0723 #------------------------------------------------------------------------------- 0724 class ExportCalendarDialog(wx.Dialog): 0725 # subclass should override these 0726 _default_file_name="" 0727 _wildcards="All files|*.*" 0728 0729 def __init__(self, parent, title): 0730 super(ExportCalendarDialog, self).__init__(parent, -1, title) 0731 # make the ui 0732 vbs=wx.BoxSizer(wx.VERTICAL) 0733 hbs=wx.BoxSizer(wx.HORIZONTAL) 0734 hbs.Add(wx.StaticText(self, -1, "File"), 0, wx.ALL|wx.ALIGN_CENTRE, 5) 0735 self.filenamectrl=wx.TextCtrl(self, -1, self._default_file_name) 0736 hbs.Add(self.filenamectrl, 1, wx.ALL|wx.EXPAND, 5) 0737 self.browsectrl=wx.Button(self, wx.NewId(), "Browse...") 0738 hbs.Add(self.browsectrl, 0, wx.ALL|wx.EXPAND, 5) 0739 vbs.Add(hbs, 0, wx.EXPAND|wx.ALL, 5) 0740 # selection GUI 0741 vbs.Add(self.GetSelectionGui(self), 5, wx.EXPAND|wx.ALL, 5) 0742 # the buttons 0743 vbs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL,5) 0744 vbs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTER|wx.ALL, 5) 0745 # event handlers 0746 wx.EVT_BUTTON(self, self.browsectrl.GetId(), self.OnBrowse) 0747 wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk) 0748 # all done 0749 self.SetSizer(vbs) 0750 self.SetAutoLayout(True) 0751 vbs.Fit(self) 0752 0753 def GetSelectionGui(self, parent): 0754 hbs=wx.BoxSizer(wx.HORIZONTAL) 0755 self._selection=wx.RadioBox(parent, wx.NewId(), 'Events Selection', 0756 choices=['All', 'Date Range'], 0757 style=wx.RA_SPECIFY_ROWS) 0758 hbs.Add(self._selection, 0, wx.EXPAND|wx.ALL, 5) 0759 sbs=wx.StaticBoxSizer(wx.StaticBox(parent, -1, 'Date Range'), wx.VERTICAL) 0760 gs=wx.FlexGridSizer(-1, 2, 5, 5) 0761 gs.AddGrowableCol(1) 0762 gs.Add(wx.StaticText(self, -1, 'Start:'), 0, wx.ALL, 0) 0763 self._start_date=wx.DatePickerCtrl(self, style=wx.DP_DROPDOWN | wx.DP_SHOWCENTURY) 0764 gs.Add(self._start_date, 0, wx.ALL, 0) 0765 gs.Add(wx.StaticText(self, -1, 'End:'), 0, wx.ALL, 0) 0766 self._end_date=wx.DatePickerCtrl(self, style=wx.DP_DROPDOWN | wx.DP_SHOWCENTURY) 0767 gs.Add(self._end_date, 0, wx.ALL, 0) 0768 sbs.Add(gs, 1, wx.EXPAND|wx.ALL, 5) 0769 hbs.Add(sbs, 0, wx.EXPAND|wx.ALL, 5) 0770 return hbs 0771 0772 def OnBrowse(self, _): 0773 with guihelper.WXDialogWrapper(wx.FileDialog(self, defaultFile=self.filenamectrl.GetValue(), 0774 wildcard=self._wildcards, style=wx.SAVE|wx.CHANGE_DIR), 0775 True) as (dlg, retcode): 0776 if retcode==wx.ID_OK: 0777 self.filenamectrl.SetValue(dlg.GetPath()) 0778 0779 def _export(self): 0780 # perform the actual caledar data import, subclass MUST override 0781 raise NotImplementedError 0782 0783 def OnOk(self, _): 0784 # do export 0785 self._export() 0786 self.EndModal(wx.ID_OK) 0787
Generated by PyXR 0.9.4