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

Source Code for Module phonebookentryeditor

   1  ### BITPIM 
   2  ### 
   3  ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.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: phonebookentryeditor.py 4775 2010-01-04 03:44:57Z djpham $ 
   9   
  10  from __future__ import with_statement 
  11  import wx 
  12   
  13  import fixedscrolledpanel 
  14  import pubsub 
  15  import bphtml 
  16  import database 
  17  import nameparser 
  18  import wallpaper 
  19  import guihelper 
  20  import field_color 
  21  import helpids 
  22   
  23  """The dialog for editing a phonebook entry""" 
  24   
  25  # global ringone & wallpaper list 
  26  _ringtone_list=None 
  27  _wallpaper_list=None 
  28   
  29  # NavToolBar-------------------------------------------------------------------- 
  63   
  64  # DirtyUIBase------------------------------------------------------------------- 
  65  myEVT_DIRTY_UI=wx.NewEventType() 
  66  EVT_DIRTY_UI=wx.PyEventBinder(myEVT_DIRTY_UI, 1) 
  67   
68 -class DirtyUIBase(wx.Panel):
69 """ Base class to add the capability to generate a DirtyUI event"""
70 - def __init__(self, parent):
71 wx.Panel.__init__(self, parent, -1) 72 self.dirty=self.ignore_dirty=False
73
74 - def OnDirtyUI(self, evt):
75 if self.dirty or self.ignore_dirty: 76 return 77 self.dirty=True 78 self.GetEventHandler().ProcessEvent(\ 79 wx.PyCommandEvent(myEVT_DIRTY_UI, self.GetId()))
80 - def Clean(self):
81 self.dirty=False 82 self.ignore_dirty=False
83 - def Ignore(self, ignore=True):
84 self.ignore_dirty=ignore
85 - def Enable(self, enable=True):
86 super(DirtyUIBase, self).Enable(enable) 87 self.Refresh()
88 89 # My ListBox class--------------------------------------------------------------
90 -class ListBox(wx.ListBox):
91 """BitPim ListBox class that caches the selection string necessary for this 92 implementation. 93 """
94 - def __init__(self, *args, **kwargs):
95 super(ListBox, self).__init__(*args, **kwargs) 96 self._selstr='' 97 wx.EVT_LISTBOX(self, self.GetId(), self._OnSelected)
98 - def _OnSelected(self, evt):
99 self._selstr=evt.GetString() 100 evt.Skip()
101 - def GetStringSelection(self):
102 return self._selstr
103 - def SetStringSelection(self, selection):
104 try: 105 super(ListBox, self).SetStringSelection(selection) 106 self._selstr=selection 107 except: 108 self._selstr=''
109 - def SetSelection(self, idx):
110 try: 111 super(ListBox, self).SetSelection(idx) 112 self._selstr=self.GetString(idx) 113 except: 114 self._selstr=''
115 116 # RingtoneEditor----------------------------------------------------------------
117 -class MediaPreviewWindow(bphtml.HTMLWindow):
118 """A subclass of BitPim HTMLWindow that launches a media item when clicked"""
119 - def OnLinkClicked(self, evt):
120 pubsub.publish(pubsub.REQUEST_MEDIA_OPEN, 121 (evt.GetHref(), None))
122
123 -class RingtoneEditor(DirtyUIBase):
124 "Edit a ringtone" 125 126 # this is almost an exact clone of the wallpaper editor 127 128 unnamed="Select:" 129 unknownselprefix=": " 130 131 choices=["call", "message", "calendar"] 132 133 ID_LIST=wx.NewId() 134 135 _bordersize=3 136
137 - def __init__(self, parent, _, has_type=True, navtoolbar=False):
138 DirtyUIBase.__init__(self, parent) 139 140 _box=field_color.build_color_field(self, wx.StaticBox, 141 (self, -1, "Ringtone"), 'ringtone') 142 hs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 143 self.static_box=_box 144 vs=wx.BoxSizer(wx.VERTICAL) 145 146 self.preview=MediaPreviewWindow(self, -1) 147 self.preview.SetBorders(self._bordersize) 148 vs.Add(self.preview, 1, wx.EXPAND|wx.ALL, 5) 149 self.type=wx.ComboBox(self, -1, "call", choices=self.choices, style=wx.CB_READONLY) 150 self.type.SetSelection(0) 151 vs.Add(self.type, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 152 # Hide the 'type' combo box if not requested 153 if not has_type: 154 vs.Hide(1) 155 156 hs.Add(vs, 1, wx.EXPAND|wx.ALL, 5) 157 158 self.ringtone=ListBox(self, self.ID_LIST, choices=[self.unnamed], size=(-1,200)) 159 hs.Add(self.ringtone, 1, wx.EXPAND|wx.ALL, 5) 160 if navtoolbar: 161 hs.Add(NavToolBar(self, False), 0, wx.EXPAND|wx.BOTTOM, 5) 162 self.SetSizer(hs) 163 hs.Fit(self) 164 165 pubsub.subscribe(self.OnRingtoneUpdates, pubsub.ALL_RINGTONES) 166 wx.CallAfter(pubsub.publish, pubsub.REQUEST_RINGTONES) # make the call once we are onscreen 167 pubsub.subscribe(self.OnPreviewUpdate, pubsub.RESPONSE_MEDIA_INFO) 168 169 wx.EVT_LISTBOX(self, self.ID_LIST, self.OnLBClicked) 170 wx.EVT_LISTBOX_DCLICK(self, self.ID_LIST, self.OnLBClicked)
171
172 - def __del__(self):
176
177 - def OnRingtoneUpdates(self, msg):
178 # wxPython/wxWidget bug: ListBox.Clear emits a wx.EVT_LISTBOX event 179 # it shouldn't 180 self.Ignore() 181 tones=msg.data[:] 182 cur=self._get() 183 self.ringtone.Clear() 184 self.ringtone.Append(self.unnamed) 185 for p in tones: 186 self.ringtone.Append(p) 187 self._set(cur) 188 self.Clean()
189
190 - def OnLBClicked(self, evt=None):
191 if self.ringtone.GetSelection()==wx.NOT_FOUND: 192 return 193 self.OnDirtyUI(evt) 194 self._updaterequested=False 195 v=self._get().get('ringtone', None) 196 self.SetPreview(v)
197 198 _preview_html='<img src="bpimage:ringer.png;width=24;height=24"><P>%s'
199 - def OnPreviewUpdate(self, msg):
200 # Media tab replies with some description about the selected media item 201 if msg.data['client'] is self: 202 # this one's for moi! 203 if msg.data['canopen']: 204 _s='<A HREF="%s">%s</A><BR>'%(msg.data['desc'][0], msg.data['desc'][0]) +\ 205 '<BR>'.join(msg.data['desc'][1:]) 206 else: 207 _s='<BR>'.join(msg.data['desc']) 208 self.preview.SetPage(self._preview_html%_s)
209
210 - def SetPreview(self, name):
211 if name is None or name==self.unnamed: 212 self.preview.SetPage('') 213 else: 214 self.preview.SetPage(self._preview_html%name) 215 pubsub.publish(pubsub.REQUEST_MEDIA_INFO, (self, name, None))
216
217 - def _set(self, data):
218 if data is None: 219 wp=self.unnamed 220 type='call' 221 else: 222 wp=data.get("ringtone", self.unnamed) 223 type=data.get("use", "call") 224 225 self.SetPreview(wp) 226 if type=='calendar': 227 self.type.SetSelection(2) 228 elif type=="message": 229 self.type.SetSelection(1) 230 else: 231 self.type.SetSelection(0) 232 233 # zero len? 234 if len(wp)==0: 235 self.ringtone.SetSelection(0) 236 return 237 238 # try using straight forward name 239 try: 240 self.ringtone.SetStringSelection(wp) 241 return 242 except: 243 pass 244 245 # ok, with unknownselprefix 246 try: 247 self.ringtone.SetStringSelection(self.unknownselprefix+wp) 248 return 249 except: 250 pass 251 252 # ok, just add it 253 self.ringtone.InsertItems([self.unknownselprefix+wp], 1) 254 self.ringtone.SetStringSelection(self.unknownselprefix+wp)
255
256 - def Set(self, data):
257 self.Ignore(True) 258 self._set(data) 259 self.Clean()
260
261 - def _get(self):
262 res={} 263 rt=self.ringtone.GetStringSelection() 264 if rt==self.unnamed: 265 return res 266 if rt.startswith(self.unknownselprefix): 267 rt=rt[len(self.unknownselprefix):] 268 if len(rt): 269 res['ringtone']=rt 270 res['use']=self.type.GetStringSelection() 271 return res
272
273 - def Get(self):
274 self.Clean() 275 return self._get()
276 277 # WallpaperEditor---------------------------------------------------------------
278 -class WallpaperEditor(DirtyUIBase):
279 280 unnamed="Select:" 281 unknownselprefix=": " 282 283 choices=["call", "message", "calendar"] 284 285 ID_LIST=wx.NewId() 286 287 _bordersize=3 # border inside HTML widget 288
289 - def __init__(self, parent, _, has_type=True, navtoolbar=False):
290 DirtyUIBase.__init__(self, parent) 291 292 _box=field_color.build_color_field(self, wx.StaticBox, 293 (self, -1, "Wallpaper"), 294 'wallpaper') 295 296 #if it is definitely specified in field color data that you don't want the selection, then don't show it 297 #type_needed=field_color.color(self, 'wallpaper_type', None) 298 #if type_needed==wx.RED: 299 # has_type=False 300 301 hs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 302 self.static_box=_box 303 304 vs=wx.BoxSizer(wx.VERTICAL) 305 306 self.preview=wallpaper.WallpaperPreview(self) 307 self.type=wx.ComboBox(self, -1, "call", choices=self.choices, style=wx.CB_READONLY) 308 self.type.SetSelection(0) 309 vs.Add(self.preview, 1, wx.EXPAND|wx.ALL, 5) 310 vs.Add(self.type, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 311 # Hide the 'type' combo box if not requested 312 if not has_type: 313 vs.Hide(1) 314 315 hs.Add(vs, 1, wx.EXPAND|wx.ALL, 5) 316 317 self.wallpaper=ListBox(self, self.ID_LIST, choices=[self.unnamed], size=(-1,200), style=wx.LB_SINGLE) 318 hs.Add(self.wallpaper, 1, wx.EXPAND|wx.ALL, 5) 319 if navtoolbar: 320 hs.Add(NavToolBar(self, False), 0, wx.EXPAND|wx.BOTTOM, 5) 321 self.SetSizer(hs) 322 hs.Fit(self) 323 324 pubsub.subscribe(self.OnWallpaperUpdates, pubsub.ALL_WALLPAPERS) 325 wx.CallAfter(pubsub.publish, pubsub.REQUEST_WALLPAPERS) # make the call once we are onscreen 326 327 wx.EVT_LISTBOX(self, self.ID_LIST, self.OnLBClicked) 328 wx.EVT_LISTBOX_DCLICK(self, self.ID_LIST, self.OnLBClicked)
329
330 - def __del__(self):
333
334 - def OnWallpaperUpdates(self, msg):
335 "Receives pubsub message with wallpaper list" 336 # wxPython/wxWidget bug: ListBox.Clear emits a wx.EVT_LISTBOX event 337 # it shouldn't 338 self.Ignore() 339 papers=msg.data[:] 340 cur=self._get() 341 self.wallpaper.Clear() 342 self.wallpaper.Append(self.unnamed) 343 for p in papers: 344 self.wallpaper.Append(p) 345 self._set(cur) 346 self.Clean()
347
348 - def OnLBClicked(self, evt=None):
349 if self.wallpaper.GetSelection()==wx.NOT_FOUND: 350 return 351 self.OnDirtyUI(evt) 352 v=self.Get().get('wallpaper', None) 353 self.SetPreview(v)
354
355 - def SetPreview(self, name):
356 if name is None or name is self.unnamed: 357 self.preview.SetImage(None) 358 else: 359 self.preview.SetImage(name)
360
361 - def _set(self, data):
362 if data is None: 363 wp=self.unnamed 364 type='call' 365 else: 366 wp=data.get("wallpaper", self.unnamed) 367 type=data.get("use", "call") 368 369 self.SetPreview(wp) 370 if type=="message": 371 self.type.SetSelection(1) 372 elif type=='calendar': 373 self.type.SetSelection(2) 374 else: 375 self.type.SetSelection(0) 376 377 if len(wp)==0: 378 self.wallpaper.SetSelection(0) 379 return 380 381 # try using straight forward name 382 try: 383 self.wallpaper.SetStringSelection(wp) 384 return 385 except: 386 pass 387 388 # ok, with unknownselprefix 389 try: 390 self.wallpaper.SetStringSelection(self.unknownselprefix+wp) 391 return 392 except: 393 pass 394 395 # ok, just add it 396 self.wallpaper.InsertItems([self.unknownselprefix+wp], 1) 397 self.wallpaper.SetStringSelection(self.unknownselprefix+wp)
398
399 - def Set(self, data):
400 self.Ignore() 401 self._set(data) 402 self.Clean()
403
404 - def _get(self):
405 res={} 406 wp=self.wallpaper.GetStringSelection() 407 if wp==self.unnamed: 408 return res 409 if wp.startswith(self.unknownselprefix): 410 wp=wp[len(self.unknownselprefix):] 411 if len(wp): 412 res['wallpaper']=wp 413 res['use']=self.type.GetStringSelection() 414 return res
415
416 - def Get(self):
417 self.Clean() 418 return self._get()
419 420 # CategoryManager---------------------------------------------------------------
421 -class CategoryManager(wx.Dialog):
422 423 ID_LIST=wx.NewId() 424
425 - def __init__(self, parent, title="Manage Categories"):
426 wx.Dialog.__init__(self, parent, -1, title, style=wx.CAPTION|wx.SYSTEM_MENU|wx.DEFAULT_DIALOG_STYLE| 427 wx.RESIZE_BORDER) 428 429 vs=wx.BoxSizer(wx.VERTICAL) 430 hs=wx.BoxSizer(wx.HORIZONTAL) 431 self.delbut=wx.Button(self, wx.NewId(), "Delete") 432 self.addbut=wx.Button(self, wx.NewId(), "Add") 433 self.add=wx.TextCtrl(self, -1) 434 self.preview=wallpaper.WallpaperPreview(self) 435 hs.Add(self.delbut,0, wx.EXPAND|wx.ALL, 5) 436 hs.Add(self.addbut,0, wx.EXPAND|wx.ALL, 5) 437 hs.Add(self.add, 1, wx.EXPAND|wx.ALL, 5) 438 vs.Add(hs, 0, wx.EXPAND|wx.ALL, 5) 439 440 self.thelistb=wx.ListBox(self, self.ID_LIST, size=(100, 250), style=wx.LB_SORT) 441 self.addlistb=wx.ListBox(self, -1, style=wx.LB_SORT) 442 self.dellistb=wx.ListBox(self, -1, style=wx.LB_SORT) 443 444 hs=wx.BoxSizer(wx.HORIZONTAL) 445 446 vs2=wx.BoxSizer(wx.VERTICAL) 447 vs2.Add(wx.StaticText(self, -1, " Wallpaper"), 0, wx.ALL, 2) 448 vs2.Add(self.preview, 1, wx.EXPAND|wx.ALL, 0) 449 self.editbut=wx.Button(self, wx.NewId(), "Edit Wallpaper") 450 vs2.Add(self.editbut, 0, wx.EXPAND|wx.ALL, 5) 451 hs.Add(vs2, 1, wx.ALL|wx.EXPAND, 5) 452 453 vs2=wx.BoxSizer(wx.VERTICAL) 454 vs2.Add(wx.StaticText(self, -1, " List"), 0, wx.ALL, 2) 455 vs2.Add(self.thelistb, 1, wx.ALL|wx.EXPAND, 5) 456 hs.Add(vs2, 1, wx.ALL|wx.EXPAND, 5) 457 458 vs2=wx.BoxSizer(wx.VERTICAL) 459 vs2.Add(wx.StaticText(self, -1, " Added"), 0, wx.ALL, 2) 460 vs2.Add(self.addlistb, 1, wx.ALL|wx.EXPAND, 5) 461 hs.Add(vs2, 1, wx.ALL|wx.EXPAND, 5) 462 463 vs2=wx.BoxSizer(wx.VERTICAL) 464 vs2.Add(wx.StaticText(self, -1, " Deleted"), 0, wx.ALL, 2) 465 vs2.Add(self.dellistb, 1, wx.ALL|wx.EXPAND, 5) 466 hs.Add(vs2, 1, wx.ALL|wx.EXPAND, 5) 467 468 vs.Add(hs, 1, wx.EXPAND|wx.ALL, 5) 469 vs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) 470 vs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 471 472 self.SetSizer(vs) 473 vs.Fit(self) 474 475 self.curlist=None 476 self.dellist=[] 477 self.addlist=[] 478 self.wps=None 479 self.groups=None 480 481 pubsub.subscribe(self.OnUpdateCategories, pubsub.ALL_CATEGORIES) 482 pubsub.publish(pubsub.REQUEST_CATEGORIES) 483 pubsub.subscribe(self.OnWallpaperUpdates, pubsub.ALL_WALLPAPERS) 484 pubsub.publish(pubsub.REQUEST_WALLPAPERS) 485 pubsub.subscribe(self.OnUpdateCategoryWallpapers, pubsub.GROUP_WALLPAPERS) 486 pubsub.publish(pubsub.REQUEST_GROUP_WALLPAPERS) 487 488 wx.EVT_BUTTON(self, self.editbut.GetId(), self.OnEdit) 489 wx.EVT_BUTTON(self, self.addbut.GetId(), self.OnAdd) 490 wx.EVT_BUTTON(self, self.delbut.GetId(), self.OnDelete) 491 wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk) 492 wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel) 493 wx.EVT_BUTTON(self, wx.ID_HELP, lambda _: wx.GetApp().displayhelpid(helpids.ID_CATEGORY_MANAGER)) 494 wx.EVT_LISTBOX(self, self.ID_LIST, self.OnLBClicked) 495 wx.EVT_LISTBOX_DCLICK(self, self.ID_LIST, self.OnLBClicked)
496
497 - def __del__(self):
502
503 - def OnUpdateCategoryWallpapers(self, msg):
504 groups_wp=msg.data[:] 505 if self.groups is None: 506 self.groups = groups_wp
507
508 - def OnWallpaperUpdates(self, msg):
509 "Receives pubsub message with wallpaper list" 510 papers=msg.data[:] 511 if self.wps is None: 512 self.wps = papers
513
514 - def OnUpdateCategories(self, msg):
515 cats=msg.data[:] 516 if self.curlist is None: 517 self.curlist=cats 518 519 # add in any new entries that may have appeared 520 for i in cats: 521 if i not in self.curlist and i not in self.dellist: 522 self.curlist.append(i) 523 self.addlist.append(i) 524 self.curlist.sort() 525 self.addlist.sort() 526 self.UpdateLBs()
527
528 - def OnLBClicked(self, evt=None):
529 if self.thelistb.GetSelection()==wx.NOT_FOUND: 530 return 531 groupname=self.curlist[self.thelistb.GetSelection()] 532 try: 533 wallpaper=self.returnWP(groupname) 534 except: 535 wallpaper=None 536 537 if wallpaper==None: 538 self.SetPreview(None) 539 else: 540 try: 541 v_index=self.wps.index(wallpaper) 542 v=self.wps[v_index] 543 self.SetPreview(v) 544 except: 545 self.SetPreview(None)
546
547 - def SetPreview(self, name):
548 if name is None: 549 self.preview.SetImage(None) 550 else: 551 self.preview.SetImage(name)
552
553 - def UpdateLBs(self):
554 for lb,l in (self.thelistb, self.curlist), (self.addlistb, self.addlist), (self.dellistb, self.dellist): 555 lb.Clear() 556 for i in l: 557 lb.Append(i)
558
559 - def returnWP(self, groupname):
560 try: 561 gwp=self.groups[:] 562 for entry in gwp: 563 l=entry.split(":", 1) 564 name=l[0] 565 wp=l[1] 566 if name==groupname: 567 if wp==0: 568 return None 569 else: 570 return wp 571 return None 572 except: 573 return None
574
575 - def setWP(self, groupname, wallpaper):
576 gwp=self.groups[:] 577 new_entry=str(groupname)+":"+str(wallpaper) 578 entry_to_remove=None 579 for entry in gwp: 580 l=entry.split(":", 1) 581 name=l[0] 582 wp=l[1] 583 if name==groupname: 584 entry_to_remove=entry 585 break 586 if entry_to_remove is not None: 587 gwp.remove(entry_to_remove) 588 gwp.append(new_entry) 589 self.groups=gwp
590
591 - def OnOk(self, _):
592 pubsub.publish(pubsub.SET_CATEGORIES, self.curlist) 593 pubsub.publish(pubsub.SET_GROUP_WALLPAPERS, self.groups) 594 self.Show(False) 595 self.Destroy()
596
597 - def OnCancel(self, _):
598 self.Show(False) 599 self.Destroy()
600
601 - def OnEdit(self, _):
602 datakey="group_wallpapers" 603 title="Edit Category Wallpaper" 604 populate_data=[] 605 _key=self.thelistb.GetSelection() 606 if _key > -1: 607 _groupname=self.curlist[_key] 608 wp_name=self.returnWP(_groupname) 609 if wp_name is None: 610 populate_data.append({}) 611 else: 612 populate_data.append({"wallpaper": wp_name}) 613 with guihelper.WXDialogWrapper(SingleFieldEditor(self, datakey, title, populate_data), True) as (dlg, retcode): 614 if retcode==wx.ID_OK: 615 _data=dlg.GetData() 616 if _data: 617 new_wp=_data[0] #only want the first entry since you can only get 1 wallpaper per group 618 new_wp_name=new_wp.get('wallpaper', None) 619 if new_wp_name is not None: 620 self.setWP(_groupname, new_wp_name) #set new wallpaper 621 else: 622 new_wp_name=None 623 self.setWP(_groupname, 0) #clear wallpaper 624 self.SetPreview(new_wp_name)
625
626 - def OnAdd(self, _):
627 v=self.add.GetValue() 628 self.add.SetValue("") 629 self.add.SetFocus() 630 if len(v)==0: 631 return 632 if v not in self.curlist: 633 self.curlist.append(v) 634 self.curlist.sort() 635 #add group to self.groups 636 self.groups.append(str(v)+":0") 637 if v not in self.addlist: 638 self.addlist.append(v) 639 self.addlist.sort() 640 if v in self.dellist: 641 i=self.dellist.index(v) 642 del self.dellist[i] 643 self.UpdateLBs()
644
645 - def OnDelete(self,_):
646 try: 647 v=self.thelistb.GetStringSelection() 648 if v is None or len(v)==0: return 649 except: 650 return 651 i=self.curlist.index(v) 652 del self.curlist[i] 653 entry_to_remove=None 654 for entry in self.groups: 655 l=entry.split(":", 1) 656 name=l[0] 657 if name==v: 658 entry_to_remove=entry 659 break 660 if entry_to_remove is not None: 661 self.groups.remove(entry_to_remove) 662 if v in self.addlist: 663 i=self.addlist.index(v) 664 del self.addlist[i] 665 self.dellist.append(v) 666 self.dellist.sort() 667 self.UpdateLBs()
668 669 # CategoryEditor----------------------------------------------------------------
670 -class CategoryEditor(DirtyUIBase):
671 672 # we have to have an entry with a special string for the unnamed string 673 674 unnamed="Select:" 675
676 - def __init__(self, parent, pos, navtoolbar=False):
677 DirtyUIBase.__init__(self, parent) 678 _box=field_color.build_color_field(self, wx.StaticBox, 679 (self, -1, "Category"), 680 'category') 681 hs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 682 683 self.categories=[self.unnamed] 684 self.category=wx.ListBox(self, -1, choices=self.categories) 685 pubsub.subscribe(self.OnUpdateCategories, pubsub.ALL_CATEGORIES) 686 pubsub.publish(pubsub.REQUEST_CATEGORIES) 687 hs.Add(self.category, 1, wx.EXPAND|wx.ALL, 5) 688 689 if pos==0: 690 self.but=wx.Button(self, wx.NewId(), "Manage Categories") 691 hs.Add(self.but, 2, wx.ALIGN_CENTRE|wx.ALL, 5) 692 wx.EVT_BUTTON(self, self.but.GetId(), self.OnManageCategories) 693 else: 694 hs.Add(wx.StaticText(self, -1, ""), 2, wx.ALIGN_CENTRE|wx.ALL, 5) 695 696 wx.EVT_LISTBOX(self, self.category.GetId(), self.OnDirtyUI) 697 wx.EVT_LISTBOX_DCLICK(self, self.category.GetId(), self.OnDirtyUI) 698 if navtoolbar: 699 hs.Add(NavToolBar(self, False), 0, wx.EXPAND|wx.BOTTOM, 5) 700 self.SetSizer(hs) 701 hs.Fit(self)
702
703 - def __del__(self):
706
707 - def OnManageCategories(self, _):
708 with guihelper.WXDialogWrapper(CategoryManager(self), True): 709 pass
710
711 - def OnUpdateCategories(self, msg):
712 cats=msg.data[:] 713 cats=[self.unnamed]+cats 714 if self.categories!=cats: 715 self.categories=cats 716 sel=self.category.GetStringSelection() 717 self.category.Clear() 718 for i in cats: 719 self.category.Append(i) 720 try: 721 self.category.SetStringSelection(sel) 722 except: 723 # the above fails if the category we are is deleted 724 self.category.SetStringSelection(self.unnamed)
725
726 - def Get(self):
727 self.Clean() 728 v=self.category.GetStringSelection() 729 if len(v) and v!=self.unnamed: 730 return {'category': v} 731 return {}
732
733 - def Set(self, data):
734 self.Ignore() 735 if data is None: 736 v=self.unnamed 737 else: 738 v=data.get("category", self.unnamed) 739 try: 740 self.category.SetStringSelection(v) 741 except: 742 assert v!=self.unnamed 743 self.category.SetStringSelection(self.unnamed) 744 self.Clean()
745 746 # MemoEditor--------------------------------------------------------------------
747 -class MemoEditor(DirtyUIBase):
748
749 - def __init__(self, parent, _, navtoolbar=False):
750 DirtyUIBase.__init__(self, parent) 751 752 _box=field_color.build_color_field(self, wx.StaticBox, 753 (self, -1, "Memo"), 754 'memo') 755 vs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 756 self.static_box=_box 757 758 self.memo=wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE) 759 vs.Add(self.memo, 1, wx.EXPAND|wx.ALL, 5) 760 wx.EVT_TEXT(self, self.memo.GetId(), self.OnDirtyUI) 761 if navtoolbar: 762 vs.Add(NavToolBar(self, horizontal=False), 0, wx.EXPAND|wx.BOTTOM, 5) 763 self.SetSizer(vs) 764 vs.Fit(self)
765
766 - def Set(self, data):
767 self.Ignore() 768 if data is None: 769 s='' 770 else: 771 s=data.get('memo', '') 772 self.memo.SetValue(s) 773 self.Clean()
774
775 - def Get(self):
776 self.Clean() 777 if len(self.memo.GetValue()): 778 return {'memo': self.memo.GetValue()} 779 return {}
780 781 # copy/cut/paste routines
782 - def CanCopy(self):
783 return self.memo.CanCopy()
784 - def Copy(self):
785 return self.memo.Copy()
786 - def CanPaste(self):
787 return self.memo.CanPaste()
788 - def Paste(self):
789 return self.memo.Paste()
790 - def CanCut(self):
791 return self.memo.CanCut()
792 - def Cut(self):
793 return self.memo.Cut()
794 795 # NumberEditor------------------------------------------------------------------
796 -class NumberEditor(DirtyUIBase):
797 798 choices=[ ("None", "none"), ("Home", "home"), ("Office", 799 "office"), ("Cell", "cell"), ("Fax", "fax"), ("Pager", "pager"), 800 ("Data", "data"), ("Main", "main")] 801 802 _None_Value='None' 803
804 - def __init__(self, parent, _, navtoolbar=False):
805 806 DirtyUIBase.__init__(self, parent) 807 808 _field_color_dict=field_color.build_field_info(self, 'number') 809 810 hs=wx.StaticBoxSizer(field_color.build_color_field(self, 811 wx.StaticBox, 812 (self, -1, "Number details"), 813 'details', 814 _field_color_dict), 815 wx.VERTICAL) 816 _hs_top=wx.BoxSizer(wx.HORIZONTAL) 817 _txt=field_color.build_color_field(self, wx.StaticText, 818 (self, -1, "Type"), 819 'type', _field_color_dict) 820 _hs_top.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 821 822 self.type=wx.ComboBox(self, -1, "Cell", choices=[desc for desc,name in self.choices], style=wx.CB_READONLY) 823 _hs_top.Add(self.type, 0, wx.EXPAND|wx.ALL, 5) 824 825 _txt=field_color.build_color_field(self, wx.StaticText, 826 (self, -1, "SpeedDial"), 827 'speeddial', _field_color_dict) 828 _hs_top.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 829 self.speeddial=wx.TextCtrl(self, -1, "", size=(32,10)) 830 _hs_top.Add(self.speeddial, 0, wx.EXPAND|wx.ALL, 5) 831 832 _txt=field_color.build_color_field(self, wx.StaticText, 833 (self, -1, "Number"), 834 'number', _field_color_dict) 835 _hs_top.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 836 self.number=wx.TextCtrl(self, -1, "") 837 _hs_top.Add(self.number, 1, wx.EXPAND|wx.ALL, 5) 838 839 # add a toolbar w/ the Up/Down/Del buttons 840 if navtoolbar: 841 _hs_top.Add(NavToolBar(self), 0, wx.EXPAND|wx.BOTTOM, 5) 842 hs.Add(_hs_top, 0, wx.EXPAND|wx.ALL, 0) 843 # the bottom section 844 _hs_bot=wx.BoxSizer(wx.HORIZONTAL) 845 _txt=field_color.build_color_field(self, wx.StaticText, 846 (self, -1, "Ringtone"), 847 'ringtone', _field_color_dict) 848 _hs_bot.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 849 self.ringtone=wx.ComboBox(self, -1) 850 _hs_bot.Add(self.ringtone, 0, wx.EXPAND|wx.ALL, 5) 851 _txt=field_color.build_color_field(self, wx.StaticText, 852 (self, -1, "Wallpaper"), 853 'wallpaper', _field_color_dict) 854 _hs_bot.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 855 856 self.wallpaper=wx.ComboBox(self, -1) 857 _hs_bot.Add(self.wallpaper, 0, wx.EXPAND|wx.ALL, 5) 858 859 hs.Add(_hs_bot, 0, wx.EXPAND|wx.ALL, 0) 860 861 global _wallpaper_list, _ringtone_list 862 pubsub.subscribe(self.OnWallpaperUpdates, pubsub.ALL_WALLPAPERS) 863 if _wallpaper_list is None: 864 pubsub.publish(pubsub.REQUEST_WALLPAPERS) 865 else: 866 self._populate_wallpaper() 867 pubsub.subscribe(self.OnRingtoneUpdates, pubsub.ALL_RINGTONES) 868 if _ringtone_list is None: 869 pubsub.publish(pubsub.REQUEST_RINGTONES) 870 else: 871 self._populate_ringtone() 872 873 wx.EVT_TEXT(self, self.type.GetId(), self.OnDirtyUI) 874 wx.EVT_TEXT(self, self.speeddial.GetId(), self.OnDirtyUI) 875 wx.EVT_TEXT(self, self.number.GetId(), self.OnDirtyUI) 876 wx.EVT_TEXT(self, self.ringtone.GetId(), self.OnDirtyUI) 877 wx.EVT_TEXT(self, self.wallpaper.GetId(), self.OnDirtyUI) 878 self.SetSizer(hs) 879 hs.Fit(self)
880
881 - def __del__(self):
885
886 - def _populate_cb(self, cb_widget, data):
887 cb_widget.Clear() 888 cb_widget.Append(self._None_Value) 889 for _entry in data: 890 cb_widget.Append(_entry)
891
892 - def _set_cb_sel(self, cb_widget, str_sel):
893 if str_sel: 894 _sel=str_sel 895 else: 896 _sel=self._None_Value 897 try: 898 cb_widget.SetStringSelection(_sel) 899 except: 900 cb_widget.Append(sel) 901 cb_widget.SetStringSelection(_sel)
902
903 - def _get_cb_sel(self, cb_widget):
904 _sel=cb_widget.GetStringSelection() 905 if not _sel or _sel==self._None_Value: 906 return None 907 return _sel
908
909 - def _populate_ringtone(self):
910 """Populate the combo box with ringtone data""" 911 self.Ignore() 912 _str_sel=self.ringtone.GetStringSelection() 913 global _ringtone_list 914 self._populate_cb(self.ringtone, _ringtone_list) 915 self._set_cb_sel(self.ringtone, _str_sel) 916 self.Clean()
917
918 - def _populate_wallpaper(self):
919 """Ppulate the combo box with wallpaper data""" 920 self.Ignore() 921 _str_sel=self.wallpaper.GetStringSelection() 922 global _wallpaper_list 923 self._populate_cb(self.wallpaper, _wallpaper_list) 924 self._set_cb_sel(self.wallpaper, _str_sel) 925 self.Clean()
926
927 - def OnWallpaperUpdates(self, msg):
928 global _wallpaper_list 929 _wallpaper_list=msg.data[:] 930 self._populate_wallpaper()
931 - def OnRingtoneUpdates(self, msg):
932 global _ringtone_list 933 _ringtone_list=msg.data[:] 934 self._populate_ringtone()
935
936 - def Set(self, data):
937 self.Ignore() 938 sd=data.get("speeddial", "") 939 if isinstance(sd,(int, long)): 940 sd='%d'%sd 941 self.speeddial.SetValue(sd) 942 self.number.SetValue(data.get("number", "")) 943 # ringtone & wallpaper 944 self._set_cb_sel(self.ringtone, data.get('ringtone', None)) 945 self._set_cb_sel(self.wallpaper, data.get('wallpaper', None)) 946 # number of type 947 v=data.get("type", "cell") 948 for i in range(len(self.choices)): 949 if self.choices[i][1]==v: 950 self.type.SetSelection(i) 951 self.Clean() 952 return 953 self.type.SetSelection(0) 954 self.Clean()
955
956 - def Get(self):
957 self.Clean() 958 res={} 959 if len(self.number.GetValue())==0: 960 return res 961 res['number']=self.number.GetValue() 962 if len(self.speeddial.GetValue()): 963 res['speeddial']=self.speeddial.GetValue() 964 try: 965 res['speeddial']=int(res['speeddial']) 966 except: 967 pass 968 res['type']=self.choices[self.type.GetSelection()][1] 969 _sel=self._get_cb_sel(self.ringtone) 970 if _sel: 971 res['ringtone']=_sel 972 _sel=self._get_cb_sel(self.wallpaper) 973 if _sel: 974 res['wallpaper']=_sel 975 return res
976 977 # EmailEditor-------------------------------------------------------------------
978 -class EmailEditor(DirtyUIBase):
979 980 ID_TYPE=wx.NewId() 981 _None_Value='None' 982
983 - def __init__(self, parent, _, navtoolbar=False):
984 super(EmailEditor, self).__init__(parent) 985 986 _field_color_dict=field_color.build_field_info(self, 'email_details') 987 988 _box=field_color.build_color_field(self, wx.StaticBox, 989 (self, -1, 'Email Address'), 990 'email') 991 hs=wx.StaticBoxSizer(_box, wx.VERTICAL) 992 # top section 993 _hs_top=wx.BoxSizer(wx.HORIZONTAL) 994 self.type=wx.ComboBox(self, self.ID_TYPE, "", choices=["", "Home", "Business"], style=wx.CB_READONLY) 995 _hs_top.Add(self.type, 0, wx.EXPAND|wx.ALL, 5) 996 self.email=wx.TextCtrl(self, -1, "") 997 _hs_top.Add(self.email, 1, wx.EXPAND|wx.ALL, 5) 998 if navtoolbar: 999 _hs_top.Add(NavToolBar(self), 0, wx.EXPAND|wx.BOTTOM, 5) 1000 hs.Add(_hs_top, 0, wx.EXPAND|wx.ALL, 0) 1001 # bottom section 1002 _hs_bot=wx.BoxSizer(wx.HORIZONTAL) 1003 _txt=field_color.build_color_field(self, wx.StaticText, 1004 (self, -1, "SpeedDial"), 1005 'emailspeeddial', _field_color_dict) 1006 _hs_bot.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1007 self.speeddial=wx.TextCtrl(self, -1, "", size=(32,10)) 1008 _hs_bot.Add(self.speeddial, 0, wx.EXPAND|wx.ALL, 5) 1009 _txt=field_color.build_color_field(self, wx.StaticText, 1010 (self, -1, "Ringtone"), 1011 'emailringtone', _field_color_dict) 1012 _hs_bot.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1013 self.ringtone=wx.ComboBox(self, -1) 1014 _hs_bot.Add(self.ringtone, 0, wx.EXPAND|wx.ALL, 5) 1015 _txt=field_color.build_color_field(self, wx.StaticText, 1016 (self, -1, "Wallpaper"), 1017 'emailwallpaper', _field_color_dict) 1018 _hs_bot.Add(_txt, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1019 1020 self.wallpaper=wx.ComboBox(self, -1) 1021 _hs_bot.Add(self.wallpaper, 0, wx.EXPAND|wx.ALL, 5) 1022 1023 hs.Add(_hs_bot, 0, wx.EXPAND|wx.ALL, 0) 1024 1025 global _wallpaper_list, _ringtone_list 1026 pubsub.subscribe(self.OnWallpaperUpdates, pubsub.ALL_WALLPAPERS) 1027 if _wallpaper_list is None: 1028 pubsub.publish(pubsub.REQUEST_WALLPAPERS) 1029 else: 1030 self._populate_wallpaper() 1031 pubsub.subscribe(self.OnRingtoneUpdates, pubsub.ALL_RINGTONES) 1032 if _ringtone_list is None: 1033 pubsub.publish(pubsub.REQUEST_RINGTONES) 1034 else: 1035 self._populate_ringtone() 1036 1037 wx.EVT_TEXT(self, self.type.GetId(), self.OnDirtyUI) 1038 wx.EVT_TEXT(self, self.email.GetId(), self.OnDirtyUI) 1039 wx.EVT_TEXT(self, self.speeddial.GetId(), self.OnDirtyUI) 1040 wx.EVT_TEXT(self, self.ringtone.GetId(), self.OnDirtyUI) 1041 wx.EVT_TEXT(self, self.wallpaper.GetId(), self.OnDirtyUI) 1042 self.SetSizer(hs) 1043 hs.Fit(self)
1044
1045 - def __del__(self):
1049
1050 - def _populate_cb(self, cb_widget, data):
1051 cb_widget.Clear() 1052 cb_widget.Append(self._None_Value) 1053 for _entry in data: 1054 cb_widget.Append(_entry)
1055
1056 - def _set_cb_sel(self, cb_widget, str_sel):
1057 if str_sel: 1058 _sel=str_sel 1059 else: 1060 _sel=self._None_Value 1061 try: 1062 cb_widget.SetStringSelection(_sel) 1063 except: 1064 cb_widget.Append(sel) 1065 cb_widget.SetStringSelection(_sel)
1066
1067 - def _get_cb_sel(self, cb_widget):
1068 _sel=cb_widget.GetStringSelection() 1069 if not _sel or _sel==self._None_Value: 1070 return None 1071 return _sel
1072
1073 - def _populate_ringtone(self):
1074 """Populate the combo box with ringtone data""" 1075 self.Ignore() 1076 _str_sel=self.ringtone.GetStringSelection() 1077 global _ringtone_list 1078 self._populate_cb(self.ringtone, _ringtone_list) 1079 self._set_cb_sel(self.ringtone, _str_sel) 1080 self.Clean()
1081
1082 - def _populate_wallpaper(self):
1083 """Ppulate the combo box with wallpaper data""" 1084 self.Ignore() 1085 _str_sel=self.wallpaper.GetStringSelection() 1086 global _wallpaper_list 1087 self._populate_cb(self.wallpaper, _wallpaper_list) 1088 self._set_cb_sel(self.wallpaper, _str_sel) 1089 self.Clean()
1090
1091 - def OnWallpaperUpdates(self, msg):
1092 global _wallpaper_list 1093 _wallpaper_list=msg.data[:] 1094 self._populate_wallpaper()
1095 - def OnRingtoneUpdates(self, msg):
1096 global _ringtone_list 1097 _ringtone_list=msg.data[:] 1098 self._populate_ringtone()
1099
1100 - def Set(self, data):
1101 self.Ignore() 1102 self.email.SetValue(data.get("email", "")) 1103 sd=data.get("speeddial", "") 1104 if isinstance(sd, int): 1105 sd=`sd` 1106 self.speeddial.SetValue(sd) 1107 self._set_cb_sel(self.ringtone, data.get('ringtone', None)) 1108 self._set_cb_sel(self.wallpaper, data.get('wallpaper', None)) 1109 v=data.get("type", "") 1110 if v=="home": 1111 self.type.SetSelection(1) 1112 elif v=="business": 1113 self.type.SetSelection(2) 1114 else: 1115 self.type.SetSelection(0) 1116 self.Clean()
1117
1118 - def Get(self):
1119 self.Clean() 1120 res={} 1121 if len(self.email.GetValue())==0: 1122 return res 1123 res['email']=self.email.GetValue() 1124 if len(self.speeddial.GetValue()): 1125 res['speeddial']=self.speeddial.GetValue() 1126 try: 1127 res['speeddial']=int(res['speeddial']) 1128 except: 1129 pass 1130 if self.type.GetSelection()==1: 1131 res['type']='home' 1132 elif self.type.GetSelection()==2: 1133 res['type']='business' 1134 _sel=self._get_cb_sel(self.ringtone) 1135 if _sel: 1136 res['ringtone']=_sel 1137 _sel=self._get_cb_sel(self.wallpaper) 1138 if _sel: 1139 res['wallpaper']=_sel 1140 return res
1141 1142 # URLEditor---------------------------------------------------------------------
1143 -class URLEditor(DirtyUIBase):
1144 1145 ID_TYPE=wx.NewId()
1146 - def __init__(self, parent, _, navtoolbar=False):
1147 super(URLEditor, self).__init__(parent) 1148 1149 _box=field_color.build_color_field(self, wx.StaticBox, 1150 (self, -1, "URL"), 'url') 1151 hs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 1152 1153 self.type=wx.ComboBox(self, self.ID_TYPE, "", choices=["", "Home", "Business"], style=wx.CB_READONLY) 1154 hs.Add(self.type, 0, wx.EXPAND|wx.ALL, 5) 1155 self.url=wx.TextCtrl(self, -1, "") 1156 hs.Add(self.url, 1, wx.EXPAND|wx.ALL, 5) 1157 if navtoolbar: 1158 hs.Add(NavToolBar(self), 0, wx.EXPAND|wx.BOTTOM, 5) 1159 wx.EVT_TEXT(self, self.type.GetId(), self.OnDirtyUI) 1160 wx.EVT_TEXT(self, self.url.GetId(), self.OnDirtyUI) 1161 self.SetSizer(hs) 1162 hs.Fit(self)
1163
1164 - def Set(self, data):
1165 self.Ignore() 1166 self.url.SetValue(data.get("url", "")) 1167 v=data.get("type", "") 1168 if v=="home": 1169 self.type.SetSelection(1) 1170 elif v=="business": 1171 self.type.SetSelection(2) 1172 else: 1173 self.type.SetSelection(0) 1174 self.Clean()
1175
1176 - def Get(self):
1177 self.Clean() 1178 res={} 1179 if len(self.url.GetValue())==0: 1180 return res 1181 res['url']=self.url.GetValue() 1182 if self.type.GetSelection()==1: 1183 res['type']='home' 1184 elif self.type.GetSelection()==2: 1185 res['type']='business' 1186 return res
1187 1188 # IM Editor---------------------------------------------------------------------
1189 -class IMEditor(DirtyUIBase):
1190 1191 ID_TYPE=wx.NewId() 1192 _type_choices=('', 'AIM', 'Yahoo!', 'WL Messenger')
1193 - def __init__(self, parent, _, navtoolbar=False):
1194 super(IMEditor, self).__init__(parent) 1195 1196 _box=field_color.build_color_field(self, wx.StaticBox, 1197 (self, -1, "IM Name"), 'im') 1198 hs=wx.StaticBoxSizer(_box, wx.HORIZONTAL) 1199 1200 self.type=wx.ComboBox(self, self.ID_TYPE, "", choices=self._type_choices, 1201 style=wx.CB_READONLY) 1202 hs.Add(self.type, 0, wx.EXPAND|wx.ALL, 5) 1203 self.name=wx.TextCtrl(self, -1, "") 1204 hs.Add(self.name, 1, wx.EXPAND|wx.ALL, 5) 1205 if navtoolbar: 1206 hs.Add(NavToolBar(self), 0, wx.EXPAND|wx.BOTTOM, 5) 1207 wx.EVT_TEXT(self, self.type.GetId(), self.OnDirtyUI) 1208 wx.EVT_TEXT(self, self.name.GetId(), self.OnDirtyUI) 1209 self.SetSizer(hs) 1210 hs.Fit(self)
1211
1212 - def Set(self, data):
1213 self.Ignore() 1214 self.name.SetValue(data.get("username", "")) 1215 v=data.get("type", "") 1216 if v in self._type_choices: 1217 self.type.SetValue(v) 1218 else: 1219 self.type.SetSelection(0) 1220 self.Clean()
1221
1222 - def Get(self):
1223 self.Clean() 1224 res={} 1225 if len(self.name.GetValue())==0: 1226 return res 1227 res['username']=self.name.GetValue() 1228 res['type']=self.type.GetValue() 1229 return res
1230 1231 # AddressEditor-----------------------------------------------------------------
1232 -class AddressEditor(DirtyUIBase):
1233 1234 ID_TYPE=wx.NewId() 1235 1236 fieldinfos=("street", "Street"), ("street2", "Street2"), ("city", "City"), \ 1237 ("state", "State"), ("postalcode", "Postal/Zipcode"), ("country", "Country/Region") 1238
1239 - def __init__(self, parent, _, navtoolbar=False):
1240 super(AddressEditor, self).__init__(parent) 1241 1242 _fc_dict=field_color.build_field_info(self, 'address') 1243 _hs=wx.StaticBoxSizer(field_color.build_color_field(self, wx.StaticBox, 1244 (self, -1, "Address Details"), 1245 'details', _fc_dict), 1246 wx.HORIZONTAL) 1247 vs=wx.BoxSizer(wx.VERTICAL) 1248 hs=wx.BoxSizer(wx.HORIZONTAL) 1249 hs.Add(field_color.build_color_field(self, wx.StaticText, 1250 (self, -1, "Type"), 1251 'type', _fc_dict), 1252 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1253 self.type=wx.ComboBox(self, self.ID_TYPE, "Home", choices=["Home", "Business"], style=wx.CB_READONLY) 1254 hs.Add(self.type, 0, wx.EXPAND|wx.ALL, 5) 1255 hs.Add(field_color.build_color_field(self, wx.StaticText, 1256 (self, -1, "Company"), 1257 'company', _fc_dict), 1258 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1259 self.company=wx.TextCtrl(self, -1, "") 1260 hs.Add(self.company, 1, wx.EXPAND|wx.ALL, 5) 1261 1262 gs=wx.FlexGridSizer(6,2,2,5) 1263 1264 for name,desc in self.fieldinfos: 1265 gs.Add(field_color.build_color_field(self, wx.StaticText, 1266 (self, -1, desc), 1267 name, _fc_dict), 1268 0, wx.ALIGN_CENTRE) 1269 setattr(self, name, wx.TextCtrl(self, -1, "")) 1270 gs.Add(getattr(self,name), 1, wx.EXPAND) 1271 1272 gs.AddGrowableCol(1) 1273 1274 vs.Add(hs,0,wx.EXPAND|wx.ALL, 5) 1275 vs.Add(gs,0,wx.EXPAND|wx.ALL, 5) 1276 1277 _hs.Add(vs, 0, wx.EXPAND|wx.ALL, 5) 1278 if navtoolbar: 1279 _hs.Add(NavToolBar(self, horizontal=False), 0, wx.EXPAND|wx.BOTTOM, 5) 1280 # ::TODO:: disable company when type is home 1281 wx.EVT_TEXT(self, self.type.GetId(), self.OnDirtyUI) 1282 wx.EVT_TEXT(self, self.company.GetId(), self.OnDirtyUI) 1283 for name,_ in self.fieldinfos: 1284 wx.EVT_TEXT(self, getattr(self, name).GetId(), self.OnDirtyUI) 1285 self.SetSizer(_hs) 1286 vs.Fit(self)
1287
1288 - def Set(self, data):
1289 self.Ignore() 1290 # most fields 1291 for name,ignore in self.fieldinfos: 1292 getattr(self, name).SetValue(data.get(name, "")) 1293 # special cases 1294 self.company.SetValue(data.get("company", "")) 1295 if data.get("type", "home")=="home": 1296 self.type.SetValue("Home") 1297 else: 1298 self.type.SetValue("Business") 1299 self.Clean()
1300
1301 - def Get(self):
1302 self.Clean() 1303 res={} 1304 # most fields 1305 for name,ignore in self.fieldinfos: 1306 w=getattr(self, name) 1307 if len(w.GetValue()): 1308 res[name]=w.GetValue() 1309 # special cases 1310 if self.type.GetSelection()==1: 1311 if len(self.company.GetValue()): 1312 res['company']=self.company.GetValue() 1313 # only add in type field if any other type field is set 1314 if len(res): 1315 res['type']=['home', 'business'][self.type.GetSelection()] 1316 return res
1317 1318 # NameEditor--------------------------------------------------------------------
1319 -class NameEditor(DirtyUIBase):
1320
1321 - def __init__(self, parent, _, navtoolbar=False):
1322 super(NameEditor, self).__init__(parent) 1323 1324 _fc_dict=field_color.build_field_info(self, 'name') 1325 _hs=wx.StaticBoxSizer(field_color.build_color_field(self, 1326 wx.StaticBox, 1327 (self, -1, 'Name Details'), 1328 'details', _fc_dict), 1329 wx.HORIZONTAL) 1330 vs=wx.BoxSizer(wx.VERTICAL) 1331 hstop=wx.BoxSizer(wx.HORIZONTAL) 1332 hsbot=wx.BoxSizer(wx.HORIZONTAL) 1333 hstop.Add(field_color.build_color_field(self, wx.StaticText, 1334 (self, -1, "First"), 1335 'first', _fc_dict), 1336 0, wx.ALIGN_CENTRE|wx.ALL,5) 1337 self.first=wx.TextCtrl(self, -1, "") 1338 hstop.Add(self.first, 1, wx.EXPAND|wx.ALL, 5) 1339 hstop.Add(field_color.build_color_field(self, wx.StaticText, 1340 (self, -1, "Middle"), 1341 'middle', _fc_dict), 1342 0, wx.ALIGN_CENTRE|wx.ALL,5) 1343 self.middle=wx.TextCtrl(self, -1, "") 1344 hstop.Add(self.middle, 1, wx.EXPAND|wx.ALL, 5) 1345 hstop.Add(field_color.build_color_field(self, wx.StaticText, 1346 (self, -1, "Last"), 1347 'last', _fc_dict), 1348 0, wx.ALIGN_CENTRE|wx.ALL,5) 1349 self.last=wx.TextCtrl(self, -1, "") 1350 hstop.Add(self.last, 1, wx.EXPAND|wx.ALL, 5) 1351 hsbot.Add(field_color.build_color_field(self, wx.StaticText, 1352 (self, -1, "Full"), 1353 'full', _fc_dict), 1354 0, wx.ALIGN_CENTRE|wx.ALL,5) 1355 self.full=wx.TextCtrl(self, -1, "") 1356 hsbot.Add(self.full, 4, wx.EXPAND|wx.ALL, 5) 1357 hsbot.Add(field_color.build_color_field(self, wx.StaticText, 1358 (self, -1, "Nickname"), 1359 'nickname', _fc_dict), 1360 0, wx.ALIGN_CENTRE|wx.ALL,5) 1361 self.nickname=wx.TextCtrl(self, -1, "") 1362 hsbot.Add(self.nickname, 1, wx.EXPAND|wx.ALL, 5) 1363 vs.Add(hstop, 0, wx.EXPAND|wx.ALL, 5) 1364 vs.Add(hsbot, 0, wx.EXPAND|wx.ALL, 5) 1365 _hs.Add(vs, 0, wx.EXPAND|wx.ALL, 5) 1366 # add a toolbar w/ the Up/Down/Del buttons 1367 if navtoolbar: 1368 _hs.Add(NavToolBar(self, horizontal=False), 0, wx.EXPAND, 0) 1369 for _name in ('first', 'middle', 'last', 'full', 'nickname'): 1370 wx.EVT_TEXT(self, getattr(self, _name).GetId(), self.OnDirtyUI) 1371 1372 # use the sizer and resize ourselves according to space needed by sizer 1373 self.SetSizer(_hs) 1374 vs.Fit(self)
1375
1376 - def Set(self, data):
1377 self.Ignore() 1378 self.first.SetValue(data.get("first", "")) 1379 self.middle.SetValue(data.get("middle", "")) 1380 self.last.SetValue(data.get("last", "")) 1381 self.full.SetValue(data.get("full", "")) 1382 self.nickname.SetValue(data.get("nickname", "")) 1383 self.Clean()
1384
1385 - def Get(self):
1386 self.Clean() 1387 res={} 1388 for name,widget in ( "first", self.first), ("middle", self.middle), ("last", self.last), \ 1389 ("full", self.full), ("nickname", self.nickname): 1390 if len(widget.GetValue()): 1391 res[name]=widget.GetValue() 1392 return res
1393 1394 # MiscEditor-----------------------------------------------------------------
1395 -class MiscEditor(DirtyUIBase):
1396 - def __init__(self, parent, _, navtoolbar=False):
1397 super(MiscEditor, self).__init__(parent) 1398 _fc_dict=field_color.build_field_info(self, 'phonebook') 1399 vs=wx.StaticBoxSizer(wx.StaticBox(self, -1, "Misc Details"), 1400 wx.VERTICAL) 1401 # storage field 1402 hs=wx.BoxSizer(wx.HORIZONTAL) 1403 hs.Add(field_color.build_color_field(self, wx.StaticText, 1404 (self, -1, "Storage Option:"), 1405 'storage', _fc_dict), 1406 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1407 self._storage=wx.ComboBox(self, -1, 'Phone', choices=["Phone", "SIM"], 1408 style=wx.CB_READONLY) 1409 wx.EVT_COMBOBOX(self, self._storage.GetId(), self.OnDirtyUI) 1410 hs.Add(self._storage, 0, wx.EXPAND|wx.LEFT, 5) 1411 vs.Add(hs, 0, wx.EXPAND|wx.ALL, 5) 1412 # secret field 1413 self._secret=field_color.build_color_field(self, wx.CheckBox, 1414 (self, -1, 1415 'This entry is private/secret'), 1416 'secret', _fc_dict) 1417 1418 wx.EVT_CHECKBOX(self, self._secret.GetId(), self.OnDirtyUI) 1419 vs.Add(self._secret, 0, wx.EXPAND|wx.ALL, 5) 1420 # all done 1421 self.SetSizer(vs) 1422 vs.Fit(self)
1423
1424 - def Set(self, data):
1425 self._storage.SetValue('SIM' if data.get('sim', False) else 'Phone') 1426 self._secret.SetValue(data.get('secret', False))
1427
1428 - def Get(self):
1429 _res={} 1430 if self._storage.GetValue()=='SIM': 1431 _res['sim']=True 1432 if self._secret.GetValue(): 1433 _res['secret']=True 1434 return _res
1435 1436 # ICEEditor-----------------------------------------------------------------
1437 -class ICEEditor(DirtyUIBase):
1438 - def __init__(self, parent, _, navtoolbar=False):
1439 super(ICEEditor, self).__init__(parent) 1440 _fc_dict=field_color.build_field_info(self, 'phonebook') 1441 vs=wx.StaticBoxSizer(field_color.build_color_field(self, 1442 wx.StaticBox, 1443 (self, -1, "ICE Details"), 1444 'ICE', _fc_dict), 1445 wx.VERTICAL) 1446 # ICE field 1447 hs=wx.BoxSizer(wx.HORIZONTAL) 1448 hs.Add(field_color.build_color_field(self, wx.StaticText, 1449 (self, -1, "Assign this contact as:"), 1450 'ICE', _fc_dict), 1451 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1452 self._ice=wx.ComboBox(self, -1, 'None', 1453 choices=['None', 'ICE 1', 'ICE 2', 'ICE 3'], 1454 style=wx.CB_READONLY) 1455 wx.EVT_COMBOBOX(self, self._ice.GetId(), self.OnDirtyUI) 1456 hs.Add(self._ice, 0, wx.EXPAND|wx.LEFT, 5) 1457 vs.Add(hs, 0, wx.EXPAND|wx.ALL, 5) 1458 # all done 1459 self.SetSizer(vs) 1460 vs.Fit(self)
1461
1462 - def Set(self, data):
1463 if data.has_key('iceindex'): 1464 _val=data['iceindex']+1 1465 else: 1466 _val=0 1467 self._ice.SetSelection(_val)
1468
1469 - def Get(self):
1470 _res={} 1471 _val=self._ice.GetSelection() 1472 if _val: 1473 _res['iceindex']=_val-1 1474 return _res
1475 1476 1477 # FavoriteEditor-----------------------------------------------------------------
1478 -class FavoriteEditor(DirtyUIBase):
1479 - def __init__(self, parent, _, navtoolbar=False):
1480 super(FavoriteEditor, self).__init__(parent) 1481 _fc_dict=field_color.build_field_info(self, 'phonebook') 1482 vs=wx.StaticBoxSizer(field_color.build_color_field(self, 1483 wx.StaticBox, 1484 (self, -1, "Favorite Details"), 1485 'Favorite', _fc_dict), 1486 wx.VERTICAL) 1487 # Favorite field 1488 hs=wx.BoxSizer(wx.HORIZONTAL) 1489 hs.Add(field_color.build_color_field(self, wx.StaticText, 1490 (self, -1, "Assign this contact as:"), 1491 'Favorite', _fc_dict), 1492 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1493 self._favorite=wx.ComboBox(self, -1, 'None', 1494 choices=['None'] + ['Favorite ' + `n` for n in range(1,10)], 1495 style=wx.CB_READONLY) 1496 wx.EVT_COMBOBOX(self, self._favorite.GetId(), self.OnDirtyUI) 1497 hs.Add(self._favorite, 0, wx.EXPAND|wx.LEFT, 5) 1498 vs.Add(hs, 0, wx.EXPAND|wx.ALL, 5) 1499 # all done 1500 self.SetSizer(vs) 1501 vs.Fit(self)
1502
1503 - def Set(self, data):
1504 if data.has_key('favoriteindex'): 1505 _val=data['favoriteindex']+1 1506 else: 1507 _val=0 1508 self._favorite.SetSelection(_val)
1509
1510 - def Get(self):
1511 _res={} 1512 _val=self._favorite.GetSelection() 1513 if _val: 1514 _res['favoriteindex']=_val-1 1515 return _res
1516 1517 # EditorManager-----------------------------------------------------------------
1518 -class EditorManager(fixedscrolledpanel.wxScrolledPanel):
1519 1520 ID_DOWN=wx.NewId() 1521 ID_UP=wx.NewId() 1522 ID_ADD=wx.NewId() 1523 ID_DELETE=wx.NewId() 1524 instruction_text=""" 1525 \n\nPress Add above to add a field. Press Delete to remove the field your 1526 cursor is on. 1527 1528 You can use Up and Down to change the priority of items. For example, some 1529 phones store the first five numbers in the numbers tab, and treat the first 1530 number as the default to call. Other phones can only store one email address 1531 so only the first one would be stored. 1532 """ 1533
1534 - def __init__(self, parent, childclass):
1535 """Constructor 1536 1537 @param parent: Parent window 1538 @param childclass: One of the *Editor classes which is used as a factory for making the 1539 widgets that correspond to each value""" 1540 fixedscrolledpanel.wxScrolledPanel.__init__(self, parent) 1541 self.dirty_ui_handler=getattr(parent, 'OnDirtyUI', None) 1542 self.sizer=wx.BoxSizer(wx.VERTICAL) 1543 self.SetSizer(self.sizer) 1544 self.widgets=[] 1545 self.childclass=childclass 1546 self.instructions=wx.StaticText(self, -1, EditorManager.instruction_text) 1547 self.sizer.Add(self.instructions, 0, wx.ALIGN_CENTER ) 1548 self.SetupScrolling()
1549
1550 - def Get(self):
1551 """Returns a list of dicts corresponding to the values""" 1552 res=[] 1553 for i in self.widgets: 1554 g=i.Get() 1555 if len(g): 1556 res.append(g) 1557 return res
1558
1559 - def Populate(self, data):
1560 """Fills in the editors according to the list of dicts in data 1561 1562 The editor widgets are created and destroyed as needed""" 1563 callsus=False 1564 while len(data)>len(self.widgets): 1565 callsus=True 1566 _w=self.childclass(self, len(self.widgets), navtoolbar=True) 1567 if self.dirty_ui_handler: 1568 EVT_DIRTY_UI(self, _w.GetId(), self.dirty_ui_handler) 1569 self.widgets.append(_w) 1570 self.sizer.Add(_w, 0, wx.EXPAND|wx.ALL, 10) 1571 while len(self.widgets)>len(data): 1572 callsus=True 1573 self.sizer.Remove(self.widgets[-1]) 1574 self.widgets[-1].Destroy() 1575 del self.widgets[-1] 1576 for num in range(len(data)): 1577 self.widgets[num].Clean() 1578 self.widgets[num].Set(data[num]) 1579 callsus=self.DoInstructionsLayout() or callsus 1580 if callsus: 1581 self.sizer.Layout() 1582 self.SetupScrolling()
1583
1584 - def DoInstructionsLayout(self):
1585 "Returns True if Layout should be called" 1586 if len(self.widgets): 1587 if self.instructions.IsShown(): 1588 self.sizer.Remove(self.instructions) 1589 self.instructions.Show(False) 1590 return True 1591 else: 1592 if not self.instructions.IsShown(): 1593 self.sizer.Add(self.instructions, 0, wx.ALIGN_CENTER ) 1594 self.instructions.Show(True) 1595 return True 1596 return False
1597 1598
1599 - def GetCurrentWidgetIndex(self):
1600 """Returns the index of the currently selected editor widget 1601 1602 @raise IndexError: if there is no selected one""" 1603 focuswin=wx.Window.FindFocus() 1604 win=focuswin 1605 while win is not None and win not in self.widgets: 1606 win=win.GetParent() 1607 if win is None: 1608 raise IndexError("no idea who is selected") 1609 if win not in self.widgets: 1610 raise IndexError("no idea what that thing is") 1611 pos=self.widgets.index(win) 1612 return pos
1613
1614 - def Add(self):
1615 """Adds a new widget at the currently selected location""" 1616 gets=[x.Get() for x in self.widgets] 1617 try: 1618 pos=self.GetCurrentWidgetIndex() 1619 except IndexError: 1620 pos=len(gets)-1 1621 _w=self.childclass(self, len(self.widgets), navtoolbar=True) 1622 if self.dirty_ui_handler: 1623 EVT_DIRTY_UI(self, _w.GetId(), self.dirty_ui_handler) 1624 self.dirty_ui_handler(None) 1625 self.widgets.append(_w) 1626 self.sizer.Add(_w, 0, wx.EXPAND|wx.ALL, 10) 1627 self.DoInstructionsLayout() 1628 self.sizer.Layout() 1629 self.SetupScrolling() 1630 if len(self.widgets)>1: 1631 for num,value in zip( range(pos+2, len(self.widgets)), gets[pos+1:]): 1632 self.widgets[num].Set(value) 1633 self.widgets[pos+1].Set({}) 1634 self.widgets[pos+1].SetFocus() 1635 else: 1636 self.widgets[0].SetFocus()
1637
1638 - def MoveField(self, field, delta):
1639 try: 1640 pos=self.widgets.index(field) 1641 except IndexError: 1642 wx.Bell() 1643 return 1644 if pos+delta<0: 1645 print "that would go off top" 1646 return 1647 if pos+delta>=len(self.widgets): 1648 print "that would go off bottom" 1649 return 1650 if self.dirty_ui_handler: 1651 self.dirty_ui_handler(None) 1652 gets=[x.Get() for x in self.widgets] 1653 # swap value 1654 path,settings=self.GetWidgetPathAndSettings(self.widgets[pos], field) 1655 self.widgets[pos+delta].Set(gets[pos]) 1656 self.widgets[pos].Set(gets[pos+delta]) 1657 self.SetWidgetPathAndSettings(self.widgets[pos+delta], path, settings)
1658
1659 - def DeleteField(self, field):
1660 """Deletes the currently select widget""" 1661 # ignore if there is nothing to delete 1662 if len(self.widgets)==0: 1663 return 1664 # get the current value of all widgets 1665 gets=[x.Get() for x in self.widgets] 1666 try: 1667 pos=self.widgets.index(field) 1668 except IndexError: 1669 wx.Bell() 1670 return 1671 if self.dirty_ui_handler: 1672 self.dirty_ui_handler(None) 1673 # remove the last widget (the UI, not the value) 1674 self.sizer.Remove(self.widgets[-1]) 1675 self.widgets[-1].Destroy() 1676 del self.widgets[-1] 1677 # if we deleted last item and it had focus, move focus 1678 # to second to last item 1679 if len(self.widgets): 1680 if pos==len(self.widgets): 1681 self.widgets[pos-1].SetFocus() 1682 self.DoInstructionsLayout() 1683 self.sizer.Layout() 1684 self.SetupScrolling() 1685 1686 # update from one we deleted to end 1687 for i in range(pos, len(self.widgets)): 1688 self.widgets[i].Set(gets[i+1]) 1689 1690 if len(self.widgets): 1691 # change focus if we deleted the last widget 1692 if pos<len(self.widgets): 1693 self.widgets[pos].SetFocus()
1694
1695 - def Delete(self):
1696 """Deletes the currently select widget""" 1697 # ignore if there is nothing to delete 1698 if len(self.widgets)==0: 1699 return 1700 # get the current value of all widgets 1701 gets=[x.Get() for x in self.widgets] 1702 try: 1703 pos=self.GetCurrentWidgetIndex() 1704 except IndexError: 1705 wx.Bell() 1706 return 1707 # remove the last widget (the UI, not the value) 1708 self.sizer.Remove(self.widgets[-1]) 1709 self.widgets[-1].Destroy() 1710 del self.widgets[-1] 1711 # if we deleted last item and it had focus, move focus 1712 # to second to last item 1713 if len(self.widgets): 1714 if pos==len(self.widgets): 1715 self.widgets[pos-1].SetFocus() 1716 self.DoInstructionsLayout() 1717 self.sizer.Layout() 1718 self.SetupScrolling() 1719 1720 # update from one we deleted to end 1721 for i in range(pos, len(self.widgets)): 1722 self.widgets[i].Set(gets[i+1]) 1723 1724 if len(self.widgets): 1725 # change focus if we deleted the last widget 1726 if pos<len(self.widgets): 1727 self.widgets[pos].SetFocus()
1728 1729
1730 - def Move(self, delta):
1731 """Moves the currently selected widget 1732 1733 @param delta: positive to move down, negative to move up 1734 """ 1735 focuswin=wx.Window_FindFocus() 1736 try: 1737 pos=self.GetCurrentWidgetIndex() 1738 except IndexError: 1739 wx.Bell() 1740 return 1741 if pos+delta<0: 1742 print "that would go off top" 1743 return 1744 if pos+delta>=len(self.widgets): 1745 print "that would go off bottom" 1746 return 1747 gets=[x.Get() for x in self.widgets] 1748 # swap value 1749 path,settings=self.GetWidgetPathAndSettings(self.widgets[pos], focuswin) 1750 self.widgets[pos+delta].Set(gets[pos]) 1751 self.widgets[pos].Set(gets[pos+delta]) 1752 self.SetWidgetPathAndSettings(self.widgets[pos+delta], path, settings)
1753
1754 - def GetWidgetPathAndSettings(self, widgetfrom, controlfrom):
1755 """Finds the specified control within the editor widgetfrom. 1756 The values are for calling L{SetWidgetPathAndSettings}. 1757 1758 Returns a tuple of (path, settings). path corresponds 1759 to the hierarchy with an editor (eg a panel contains a 1760 radiobox contains the radio button widget). settings 1761 means something to L{SetWidgetPathAndSettings}. For example, 1762 if the widget is a text widget it contains the current insertion 1763 point and selection.""" 1764 # we find where the control is in the hierarchy of widgetfrom 1765 path=[] 1766 1767 # this is the same algorithm getpwd uses on Unix 1768 win=controlfrom 1769 while win is not widgetfrom: 1770 p=win.GetParent() 1771 kiddies=p.GetChildren() 1772 found=False 1773 for kid in range(len(kiddies)): 1774 if kiddies[kid] is win: 1775 path=[kid]+path 1776 win=p 1777 found=True 1778 break 1779 if found: 1780 continue 1781 print "i don't appear to be my parent's child!!!" 1782 return 1783 1784 1785 # save some settings we know about 1786 settings=[] 1787 if isinstance(controlfrom, wx.TextCtrl): 1788 settings=[controlfrom.GetInsertionPoint(), controlfrom.GetSelection()] 1789 1790 return path,settings
1791
1792 - def SetWidgetPathAndSettings(self,widgetto,path,settings):
1793 """See L{GetWidgetPathAndSettings}""" 1794 # now have the path. follow it in widgetto 1795 print path 1796 win=widgetto 1797 for p in path: 1798 kids=win.GetChildren() 1799 win=kids[p] 1800 controlto=win 1801 1802 controlto.SetFocus() 1803 1804 if isinstance(controlto, wx.TextCtrl): 1805 controlto.SetInsertionPoint(settings[0]) 1806 controlto.SetSelection(settings[1][0], settings[1][1])
1807
1808 - def SetFocusOnValue(self, index):
1809 """Sets focus to the editor widget corresponding to the supplied index""" 1810 wx.CallAfter(self.widgets[index].SetFocus)
1811 1812 # Editor------------------------------------------------------------------------
1813 -class Editor(wx.Dialog):
1814 "The Editor Dialog itself. It contains panes for the various field types." 1815 1816 ID_DOWN=wx.NewId() 1817 ID_UP=wx.NewId() 1818 ID_ADD=wx.NewId() 1819 ID_DELETE=wx.NewId() 1820 1821 color_field_name='phonebook' 1822 1823 # the tabs and classes within them 1824 tabsfactory=[ 1825 ("Names", "names", NameEditor), 1826 ("Numbers", "numbers", NumberEditor), 1827 ("Emails", "emails", EmailEditor), 1828 ("Addresses", "addresses", AddressEditor), 1829 ("URLs", "urls", URLEditor), 1830 ("Memos", "memos", MemoEditor), 1831 ("Categories", "categories", CategoryEditor), 1832 ("Wallpapers", "wallpapers", WallpaperEditor), 1833 ("Ringtones", "ringtones", RingtoneEditor), 1834 ("ICE", 'ice', ICEEditor), 1835 ("Favorite", "favorite", FavoriteEditor), 1836 ("IM Names", "ims", IMEditor), 1837 ("Misc", 'flags', MiscEditor), 1838 ] 1839
1840 - def __init__(self, parent, data, title="Edit PhoneBook Entry", 1841 keytoopenon=None, dataindex=None, 1842 factory=database.dictdataobjectfactory, readonly=False, 1843 datakey=None, movement=False):
1844 """Constructor for phonebookentryeditor dialog 1845 1846 @param parent: parent window 1847 @param data: dict of values to edit 1848 @param title: window title 1849 @param keytoopenon: The key to open on. This is the key as stored in the data such as "names", "numbers" 1850 @param dataindex: Which value within the tab specified by keytoopenon to set focus to 1851 @param readonly: Indicates read-only data. 1852 """ 1853 global _ringtone_list, _wallpaper_list 1854 wx.Dialog.__init__(self, parent, -1, title, size=(900,580), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) 1855 field_color.get_color_info_from_profile(self) 1856 _ringtone_list=None 1857 _wallpaper_list=None 1858 self._data_key=datakey 1859 if movement and datakey is None and __debug__: 1860 self.log('Movement and datakey is None') 1861 raise ValueError 1862 # make a copy of the data we are going to work on 1863 self.dirty_widgets={ True: [], False: [] } 1864 self.data=factory.newdataobject(data) 1865 vs=wx.BoxSizer(wx.VERTICAL) 1866 # the title & direction button 1867 _hbs=wx.BoxSizer(wx.HORIZONTAL) 1868 self._title=wx.StaticText(self, -1, "Name here", style=wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE) 1869 _add_btn=wx.BitmapButton(self, wx.NewId(), 1870 wx.ArtProvider.GetBitmap(guihelper.ART_ADD_FIELD), name="Prev Item") 1871 if movement: 1872 _prev_btn=wx.BitmapButton(self, wx.NewId(), wx.ArtProvider.GetBitmap(guihelper.ART_ARROW_LEFT), name="Prev Item") 1873 _next_btn=wx.BitmapButton(self, wx.NewId(), wx.ArtProvider.GetBitmap(guihelper.ART_ARROW_RIGHT), name="Next Item") 1874 self.dirty_widgets[False].append(_prev_btn) 1875 self.dirty_widgets[False].append(_next_btn) 1876 _hbs.Add(_prev_btn, 0, wx.EXPAND, 0) 1877 _hbs.Add(_add_btn, 0, wx.EXPAND|wx.LEFT, 10) 1878 _hbs.Add(self._title, 1, wx.EXPAND, 0) 1879 _hbs.Add(_next_btn, 0, wx.EXPAND, 0) 1880 wx.EVT_BUTTON(self, _prev_btn.GetId(), self.OnMovePrev) 1881 wx.EVT_BUTTON(self, _next_btn.GetId(), self.OnMoveNext) 1882 else: 1883 _hbs.Add(_add_btn, 0, wx.EXPAND|wx.LEFT, 10) 1884 _hbs.Add(self._title, 1, wx.EXPAND, 0) 1885 wx.EVT_BUTTON(self, _add_btn.GetId(), self.Add) 1886 vs.Add(_hbs, 0, wx.ALL|wx.EXPAND, 5) 1887 1888 nb=wx.Notebook(self, -1) 1889 self.nb=nb 1890 self.nb.OnDirtyUI=self.OnDirtyUI 1891 vs.Add(nb,1,wx.EXPAND|wx.ALL,5) 1892 1893 self.tabs=[] 1894 # instantiate the nb widgets 1895 for name,key,klass in self.tabsfactory: 1896 widget=EditorManager(self.nb, klass) 1897 nb.AddPage(widget,name) 1898 if key==keytoopenon or keytoopenon in key: 1899 nb.SetSelection(len(self.tabs)) 1900 self.tabs.append(widget) 1901 # populate the data 1902 self.Populate() 1903 # and focus on the right one if specified 1904 for _idx, (name,key,klass) in enumerate(self.tabsfactory): 1905 if key and key==keytoopenon and dataindex is not None: 1906 self.tabs[_idx].SetFocusOnValue(dataindex) 1907 1908 vs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) 1909 1910 _btn_sizer=wx.StdDialogButtonSizer() 1911 if not readonly: 1912 _btn_sizer.AddButton(wx.Button(self, wx.ID_OK)) 1913 if self._data_key is not None: 1914 _w=wx.Button(self, wx.ID_APPLY) 1915 self.dirty_widgets[True].append(_w) 1916 _btn_sizer.AddButton(_w) 1917 wx.EVT_BUTTON(self, wx.ID_APPLY, self.OnApply) 1918 _btn_sizer.AddButton(wx.Button(self, wx.ID_CANCEL)) 1919 _w=wx.Button(self, wx.ID_REVERT_TO_SAVED) 1920 self.dirty_widgets[True].append(_w) 1921 _btn_sizer.SetNegativeButton(_w) 1922 _btn_sizer.Realize() 1923 vs.Add(_btn_sizer, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1924 1925 self.SetSizer(vs) 1926 1927 wx.EVT_BUTTON(self, wx.ID_REVERT_TO_SAVED, self.Revert) 1928 wx.EVT_TOOL(self, self.ID_UP, self.MoveUp) 1929 wx.EVT_TOOL(self, self.ID_DOWN, self.MoveDown) 1930 wx.EVT_TOOL(self, self.ID_ADD, self.Add) 1931 wx.EVT_TOOL(self, self.ID_DELETE, self.Delete) 1932 self.ignore_dirty=False 1933 self.dirty=False 1934 self.setdirty(False)
1935
1936 - def Revert(self, _):
1937 # reload data 1938 self.Populate() 1939 self.setdirty(False)
1940
1941 - def OnDirtyUI(self, _):
1942 self.setdirty()
1943
1944 - def setdirty(self, flg=True):
1945 if self.ignore_dirty: 1946 return 1947 self.dirty=flg 1948 for w in self.dirty_widgets[self.dirty]: 1949 w.Enable(True) 1950 for w in self.dirty_widgets[not self.dirty]: 1951 w.Enable(False)
1952
1953 - def OnApply(self, _):
1954 # Save the current data 1955 self.GetParent().SaveData(self.GetData(), self.GetDataKey()) 1956 self.setdirty(False)
1957
1958 - def Populate(self):
1959 # populate various widget with data 1960 self._set_title() 1961 for _idx, (name,key,klass) in enumerate(self.tabsfactory): 1962 if key is None: 1963 # the fields are in data, not in data[key] 1964 self.tabs[_idx].Populate([self.data]) 1965 else: 1966 self.tabs[_idx].Populate(self.data.get(key, {}))
1967
1968 - def GetData(self):
1969 res=self.data 1970 for i in range(len(self.tabsfactory)): 1971 widget=self.nb.GetPage(i) 1972 data=widget.Get() 1973 key=self.tabsfactory[i][1] 1974 if len(data): 1975 if key is None: 1976 res.update(data[0]) 1977 else: 1978 res[key]=data 1979 else: 1980 # remove the key 1981 try: 1982 if key is not None: 1983 del res[key] 1984 except KeyError: 1985 # which may not have existed ... 1986 pass 1987 return res
1988
1989 - def GetDataKey(self):
1990 return self._data_key
1991
1992 - def MoveUp(self, _):
1993 self.nb.GetPage(self.nb.GetSelection()).Move(-1) 1994 self.setdirty()
1995
1996 - def MoveDown(self, _):
1997 self.nb.GetPage(self.nb.GetSelection()).Move(+1) 1998 self.setdirty()
1999
2000 - def Add(self, _):
2001 self.nb.GetPage(self.nb.GetSelection()).Add()
2002
2003 - def Delete(self, _):
2004 self.nb.GetPage(self.nb.GetSelection()).Delete() 2005 self.setdirty()
2006
2007 - def _set_title(self):
2008 if hasattr(self, '_title'): 2009 self._title.SetLabel(nameparser.getfullname(self.data['names'][0]))
2010
2011 - def OnMoveNext(self, _):
2012 _key,_data=self.GetParent().GetNextEntry(True) 2013 if _data: 2014 self.data=_data 2015 self._data_key=_key 2016 self.Populate()
2017
2018 - def OnMovePrev(self, _):
2019 _key,_data=self.GetParent().GetNextEntry(False) 2020 if _data: 2021 self.data=_data 2022 self._data_key=_key 2023 self.Populate()
2024 2025 # SingleFieldEditor-------------------------------------------------------------
2026 -class SingleFieldEditor(wx.Dialog):
2027 "Edit a single field for a groups of entries" 2028 2029 ID_DOWN=wx.NewId() 2030 ID_UP=wx.NewId() 2031 ID_ADD=wx.NewId() 2032 ID_DELETE=wx.NewId() 2033 2034 tabsfactory={ 2035 'categories': ("Categories", "categories", CategoryEditor), 2036 'wallpapers': ("Wallpapers", "wallpapers", WallpaperEditor), 2037 'group_wallpapers': ("Group Wallpapers", "group_wallpapers", WallpaperEditor), 2038 'ringtones': ("Ringtones", "ringtones", RingtoneEditor) } 2039 2040 color_field_name='phonebook' 2041
2042 - def __init__(self, parent, key, caption="Edit PhoneBook Entry", populatedata=None):
2043 if not self.tabsfactory.has_key(key): 2044 raise KeyError 2045 super(SingleFieldEditor, self).__init__(parent, -1, 2046 caption, 2047 size=(740,580), 2048 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) 2049 field_color.get_color_info_from_profile(self) 2050 2051 self._key=key 2052 vs=wx.BoxSizer(wx.VERTICAL) 2053 _hbs=wx.BoxSizer(wx.HORIZONTAL) 2054 _add_btn=wx.BitmapButton(self, wx.NewId(), 2055 wx.ArtProvider.GetBitmap(guihelper.ART_ADD_FIELD), name="Prev Item") 2056 _hbs.Add(_add_btn, 0, wx.EXPAND|wx.LEFT, 10) 2057 wx.EVT_BUTTON(self, _add_btn.GetId(), self.Add) 2058 vs.Add(_hbs, 0, wx.ALL|wx.EXPAND, 5) 2059 2060 self.nb=wx.Notebook(self, -1) 2061 vs.Add(self.nb,1,wx.EXPAND|wx.ALL,5) 2062 2063 # instantiate the nb widgets 2064 name,key,klass=self.tabsfactory[key] 2065 if name in ('Group Wallpapers'): 2066 #instantiate WallpaperEditor class with arguments, because I can't pass in args thru EditorManager 2067 #widget=klass(self.nb, parent, False) 2068 widget=EditorManager(self.nb, klass) 2069 #hide the add widget button since we aren't using EditorManager 2070 #vs.Hide(0) 2071 if populatedata is not None: 2072 widget.Populate(populatedata) 2073 else: 2074 widget=EditorManager(self.nb, klass) 2075 self.nb.AddPage(widget,name) 2076 2077 vs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) 2078 _btn_sizer=self.CreateButtonSizer(wx.OK|wx.CANCEL) 2079 vs.Add(_btn_sizer, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 2080 2081 self.SetSizer(vs) 2082 2083 wx.EVT_TOOL(self, self.ID_UP, self.MoveUp) 2084 wx.EVT_TOOL(self, self.ID_DOWN, self.MoveDown) 2085 wx.EVT_TOOL(self, self.ID_ADD, self.Add) 2086 wx.EVT_TOOL(self, self.ID_DELETE, self.Delete)
2087
2088 - def MoveUp(self, _):
2089 self.nb.GetPage(0).Move(-1)
2090
2091 - def MoveDown(self, _):
2092 self.nb.GetPage(0).Move(+1)
2093
2094 - def Add(self, _):
2095 self.nb.GetPage(0).Add()
2096
2097 - def Delete(self, _):
2098 self.nb.GetPage(0).Delete()
2099
2100 - def GetData(self):
2101 return self.nb.GetPage(0).Get()
2102 2103 # main-------------------------------------------------------------------------- 2104 if __name__=='__main__': 2105 2106 # data to edit 2107 2108 data={ 'names': [ { 'full': 'John Smith'}, { 'nickname': 'I Love Testing'} ], 2109 'categories': [ {'category': 'business'}, {'category': 'friend' } ], 2110 # 'emails': [ {'email': 'ex1@example.com'}, {'email': 'ex2@example.net', 'type': 'home'} ], 2111 'urls': [ {'url': 'www.example.com'}, {'url': 'http://www.example.net', 'type': 'home'} ], 2112 'ringtones': [ {'ringtone': 'mi2.mid', 'use': 'call'}, {'ringtone': 'dots.mid', 'use': 'message'}], 2113 'addresses': [ {'type': 'home', 'street': '123 Main Street', 'city': 'Main Town', 'state': 'CA', 'postalcode': '12345'}, 2114 {'type': 'business', 'company': 'Acme Widgets Inc', 'street': '444 Industrial Way', 'street2': 'Square Business Park', 2115 'city': 'City Of Quality', 'state': 'Northern', 'postalcode': 'GHGJJ-12324', 'country': 'Nations United'} 2116 ], 2117 'wallpapers': [{'wallpaper': 'pic1.bmp', 'use': 'call'}, {'wallpaper': 'alert.jpg', 'use': 'message'}], 2118 'flags': [ {'secret': True}, {'wierd': 'orange'} ], 2119 'memos': [ {'memo': 'Some stuff about this person " is usually welcome'}, {'memo': 'A second note'}], 2120 'numbers': [ {'number': '123-432-2342', 'type': 'home', 'speeddial': 3}, {'number': '121=+4321/4', 'type': 'fax'}] 2121 } 2122 2123 app=wx.PySimpleApp() 2124 with guihelper.WXDialogWrapper(Editor(None,data), True): 2125 pass 2126