1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12  """ Handle Import Calendar Preset feature 
 13  """ 
 14   
 15   
 16  from __future__ import with_statement 
 17  import calendar 
 18  import copy 
 19  import datetime 
 20  import random 
 21  import sha 
 22   
 23   
 24  import wx 
 25  import wx.wizard as wiz 
 26   
 27   
 28  import common_calendar 
 29  import database 
 30  import guihelper 
 31  import imp_cal_wizard 
 32  import importexport 
 33  import setphone_wizard 
 34   
 35   
 36  IMP_OPTION_REPLACEALL=0 
 37  IMP_OPTION_ADD=1 
 38  IMP_OPTION_PREVIEW=2 
 39  IMP_OPTION_MERGE=3 
 49  importcalendarobjectfactory=database.dataobjectfactory(ImportCalendarDataObject) 
 50   
 51   
 52 -class ImportCalendarEntry(dict): 
  53       
 54       
 55   
 56 -    def __init__(self, data=None): 
  60   
 61      _persistrandom=random.Random() 
 62 -    def _create_id(self): 
  63          "Create a BitPim serial for this entry" 
 64          rand2=random.Random()  
 65          num=sha.new() 
 66          num.update(`self._persistrandom.random()`) 
 67          num.update(`rand2.random()`) 
 68          return num.hexdigest() 
  70          s=self.get('serials', []) 
 71          _id=None 
 72          for n in s: 
 73              if n.get('sourcetype', None)=='bitpim': 
 74                  _id=n.get('id', None) 
 75                  break 
 76          if not _id: 
 77              _id=self._create_id() 
 78              self._set_id(_id) 
 79          return _id 
  80 -    def _set_id(self, id): 
  81          s=self.get('serials', []) 
 82          for n in s: 
 83              if n.get('sourcetype', None)=='bitpim': 
 84                  n['id']=id 
 85                  return 
 86          self.setdefault('serials', []).append({'sourcetype': 'bitpim', 'id': id } ) 
  87      id=property(fget=_get_id, fset=_set_id) 
 88   
 90           
 91           
 92          _del_keys=[x for x in self \ 
 93                     if not x in ImportCalendarDataObject.allproperties] 
 94          for _key in  _del_keys: 
 95              del self[_key] 
   96   
 99 -    def __init__(self, parent, id, caption, data): 
 102   
108   
109 -class PresetNamePage(setphone_wizard.MyPage): 
 110 -    def __init__(self, parent): 
 111          super(PresetNamePage, self).__init__(parent, 
112                                               'Calendar Import Preset Name') 
 113   
114 -    def GetMyControls(self): 
 115          vbs=wx.BoxSizer(wx.VERTICAL) 
116          vbs.Add(wx.StaticText(self, -1, 'Preset Name:'), 0, 
117                  wx.ALL|wx.EXPAND, 5) 
118          self._name=wx.TextCtrl(self, -1, '') 
119          vbs.Add(self._name, 0, wx.ALL|wx.EXPAND, 5) 
120          return vbs 
 121   
123          return bool(self._name.GetValue()) 
 124 -    def get(self, data): 
 125          data['name']=self._name.GetValue() 
 126 -    def set(self, data): 
 127          self._name.SetValue(data.get('name', '')) 
 129   
130 -class PresetFilterPage(setphone_wizard.MyPage): 
 131 -    def __init__(self, parent): 
 132          self._data={} 
133          super(PresetFilterPage, self).__init__(parent, 
134                                                 'Calendar Preset Filter') 
 135      _col_names=({ 'label': 'Start Date:', 'attr': '_start' }, 
136                  { 'label': 'End Date:', 'attr': '_end' }, 
137                  { 'label': 'Preset Duration:', 'attr': '_preset' }, 
138                  { 'label': 'Repeat Events:', 'attr': '_repeat' }, 
139                  { 'label': 'Alarm Setting:', 'attr': '_alarm' }, 
140                  { 'label': 'Alarm Vibrate:', 'attr': '_vibrate' }, 
141                  { 'label': 'Alarm Ringtone:', 'attr': '_ringtone' }, 
142                  { 'label': 'Alarm Value:', 'attr': '_alarm_value' }, 
143                  ) 
144 -    def GetMyControls(self): 
 145          gs=wx.GridBagSizer(5, 10) 
