Trees | Indices | Help |
|
---|
|
1 ### BITPIM 2 ### 3 ### Copyright (C) 2005 Joe Pham <djpham@netzero.net> 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: memo.py 4714 2008-10-21 01:50:47Z djpham $ 9 10 """ 11 Code to handle memo/note items 12 13 The format for the memo is standardized. It is a dict with the following 14 fields: 15 16 MemoEntry properties: 17 subject - 'string subject' 18 text - 'string text' 19 categories - [{ 'category': 'string' }] 20 secret - True/<False|None> 21 date - date time/stamp 'Mmm dd, YYYY HH:MM' (Read only) 22 id - unique id string that can be used as a dict key. 23 24 MemoEntry methods: 25 get() - return a copy of the memo dict. 26 set(dict) - set the internal dict to the new dict. 27 set_date_now() - set the date/time stamp to the current date/time 28 set_date_isostr(iso_string) - set the date/time stamp to the ISO date string 29 (YYYYMMDDTHHMMSS) 30 31 To implement memo read/write for a phone module: 32 Add 2 entries into Profile._supportedsyncs: 33 ... 34 ('memo', 'read', None), # all memo reading 35 ('memo', 'write', 'OVERWRITE') # all memo writing 36 37 implement the following 2 methods in your Phone class: 38 def getmemo(self, result): 39 ... 40 return result 41 42 def savememo(self, result, merge): 43 ... 44 return result 45 46 The result dict key is 'memo'. 47 """ 48 49 # standard modules 50 from __future__ import with_statement 51 import copy 52 import datetime 53 import time 54 55 # wx modules 56 import wx 57 58 # BitPim modules 59 import bptime 60 import calendarentryeditor as cal_editor 61 import database 62 import field_color 63 import helpids 64 import phonebookentryeditor as pb_editor 65 import pubsub 66 import today 67 import guihelper 68 import guiwidgets 69 import widgets 70 71 widgets_list=[] 72 module_debug=False 73 74 #-------------------------------------------------------------------------------76 _knownproperties=['subject', 'date'] 77 _knownlistproperties=database.basedataobject._knownlistproperties.copy() 78 _knownlistproperties.update( {'categories': ['category'], 79 'flags': ['secret'], 80 'body': ['type', 'data', '*' ] }) 8186 memoobjectfactory=database.dataobjectfactory(MemoDataObject) 87 88 #-------------------------------------------------------------------------------90 _body_subject_len=12 # the # of chars from body to fill in for subj + ... 91 _id_index=0 92 _max_id_index=999 97196 197 #-------------------------------------------------------------------------------99 return copy.deepcopy(self._data, {})103105 return self.get()107 self.set(d)108110 if v is None or v in v_list: 111 if self._data.has_key(key): 112 del self._data[key] 113 else: 114 self._data[key]=v115117 return self._data.get('subject', '')119 self._set_or_del('subject', v, ('',))120 subject=property(fget=_get_subject, fset=_set_subject) 121123 b=self._data.get('body', []) 124 for n in b: 125 if n.get('type', None)=='text': 126 return n.get('data', '') 127 return ''129 if v is None: 130 v='' 131 if not self.subject: 132 self.subject=v[:self._body_subject_len]+'...' 133 b=self._data.get('body', []) 134 for n in b: 135 if n.get('type', None)=='text': 136 n['data']=v 137 return 138 self._data.setdefault('body', []).append(\ 139 {'type': 'text', 'data': v })140 text=property(fget=_get_text, fset=_set_text) 141143 f=self._data.get('flags', []) 144 for n in f: 145 if n.has_key('secret'): 146 return n['secret'] 147 return False149 f=self._data.get('flags', []) 150 for i, n in enumerate(f): 151 if n.has_key('secret'): 152 if v is None or not v: 153 del f[i] 154 if not self._data['flags']: 155 del self._data['flags'] 156 else: 157 n['secret']=v 158 return 159 if v is not None and v: 160 self._data.setdefault('flags', []).append({'secret': v})161 secret=property(fget=_get_secret, fset=_set_secret) 162164 return self._data.get('categories', [])166 self._set_or_del('categories', v, ([],))167 categories=property(fget=_get_categories, fset=_set_categories) 168170 # set the date/time stamp to now 171 n=datetime.datetime.now() 172 self._data['date']=n.strftime('%b %d, %Y %H:%M')174 n=bptime.BPTime(iso_string) 175 self._data['date']=n.date.strftime('%b %d, %Y')+n.time.strftime(' %H:%M')177 return self._data.get('date', '')178 date=property(fget=_get_date) 179181 "Create a BitPim serial for this entry" 182 self._data.setdefault("serials", []).append(\ 183 {"sourcetype": "bitpim", 184 "id": '%.3f%03d'%(time.time(), MemoEntry._id_index) }) 185 if MemoEntry._id_index<MemoEntry._max_id_index: 186 MemoEntry._id_index+=1 187 else: 188 MemoEntry._id_index=0190 s=self._data.get('serials', []) 191 for n in s: 192 if n.get('sourcetype', None)=='bitpim': 193 return n.get('id', None) 194 return None195 id=property(fget=_get_id)199 _dict_key_index=0 200 _label_index=1 201 _class_index=2 202 _get_index=3 203 _set_index=4 204 _w_index=5266 267 #-------------------------------------------------------------------------------206 global widgets_list 207 208 pb_editor.DirtyUIBase.__init__(self, parent) 209 self._fields=[ 210 ['subject', 'Subject:', cal_editor.DVTextControl, None, None, None], 211 ['date', 'Date:', wx.StaticText, self._get_date_str, self._set_date_str, None], 212 ['secret', 'Private:', wx.CheckBox, None, None, None] 213 ] 214 gs=wx.FlexGridSizer(-1, 2, 5, 5) 215 gs.AddGrowableCol(1) 216 for n in self._fields: 217 _txt=wx.StaticText(self, -1, n[self._label_index], 218 style=wx.ALIGN_LEFT) 219 widgets_list.append((_txt, n[0])) 220 gs.Add(_txt, 0, wx.EXPAND|wx.BOTTOM, 5) 221 w=n[self._class_index](self, -1) 222 gs.Add(w, 0, wx.EXPAND|wx.BOTTOM, 5) 223 n[self._w_index]=w 224 # event handlers 225 wx.EVT_CHECKBOX(self, self._fields[2][self._w_index].GetId(), 226 self.OnMakeDirty) 227 # all done 228 self.SetSizer(gs) 229 self.SetAutoLayout(True) 230 gs.Fit(self)231237 self.OnDirtyUI(evt)238240 self.ignore_dirty=True 241 if data is None: 242 for n in self._fields: 243 n[self._w_index].Enable(False) 244 else: 245 for n in self._fields: 246 w=n[self._w_index] 247 w.Enable(True) 248 if n[self._set_index] is None: 249 w.SetValue(getattr(data, n[self._dict_key_index])) 250 else: 251 n[self._set_index](w, data) 252 self.ignore_dirty=self.dirty=False253255 self.ignore_dirty=self.dirty=False 256 if data is None: 257 return 258 for n in self._fields: 259 w=n[self._w_index] 260 if n[self._get_index] is None: 261 v=w.GetValue() 262 else: 263 v=n[self._get_index](w, None) 264 if v is not None: 265 setattr(data, n[self._dict_key_index], v)269 color_field_name='memo' 270558272 wx.Panel.__init__(self, parent, -1) 273 self._main_window=mainwindow 274 self._data={} 275 self._data_map={} 276 # main box sizer 277 vbs=wx.BoxSizer(wx.VERTICAL) 278 # horizontal sizer for the listbox and tabs 279 hbs=wx.BoxSizer(wx.HORIZONTAL) 280 # the list box 281 self._item_list=wx.ListBox(self, wx.NewId(), 282 style=wx.LB_SINGLE|wx.LB_HSCROLL|wx.LB_NEEDED_SB) 283 hbs.Add(self._item_list, 1, wx.EXPAND|wx.BOTTOM, border=5) 284 # the detailed info pane 285 vbs1=wx.BoxSizer(wx.VERTICAL) 286 self._items=( 287 (GeneralEditor, 0, None), 288 (cal_editor.CategoryEditor, 1, 'category'), 289 (pb_editor.MemoEditor, 1, 'memo') 290 ) 291 self._w=[] 292 for n in self._items: 293 w=n[0](self, -1) 294 vbs1.Add(w, n[1], wx.EXPAND|wx.ALL, 5) 295 self._w.append(w) 296 if n[2]: 297 widgets_list.append((w.static_box, n[2])) 298 hbs.Add(vbs1, 3, wx.EXPAND|wx.ALL, border=5) 299 self._general_editor_w=self._w[0] 300 self._cat_editor_w=self._w[1] 301 self._memo_editor_w=self._w[2] 302 # the bottom buttons 303 hbs1=wx.BoxSizer(wx.HORIZONTAL) 304 self._save_btn=wx.Button(self, wx.ID_SAVE) 305 self._revert_btn=wx.Button(self, wx.ID_REVERT_TO_SAVED) 306 help_btn=wx.Button(self, wx.ID_HELP) 307 hbs1.Add(self._save_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 308 hbs1.Add(help_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 309 hbs1.Add(self._revert_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 310 # all done 311 vbs.Add(hbs, 1, wx.EXPAND|wx.ALL, 5) 312 vbs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) 313 vbs.Add(hbs1, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 314 self.SetSizer(vbs) 315 self.SetAutoLayout(True) 316 vbs.Fit(self) 317 # event handlers 318 wx.EVT_LISTBOX(self, self._item_list.GetId(), self._OnListBoxItem) 319 wx.EVT_BUTTON(self, self._save_btn.GetId(), self._OnSave) 320 wx.EVT_BUTTON(self, self._revert_btn.GetId(), self._OnRevert) 321 wx.EVT_BUTTON(self, wx.ID_HELP, 322 lambda _: wx.GetApp().displayhelpid(helpids.ID_TAB_MEMO)) 323 # DIRTY UI Event handlers 324 for w in self._w: 325 pb_editor.EVT_DIRTY_UI(self, w.GetId(), self.OnMakeDirty) 326 # populate data 327 self._populate() 328 # turn on dirty flag 329 self.ignoredirty=False 330 self.setdirty(False) 331 # register for Today selection 332 today.bind_notification_event(self.OnTodaySelection, 333 today.Today_Group_Memo) 334 # color code editable labels 335 field_color.reload_color_info(self, widgets_list) 336 pubsub.subscribe(self.OnPhoneChanged, pubsub.PHONE_MODEL_CHANGED)337339 # just reload the color info based on the new phone 340 field_color.reload_color_info(self, widgets_list) 341 self.Refresh()342344 keys=self._data.keys() 345 keys.sort() 346 keys.reverse() 347 today_event=today.TodayMemoEvent() 348 for k in keys: 349 today_event.append(self._data[k].subject, 350 { 'key': k, 'index': self._data_map[k] }) 351 today_event.broadcast()352354 self.ActivateSelf() 355 if evt.data: 356 self._item_list.SetSelection(evt.data.get('index', wx.NOT_FOUND)) 357 self._populate_each(evt.data.get('key', None))358 362 368370 # populate new data 371 self._clear() 372 self._data_map={} 373 # populate the list with data 374 keys=self._data.keys() 375 keys.sort() 376 for k in keys: 377 n=self._data[k] 378 i=self._item_list.Append(n.subject) 379 self._item_list.SetClientData(i, k) 380 self._data_map[k]=i 381 self._send_today_data()382384 # populate the detailed info of the item keyed k 385 if k is None: 386 # clear out all the subfields 387 self._clear_each() 388 return 389 # there're data, first enable the widgets 390 self.ignoredirty=True 391 for w in self._w: 392 w.Enable(True) 393 entry=self._data[k] 394 # set the general detail 395 self._general_editor_w.Set(entry) 396 self._cat_editor_w.Set(entry.categories) 397 self._memo_editor_w.Set({ 'memo': entry.text }) 398 self.ignoredirty=False 399 self.setdirty(False)400 401 # called from various widget update callbacks403 """A public function you can call that will set the dirty flag""" 404 if self.dirty or self.ignoredirty or not self.IsShown(): 405 # already dirty, no need to make it worse 406 return 407 self.setdirty(True)408410 """Set the dirty flag""" 411 if self.ignoredirty: 412 return 413 self.dirty=val 414 self._item_list.Enable(not self.dirty) 415 self._save_btn.Enable(self.dirty) 416 self._revert_btn.Enable(self.dirty)417 422 425 428430 # add a new memo item 431 if self.dirty: 432 # busy editing, cannot add now, just return 433 return 434 m=MemoEntry() 435 m.subject='New Memo' 436 self._data[m.id]=m 437 self._populate() 438 self._save_to_db(self._data) 439 self._item_list.Select(self._data_map[m.id]) 440 self._populate_each(m.id)441443 sel_idx=self._item_list.GetSelection() 444 if sel_idx is None or sel_idx==-1: 445 return False 446 return True447449 # delete the current selected item 450 sel_idx=self._item_list.GetSelection() 451 if sel_idx is None or sel_idx==-1: 452 # none selected 453 return 454 self.ignoredirty=True 455 k=self._item_list.GetClientData(sel_idx) 456 self._item_list.Delete(sel_idx) 457 self._clear_each() 458 del self._data[k] 459 del self._data_map[k] 460 self._save_to_db(self._data) 461 self.ignoredirty=False 462 self.setdirty(False)463 467469 # return a dict of selected items 470 res={} 471 for _idx in self._item_list.GetSelections(): 472 _key=self._item_list.GetClientData(_idx) 473 if _key: 474 res[_key]=self._data[_key] 475 return res476 479 483485 db_rr={} 486 for k, e in memo_dict.items(): 487 db_rr[k]=MemoDataObject(e) 488 database.ensurerecordtype(db_rr, memoobjectfactory) 489 self._main_window.database.savemajordict('memo', db_rr)490 494496 # read data from the database 497 memo_dict=self._main_window.database.getmajordictvalues('memo', 498 memoobjectfactory) 499 r={} 500 for k,e in memo_dict.items(): 501 if __debug__ and module_debug: 502 print e 503 ce=MemoEntry() 504 ce.set_db_dict(e) 505 r[ce.id]=ce 506 result.update({ 'memo': r }) 507 return result508510 # an item was clicked on/selected 511 self._populate_each(self._item_list.GetClientData(evt.GetInt())) 512 self.Refresh()513515 # save the current changes 516 self.ignoredirty=True 517 sel_idx=self._item_list.GetSelection() 518 k=self._item_list.GetClientData(sel_idx) 519 entry=self._data[k] 520 self._general_editor_w.Get(entry) 521 entry.text=self._memo_editor_w.Get().get('memo', None) 522 entry.categories=self._cat_editor_w.Get() 523 entry.set_date_now() 524 self._general_editor_w.Set(entry) 525 self._item_list.SetString(sel_idx, entry.subject) 526 self._save_to_db(self._data) 527 self._send_today_data() 528 self.ignoredirty=False 529 self.setdirty(False)530532 self.ignoredirty=True 533 # Enable the list to get the selection 534 self._item_list.Enable() 535 sel_idx=self._item_list.GetSelection() 536 if sel_idx!=wx.NOT_FOUND: 537 k=self._item_list.GetClientData(sel_idx) 538 self._populate_each(k) 539 self.ignoredirty=False 540 self.setdirty(False)541543 with guihelper.WXDialogWrapper(guiwidgets.MemoPrintDialog(self, mainwindow, config), 544 True): 545 pass548550 """Return the list of keys as being displayed""" 551 return [ self._item_list.GetClientData(x) \ 552 for x in range(self._item_list.GetCount()) ]553555 """Return the list of keys of selected items being displayed""" 556 return [ self._item_list.GetClientData(x) \ 557 for x in self._item_list.GetSelections() ]
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Sun Jan 24 16:22:13 2010 | http://epydoc.sourceforge.net |