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: sms_tab.py 4784 2010-01-15 01:44:50Z djpham $ 9 10 """ 11 Code to handle the SMS Tab of the BitPim main display. 12 The read flag is not required for outbox and saved message, delivery 13 status is not needed for saved and inbox message, from is not required for 14 save and outbox, to is not required for inbox etc. 15 16 """ 17 # standard modules 18 from __future__ import with_statement 19 20 import copy 21 22 # wx modules 23 import wx 24 import wx.gizmos as gizmos 25 import wx.lib.scrolledpanel as scrolled 26 27 # BitPim modules 28 import common 29 import database 30 import guiwidgets 31 import helpids 32 import phonebookentryeditor as pb_editor 33 import phonenumber 34 import pubsub 35 import sms 36 import today 37 import guihelper 38 import guiwidgets 39 import widgets 40 import xyaptu 41 42 #------------------------------------------------------------------------------- 54 55 #------------------------------------------------------------------------------- 66 67 #------------------------------------------------------------------------------- 73 74 #-------------------------------------------------------------------------------76 _dict_key_index=0 77 _label_index=1 78 _class_index=2 79 _get_index=3 80 _set_index=4 81 _w_index=5 82 _flg_index=6 83 _not_used_fields={ 84 ## sms.SMSEntry.Folder_Inbox: ('delivery_status', '_to'), 85 ## sms.SMSEntry.Folder_Sent: ('read', '_from'), 86 ## sms.SMSEntry.Folder_Saved: ('delivery_status',) } 87 sms.SMSEntry.Folder_Inbox: ('delivery_status',), 88 sms.SMSEntry.Folder_Sent: ('read',), 89 sms.SMSEntry.Folder_Saved: ('delivery_status',) }148 149 #-------------------------------------------------------------------------------91 super(SMSInfo, self).__init__(parent) 92 self._fields=[ 93 ['_from', 'From:', StaticText, None, None, None, 0], 94 ['_to', 'To:', StaticText, None, None, None, 0], 95 ['callback', 'Callback #:', StaticText, None, None, None, 0], 96 ['subject', 'Subject:', StaticText, None, None, None, 0], 97 ['datetime', 'Date:', TimeStamp, None, None, None, 0], 98 ['priority_str', 'Priority:', StaticText, None, None, None, 0], 99 ['read', 'Read?:', wx.CheckBox, None, None, None, 0], 100 ['locked', 'Locked:', wx.CheckBox, None, None, None, 0], 101 ['delivery_status', 'Delivery Status:', DeliveryStatus, None, None, 102 None, wx.EXPAND], 103 ] 104 gs=wx.FlexGridSizer(-1, 2, 5, 5) 105 gs.AddGrowableCol(1) 106 for n in self._fields: 107 gs.Add(wx.StaticText(self, -1, n[self._label_index], 108 style=wx.ALIGN_LEFT),0, wx.EXPAND|wx.BOTTOM, 0) 109 w=n[self._class_index](self, -1) 110 gs.Add(w, 0, n[self._flg_index]|wx.BOTTOM, 0) 111 n[self._w_index]=w 112 # all done 113 self.SetSizer(gs) 114 self.SetAutoLayout(True) 115 gs.Fit(self) 116 self._gs=gs117119 self.OnDirtyUI(evt)120122 self.ignore_dirty=True 123 if data is None: 124 for n in self._fields: 125 if n[self._class_index]==StaticText or n[self._class_index]==DeliveryStatus or \ 126 n[self._class_index]==TimeStamp: 127 w=n[self._w_index] 128 w.SetValue('') 129 if n[self._class_index]==wx.CheckBox: 130 f=n[self._w_index] 131 f.SetValue(False) 132 else: 133 _bad_fields=self._not_used_fields.get(data.folder, ()) 134 for i,n in enumerate(self._fields): 135 w=n[self._w_index] 136 if n[self._dict_key_index] in _bad_fields: 137 self._gs.Show(i*2, False) 138 self._gs.Show(i*2+1, False) 139 else: 140 self._gs.Show(i*2, True) 141 self._gs.Show(i*2+1, True) 142 w.SetValue(getattr(data, n[self._dict_key_index])) 143 self._gs.Layout() 144 self.ignore_dirty=self.dirty=False145147 self.Set(None)151 _data_key='sms' 152 _canned_data_key='canned_msg' 153 msg_type_list=(sms.SMSEntry.Folder_Saved, sms.SMSEntry.Folder_Sent, sms.SMSEntry.Folder_Inbox, 'All')365 366 #-------------------------------------------------------------------------------155 super(SMSWidget, self).__init__(parent, -1) 156 self._main_window=mainwindow 157 #self._data=self._canned_data={} 158 self._data={} 159 self._parent=parent 160 self.sms_tree_nodes={} 161 # main box sizer 162 vbs=wx.BoxSizer(wx.VERTICAL) 163 # data date adjuster 164 hbs=wx.BoxSizer(wx.HORIZONTAL) 165 self.read_only=False 166 self.historical_date=None 167 static_bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Historical Data Status:'), 168 wx.VERTICAL) 169 self.historical_data_label=wx.StaticText(self, -1, 'Current Data') 170 static_bs.Add(self.historical_data_label, 1, wx.EXPAND|wx.ALL, 5) 171 hbs.Add(static_bs, 1, wx.EXPAND|wx.ALL, 5) 172 vbs.Add(hbs, 0, wx.EXPAND|wx.ALL, 5) 173 static_bs1=wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Canned Messages:'), 174 wx.HORIZONTAL) 175 self.canned_list=gizmos.EditableListBox(self, -1, 'User Defined Canned Messages:') 176 static_bs1.Add(self.canned_list, 1, wx.EXPAND|wx.ALL, 5) 177 vbs1=wx.BoxSizer(wx.VERTICAL) 178 vbs1.Add(wx.StaticText(self, -1, ' Built-in Canned Messages:'), 0, wx.ALL, 0) 179 self.builtin_canned_list=wx.ListBox(self, -1) 180 vbs1.Add(self.builtin_canned_list, 1, wx.EXPAND|wx.ALL, 5) 181 static_bs1.Add(vbs1, 1, wx.EXPAND|wx.ALL, 5) 182 vbs.Add(static_bs1, 1, wx.EXPAND|wx.ALL, 5) 183 self.save_btn=wx.Button(self, wx.ID_SAVE) 184 vbs.Add(self.save_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 185 self.list_widget=SMSList(self._main_window, self._parent, self) 186 wx.EVT_BUTTON(self, self.save_btn.GetId(), self.OnSaveCannedMsg) 187 # all done 188 self.SetSizer(vbs) 189 self.SetAutoLayout(True) 190 vbs.Fit(self)191193 for stat in self.msg_type_list: 194 self.sms_tree_nodes[stat]=self.AddSubPage(self.list_widget, stat, self._tree.message)195197 result=[] 198 result.append((widgets.BitPimWidget.MENU_NORMAL, guihelper.ID_EXPORT_SMS, "Export SMS ...", "Export the SMS")) 199 result.append((widgets.BitPimWidget.MENU_NORMAL, guihelper.ID_DATAHISTORICAL, "Historical Data ...", "Display Historical Data")) 200 return result201203 self.list_widget.populate() 204 # populate the canned data 205 self.canned_list.SetStrings( 206 self._canned_data.user_list) 207 self.builtin_canned_list.Set(self._canned_data.builtin_list)208210 if self.read_only: 211 wx.MessageBox('You are viewing historical data which cannot be changed or saved', 212 'Cannot Save SMS Data', 213 style=wx.OK|wx.ICON_ERROR) 214 return 215 self._canned_data.user_list=self.canned_list.GetStrings() 216 self._save_to_db(canned_msg_dict=self._canned_data)217 220 223225 dict[self._data_key]=copy.deepcopy(self._data, {}) 226 dict[self._canned_data_key]=self._canned_data.get().get( 227 self._canned_data_key, {})228230 # return a dict of selected items 231 res={} 232 for sel_idx in self.list_widget._item_list.GetSelections().values(): 233 k=self.list_widget._item_list.GetItemData(sel_idx) 234 if k: 235 res[k]=self._data[k] 236 return res237 240245 """Return the list of keys of selected items being displayed""" 246 return self.list_widget.GetSelectedKeys()247249 if self.read_only and not force: 250 return 251 if not self.read_only: 252 self._canned_data=sms.CannedMsgEntry() 253 self._canned_data.set({ self._canned_data_key: dict.get(self._canned_data_key, [])}) 254 self._data=dict.get(self._data_key, {}) 255 self._populate()256258 if self.read_only: 259 return 260 if sms_dict is not None: 261 db_rr={} 262 for k, e in sms_dict.items(): 263 db_rr[k]=sms.SMSDataObject(e) 264 database.ensurerecordtype(db_rr, sms.smsobjectfactory) 265 self._main_window.database.savemajordict(self._data_key, db_rr) 266 if canned_msg_dict is not None: 267 db_rr={} 268 db_rr[self._canned_data_key]=sms.CannedMsgDataObject( 269 canned_msg_dict) 270 database.ensurerecordtype(db_rr, sms.cannedmsgobjectfactory) 271 self._main_window.database.savemajordict(self._canned_data_key, 272 db_rr)274 if self.read_only: 275 wx.MessageBox('You are viewing historical data which cannot be changed or saved', 276 'Cannot Save SMS Data', 277 style=wx.OK|wx.ICON_ERROR) 278 return 279 canned_msg=sms.CannedMsgEntry() 280 canned_msg.set({ self._canned_data_key: dict.get(self._canned_data_key, [])}) 281 self._save_to_db(sms_dict=dict.get(self._data_key, []), 282 canned_msg_dict=canned_msg) 283 return dict284286 # read data from the database 287 sms_dict=self._main_window.database.\ 288 getmajordictvalues(self._data_key, sms.smsobjectfactory, 289 at_time=timestamp) 290 r={} 291 for k,e in sms_dict.items(): 292 ce=sms.SMSEntry() 293 ce.set_db_dict(e) 294 r[ce.id]=ce 295 result.update({ self._data_key: r }) 296 # read the canned messages 297 canned_msg_dict=self._main_window.database.\ 298 getmajordictvalues(self._canned_data_key, 299 sms.cannedmsgobjectfactory) 300 for k,e in canned_msg_dict.items(): 301 ce=sms.CannedMsgEntry() 302 ce.set_db_dict(e) 303 result.update(ce.get()) 304 return result305307 # merge this data with our data 308 # the merge criteria is simple: reject if msg_id's are same 309 if self.read_only: 310 wx.MessageBox('You are viewing historical data which cannot be changed or saved', 311 'Cannot Save SMS Data', 312 style=wx.OK|wx.ICON_ERROR) 313 return 314 existing_id=[e.msg_id for k,e in self._data.items()] 315 d=dict.get(self._data_key, {}) 316 for k,e in d.items(): 317 if e.msg_id not in existing_id: 318 self._data[e.id]=e 319 # save the canned data 320 self._canned_data=sms.CannedMsgEntry() 321 self._canned_data.set({ self._canned_data_key: dict.get(self._canned_data_key, []) } ) 322 # populate the display and save the data 323 self._populate() 324 self._save_to_db(sms_dict=self._data, 325 canned_msg_dict=self._canned_data)326 329331 """Display current or historical data""" 332 if self.read_only: 333 current_choice=guiwidgets.HistoricalDataDialog.Historical_Data 334 else: 335 current_choice=guiwidgets.HistoricalDataDialog.Current_Data 336 with guihelper.WXDialogWrapper(guiwidgets.HistoricalDataDialog(self, 337 current_choice=current_choice, 338 historical_date=self.historical_date, 339 historical_events=\ 340 self._main_window.database.getchangescount(self._data_key)), 341 True) as (dlg, retcode): 342 if retcode==wx.ID_OK: 343 with guihelper.MWBusyWrapper(self._main_window): 344 current_choice, self.historical_date=dlg.GetValue() 345 r={} 346 if current_choice==guiwidgets.HistoricalDataDialog.Current_Data: 347 self.read_only=False 348 msg_str='Current Data' 349 self.getfromfs(r) 350 else: 351 self.read_only=True 352 msg_str='Historical Data as of %s'%\ 353 str(wx.DateTimeFromTimeT(self.historical_date)) 354 self.getfromfs(r, self.historical_date) 355 self.populate(r, True) 356 self.historical_data_label.SetLabel(msg_str) 357 self.list_widget.historical_data_label.SetLabel(msg_str)358360 with guihelper.WXDialogWrapper(guiwidgets.SMSPrintDialog(self, mainwindow, config), 361 True): 362 pass368 _by_type=0 369 _by_date=1 370 _by_number=2 371 _me_name='<Me>'602373 super(SMSList, self).__init__(parent, -1) 374 self._main_window=mainwindow 375 self._stats=stats 376 self.nodes={} 377 self.nodes_keys={} 378 self._display_filter="All" 379 self._name_map={} 380 self._data_map={} 381 382 # main box sizer 383 vbs=wx.BoxSizer(wx.VERTICAL) 384 # data date adjuster 385 hbs=wx.BoxSizer(wx.HORIZONTAL) 386 static_bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Historical Data Status:'), 387 wx.VERTICAL) 388 self.historical_data_label=wx.StaticText(self, -1, 'Current Data') 389 static_bs.Add(self.historical_data_label, 1, wx.EXPAND|wx.ALL, 5) 390 hbs.Add(static_bs, 1, wx.EXPAND|wx.ALL, 5) 391 vbs.Add(hbs, 0, wx.EXPAND|wx.ALL, 5) 392 # main list 393 hbmessage=wx.BoxSizer(wx.HORIZONTAL) 394 column_info=[] 395 column_info.append(("From", 105, False)) 396 column_info.append(("To", 120, False)) 397 column_info.append(("Date", 180, False)) 398 self._item_list=guiwidgets.BitPimListCtrl(self, column_info) 399 self._item_list.ResetView(self.nodes, self.nodes_keys) 400 vbs0=wx.BoxSizer(wx.VERTICAL) 401 vbs0.Add(self._item_list, 1, wx.EXPAND|wx.ALL, 5) 402 vbs0.Add(wx.StaticText(self, -1, ' Note: Click column headings to sort data'), 0, wx.ALIGN_CENTRE|wx.BOTTOM, 10) 403 hbmessage.Add(vbs0, 1, wx.EXPAND|wx.ALL, 5) 404 vbs1=wx.BoxSizer(wx.VERTICAL) 405 self._item_info=SMSInfo(self) 406 vbs1.Add(self._item_info, 0, wx.EXPAND|wx.ALL, 5) 407 self._item_text=pb_editor.MemoEditor(self, -1) 408 vbs1.Add(self._item_text, 1, wx.EXPAND|wx.ALL, 5) 409 hbmessage.Add(vbs1, 0, wx.EXPAND|wx.ALL, 5) 410 hbmessage.SetItemMinSize(1, (350, 20)) 411 vbs.Add(hbmessage, 1, wx.EXPAND|wx.ALL, 5) 412 wx.EVT_LIST_ITEM_SELECTED(self, self._item_list.GetId(), self._OnSelChanged) 413 pubsub.subscribe(self._OnPBLookup, pubsub.RESPONSE_PB_LOOKUP) 414 # register for Today selection 415 self.today_data=None 416 today.bind_notification_event(self.OnTodaySelection, 417 today.Today_Group_IncomingSMS) 418 # all done 419 self.SetSizer(vbs) 420 self.SetAutoLayout(True) 421 vbs.Fit(self)422424 return self._item_text.CanCopy()426 self._item_text.Copy()427429 for stat in self._stats.msg_type_list: 430 if self._stats.sms_tree_nodes[stat]==node: 431 if self._display_filter!=stat: 432 self._display_filter=stat 433 # for some reason GetTopItem return 0 (instead of -1) 434 # when the list is empty 435 if self._item_list.GetItemCount(): 436 item=self._item_list.GetTopItem() 437 # deselect all the items when changing view 438 while item!=-1: 439 self._item_list.Select(item, 0) 440 item=self._item_list.GetNextItem(item) 441 self._item_info.Clear() 442 self._item_text.Set(None) 443 self.populate() 444 self._on_today_selection() 445 return446448 result=[] 449 result.append((widgets.BitPimWidget.MENU_NORMAL, guihelper.ID_EDITSELECTALL, "Select All", "Select All Items")) 450 result.append((widgets.BitPimWidget.MENU_NORMAL, guihelper.ID_EDITDELETEENTRY, "Delete Selected", "Delete Selected Items")) 451 result.append((widgets.BitPimWidget.MENU_SPACER, 0, "", "")) 452 result.append((widgets.BitPimWidget.MENU_NORMAL, guihelper.ID_EXPORT_SMS, "Export SMS ...", "Export the SMS")) 453 result.append((widgets.BitPimWidget.MENU_NORMAL, guihelper.ID_DATAHISTORICAL, "Historical Data ...", "Display Historical Data")) 454 return result455 460462 d=msg.data 463 k=d.get('item', None) 464 name=d.get('name', None) 465 if k is None: 466 return 467 self._name_map[k]=name468470 keys=[(x.datetime,k) for k,x in self._stats._data.items()] 471 keys.sort() 472 keys.reverse() 473 today_event=today.TodaySMSEvent() 474 for _,k in keys: 475 if self._stats._data[k].folder==sms.SMSEntry.Folder_Inbox: 476 today_event.append(self._stats._data[k].text, 477 { 'id': k } ) 478 today_event.broadcast()479481 inbox_node=self._stats.sms_tree_nodes[sms.SMSEntry.Folder_Inbox] 482 self.today_data=evt.data 483 self.ActivateSelf(inbox_node)484486 if self.today_data and self._item_list.GetItemCount(): 487 item=self._item_list.GetTopItem() 488 while item>=0: 489 if self.today_data['id']==self._item_list.GetItemData(item): 490 self._item_list.Select(item, 1) 491 self._item_list.EnsureVisible(item) 492 else: 493 self._item_list.Select(item, 0) 494 item=self._item_list.GetNextItem(item) 495 self.today_data=None496498 item=self._item_list.GetTopItem() 499 while item!=-1: 500 self._item_list.Select(item) 501 item=self._item_list.GetNextItem(item)502504 # Lookup name from number string 505 _s=self._name_map.get(numstr, None) 506 if _s is None: 507 return phonenumber.format(numstr) 508 return _s509511 # an item was clicked on/selected 512 item=evt.GetIndex() 513 k=self._item_list.GetItemData(item) 514 # populate the detailed info of the item keyed k 515 if k is None: 516 # clear out all the subfields 517 self._item_info.Clear() 518 self._item_text.Set(None) 519 return 520 entry=self._stats._data.get(k, None) 521 if entry is None: 522 return 523 # set the general detail 524 e=copy.deepcopy(entry) 525 # lookup names if available 526 e._from=self._me_name if e.folder in (e.Folder_Sent, e.Folder_Saved) else \ 527 self._number2name(e._from) 528 e._to=self._me_name if e.folder==e.Folder_Inbox else self._number2name(e._to) 529 e.callback=self._number2name(e.callback) 530 self._item_info.Set(e) 531 self._item_text.Set({'memo': e.text})532534 return self._stats.HasHistoricalData()535537 return self._stats.OnHistoricalData()538540 self.nodes={} 541 self.nodes_keys={} 542 index=0 543 for k,e in self._stats._data.items(): 544 if len(e._from) and not self._name_map.has_key(e._from): 545 pubsub.publish(pubsub.REQUEST_PB_LOOKUP, 546 { 'item': e._from } ) 547 if len(e._to) and not self._name_map.has_key(e._to): 548 pubsub.publish(pubsub.REQUEST_PB_LOOKUP, 549 { 'item': e._to } ) 550 if len(e.callback) and not self._name_map.has_key(e.callback): 551 pubsub.publish(pubsub.REQUEST_PB_LOOKUP, 552 { 'item': e.callback } ) 553 if self._display_filter=='All' or e.folder==self._display_filter: 554 _from=self._me_name if e.folder in (e.Folder_Sent, e.Folder_Saved) \ 555 else self._number2name(e._from) 556 _to=self._me_name if e.folder==e.Folder_Inbox \ 557 else self._number2name(e._to) 558 self.nodes[index]=(_from, _to, e.get_date_time_str()) 559 self.nodes_keys[index]=k 560 self._data_map[k]=index 561 index+=1 562 self._item_list.ResetView(self.nodes, self.nodes_keys) 563 self.publish_today_data()564566 if self._stats.read_only: 567 return False 568 sels_idx=self._item_list.GetFirstSelected() 569 if sels_idx==-1: 570 return False 571 return True572 575577 if self._stats.read_only: 578 return 579 sels_idx=self._item_list.GetSelections() 580 if len(sels_idx): 581 # delete them from the data list 582 for i,item in sels_idx.items(): 583 del self._stats._data[self._item_list.GetItemData(item)] 584 self._item_list.Select(item, 0) 585 self.populate() 586 self._stats._save_to_db(self._stats._data)590 self._stats.OnPrintDialog(mainwindow, config)597 _sel_items=self._item_list.GetSelections() 598 _keys=_sel_items.keys() 599 _keys.sort() 600 return [ self._item_list.GetItemData(_sel_items[x]) \ 601 for x in _keys ]
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Sun Jan 24 16:24:30 2010 | http://epydoc.sourceforge.net |