146          gs.AddGrowableCol(1) 
147          for _row, _col in enumerate(PresetFilterPage._col_names): 
148              gs.Add(wx.StaticText(self, -1, _col['label']), 
149                     pos=(_row, 0), flag=wx.ALIGN_CENTER_VERTICAL) 
150              _w=wx.StaticText(self, -1, _col['attr']) 
151              setattr(self, _col['attr'], _w) 
152              gs.Add(_w, pos=(_row, 1), flag=wx.ALIGN_CENTER_VERTICAL) 
153          _btn=wx.Button(self, -1, 'Modify') 
154          wx.EVT_BUTTON(self, _btn.GetId(), self._OnFilter) 
155          gs.Add(_btn, pos=(_row+1, 0)) 
156          return gs 
 157   
158 -    def _OnFilter(self, _): 
 159          with guihelper.WXDialogWrapper(FilterDialog(self, -1, 'Filtering Parameters', self._data), 
160                                         True) as (dlg, retcode): 
161              if retcode==wx.ID_OK: 
162                  self._data.update(dlg.get()) 
163                  self._populate() 
 164   
165 -    def _display(self, key, attr, fmt): 
 166           
167          _v=self._data.get(key, None) 
168          getattr(self, attr).SetLabel(_v is not None and eval(fmt) or '') 
 169 -    def _populate(self): 
 170           
171          if self._data.get('preset_date', None) is None: 
172              _fmt="'%04d/%02d/%02d'%(_v[0], _v[1], _v[2])" 
173          else: 
174              _fmt="'<Preset>'" 
175          self._display('start', '_start', _fmt) 
176          self._display('end', '_end', _fmt) 
177          self._display('preset_date', '_preset', 
178                        "['This Week', 'This Month', 'This Year', 'Next 7 Days'][_v]") 
179          self._display('rpt_events', '_repeat', 
180                        "{ True: 'Import as mutil-single events', False: ''}[_v]") 
181          if self._data.get('no_alarm', None): 
182              _s='Disable All Alarms' 
183          elif self._data.get('alarm_override', None): 
184              _s='Set Alarm on All Events' 
185          else: 
186              _s='Use Alarm Settings from Import Source' 
187          self._alarm.SetLabel(_s) 
188          self._display('vibrate', '_vibrate', 
189                        "{ True: 'Enable Vibrate for Alarms', False: ''}[_v]") 
190          self._display('ringtone', '_ringtone', "'%s'%((_v != 'Select:') and _v or '',)") 
191          self._display('alarm_value', '_alarm_value', "'%d'%_v") 
 192 -    def get(self, data): 
 193          data.update(self._data) 
 194 -    def set(self, data): 
 195          self._data=data 
196          self._populate() 
 198   
199 -class ImportOptionPage(imp_cal_wizard.ImportOptionPage): 
 200      _choices=('Replace All', 'Add', 'Preview', 'Merge') 
 201   
204      ID_ADD=wx.NewId() 
205 -    def __init__(self, parent, entry, 
206                   id=-1, title='Calendar Import Preset Wizard'): 
 207          super(ImportCalendarPresetWizard, self).__init__(parent, id, title) 
208          self._data=entry 
209          _import_name_page=PresetNamePage(self) 
210          _import_type_page=imp_cal_wizard.ImportTypePage(self) 
211          _import_source_page=imp_cal_wizard.ImportSourcePage(self) 
212          _import_filter_page=PresetFilterPage(self) 
213          _import_option=ImportOptionPage(self) 
214   
215          wiz.WizardPageSimple_Chain(_import_name_page, _import_type_page) 
216          wiz.WizardPageSimple_Chain(_import_type_page, _import_source_page) 
217          wiz.WizardPageSimple_Chain(_import_source_page, _import_filter_page) 
218          wiz.WizardPageSimple_Chain(_import_filter_page, _import_option) 
219          self.first_page=_import_name_page 
220          self.GetPageAreaSizer().Add(self.first_page, 1, wx.EXPAND|wx.ALL, 5) 
221          wiz.EVT_WIZARD_PAGE_CHANGING(self, self.GetId(), self.OnPageChanging) 
222          wiz.EVT_WIZARD_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged) 
 223   
