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
107
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', ''))
128
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()
197
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