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

Source Code for Module calendarentryeditor

   1  ### BITPIM 
   2  ### 
   3  ### Copyright (C) 2003-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: calendarentryeditor.py 4708 2008-09-06 04:10:44Z djpham $ 
   9   
  10  from __future__ import with_statement 
  11  import calendar 
  12  import copy 
  13  import datetime 
  14  import time 
  15   
  16  import wx 
  17  import wx.lib 
  18  import wx.lib.masked.textctrl 
  19  import wx.lib.intctrl 
  20  import wx.lib.scrolledpanel as scrolled 
  21   
  22  import bpcalendar 
  23  import field_color 
  24  import helpids 
  25  import phonebookentryeditor as pb_editor 
  26  import pubsub 
  27  import guihelper 
  28  import guiwidgets 
  29   
  30  widgets_list=[] 
  31   
32 -class RepeatEditor(pb_editor.DirtyUIBase):
33 _repeat_type= { 34 'daily': 1, 35 'weekly': 2, 36 'monthly': 3, 37 'yearly': 4 } 38 _repeat_options=('None', 'Daily', 'Weekly', 'Monthly', 'Yearly') 39 _dow=('Sun', 'Mon', 'Tues', 'Wed', 'Thu', 'Fri', 'Sat') 40 _monthly_nth_day=('First', 'Second', 'Third', 'Fourth', 'Last') 41 _daily_option_index=0 42 _weekly_option_index=1 43 _monthly_option_index=2 44 _weekly_wkst_str=(None, 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun') 45 _weekly_wkst_idx=(7, 1, 2, 3, 4, 5, 6) 46
47 - def __init__(self, parent, _):
48 global widgets_list 49 pb_editor.DirtyUIBase.__init__(self, parent) 50 # overall container 51 self._main_bs=wx.BoxSizer(wx.VERTICAL) 52 # vertical sizebox & checkboxes for different repreat options 53 hbs_1=wx.BoxSizer(wx.HORIZONTAL) 54 self._repeat_option_rb = wx.RadioBox( 55 self, -1, "Repeat Types:", wx.DefaultPosition, wx.DefaultSize, 56 self._repeat_options, 1, wx.RA_SPECIFY_COLS) 57 widgets_list.append((self._repeat_option_rb, 'repeat')) 58 wx.EVT_RADIOBOX(self, self._repeat_option_rb.GetId(), self.OnRepeatType) 59 hbs_1.Add(self._repeat_option_rb, 0, wx.LEFT, 5) 60 # daily options widgets 61 self._option_bs=wx.BoxSizer(wx.VERTICAL) 62 _box=wx.StaticBox(self, -1, 'Daily Options:') 63 widgets_list.append((_box, 'repeat')) 64 vbs=wx.StaticBoxSizer(_box, wx.VERTICAL) 65 hbs=wx.BoxSizer(wx.HORIZONTAL) 66 self._dl_every_nday=wx.RadioButton(self, -1, 'Every ', style=wx.RB_GROUP) 67 self._dl_every_nday.SetValue(True) 68 self._dl_every_wday=wx.RadioButton(self, -1, 'Every Weekday') 69 wx.EVT_RADIOBUTTON(self, self._dl_every_nday.GetId(), self.OnDirtyUI) 70 wx.EVT_RADIOBUTTON(self, self._dl_every_wday.GetId(), self.OnDirtyUI) 71 hbs.Add(self._dl_every_nday, 0, wx.LEFT, 0) 72 self._dl_interval=wx.TextCtrl(self, -1, '1') 73 wx.EVT_TEXT(self, self._dl_interval.GetId(), self.OnDirtyUI) 74 hbs.Add(self._dl_interval, 0, wx.LEFT, 0) 75 hbs.Add(wx.StaticText(self, -1, ' day(s)'), 0, wx.LEFT, 0) 76 vbs.Add(hbs, 0, wx.LEFT|wx.TOP, 10) 77 vbs.Add(self._dl_every_wday, 0, wx.LEFT, 10) 78 self._option_bs.Add(vbs, 0, wx.LEFT, 5) 79 self._daily_option_bs=vbs 80 # weekly options widgets 81 _box=wx.StaticBox(self, -1, 'Weekly Options:') 82 widgets_list.append((_box, 'repeat')) 83 vbs=wx.StaticBoxSizer(_box, wx.VERTICAL) 84 hbs=wx.BoxSizer(wx.HORIZONTAL) 85 hbs.Add(wx.StaticText(self, -1, 'Every '),0, wx.LEFT, 0) 86 self._wl_interval=wx.TextCtrl(self, -1, '1') 87 wx.EVT_TEXT(self, self._wl_interval.GetId(), self.OnDirtyUI) 88 hbs.Add(self._wl_interval, 0, wx.LEFT, 0) 89 hbs.Add(wx.StaticText(self, -1, ' week(s)'), 0, wx.LEFT, 0) 90 vbs.Add(hbs, 0, wx.LEFT|wx.TOP, 10) 91 vbs.Add(wx.StaticText(self, -1, 'On:'), 0, wx.LEFT, 10) 92 hbs=wx.GridSizer(2, 4) 93 self._wl_dow={} 94 for i, n in enumerate(self._dow): 95 self._wl_dow[i]=wx.CheckBox(self, -1, n) 96 wx.EVT_CHECKBOX(self, self._wl_dow[i].GetId(), self.OnDirtyUI) 97 hbs.Add(self._wl_dow[i], 0, wx.LEFT|wx.TOP, 5) 98 vbs.Add(hbs, 0, wx.LEFT, 5) 99 hbs=wx.BoxSizer(wx.HORIZONTAL) 100 hbs.Add(wx.StaticText(self, -1, 'Week starts on:'), 0, wx.LEFT, 10) 101 self._wl_wkst=wx.ComboBox(self, -1, value=self._dow[0], 102 choices=self._dow, style=wx.CB_READONLY) 103 wx.EVT_COMBOBOX(self, self._wl_wkst.GetId(), self.OnDirtyUI) 104 hbs.Add(self._wl_wkst, 0, wx.LEFT, 5) 105 vbs.Add(hbs, 0, wx.TOP, 10) 106 self._option_bs.Add(vbs, 0, wx.LEFT, 5) 107 self._weekly_option_bs=vbs 108 # monthly option widgets 109 _box=wx.StaticBox(self, -1, 'Monthly Options:') 110 widgets_list.append((_box, 'repeat')) 111 vbs=wx.StaticBoxSizer(_box, wx.VERTICAL) 112 hbs=wx.BoxSizer(wx.HORIZONTAL) 113 hbs.Add(wx.StaticText(self, -1, 'Every '),0, wx.LEFT, 0) 114 self._ml_interval=wx.TextCtrl(self, -1, '1') 115 wx.EVT_TEXT(self, self._ml_interval.GetId(), self.OnDirtyUI) 116 hbs.Add(self._ml_interval, 0, wx.LEFT, 0) 117 hbs.Add(wx.StaticText(self, -1, ' month(s)'), 0, wx.LEFT, 0) 118 vbs.Add(hbs, 0, wx.LEFT|wx.TOP, 10) 119 vbs.Add(wx.StaticText(self, -1, 'On:'), 0, wx.LEFT, 10) 120 self._ml_every_nday=wx.RadioButton(self, -1, 'Every nth day', style=wx.RB_GROUP) 121 self._ml_every_nday.SetValue(True) 122 self._ml_every_wday=wx.RadioButton(self, -1, 'Every ') 123 wx.EVT_RADIOBUTTON(self, self._ml_every_nday.GetId(), self.OnDirtyUI) 124 wx.EVT_RADIOBUTTON(self, self._ml_every_wday.GetId(), self.OnDirtyUI) 125 vbs.Add(self._ml_every_nday, 0, wx.LEFT|wx.TOP, 10) 126 hbs=wx.BoxSizer(wx.HORIZONTAL) 127 hbs.Add(self._ml_every_wday, 0, wx.LEFT, 0) 128 self._ml_nth_day=wx.ComboBox(self, -1, value=self._monthly_nth_day[0], 129 choices=self._monthly_nth_day, 130 style=wx.CB_READONLY) 131 self._ml_wday=wx.ComboBox(self, -1, value=self._dow[0], 132 choices=self._dow, style=wx.CB_READONLY) 133 wx.EVT_COMBOBOX(self, self._ml_nth_day.GetId(), self.OnDirtyUI) 134 wx.EVT_COMBOBOX(self, self._ml_wday.GetId(), self.OnDirtyUI) 135 hbs.Add(self._ml_nth_day, 0, wx.LEFT, 5) 136 hbs.Add(self._ml_wday, 0, wx.LEFT, 5) 137 vbs.Add(hbs, 0, wx.LEFT|wx.TOP, 10) 138 139 self._option_bs.Add(vbs, 0, wx.LEFT, 5) 140 self._monthly_option_bs=vbs 141 142 hbs_1.Add(self._option_bs, 0, wx.LEFT, 5) 143 self._main_bs.Add(hbs_1, 0, wx.LEFT|wx.TOP, 5) 144 # the exceptions list 145 _box=wx.StaticBox(self, -1, 'Excluded Dates:') 146 widgets_list.append((_box, 'repeat')) 147 hbs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 148 self._exception_list=wx.ListBox(self, -1) 149 hbs.Add(self._exception_list, 1, wx.LEFT|wx.TOP|wx.EXPAND, 5) 150 exception_del=wx.Button(self, -1, 'Include') 151 wx.EVT_BUTTON(self, exception_del.GetId(), self.OnIncludeException) 152 hbs.Add(exception_del, 0, wx.LEFT|wx.TOP, 5) 153 self._main_bs.Add(hbs, 1, wx.LEFT|wx.TOP|wx.EXPAND, 5) 154 # all done 155 self.SetSizer(self._main_bs) 156 self.SetAutoLayout(True) 157 self._main_bs.Fit(self) 158 self.OnRepeatType(None)
159
160 - def populate(self, data):
161 if data is None: 162 self._repeat_option_rb.SetSelection(0) 163 self._exception_list.Clear() 164 self.OnRepeatType(None) 165 return 166 rt=data.repeat_type 167 if rt==data.daily: 168 self._repeat_option_rb.SetSelection(1) 169 if data.interval: 170 self._dl_every_nday.SetValue(True) 171 self._dl_interval.SetValue(`data.interval`) 172 else: 173 self._dl_every_wday.SetValue(True) 174 self._dl_interval.SetValue('') 175 elif rt==data.weekly: 176 self._repeat_option_rb.SetSelection(2) 177 self._wl_interval.SetValue(`data.interval`) 178 dow_mask=data.dow 179 for i in range(len(self._wl_dow)): 180 b=((1<<i)&dow_mask)!=0 181 self._wl_dow[i].SetValue(b) 182 self._wl_wkst.SetValue(self._weekly_wkst_str[data.weekstart]) 183 elif rt==data.monthly: 184 self._repeat_option_rb.SetSelection(3) 185 self._ml_interval.SetValue(`data.interval2`) 186 if data.dow: 187 # every 1st *day of the month 188 self._ml_every_wday.SetValue(True) 189 self._ml_nth_day.SetSelection(data.interval-1) 190 dow_mask=data.dow 191 for i,e in enumerate(self._dow): 192 if (1<<i)&dow_mask: 193 self._ml_wday.SetValue(e) 194 break 195 else: 196 # every nth day of the month 197 self._ml_every_nday.SetValue(True) 198 else: 199 self._repeat_option_rb.SetSelection(4) 200 self._exception_list.Set(data.get_suppressed_list()) 201 self.OnRepeatType(None)
202
203 - def Set(self, data):
204 self.ignore_dirty=True 205 self.populate(data) 206 self.dirty=self.ignore_dirty=False
207
208 - def _get_daily_options(self, r):
209 r.repeat_type=r.daily 210 try: 211 b=self._dl_every_nday.GetValue() 212 except: 213 b=False 214 self._dl_every_nday.SetValue(False) 215 if b: 216 try: 217 r.interval=int(self._dl_interval.GetValue()) 218 except: 219 # default to 1 220 r.interval=1 221 else: 222 r.interval=0
223 - def _get_weekly_options(self, r):
224 r.repeat_type=r.weekly 225 try: 226 r.interval=int(self._wl_interval.GetValue()) 227 except: 228 # default to 1 229 r.interval=1 230 m=0 231 for i in range(len(self._wl_dow)): 232 if self._wl_dow[i].GetValue(): 233 m=m|(1<<i) 234 r.dow=m 235 r.weekstart=self._weekly_wkst_idx[self._wl_wkst.GetSelection()]
236 - def _get_monthly_options(self, r):
237 r.repeat_type=r.monthly 238 try: 239 r.interval2=int(self._ml_interval.GetValue()) 240 except: 241 r.interval2=1 242 try: 243 b=self._ml_every_wday.GetValue() 244 except: 245 b=False 246 self._ml_every_wday.SetValue(False) 247 if b: 248 # every 1st Monday etc. 249 r.interval=self._ml_nth_day.GetSelection()+1 250 r.dow=1<<self._ml_wday.GetSelection()
251
252 - def Get(self):
253 self.dirty=self.ignore_dirty=False 254 rt=self._repeat_option_rb.GetSelection() 255 if rt==0: 256 # No repeat 257 return None 258 r=bpcalendar.RepeatEntry() 259 if rt==1: 260 # daily 261 self._get_daily_options(r) 262 elif rt==2: 263 # weekly 264 self._get_weekly_options(r) 265 elif rt==3: 266 # monthly 267 self._get_monthly_options(r) 268 else: 269 r.repeat_type=r.yearly 270 # get the list of exceptions 271 r.suppressed=[str(self._exception_list.GetString(i)) \ 272 for i in range(self._exception_list.GetCount())] 273 # and return the result 274 return r
275
276 - def OnRepeatType(self, evt):
277 s=self._repeat_option_rb.GetSelection() 278 self._option_bs.Hide(self._weekly_option_index) 279 self._option_bs.Hide(self._daily_option_index) 280 self._option_bs.Hide(self._monthly_option_index) 281 if s==1: 282 self._option_bs.Show(self._daily_option_index) 283 elif s==2: 284 self._option_bs.Show(self._weekly_option_index) 285 elif s==3: 286 self._option_bs.Show(self._monthly_option_index) 287 self._option_bs.Layout() 288 self.OnDirtyUI(evt)
289
290 - def OnIncludeException(self, evt):
291 print 'OnIncludeException' 292 s=self._exception_list.GetSelections() 293 if not len(s): 294 # nothing selected 295 return 296 self._exception_list.Delete(s[0]) 297 self.OnDirtyUI(evt)
298 299 #------------------------------------------------------------------------------
300 -class GeneralEditor(pb_editor.DirtyUIBase):
301 _dict_key_index=0 302 _label_index=1 303 _class_index=2 304 _get_index=3 305 _set_index=4 306 _w_index=5 307 color_field_name='general'
308 - def __init__(self, parent, _):
309 global widgets_list 310 # base clase 311 pb_editor.DirtyUIBase.__init__(self, parent) 312 # structure to hold all the widgets of this panel 313 self._fields=[ 314 ['description', 'Summary:', DVTextControl, None, None, None], 315 ['location', 'Location:', DVTextControl, None, None, None], 316 ['allday', 'All-Day:', wx.CheckBox, None, None, None], 317 ['start', 'From:', DVDateTimeControl, None, self._set_start_datetime, None], 318 ['end', 'To:', DVDateTimeControl, None, self._set_end_datetime, None], 319 ['priority', 'Priority:', None, self._get_priority, self._set_priority, None], 320 ['alarm', 'Alarm:', DVIntControl, None, None, None], 321 ['vibrate', 'Vibrate:', wx.CheckBox, None, None, None], 322 ] 323 # overall container 324 vbs=wx.StaticBoxSizer(wx.StaticBox(self, -1), wx.VERTICAL) 325 # instantiate the widgets 326 self._w={} 327 gs=wx.FlexGridSizer(-1,2,5,5) 328 gs.AddGrowableCol(1) 329 for n in self._fields: 330 desc=n[self._label_index] 331 t=wx.StaticText(self, -1, desc, style=wx.ALIGN_LEFT) 332 widgets_list.append((t, n[self._dict_key_index])) 333 gs.Add(t) 334 if desc=='Priority:': 335 c=wx.ComboBox(self, -1, "", (-1, -1), (-1, -1), 336 ['<None>', '1 - Highest', '2', '3', '4', '5 - Normal', 337 '6', '7' ,'8', '9', '10 - Lowest'], wx.CB_DROPDOWN) 338 else: 339 c=n[self._class_index](self, -1) 340 gs.Add(c, 0, wx.EXPAND, 0) 341 n[self._w_index]=self._w[n[self._dict_key_index]]=c 342 vbs.Add(gs, 0, wx.EXPAND|wx.ALL, 5) 343 # event handlers 344 wx.EVT_CHECKBOX(self, self._w['allday'].GetId(), self.OnAllday) 345 wx.EVT_CHECKBOX(self, self._w['vibrate'].GetId(), self.OnDirtyUI) 346 wx.EVT_COMBOBOX(self, self._w['priority'].GetId(), self.OnDirtyUI) 347 # all done 348 self.SetSizer(vbs) 349 self.SetAutoLayout(True) 350 vbs.Fit(self)
351
352 - def OnMakeDirty(self, evt):
353 self.OnDirtyUI(evt)
354
355 - def OnAllday(self, evt):
356 v=evt.IsChecked() 357 self._w['start'].SetAllday(v) 358 self._w['end'].SetAllday(v) 359 self.OnDirtyUI(evt)
360
361 - def IsValid(self):
362 # validate and return T if so or F otherwise 363 # check for valid date/time entries 364 for w in (self._w['start'], self._w['end']): 365 if not w.IsValid() or w.IsEmpty(): 366 w.SetFocus() 367 wx.Bell() 368 return False 369 # whine if end is before start 370 start=datetime.datetime(*self._w['start'].GetValue()) 371 end=datetime.datetime(*self._w['end'].GetValue()) 372 if start>end: 373 # scold the user 374 guihelper.MessageDialog(self, "End date and time is before start!", "Time Travel Attempt Detected", 375 wx.OK|wx.ICON_EXCLAMATION) 376 # move focus 377 self._w['end'].SetFocus() 378 return False 379 return True
380
381 - def Set(self, data):
382 self.ignore_dirty=True 383 if data is None: 384 for n in self._fields: 385 n[self._w_index].Enable(False) 386 else: 387 for n in self._fields: 388 w=n[self._w_index] 389 w.Enable(True) 390 if n[self._set_index] is None: 391 w.SetValue(getattr(data, n[self._dict_key_index])) 392 else: 393 n[self._set_index](w, data) 394 self.ignore_dirty=self.dirty=False
395
396 - def Get(self, data):
397 self.ignore_dirty=self.dirty=False 398 if data is None: 399 return 400 for n in self._fields: 401 w=n[self._w_index] 402 if n[self._get_index] is None: 403 v=w.GetValue() 404 else: 405 v=n[self._get_index](w, None) 406 setattr(data, n[self._dict_key_index], v)
407
408 - def _set_priority(self, w, entry):
409 p=entry.priority 410 if p is None: 411 w.SetSelection(0) 412 else: 413 w.SetSelection(p)
414 - def _get_priority(self, w, _):
415 s=w.GetSelection() 416 if s: 417 return s 418 else: 419 return None
420
421 - def _set_start_datetime(self, w, entry):
422 w.SetAllday(entry.allday, entry.start)
423
424 - def _set_end_datetime(self, w, entry):
425 w.SetAllday(entry.allday, entry.end)
426 427 #------------------------------------------------------------------------------
428 -class CategoryEditor(pb_editor.DirtyUIBase):
429 430 # we have to have an entry with a special string for the unnamed string 431 432 unnamed="Select:" 433
434 - def __init__(self, parent, pos):
435 global widgets_list 436 437 pb_editor.DirtyUIBase.__init__(self, parent) 438 self.static_box=wx.StaticBox(self, -1, "Category") 439 hs=wx.StaticBoxSizer(self.static_box, wx.HORIZONTAL) 440 441 self.categories=[] 442 self.category=wx.ListBox(self, -1, choices=self.categories) 443 pubsub.subscribe(self.OnUpdateCategories, pubsub.ALL_CATEGORIES) 444 pubsub.publish(pubsub.REQUEST_CATEGORIES) 445 # a boxsizer for the master category list 446 vbs=wx.BoxSizer(wx.VERTICAL) 447 vbs.Add(wx.StaticText(self, -1, 'Master Category'), 0, 448 wx.TOP|wx.LEFT, 5) 449 vbs.Add(self.category, 1, wx.EXPAND|wx.ALL, 5) 450 hs.Add(vbs, 1, wx.EXPAND|wx.ALL, 5) 451 # a boxsizer for the buttons 452 vbs=wx.BoxSizer(wx.VERTICAL) 453 self.but=wx.Button(self, wx.NewId(), "Manage Categories:") 454 add_btn=wx.Button(self, -1, 'Add ->') 455 del_btn=wx.Button(self, -1, '<- Remove') 456 vbs.Add(self.but, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 457 vbs.Add(add_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 458 vbs.Add(del_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 459 hs.Add(vbs, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 460 wx.EVT_BUTTON(self, add_btn.GetId(), self.OnAddCategory) 461 wx.EVT_BUTTON(self, del_btn.GetId(), self.OnDelCategory) 462 # box sizer for the selected category 463 vbs=wx.BoxSizer(wx.VERTICAL) 464 vbs.Add(wx.StaticText(self, -1, 'Selected Category:'), 0, 465 wx.TOP|wx.LEFT, 5) 466 self._my_category=wx.ListBox(self, -1) 467 vbs.Add(self._my_category, 1, wx.EXPAND|wx.ALL, 5) 468 hs.Add(vbs, 1, wx.EXPAND|wx.ALL, 5) 469 wx.EVT_BUTTON(self, self.but.GetId(), self.OnManageCategories) 470 471 self.SetSizer(hs) 472 hs.Fit(self)
473
474 - def OnManageCategories(self, _):
475 with guihelper.WXDialogWrapper(pb_editor.CategoryManager(self), 476 True): 477 pass
478
479 - def OnUpdateCategories(self, msg):
480 cats=msg.data[:] 481 if self.categories!=cats: 482 self.categories=cats 483 sel=self.category.GetStringSelection() 484 self.category.Clear() 485 for i in cats: 486 self.category.Append(i) 487 try: 488 if len(sel): 489 self.category.SetStringSelection(sel) 490 except: 491 pass
492
493 - def Get(self):
494 self.ignore_dirty=self.dirty=False 495 r=[] 496 count=self._my_category.GetCount() 497 if count==0: 498 return r 499 for i in range(count): 500 r.append({ 'category': self._my_category.GetString(i) }) 501 return r
502
503 - def Set(self, data):
504 self.ignore_dirty=True 505 self._my_category.Clear() 506 if data is None or len(data)==0: 507 # none or empty list, do nothing 508 return 509 for n in data: 510 v=n.get('category', None) 511 if v is not None: 512 self._my_category.Append(v) 513 self.ignore_dirty=self.dirty=False
514
515 - def OnAddCategory(self, evt):
516 v=self.category.GetStringSelection() 517 if not len(v): 518 # no selection made, do nothing 519 return 520 self.ignore_dirty=True 521 self._my_category.Append(v) 522 self._my_category.SetStringSelection(v) 523 self.ignore_dirty=False 524 self.OnDirtyUI(evt)
525
526 - def OnDelCategory(self, evt):
527 v=self._my_category.GetSelection() 528 if v==wx.NOT_FOUND: 529 # no selection, do nothing 530 return 531 self.ignore_dirty=True 532 self._my_category.Delete(v) 533 self.ignore_dirty=False 534 self.OnDirtyUI(evt)
535 536 #------------------------------------------------------------------------------
537 -class Editor(wx.Dialog):
538 539 # results on asking if the user wants to change the original (repeating) entry, just 540 # this instance, or cancel 541 ANSWER_ORIGINAL=1 542 ANSWER_THIS=2 543 ANSWER_CANCEL=3 544 _dict_key_index=0 545 _label_index=1 546 _get_index=2 547 _set_index=3 548 _w_index=4 549 # notebook items 550 _general_page=0 551 _repeat_page=1 552 _notes_page=2 553 _categories_page=3 554 _wallpapers_page=4 555 _ringtones_page=5 556 _last_page=6 557 _items=[ 558 ("General", None, GeneralEditor, None), 559 ("Repeat", 'repeat', RepeatEditor, None), 560 ("Notes", "notes", pb_editor.MemoEditor, 'memo'), 561 ("Categories", "categories", CategoryEditor, 'category'), 562 ("Wallpapers", "wallpapers", pb_editor.WallpaperEditor, 'wallpaper'), 563 ("Ringtones", "ringtones", pb_editor.RingtoneEditor, 'ringtone'), 564 ] 565 color_field_name='calendar' 566
567 - def __init__(self, parent):
568 global widgets_list 569 wx.Dialog.