226   
227 -    def OnPageChanging(self, evt): 
 228          pg=evt.GetPage() 
229          if not evt.GetDirection() or pg.ok(): 
230              pg.get(self._data) 
231          else: 
232              evt.Veto() 
 233   
234 -    def OnPageChanged(self, evt): 
 235          evt.GetPage().set(self._data) 
 236   
239   
242   
244          if self._data.get('data_obj', None): 
245              return self._data['data_obj'].get_category_list() 
246          return [] 
  247   
250      ID_ADD=wx.NewId() 
251      ID_REPLACE=wx.NewId() 
252      ID_MERGE=wx.NewId() 
254          super(CalendarPreviewDialog, self).__init__(parent, -1, 
255                                                      'Calendar Import Preview') 
256          _vbs=wx.BoxSizer(wx.VERTICAL) 
257          _lb=wx.ListBox(self, -1, style=wx.LB_SINGLE|wx.LB_HSCROLL|wx.LB_NEEDED_SB, 
258                         choices=['%04d/%02d/%02d %02d:%02d - '%x.start+x.description\ 
259                                  for _,x in data.items()]) 
260          _vbs.Add(_lb, 0, wx.EXPAND|wx.ALL, 5) 
261          _vbs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 
262          _hbs=wx.BoxSizer(wx.HORIZONTAL) 
263          _btn=wx.Button(self, self.ID_REPLACE, 'Replace All') 
264          wx.EVT_BUTTON(self, self.ID_REPLACE, self._OnButton) 
265          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
266          _btn=wx.Button(self, self.ID_ADD, 'Add') 
267          wx.EVT_BUTTON(self, self.ID_ADD, self._OnButton) 
268          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
269          _btn=wx.Button(self, self.ID_MERGE, 'Merge') 
270          wx.EVT_BUTTON(self, self.ID_MERGE, self._OnButton) 
271          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
272          _hbs.Add(wx.Button(self, wx.ID_CANCEL, 'Cancel'), 0, 
273                   wx.ALIGN_CENTRE|wx.ALL, 5) 
274          _vbs.Add(_hbs, 0, wx.EXPAND|wx.ALL, 5) 
275          self.SetSizer(_vbs) 
276          self.SetAutoLayout(True) 
277          _vbs.Fit(self) 
 278   
 281   
284      ID_ADD=wx.NewId() 
285      ID_MERGE=wx.NewId() 
286   
288          self._parent=parent 
289          self._data={} 
290          self._import_data=None 
291          self._buttons=[] 
292          super(ImportCalendarPresetDialog, self).__init__(parent, id, 
293                                                           title, 
294                                                           size=(500, 500)) 
295          _vbs=wx.BoxSizer(wx.VERTICAL) 
296          _static_bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, 
297                                                    'Available Presets:'), 
298                                       wx.VERTICAL) 
299          self._name_lb=wx.ListBox(self, -1, style=wx.LB_SINGLE|wx.LB_NEEDED_SB) 
300          wx.EVT_LISTBOX(self, self._name_lb.GetId(), self._set_button_states) 
301          _static_bs.Add(self._name_lb, 0, wx.EXPAND|wx.ALL, 5) 
302          _vbs.Add(_static_bs, 0, wx.EXPAND|wx.ALL, 5) 
303          _vbs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 
304          _hbs=wx.BoxSizer(wx.HORIZONTAL) 
305          _btn=wx.Button(self, -1, 'Import') 
306          wx.EVT_BUTTON(self, _btn.GetId(), self._OnRun) 
307          self._buttons.append(_btn) 
308          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
309          _btn=wx.Button(self, wx.ID_NEW) 
310          wx.EVT_BUTTON(self, _btn.GetId(), self._OnNew) 
311          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
312          _btn=wx.Button(self, -1, 'Edit') 
313          wx.EVT_BUTTON(self, _btn.GetId(), self._OnEdit) 
314          self._buttons.append(_btn) 
315          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
316          _btn=wx.Button(self, wx.ID_DELETE) 
317          self._buttons.append(_btn) 
318          wx.EVT_BUTTON(self, _btn.GetId(), self._OnDel) 
319          _hbs.Add(_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
320          _hbs.Add(wx.Button(self, wx.ID_CANCEL), 
321                   0, wx.ALIGN_CENTRE|wx.ALL, 5) 
322          _vbs.Add(_hbs, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 
323          self.SetSizerAndFit(_vbs) 
324          if guihelper.IsGtk(): 
325               
326              self.SetSizeHints(-1, 175) 
327          self._get_from_fs() 
328          self._populate() 
 329   
335   
347   
349           
350          _today=datetime.date.today() 
351          _dow=_today.isoweekday()%7   
352          _end=_today+datetime.timedelta(6-_dow) 
353          return ((_today.year, _today.month, _today.day), 
354                  (_end.year, _end.month, _end.day)) 
 355   
357           
358          _today=datetime.date.today() 
359          _end=_today.replace(day=calendar.monthrange(_today.year,_today.month)[1]) 
360          return ((_today.year, _today.month, _today.day), 
361                  (_end.year, _end.month, _end.day)) 
 362   
364           
365          _today=datetime.date.today() 
366          _end=_today.replace(month=12, day=31) 
367          return ((_today.year, _today.month, _today.day), 
368                  (_end.year, _end.month, _end.day)) 
 369   
371           
372          _today=datetime.date.today() 
373          _end=_today+datetime.timedelta(days=6) 
374          return ((_today.year, _today.month, _today.day), 
375                  (_end.year, _end.month, _end.day)) 
 376   
378           
379          _preset_date=entry.get('preset_date', None) 
380          if _preset_date is None: 
381               
382              return 
383          entry['start'], entry['end']=getattr(self, 
384                                               ['_get_preset_thisweek', 
385                                                '_get_preset_thismonth', 
386                                                '_get_preset_thisyear', 
387                                                '_get_preset_next7'][_preset_date])() 
 388      @guihelper.BusyWrapper 
420   
445          _idx=self._name_lb.GetSelection() 
446          if _idx==wx.NOT_FOUND: 
447              return 
448          _key=self._name_lb.GetClientData(_idx) 
449          del self._data[_key] 
450          self._save_to_fs() 
451          self._populate() 
 452   
459   
461          item={} 
462          item.update(entry) 
463          if item.has_key('categories'): 
464              del item['categories'] 
465          if item.has_key('start'): 
466              del item['start'] 
467              if entry['start']: 
468                  item['start']=[{'year': entry['start'][0], 
469                                  'month': entry['start'][1], 
470                                  'day': entry['start'][2] }] 
471          if item.has_key('end'): 
472              del item['end'] 
473              if entry['end']: 
474                  item['end']=[{'year': entry['end'][0], 
475                                'month': entry['end'][1], 
476                                'day': entry['end'][2] }] 
477          return item 
 479          item={} 
480          item.update(entry) 
481          item['categories']=None 
482          if item.has_key('start') and item['start']: 
483              _d0=item['start'][0] 
484              item['start']=(_d0['year'], _d0['month'], _d0['day']) 
485          else: 
486              item['start']=None 
487          if item.has_key('end') and item['end']: 
488              _d0=entry['end'][0] 
489              item['end']=(_d0['year'], _d0['month'], _d0['day']) 
490          else: 
491              item['end']=None 
492          return item 
 493   
503   
512   
514          if self._import_data: 
515              return self._import_data.get() 
516          return {} 
 517   
519          if self._import_data: 
520              return self._import_data.get_category_list() 
521          return [] 
 522   
 525   
526   
527   
528  if __name__=="__main__": 
529      app=wx.PySimpleApp() 
530      f=wx.Frame(None, title='imp_cal_preset') 
531      _data=ImportCalendarEntry() 
532      _data.id 
533      with guihelper.WXDialogWrapper(ImportCalendarPresetWizard(f, _data)) \ 
534           as w: 
535          print 'RunWizard:',w.RunWizard() 
536          print 'Data:',w.get() 
537