1 # -*- coding: UTF-8 -*-
2 # vim: expandtab sw=4 ts=4 sts=4:
7 __author__
= 'Michal Čihař'
8 __email__
= 'michal@cihar.com'
10 Copyright © 2003 - 2008 Michal Čihař
12 This program is free software; you can redistribute it and/or modify it
13 under the terms of the GNU General Public License version 2 as published by
14 the Free Software Foundation.
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 import Wammu
.Webbrowser
40 # We can use dbus for some fancy stuff
50 except SystemError, err
:
51 Wammu
.gammu_error
= err
52 except ImportError, err
:
53 Wammu
.gammu_error
= err
56 import Wammu
.Displayer
68 from Wammu
.Paths
import *
73 import Wammu
.MessageDisplay
74 import Wammu
.PhoneSearch
76 import Wammu
.ErrorMessage
77 import Wammu
.TalkbackDialog
78 import Wammu
.WammuSettings
79 import Wammu
.SMSExport
80 from Wammu
.Locales
import StrConv
, ConsoleStrConv
85 def SortDataKeys(a
, b
):
93 def SortDataSubKeys(a
, b
):
102 displaydata
['info'] = {}
103 displaydata
['call'] = {}
104 displaydata
['contact'] = {}
105 displaydata
['message'] = {}
106 displaydata
['todo'] = {}
107 displaydata
['calendar'] = {}
110 displaydata
['info'][' '] = ('', _('Phone'), _('Phone Information'), 'phone', [
111 {'Name':_('Wammu version'), 'Value':Wammu
.__version
__, 'Synced': True},
113 if Wammu
.gammu_error
== None:
114 displaydata
['info'][' '][4].append({'Name':_('Gammu version'), 'Value':gammu
.Version()[0], 'Synced': True})
115 displaydata
['info'][' '][4].append({'Name':_('python-gammu version'), 'Value':gammu
.Version()[1], 'Synced': True})
118 displaydata
['call'][' '] = ('info', _('Calls'), _('All Calls'), 'call', [])
119 displaydata
['call']['RC'] = ('call', _('Received'), _('Received Calls'), 'call-received', [])
120 displaydata
['call']['MC'] = ('call', _('Missed'), _('Missed Calls'), 'call-missed', [])
121 displaydata
['call']['DC'] = ('call', _('Outgoing'), _('Outgoing Calls'), 'call-outgoing', [])
124 displaydata
['contact'][' '] = ('info', _('Contacts'), _('All Contacts'), 'contact', [])
125 displaydata
['contact']['SM'] = ('contact', _('SIM'), _('SIM Contacts'), 'contact-sim', [])
126 displaydata
['contact']['ME'] = ('contact', _('Phone'), _('Phone Contacts'), 'contact-phone', [])
129 displaydata
['message'][' '] = ('info', _('Messages'), _('All Messages'), 'message', [])
130 displaydata
['message']['Read'] = ('message', _('Read'), _('Read Messages'), 'message-read', [])
131 displaydata
['message']['UnRead'] = ('message', _('Unread'), _('Unread Messages'), 'message-unread', [])
132 displaydata
['message']['Sent'] = ('message', _('Sent'), _('Sent Messages'), 'message-sent', [])
133 displaydata
['message']['UnSent'] = ('message', _('Unsent'), _('Unsent Messages'), 'message-unsent', [])
136 displaydata
['todo'][' '] = ('info', _('Todos'), _('All Todo Items'), 'todo', [])
139 displaydata
['calendar'][' '] = ('info', _('Calendar'), _('All Calendar Events'), 'calendar', [])
142 ## Create a new frame class, derived from the wxPython Frame.
143 class WammuFrame(wx
.Frame
):
145 def __init__(self
, parent
, id):
146 self
.cfg
= Wammu
.WammuSettings
.WammuConfig()
147 Wammu
.configuration
= self
.cfg
148 if self
.cfg
.HasEntry('/Main/X') and self
.cfg
.HasEntry('/Main/Y'):
149 pos
= wx
.Point(self
.cfg
.ReadInt('/Main/X'), self
.cfg
.ReadInt('/Main/Y'))
151 pos
=wx
.DefaultPosition
152 size
= wx
.Size(self
.cfg
.ReadInt('/Main/Width'), self
.cfg
.ReadInt('/Main/Height'))
154 wx
.Frame
.__init
__(self
, parent
, id, 'Wammu', pos
, size
, wx
.DEFAULT_FRAME_STYLE
)
156 if sys
.platform
== 'win32':
157 img
= wx
.Image(AppIconPath('wammu'), wx
.BITMAP_TYPE_ICO
)
159 img
= wx
.Image(AppIconPath('wammu'), wx
.BITMAP_TYPE_PNG
)
161 self
.icon
= wx
.EmptyIcon()
162 self
.icon
.CopyFromBitmap(wx
.BitmapFromImage(img
))
164 if self
.icon
.GetWidth() == 16 and self
.icon
.GetHeight() == 16:
165 self
.icon16
= self
.icon
168 self
.icon16
= wx
.EmptyIcon()
169 self
.icon16
.CopyFromBitmap(wx
.BitmapFromImage(img
))
171 self
.SetIcon(self
.icon
)
173 self
.CreateStatusBar(2)
174 self
.SetStatusWidths([-1,400])
176 # Associate some events with methods of this class
177 wx
.EVT_CLOSE(self
, self
.CloseWindow
)
178 Wammu
.Events
.EVT_PROGRESS(self
, self
.OnProgress
)
179 Wammu
.Events
.EVT_SHOW_MESSAGE(self
, self
.OnShowMessage
)
180 Wammu
.Events
.EVT_LINK(self
, self
.OnLink
)
181 Wammu
.Events
.EVT_DATA(self
, self
.OnData
)
182 Wammu
.Events
.EVT_SHOW(self
, self
.OnShow
)
183 Wammu
.Events
.EVT_EDIT(self
, self
.OnEdit
)
184 Wammu
.Events
.EVT_SEND(self
, self
.OnSend
)
185 Wammu
.Events
.EVT_CALL(self
, self
.OnCall
)
186 Wammu
.Events
.EVT_MESSAGE(self
, self
.OnMessage
)
187 Wammu
.Events
.EVT_DUPLICATE(self
, self
.OnDuplicate
)
188 Wammu
.Events
.EVT_REPLY(self
, self
.OnReply
)
189 Wammu
.Events
.EVT_DELETE(self
, self
.OnDelete
)
190 Wammu
.Events
.EVT_BACKUP(self
, self
.OnBackup
)
191 Wammu
.Events
.EVT_EXCEPTION(self
, self
.OnException
)
193 self
.splitter
= wx
.SplitterWindow(self
, -1)
194 il
= wx
.ImageList(16, 16)
196 self
.tree
= wx
.TreeCtrl(self
.splitter
)
197 self
.tree
.AssignImageList(il
)
202 keys
= displaydata
.keys()
203 keys
.sort(SortDataKeys
)
205 self
.treei
[type] = {}
206 self
.values
[type] = {}
207 subkeys
= displaydata
[type].keys()
208 subkeys
.sort(SortDataSubKeys
)
209 for subtype
in subkeys
:
210 self
.values
[type][subtype
] = displaydata
[type][subtype
][4]
211 if displaydata
[type][subtype
][0] == '':
212 self
.treei
[type][subtype
] = self
.tree
.AddRoot(
213 displaydata
[type][subtype
][1],
214 il
.Add(wx
.Bitmap(IconPath(displaydata
[type][subtype
][3]))))
216 self
.treei
[type][subtype
] = self
.tree
.AppendItem(
217 self
.treei
[displaydata
[type][subtype
][0]][' '],
218 displaydata
[type][subtype
][1],
219 il
.Add(wx
.Bitmap(IconPath(displaydata
[type][subtype
][3]))))
222 self
.tree
.Expand(self
.treei
[type][' '])
224 wx
.EVT_TREE_SEL_CHANGED(self
, self
.tree
.GetId(), self
.OnTreeSel
)
226 # common border sizes (Gnome HIG)
227 self
.separatorHalf
= 3
228 self
.separatorNormal
= 6
229 self
.separatorTwice
= 12
232 self
.rightsplitter
= wx
.SplitterWindow(self
.splitter
, -1)
233 self
.rightwin
= wx
.Panel(self
.rightsplitter
, -1)
234 self
.rightwin
.sizer
= wx
.BoxSizer(wx
.VERTICAL
)
237 self
.righttitle
= wx
.StaticText(self
.rightwin
, -1, 'Wammu')
238 self
.rightwin
.sizer
.Add(self
.righttitle
, 0, wx
.LEFT|wx
.ALL|wx
.EXPAND
, self
.separatorNormal
)
241 self
.rightwin
.sizer
.Add(wx
.StaticLine(self
.rightwin
, -1), 0 , wx
.EXPAND
)
244 self
.searchpanel
= wx
.Panel(self
.rightwin
, -1)
245 self
.searchpanel
.sizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
246 self
.searchpanel
.sizer
.Add(wx
.StaticText(self
.searchpanel
, -1, _('Search: ')), 0, wx
.LEFT | wx
.CENTER
)
247 self
.searchinput
= wx
.TextCtrl(self
.searchpanel
, -1)
248 self
.searchinput
.SetToolTipString(_('Enter text to search for, please note that search type is selected next to this field. Matching is done over all fields.'))
249 self
.searchpanel
.sizer
.Add(self
.searchinput
, 1, wx
.CENTER | wx
.ALIGN_CENTER_VERTICAL
)
250 self
.searchchoice
= wx
.Choice(self
.searchpanel
, choices
= [_('Text'), _('Regexp'), _('Wildcard')])
251 self
.searchchoice
.SetToolTipString(_('Select search type'))
252 self
.searchchoice
.SetSelection(self
.cfg
.ReadInt('/Defaults/SearchType'))
253 self
.searchpanel
.sizer
.Add(self
.searchchoice
, 0, wx
.LEFT | wx
.CENTER | wx
.EXPAND
, self
.separatorNormal
)
254 self
.searchclear
= wx
.Button(self
.searchpanel
, wx
.ID_CLEAR
)
255 self
.searchpanel
.sizer
.Add(self
.searchclear
, 0, wx
.LEFT | wx
.CENTER | wx
.EXPAND
, self
.separatorNormal
)
256 self
.searchpanel
.SetSizer(self
.searchpanel
.sizer
)
257 self
.rightwin
.sizer
.Add(self
.searchpanel
, 0, wx
.LEFT | wx
.ALL | wx
.EXPAND
, self
.separatorNormal
)
259 self
.Bind(wx
.EVT_CHOICE
, self
.OnSearch
, self
.searchchoice
)
260 self
.Bind(wx
.EVT_TEXT
, self
.OnSearch
, self
.searchinput
)
261 self
.Bind(wx
.EVT_BUTTON
, self
.ClearSearch
, self
.searchclear
)
264 self
.browser
= Wammu
.Browser
.Browser(self
.rightwin
, self
, self
.cfg
)
265 self
.rightwin
.sizer
.Add(self
.browser
, 1, wx
.EXPAND
)
266 self
.rightwin
.SetSizer(self
.rightwin
.sizer
)
269 self
.content
= Wammu
.Displayer
.Displayer(self
.rightsplitter
, self
)
271 self
.splitter
.SplitVertically(self
.tree
, self
.rightsplitter
, self
.cfg
.ReadInt('/Main/Split'))
272 self
.rightsplitter
.SplitHorizontally(self
.rightwin
, self
.content
, self
.cfg
.ReadInt('/Main/SplitRight'))
275 self
.content
.SetContent('<font size=+1><b>%s</b></font>' % (_('Welcome to Wammu %s') % Wammu
.__version
__))
277 # Prepare the menu bar
278 self
.menuBar
= wx
.MenuBar()
281 menu1
.Append(100, _('&Write data'), _('Write data (except messages) to file.'))
282 menu1
.Append(101, _('W&rite message'), _('Write messages to file.'))
283 menu1
.Append(102, _('&Read data'), _('Read data (except messages) from file (does not import to the phone).'))
284 menu1
.Append(103, _('R&ead messages'), _('Read messages from file (does not import to the phone).'))
285 menu1
.AppendSeparator()
286 menu1
.Append(150, _('&Phone wizard'), _('Search for phone or configure it using guided wizard.'))
287 menu1
.Append(151, _('Se&ttings'), _('Change Wammu settings.'))
288 menu1
.AppendSeparator()
289 menu1
.Append(199, _('E&xit'), _('Terminate Wammu.'))
290 # Add menu to the menu bar
291 self
.menuBar
.Append(menu1
, _('&Wammu'))
294 menu2
.Append(201, _('&Connect'), _('Connect the device.'))
295 menu2
.Append(202, _('&Disconnect'), _('Disconnect the device.'))
296 menu2
.AppendSeparator()
297 menu2
.Append(210, _('&Synchronise time'), _('Synchronise time in mobile with PC.'))
298 menu2
.AppendSeparator()
299 menu2
.Append(250, _('Send &file'), _('Send file to phone.'))
300 # Add menu to the menu bar
301 self
.menuBar
.Append(menu2
, _('&Phone'))
304 menu3
.Append(301, _('&Info'), _('Retrieve phone information.'))
305 menu3
.AppendSeparator()
306 menu3
.Append(310, _('Contacts (&SIM)'), _('Retrieve contacts from SIM.'))
307 menu3
.Append(311, _('Contacts (&phone)'), _('Retrieve contacts from phone memory.'))
308 menu3
.Append(312, _('&Contacts (All)'), _('Retrieve contacts from phone and SIM memory.'))
309 menu3
.AppendSeparator()
310 menu3
.Append(320, _('C&alls'), _('Retrieve call history.'))
311 menu3
.AppendSeparator()
312 menu3
.Append(330, _('&Messages'), _('Retrieve messages.'))
313 menu3
.AppendSeparator()
314 menu3
.Append(340, _('&Todos'), _('Retrieve todos.'))
315 menu3
.AppendSeparator()
316 menu3
.Append(350, _('Calenda&r'), _('Retrieve calendar events.'))
317 # Add menu to the menu bar
318 self
.menuBar
.Append(menu3
, _('&Retrieve'))
321 menu4
.Append(401, _('&Contact'), _('Create new contact.'))
322 menu4
.Append(402, _('Calendar &event'), _('Create new calendar event.'))
323 menu4
.Append(403, _('&Todo'), _('Create new todo.'))
324 menu4
.Append(404, _('&Message'), _('Create new message.'))
325 # Add menu to the menu bar
326 self
.menuBar
.Append(menu4
, _('&Create'))
329 menu5
.Append(501, _('&Save'), _('Save currently retrieved data (except messages) to backup.'))
330 menu5
.Append(502, _('S&ave messages'), _('Save currently retrieved messages to backup.'))
331 menu5
.Append(503, _('&Import'), _('Import data from backup to phone.'))
332 menu5
.Append(504, _('I&mport messages'), _('Import messages from backup to phone.'))
333 menu5
.AppendSeparator()
334 menu5
.Append(510, _('Export messages to &emails'), _('Export messages to emails in storage you choose.'))
335 # Add menu to the menu bar
336 self
.menuBar
.Append(menu5
, _('&Backups'))
339 menuhelp
.Append(1001, _('&Website'), _('Visit Wammu website.'))
340 menuhelp
.Append(1002, _('&Support'), _('Visit Wammu support website.'))
341 menuhelp
.Append(1003, _('&Report bug'), _('Report bug in Wammu, please include saved debug log if possible.'))
342 menuhelp
.Append(1004, _('&Save debug log'), _('Save a copy of debug log, please include this in bug report.'))
343 menuhelp
.AppendSeparator()
344 menuhelp
.Append(1010, _('&Gammu Phone Database'), _('Visit database of user experiences with phones.'))
345 menuhelp
.Append(1011, _('&Talkback'), _('Report your experiences into Gammu Phone Database.'))
346 menuhelp
.AppendSeparator()
347 menuhelp
.Append(1020, _('&Donate'), _('Donate to Wammu project.'))
348 menuhelp
.AppendSeparator()
349 menuhelp
.Append(1100, _('&About'), _('Information about program.'))
350 # Add menu to the menu bar
351 self
.menuBar
.Append(menuhelp
, _('&Help'))
354 self
.SetMenuBar(self
.menuBar
)
357 wx
.EVT_MENU(self
, 100, self
.WriteData
)
358 wx
.EVT_MENU(self
, 101, self
.WriteSMSData
)
359 wx
.EVT_MENU(self
, 102, self
.ReadData
)
360 wx
.EVT_MENU(self
, 103, self
.ReadSMSData
)
361 wx
.EVT_MENU(self
, 150, self
.SearchPhone
)
362 wx
.EVT_MENU(self
, 151, self
.Settings
)
363 wx
.EVT_MENU(self
, 199, self
.CloseWindow
)
365 wx
.EVT_MENU(self
, 201, self
.PhoneConnect
)
366 wx
.EVT_MENU(self
, 202, self
.PhoneDisconnect
)
367 wx
.EVT_MENU(self
, 210, self
.SyncTime
)
368 wx
.EVT_MENU(self
, 250, self
.SendFile
)
370 wx
.EVT_MENU(self
, 301, self
.ShowInfo
)
371 wx
.EVT_MENU(self
, 310, self
.ShowContactsSM
)
372 wx
.EVT_MENU(self
, 311, self
.ShowContactsME
)
373 wx
.EVT_MENU(self
, 312, self
.ShowContacts
)
374 wx
.EVT_MENU(self
, 320, self
.ShowCalls
)
375 wx
.EVT_MENU(self
, 330, self
.ShowMessages
)
376 wx
.EVT_MENU(self
, 340, self
.ShowTodos
)
377 wx
.EVT_MENU(self
, 350, self
.ShowCalendar
)
379 wx
.EVT_MENU(self
, 401, self
.NewContact
)
380 wx
.EVT_MENU(self
, 402, self
.NewCalendar
)
381 wx
.EVT_MENU(self
, 403, self
.NewTodo
)
382 wx
.EVT_MENU(self
, 404, self
.NewMessage
)
384 wx
.EVT_MENU(self
, 501, self
.Backup
)
385 wx
.EVT_MENU(self
, 502, self
.BackupSMS
)
386 wx
.EVT_MENU(self
, 503, self
.Import
)
387 wx
.EVT_MENU(self
, 504, self
.ImportSMS
)
388 wx
.EVT_MENU(self
, 510, self
.SMSToMails
)
390 wx
.EVT_MENU(self
, 1001, self
.Website
)
391 wx
.EVT_MENU(self
, 1002, self
.Support
)
392 wx
.EVT_MENU(self
, 1003, self
.ReportBug
)
393 wx
.EVT_MENU(self
, 1004, self
.SaveLog
)
394 wx
.EVT_MENU(self
, 1010, self
.PhoneDB
)
395 wx
.EVT_MENU(self
, 1011, self
.Talkback
)
396 wx
.EVT_MENU(self
, 1020, self
.Donate
)
397 wx
.EVT_MENU(self
, 1100, self
.About
)
400 self
.TogglePhoneMenus(False)
402 self
.type = ['info',' ']
404 self
.TimerId
= wx
.NewId()
406 if Wammu
.gammu_error
== None:
407 # create state machine
408 self
.sm
= gammu
.StateMachine()
410 # create temporary file for logs
411 fd
, self
.logfilename
= tempfile
.mkstemp('.log', 'wammu')
413 # set filename to be used for error reports
414 Wammu
.ErrorLog
.DEBUG_LOG_FILENAME
= self
.logfilename
416 if sys
.platform
!= 'win32':
417 print ConsoleStrConv(
418 _('Debug log created in temporary file <%s>. In case of crash please include it in bugreport!') % self
.logfilename
421 self
.logfilefd
= os
.fdopen(fd
, 'w+')
422 # use temporary file for logs
423 gammu
.SetDebugFile(self
.logfilefd
)
424 gammu
.SetDebugLevel('textalldate')
426 # initialize variables
429 self
.Manufacturer
= ''
434 def HandleGammuError(self
):
436 Show error about gammu import failure. Try to help user with various
437 situation which could happened, so that he can solve this problem.
439 error
= str(Wammu
.gammu_error
)
440 if error
.find('Runtime libGammu version does not match compile time version') != -1:
441 result
= re
.match('Runtime libGammu version does not match compile time version \(runtime: (\S+), compiletime: (\S+)\)', error
)
443 wx
.MessageDialog(self
,
444 _('Wammu could not import gammu module, program will be terminated.') + '\n\n' +
445 _('The import failed because python-gammu is compiled with different version of Gammu than it is now using (it was compiled with version %(compile)s and now it is using version %(runtime)s).') % {'compile': result
.group(2), 'runtime': result
.group(1)} + '\n\n' +
446 _('You can fix it by recompiling python-gammu against gammu library you are currently using.'),
447 _('Gammu module not working!'),
448 wx
.OK | wx
.ICON_ERROR
).ShowModal()
449 elif error
.find('No module named gammu') != -1:
450 wx
.MessageDialog(self
,
451 _('Wammu could not import gammu module, program will be terminated.') + '\n\n' +
452 _('Gammu module was not found, you probably don\'t have properly installed python-gammu for current python version.'),
453 _('Gammu module not working!'),
454 wx
.OK | wx
.ICON_ERROR
).ShowModal()
456 wx
.MessageDialog(self
,
457 _('Wammu could not import gammu module, program will be terminated.') + '\n\n' +
458 _('The import failed with following error:') + '\n\n%s' % error
,
459 _('Gammu module not working!'),
460 wx
.OK | wx
.ICON_ERROR
).ShowModal()
463 def InitConfiguration(self
):
465 Binds Wammu configuration to Gammu one. If at least one section
466 exists, use first one (same as Gammu), otherwise we suggest search to
469 gammucfg
= self
.cfg
.gammu
.GetConfigs()
470 if len(gammucfg
) == 0:
471 dlg
= wx
.MessageDialog(self
,
472 _('Wammu configuration was not found and Gammu settings couldn\'t be read.') + '\n\n' +
473 _('Do you want to configure phone connection now?') + '\n',
474 _('Configuration not found'),
475 wx
.YES_NO | wx
.YES_DEFAULT | wx
.ICON_WARNING
)
476 if dlg
.ShowModal() == wx
.ID_YES
:
478 elif not self
.cfg
.HasEntry('/Gammu/Section'):
480 self
.cfg
.WriteInt('/Gammu/Section', 0)
482 def TalkbackCheck(self
):
484 Do ask for talkback after month of usage and at least 30 executions.
486 firstrun
= self
.cfg
.ReadFloat('/Wammu/FirstRun')
488 firstrun
= time
.time()
489 self
.cfg
.WriteFloat('/Wammu/FirstRun', firstrun
)
490 runs
= self
.cfg
.ReadInt('/Wammu/RunCounter')
491 self
.cfg
.WriteInt('/Wammu/RunCounter', runs
+ 1)
492 if self
.cfg
.Read('/Wammu/TalkbackDone') == 'no':
493 if (firstrun
+ (3600 * 24 * TALKBACK_DAYS
) < time
.time()
494 and runs
> TALKBACK_COUNT
):
495 dlg
= wx
.MessageDialog(self
,
496 _('You are using Wammu for more than a month. We would like to hear from you how your phone is supported. Do you want to participate in this survey?') +
497 '\n\n' + _('Press Cancel to never show this question again.'),
498 _('Thanks for using Wammu'),
499 wx
.YES_NO | wx
.CANCEL | wx
.ICON_INFORMATION
)
500 ret
= dlg
.ShowModal()
503 elif ret
== wx
.ID_CANCEL
:
504 self
.cfg
.Write('/Wammu/TalkbackDone', 'skipped')
506 def MigrateConfiguration(self
):
508 Migrate configuration from pre-0.18 style one (Gammu was configured
509 inside Wammu configuration) to using .gammurc.
511 connection
= self
.cfg
.Read('/Gammu/Connection')
512 device
= self
.cfg
.Read('/Gammu/Device')
513 model
= self
.cfg
.Read('/Gammu/Model')
514 gammucfg
= self
.cfg
.gammu
.GetConfigs()
515 if len(gammucfg
) > 0:
517 cfg
= self
.cfg
.gammu
.GetConfig(i
['Id'])
518 if cfg
['Model'] == model
and cfg
['Connection'] == connection
and cfg
['Device'] == device
:
519 self
.cfg
.WriteInt('/Gammu/Section', i
['Id'])
521 if not self
.cfg
.HasEntry('/Gammu/Section'):
522 index
= self
.cfg
.gammu
.FirstFree()
523 self
.cfg
.gammu
.SetConfig(index
, device
, connection
, _('Migrated from older Wammu'), model
)
524 self
.cfg
.WriteInt('/Gammu/Section', index
)
526 def PostInit(self
, appparent
):
528 Do things which need window opened to behave correctly.
530 - Activate initial view.
531 - Show if something wrong has happened on gammu import.
532 - Initialize or migrate Gammu configuration.
533 - Connect to phone if required.
535 - Setup internal information.
537 self
.ActivateView('info', ' ')
538 self
.appparent
= appparent
540 if Wammu
.gammu_error
!= None:
541 self
.HandleGammuError()
543 if not self
.cfg
.HasEntry('/Gammu/Section') and self
.cfg
.HasEntry('/Gammu/Connection'):
544 self
.MigrateConfiguration()
546 self
.InitConfiguration()
548 self
.DoDebug(self
.cfg
.Read('/Debug/Show'))
550 if (self
.cfg
.Read('/Wammu/AutoConnect') == 'yes'):
555 self
.SetupNumberPrefix()
557 self
.SetupStatusRefresh()
565 Initializes DBUS handlers if available.
567 self
.dbus_notify
= None
568 self
.last_dbus_id
= 0
571 bus
= dbus
.SessionBus() #mainloop = self.appparent.MainLoop)
572 interface
= 'org.freedesktop.Notifications'
573 path
= '/org/freedesktop/Notifications'
574 if Wammu
.Utils
.DBUSServiceAvailable(bus
, interface
, True):
575 obj
= bus
.get_object(interface
, path
)
576 self
.dbus_notify
= dbus
.Interface(obj
, interface
)
577 self
.dbus_notify
.connect_to_signal('ActionInvoked', self
.DBUSActionCallback
)
578 except dbus
.DBusException
:
579 self
.dbus_notify
= None
580 self
.last_dbus_id
= 0
582 def SetupTrayIcon(self
):
583 if self
.cfg
.Read('/Wammu/TaskBarIcon') != 'yes':
584 if self
.tbicon
is not None:
585 self
.tbicon
.Destroy()
587 if self
.tbicon
is not None:
590 self
.tbicon
= wx
.TaskBarIcon()
591 self
.tbicon
.SetIcon(self
.icon16
, 'Wammu')
592 self
.tbicon
.Bind(wx
.EVT_TASKBAR_RIGHT_UP
, self
.OnTaskBarRightClick
)
593 self
.tbicon
.Bind(wx
.EVT_TASKBAR_LEFT_UP
, self
.OnTaskBarLeftClick
)
594 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.Settings
, id=151)
595 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.PhoneConnect
, id=201)
596 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.PhoneDisconnect
, id=202)
597 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRestore
, id=100000)
598 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarMinimize
, id=100001)
599 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=100002)
601 def OnTaskBarRightClick(self
, evt
):
602 menutaskbar
= wx
.Menu()
603 menutaskbar
.Append(201, _('Connect'))
604 menutaskbar
.Append(202, _('Disconnect'))
605 menutaskbar
.AppendSeparator()
606 menutaskbar
.Append(151, _('Settings'))
607 menutaskbar
.AppendSeparator()
608 menutaskbar
.Append(100000, _('Restore'))
609 menutaskbar
.Append(100001, _('Minimize'))
610 menutaskbar
.AppendSeparator()
611 menutaskbar
.Append(100002, _('Close'))
612 self
.tbicon
.PopupMenu(menutaskbar
)
613 menutaskbar
.Destroy()
615 def OnTaskBarLeftClick(self
, evt
):
621 def OnTaskBarRestore(self
, evt
):
624 def OnTaskBarMinimize(self
, evt
):
627 def OnTaskBarClose(self
, evt
):
628 self
.CloseWindow(evt
)
630 def OnTimer(self
, evt
= None):
633 s
= self
.sm
.GetSignalQuality()
634 b
= self
.sm
.GetBatteryCharge()
635 d
= self
.sm
.GetDateTime()
639 if b
['ChargeState'] == 'BatteryPowered':
641 elif b
['ChargeState'] == 'BatteryConnected':
643 elif b
['ChargeState'] == 'BatteryNotConnected':
644 power
= _('no battery')
645 elif b
['ChargeState'] == 'PowerFault':
647 elif b
['ChargeState'] == 'BatteryCharging':
648 power
= _('charging')
649 elif b
['ChargeState'] == 'BatteryFull':
652 # Time might be None if it is invalid (eg. 0.0.0000 date)
656 time
= StrConv(d
.strftime('%c'))
658 # Detect unknown signal quality
659 if s
['SignalPercent'] == -1:
660 signal
= _('Unknown')
662 # l10n: Formatting of signal percentage, usually you can keep this as it is.
663 signal
= _('%d %%') % s
['SignalPercent']
665 self
.SetStatusText(_('Bat: %(battery_percent)d %% (%(power_source)s), Sig: %(signal_level)s, Time: %(time)s') %
667 'battery_percent':b
['BatteryPercent'],
668 'power_source':power
,
669 'signal_level':signal
,
672 except gammu
.GSMError
:
675 def SetupNumberPrefix(self
):
676 self
.prefix
= self
.cfg
.Read('/Wammu/PhonePrefix')
677 if self
.prefix
== 'Auto':
681 on
= Wammu
.Utils
.ParseMemoryEntry(self
.sm
.GetMemory(Location
= 1, Type
= 'ON'), self
.cfg
)['Number']
682 self
.prefix
= Wammu
.Utils
.GrabNumberPrefix(on
, Wammu
.Data
.InternationalPrefixes
)
683 except gammu
.GSMError
:
685 if self
.prefix
is None:
687 smsc
= self
.sm
.GetSMSC()['Number']
688 self
.prefix
= Wammu
.Utils
.GrabNumberPrefix(smsc
, Wammu
.Data
.InternationalPrefixes
)
689 except gammu
.GSMError
:
691 if self
.prefix
is None:
692 self
.prefix
= self
.cfg
.Read('/Wammu/LastPhonePrefix')
694 self
.cfg
.Write('/Wammu/LastPhonePrefix', self
.prefix
)
696 self
.prefix
= self
.cfg
.Read('/Wammu/LastPhonePrefix')
697 Wammu
.Utils
.NumberPrefix
= self
.prefix
699 def SetupStatusRefresh(self
):
700 repeat
= self
.cfg
.ReadInt('/Wammu/RefreshState')
705 self
.timer
= wx
.Timer(self
, self
.TimerId
)
706 wx
.EVT_TIMER(self
, self
.TimerId
, self
.OnTimer
)
707 self
.timer
.Start(repeat
)
709 def DoDebug(self
, newdebug
):
710 if newdebug
!= self
.showdebug
:
711 self
.showdebug
= newdebug
712 if self
.showdebug
== 'yes':
713 self
.logwin
= Wammu
.Logger
.LogFrame(self
, self
.cfg
)
714 self
.logwin
.Show(True)
715 wx
.EVT_CLOSE(self
.logwin
, self
.LogClose
)
716 self
.logger
= Wammu
.Logger
.Logger(self
.logwin
, self
.logfilename
)
719 self
.CloseLogWindow()
721 def SaveWinSize(self
, win
, key
):
722 x
,y
= win
.GetPositionTuple()
723 w
,h
= win
.GetSizeTuple()
725 self
.cfg
.WriteInt('/%s/X' % key
, x
)
726 self
.cfg
.WriteInt('/%s/Y' % key
, y
)
727 self
.cfg
.WriteInt('/%s/Width' % key
, w
)
728 self
.cfg
.WriteInt('/%s/Height' % key
, h
)
730 def CloseLogWindow(self
):
731 if hasattr(self
, 'logwin'):
732 self
.SaveWinSize(self
.logwin
, 'Debug')
733 if hasattr(self
, 'logger'):
734 self
.logger
.canceled
= True
736 if hasattr(self
, 'logwin'):
737 self
.logwin
.Destroy()
741 def LogClose(self
, evt
= None):
742 self
.cfg
.Write('/Debug/Show', 'no')
743 self
.CloseLogWindow()
745 def TogglePhoneMenus(self
, enable
):
746 self
.connected
= enable
748 self
.SetStatusText(_('Connected'), 1)
749 if self
.timer
!= None:
752 self
.SetStatusText(_('Disconnected'), 1)
755 mb
.Enable(201, not enable
);
756 mb
.Enable(202, enable
);
758 mb
.Enable(210, enable
);
760 mb
.Enable(250, enable
);
762 mb
.Enable(301, enable
);
764 mb
.Enable(310, enable
);
765 mb
.Enable(311, enable
);
766 mb
.Enable(312, enable
);
768 mb
.Enable(320, enable
);
770 mb
.Enable(330, enable
);
772 mb
.Enable(340, enable
);
774 mb
.Enable(350, enable
);
776 mb
.Enable(401, enable
);
777 mb
.Enable(402, enable
);
778 mb
.Enable(403, enable
);
779 mb
.Enable(404, enable
);
781 mb
.Enable(501, enable
);
782 mb
.Enable(502, enable
);
783 mb
.Enable(503, enable
);
784 mb
.Enable(504, enable
);
786 mb
.Enable(510, enable
);
788 def ActivateView(self
, k1
, k2
):
789 self
.tree
.SelectItem(self
.treei
[k1
][k2
])
790 self
.ChangeView(k1
, k2
)
792 def ChangeView(self
, k1
, k2
):
793 self
.ChangeBrowser(k1
, k2
)
794 self
.righttitle
.SetLabel(displaydata
[k1
][k2
][2])
796 def ChangeBrowser(self
, k1
, k2
):
800 for k3
, v3
in self
.values
[k1
].iteritems():
803 self
.values
[k1
]['__'] = data
804 self
.browser
.Change(k1
, data
)
806 self
.browser
.Change(k1
, self
.values
[k1
][k2
])
807 self
.browser
.ShowRow(0)
809 def OnTreeSel(self
, event
):
810 item
= event
.GetItem()
811 for k1
, v1
in self
.treei
.iteritems():
812 for k2
, v2
in v1
.iteritems():
814 self
.ChangeView(k1
, k2
)
817 def OnSearch(self
, event
):
818 text
= self
.searchinput
.GetValue()
819 type = self
.searchchoice
.GetSelection()
821 self
.browser
.Filter(text
, type)
822 self
.searchinput
.SetBackgroundColour(wx
.NullColour
)
823 except Wammu
.Browser
.FilterException
:
824 self
.searchinput
.SetBackgroundColour(wx
.RED
)
826 def ClearSearch(self
, event
= None):
827 self
.searchinput
.SetValue('')
829 def Settings(self
, event
= None):
831 connection_settings
= {
832 'Connection': self
.cfg
.Read('/Gammu/Connection'),
833 'LockDevice': self
.cfg
.Read('/Gammu/LockDevice'),
834 'Device': self
.cfg
.Read('/Gammu/Device'),
835 'Model': self
.cfg
.Read('/Gammu/Model')
838 result
= Wammu
.Settings
.Settings(self
, self
.cfg
).ShowModal()
839 if result
== wx
.ID_OK
:
841 connection_settings_new
= {
842 'Connection': self
.cfg
.Read('/Gammu/Connection'),
843 'LockDevice': self
.cfg
.Read('/Gammu/LockDevice'),
844 'Device': self
.cfg
.Read('/Gammu/Device'),
845 'Model': self
.cfg
.Read('/Gammu/Model')
848 if connection_settings
!= connection_settings_new
:
849 wx
.MessageDialog(self
,
850 _('You changed parameters affecting phone connection, they will be used next time you connect to phone.'),
852 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
853 self
.DoDebug(self
.cfg
.Read('/Debug/Show'))
854 self
.SetupNumberPrefix()
855 self
.SetupStatusRefresh()
858 def CloseWindow(self
, event
):
859 self
.SaveWinSize(self
, 'Main')
860 if hasattr(self
, 'logwin'):
861 self
.CloseLogWindow()
862 self
.cfg
.WriteInt('/Main/Split', self
.splitter
.GetSashPosition())
863 self
.cfg
.WriteInt('/Main/SplitRight', self
.rightsplitter
.GetSashPosition())
864 self
.cfg
.WriteInt('/Defaults/SearchType', self
.searchchoice
.GetCurrentSelection())
866 gammu
.SetDebugFile(None)
867 gammu
.SetDebugLevel('nothing')
869 self
.logfilefd
.close()
871 if hasattr(self
, 'logger'):
872 self
.logger
.canceled
= True
875 if self
.tbicon
is not None:
876 self
.tbicon
.Destroy()
878 if sys
.platform
!= 'win32':
879 print ConsoleStrConv(
880 _('Looks like normal program termination, deleting log file.')
883 os
.unlink(self
.logfilename
)
885 print ConsoleStrConv(
886 _('Failed to unlink temporary log file, please delete it yourself.')
888 print ConsoleStrConv(
889 _('Filename: %s') % self
.logfilename
892 # Forcibily save configuration
895 # tell the window to kill itself
898 def ShowError(self
, info
):
899 evt
= Wammu
.Events
.ShowMessageEvent(
900 message
= Wammu
.Utils
.FormatError(_('Error while communicating with phone'), info
),
901 title
= _('Error Occured'),
903 type = wx
.ICON_ERROR
)
904 wx
.PostEvent(self
, evt
)
906 def ShowProgress(self
, text
):
907 self
.progress
= wx
.ProgressDialog(
908 _('Operation in progress'),
912 wx
.PD_CAN_ABORT | wx
.PD_APP_MODAL | wx
.PD_AUTO_HIDE | wx
.PD_ELAPSED_TIME | wx
.PD_REMAINING_TIME | wx
.PD_ESTIMATED_TIME
)
914 def OnProgress(self
, evt
):
915 if hasattr(self
, 'progress'):
916 if not self
.progress
.Update(evt
.progress
):
921 if (evt
.progress
== 100):
923 if hasattr(evt
, 'lock'):
926 def OnException(self
, evt
):
927 Wammu
.Error
.Handler(*evt
.data
)
929 def OnData(self
, evt
):
930 self
.values
[evt
.type[0]][evt
.type[1]] = evt
.data
932 if hasattr(self
, 'progress'):
933 self
.progress
.Update(100)
936 if hasattr(self
, 'nextfun'):
943 def ShowData(self
, data
):
948 text
+= u
'<b>%s</b>: %s<br>' % (d
[0], d
[1])
950 text
+= u
'<br>%s' % d
[0]
951 self
.content
.SetContent(text
)
953 def OnShow(self
, evt
):
957 elif self
.type == ['info',' ']:
958 data
= [(evt
.data
['Name'], evt
.data
['Value'])]
959 elif self
.type[0] == 'contact' or self
.type[0] == 'call':
961 (_('Location'), str(v
['Location'])),
962 (_('Memory type'), v
['MemoryType'])]
963 for i
in v
['Entries']:
964 s
= Wammu
.Utils
.GetTypeString(i
['Type'], i
['Value'], self
.values
, linkphone
= False)
967 s
+= ', ' + (_('voice tag %x') % i
['VoiceTag'])
970 data
.append((i
['Type'], s
))
971 elif self
.type[0] == 'message':
973 (_('Number'), Wammu
.Utils
.GetNumberLink([] + self
.values
['contact']['ME'] + self
.values
['contact']['SM'], v
['Number'])),
974 (_('Date'), StrConv(v
['DateTime'])),
975 (_('Location'), StrConv(v
['Location'])),
976 (_('Folder'), StrConv(v
['SMS'][0]['Folder'])),
977 (_('Memory'), StrConv(v
['SMS'][0]['Memory'])),
978 (_('SMSC'), Wammu
.Utils
.GetNumberLink([] + self
.values
['contact']['ME'] + self
.values
['contact']['SM'], v
['SMS'][0]['SMSC']['Number'])),
979 (_('State'), StrConv(v
['State']))]
981 data
.append((_('Name'), StrConv(v
['Name'])))
982 data
.append((Wammu
.MessageDisplay
.SmsToHtml(self
.cfg
, v
),))
983 elif self
.type[0] == 'todo':
985 (_('Location'), str(v
['Location'])),
986 (_('Priority'), v
['Priority']),
987 (_('Type'), v
['Type']),
989 for i
in v
['Entries']:
990 data
.append((i
['Type'], Wammu
.Utils
.GetTypeString(i
['Type'], i
['Value'], self
.values
)))
991 elif self
.type[0] == 'calendar':
993 (_('Location'), str(v
['Location'])),
994 (_('Type'), v
['Type']),
996 for i
in v
['Entries']:
997 data
.append((i
['Type'], Wammu
.Utils
.GetTypeString(i
['Type'], i
['Value'], self
.values
)))
999 data
= [('Show not yet implemented! (type = %s)' % self
.type[0])]
1002 def NewContact(self
, evt
):
1003 self
.EditContact({})
1005 def NewCalendar(self
, evt
):
1006 self
.EditCalendar({})
1008 def NewTodo(self
, evt
):
1011 def NewMessage(self
, evt
):
1012 self
.ComposeMessage({})
1014 def ComposeMessage(self
, v
, action
= 'save'):
1015 if Wammu
.Composer
.SMSComposer(self
, self
.cfg
, v
, self
.values
, action
).ShowModal() == wx
.ID_OK
:
1017 if len(v
['Numbers']) == 0:
1018 v
['Numbers'] = ['Wammu']
1020 for number
in v
['Numbers']:
1021 busy
= wx
.BusyInfo(_('Writing message(s)...'))
1024 v
['Number'] = number
1025 v
['SMS'] = gammu
.EncodeSMS(v
['SMSInfo'])
1032 for msg
in v
['SMS']:
1033 msg
['SMSC']['Location'] = 1
1035 msg
['Folder'] = v
['Folder']
1036 msg
['Number'] = v
['Number']
1037 msg
['Type'] = v
['Type']
1038 msg
['State'] = v
['State']
1041 (msg
['Location'], msg
['Folder']) = self
.sm
.AddSMS(msg
)
1043 # When sending of saved message fails, send it directly:
1045 msg
['MessageReference'] = self
.sm
.SendSavedSMS(0, msg
['Location'])
1046 except gammu
.GSMError
:
1047 msg
['MessageReference'] = self
.sm
.SendSMS(msg
)
1049 result
['SMS'].append(self
.sm
.GetSMS(0, msg
['Location'])[0])
1050 except gammu
.ERR_EMPTY
:
1051 wx
.MessageDialog(self
, _('It was not possible to read saved message! There is most likely some bug in Gammu, please contact author with debug log of this operation. To see message in Wammu you need to reread all messsages.'), _('Could not read saved message!'), wx
.OK | wx
.ICON_ERROR
).ShowModal()
1053 msg
['MessageReference'] = self
.sm
.SendSMS(msg
)
1056 info
= gammu
.DecodeSMS(result
['SMS'])
1058 result
['SMSInfo'] = info
1059 Wammu
.Utils
.ParseMessage(result
, (info
!= None))
1060 result
['Synced'] = True
1061 self
.values
['message'][result
['State']].append(result
)
1063 except gammu
.GSMError
, val
:
1065 self
.ShowError(val
[0])
1069 self
.ActivateView('message', result
['State'])
1070 self
.browser
.ShowLocation(result
['Location'])
1074 def EditContact(self
, v
):
1075 backup
= copy
.deepcopy(v
)
1076 shoulddelete
= (v
== {} or v
['Location'] == 0)
1077 if Wammu
.Editor
.ContactEditor(self
, self
.cfg
, self
.values
, v
).ShowModal() == wx
.ID_OK
:
1079 busy
= wx
.BusyInfo(_('Writing contact...'))
1082 # was entry moved => delete it from internal list
1083 if not shoulddelete
:
1084 for idx
in range(len(self
.values
['contact'][backup
['MemoryType']])):
1085 if self
.values
['contact'][backup
['MemoryType']][idx
] == v
:
1086 del self
.values
['contact'][backup
['MemoryType']][idx
]
1089 # have we specified location? => add or set
1090 if v
['Location'] == 0:
1091 v
['Location'] = self
.sm
.AddMemory(v
)
1094 v
['Location'] = self
.sm
.SetMemory(v
)
1095 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1096 v
['Location'] = self
.sm
.AddMemory(v
)
1098 # was entry moved => delete it from phone
1099 if not shoulddelete
:
1100 if v
['MemoryType'] != backup
['MemoryType'] or v
['Location'] != backup
['Location']:
1102 self
.sm
.DeleteMemory(backup
['MemoryType'], backup
['Location'])
1104 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1106 v
= self
.sm
.GetMemory(v
['MemoryType'], v
['Location'])
1107 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1108 wx
.MessageDialog(self
, _('It was not possible to read saved entry! It might be different than one saved in phone untill you reread all entries.'), _('Could not read saved entry!'), wx
.OK | wx
.ICON_WARNING
).ShowModal()
1109 Wammu
.Utils
.ParseMemoryEntry(v
, self
.cfg
)
1111 # append new value to list
1112 self
.values
['contact'][v
['MemoryType']].append(v
)
1114 except gammu
.GSMError
, val
:
1117 self
.ShowError(val
[0])
1119 if (self
.type[0] == 'contact' and self
.type[1] == ' ') or not v
.has_key('MemoryType'):
1120 self
.ActivateView('contact', ' ')
1122 self
.browser
.ShowLocation(v
['Location'], ('MemoryType', v
['MemoryType']))
1126 self
.ActivateView('contact', v
['MemoryType'])
1128 self
.browser
.ShowLocation(v
['Location'])
1132 def EditCalendar(self
, v
):
1133 backup
= copy
.deepcopy(v
)
1134 shoulddelete
= (v
== {} or v
['Location'] == 0)
1135 if Wammu
.Editor
.CalendarEditor(self
, self
.cfg
, self
.values
, v
).ShowModal() == wx
.ID_OK
:
1137 busy
= wx
.BusyInfo(_('Writing calendar...'))
1140 # was entry moved => delete it from internal list
1141 if not shoulddelete
:
1142 # delete from internal list
1143 for idx
in range(len(self
.values
['calendar'][' '])):
1144 if self
.values
['calendar'][' '][idx
] == v
:
1145 del self
.values
['calendar'][' '][idx
]
1148 # have we specified location? => add or set
1149 if v
['Location'] == 0:
1150 v
['Location'] = self
.sm
.AddCalendar(v
)
1153 v
['Location'] = self
.sm
.SetCalendar(v
)
1154 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1155 v
['Location'] = self
.sm
.AddCalendar(v
)
1157 # was entry moved => delete it from phone
1158 if not shoulddelete
:
1159 if v
['Location'] != backup
['Location']:
1161 self
.sm
.DeleteCalendar(backup
['Location'])
1163 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1165 v
= self
.sm
.GetCalendar(v
['Location'])
1166 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1167 wx
.MessageDialog(self
, _('It was not possible to read saved entry! It might be different than one saved in phone untill you reread all entries.'), _('Could not read saved entry!'), wx
.OK | wx
.ICON_WARNING
).ShowModal()
1168 Wammu
.Utils
.ParseCalendar(v
)
1170 # append new value to list
1171 self
.values
['calendar'][' '].append(v
)
1173 except gammu
.GSMError
, val
:
1176 self
.ShowError(val
[0])
1178 self
.ActivateView('calendar', ' ')
1180 self
.browser
.ShowLocation(v
['Location'])
1184 def EditTodo(self
, v
):
1185 backup
= copy
.deepcopy(v
)
1186 shoulddelete
= (v
== {} or v
['Location'] == 0)
1187 if Wammu
.Editor
.TodoEditor(self
, self
.cfg
, self
.values
, v
).ShowModal() == wx
.ID_OK
:
1189 busy
= wx
.BusyInfo(_('Writing todo...'))
1192 # was entry moved => delete it from internal list
1193 if not shoulddelete
:
1194 for idx
in range(len(self
.values
['todo'][' '])):
1195 if self
.values
['todo'][' '][idx
] == v
:
1196 del self
.values
['todo'][' '][idx
]
1199 # have we specified location? => add or set
1200 if v
['Location'] == 0:
1201 v
['Location'] = self
.sm
.AddToDo(v
)
1204 v
['Location'] = self
.sm
.SetToDo(v
)
1205 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1206 v
['Location'] = self
.sm
.AddToDo(v
)
1208 # was entry moved => delete it from phone
1209 if not shoulddelete
:
1210 if v
['Location'] != backup
['Location']:
1212 self
.sm
.DeleteToDo(backup
['Location'])
1214 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1216 v
= self
.sm
.GetToDo(v
['Location'])
1217 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1218 wx
.MessageDialog(self
, _('It was not possible to read saved entry! It might be different than one saved in phone untill you reread all entries.'), _('Could not read saved entry!'), wx
.OK | wx
.ICON_WARNING
).ShowModal()
1219 Wammu
.Utils
.ParseTodo(v
)
1221 # append new value to list
1222 self
.values
['todo'][' '].append(v
)
1223 except gammu
.GSMError
, val
:
1226 self
.ShowError(val
[0])
1228 self
.ActivateView('todo', ' ')
1230 self
.browser
.ShowLocation(v
['Location'])
1235 def OnEdit(self
, evt
):
1236 if evt
.data
!= {} and not evt
.data
['Synced']:
1237 wx
.MessageDialog(self
, _('You can not work on this data, please retrieve it first from phone'), _('Data not up to date'), wx
.OK | wx
.ICON_ERROR
).ShowModal()
1239 if self
.type[0] == 'contact':
1240 self
.EditContact(evt
.data
)
1241 elif self
.type[0] == 'calendar':
1242 self
.EditCalendar(evt
.data
)
1243 elif self
.type[0] == 'todo':
1244 self
.EditTodo(evt
.data
)
1246 print 'Edit not yet implemented (type = %s)!' % self
.type[0]
1248 def OnReply(self
, evt
):
1249 if self
.type[0] == 'message':
1250 self
.ComposeMessage({'Number': evt
.data
['Number']}, action
= 'send')
1252 print 'Reply not yet implemented!'
1255 def OnCall(self
, evt
):
1256 if self
.type[0] in ['call', 'contact']:
1257 num
= Wammu
.Select
.SelectContactNumber(self
, evt
.data
)
1262 self
.sm
.DialVoice(num
)
1263 except gammu
.GSMError
, val
:
1264 self
.ShowError(val
[0])
1265 elif self
.type[0] == 'message':
1267 self
.sm
.DialVoice(evt
.data
['Number'])
1268 except gammu
.GSMError
, val
:
1269 self
.ShowError(val
[0])
1271 print 'Call not yet implemented (type = %s)!' % self
.type[0]
1273 def OnMessage(self
, evt
):
1274 if self
.type[0] in ['call', 'contact']:
1276 num
= Wammu
.Select
.SelectContactNumber(self
, evt
.data
)
1279 self
.ComposeMessage({'Number': num
}, action
= 'send')
1280 elif self
.type[0] == 'message':
1281 self
.ComposeMessage({'Number': evt
.data
['Number']}, action
= 'send')
1283 print 'Message send not yet implemented (type = %s)!' % self
.type[0]
1285 def OnDuplicate(self
, evt
):
1286 if evt
.data
!= {} and not evt
.data
['Synced']:
1287 wx
.MessageDialog(self
, _('You can not work on this data, please retrieve it first from phone'), _('Data not up to date'), wx
.OK | wx
.ICON_ERROR
).ShowModal()
1289 v
= copy
.deepcopy(evt
.data
)
1290 if self
.type[0] == 'contact':
1293 elif self
.type[0] == 'calendar':
1295 self
.EditCalendar(v
)
1296 elif self
.type[0] == 'todo':
1299 elif self
.type[0] == 'message':
1300 self
.ComposeMessage(v
)
1302 print 'Duplicate not yet implemented (type = %s)!' % self
.type[0]
1305 def OnSend(self
, evt
):
1306 if evt
.data
!= {} and not evt
.data
['Synced']:
1307 wx
.MessageDialog(self
, _('You can not work on this data, please retrieve it first from phone'), _('Data not up to date'), wx
.OK | wx
.ICON_ERROR
).ShowModal()
1309 if self
.type[0] == 'message':
1313 for loc
in v
['Location'].split(', '):
1314 self
.sm
.SendSavedSMS(0, int(loc
))
1315 except gammu
.ERR_NOTSUPPORTED
:
1316 for msg
in v
['SMS']:
1317 self
.sm
.SendSMS(msg
)
1318 except gammu
.GSMError
, val
:
1319 self
.ShowError(val
[0])
1321 def SMSToMails(self
, evt
):
1322 messages
= self
.values
['message']['Read'] + \
1323 self
.values
['message']['UnRead'] + \
1324 self
.values
['message']['Sent'] + \
1325 self
.values
['message']['UnSent']
1326 contacts
= self
.values
['contact']['ME'] + \
1327 self
.values
['contact']['SM']
1328 Wammu
.SMSExport
.SMSExport(self
, messages
, contacts
)
1330 def SelectBackupFile(self
, type, save
= True, data
= False):
1332 if type == 'message':
1333 wildcard
+= _('Gammu messages backup') + ' (*.smsbackup)|*.smsbackup|'
1334 exts
= ['smsbackup']
1337 wildcard
+= _('All backup formats') + '|*.backup;*.lmb;*.vcf;*.ldif;*.vcs;*.ics|'
1339 wildcard
+= _('Gammu backup [all data]') + ' (*.backup)|*.backup|'
1342 if type in ['contact', 'all']:
1343 wildcard
+= _('Nokia backup [contacts]') + ' (*.lmb)|*.lmb|'
1345 if type in ['contact', 'all']:
1346 wildcard
+= _('vCard [contacts]') + ' (*.vcf)|*.vcf|'
1348 if type in ['contact', 'all']:
1349 wildcard
+= _('LDIF [contacts]') + ' (*.ldif)|*.ldif|'
1351 if type in ['todo', 'calendar', 'all']:
1352 wildcard
+= _('vCalendar [todo,calendar]') + ' (*.vcs)|*.vcs|'
1354 if type in ['todo', 'calendar', 'all']:
1355 wildcard
+= _('iCalendar [todo,calendar]') + ' (*.ics)|*.ics|'
1358 wildcard
+= _('All files') + ' (*.*)|*.*'
1363 dlg
= wx
.FileDialog(self
, _('Save data as...'), os
.getcwd(), "", wildcard
, wx
.SAVE|wx
.OVERWRITE_PROMPT|wx
.CHANGE_DIR
)
1365 dlg
= wx
.FileDialog(self
, _('Read data'), os
.getcwd(), "", wildcard
, wx
.OPEN|wx
.CHANGE_DIR
)
1368 dlg
= wx
.FileDialog(self
, _('Save backup as...'), os
.getcwd(), "", wildcard
, wx
.SAVE|wx
.OVERWRITE_PROMPT|wx
.CHANGE_DIR
)
1370 dlg
= wx
.FileDialog(self
, _('Import backup'), os
.getcwd(), "", wildcard
, wx
.OPEN|wx
.CHANGE_DIR
)
1371 if dlg
.ShowModal() == wx
.ID_OK
:
1372 path
= dlg
.GetPath()
1374 ext
= exts
[dlg
.GetFilterIndex()]
1375 # Add automatic extension if we know one and file does not
1377 if (os
.path
.splitext(path
)[1] == '' and
1383 def ReadBackup(self
, type, data
= False):
1384 filename
= self
.SelectBackupFile(type, save
= False, data
= data
)
1385 if filename
== None:
1388 if type == 'message':
1389 backup
= gammu
.ReadSMSBackup(filename
)
1391 backup
= gammu
.ReadBackup(filename
)
1392 except gammu
.GSMError
, val
:
1394 evt
= Wammu
.Events
.ShowMessageEvent(
1395 message
= Wammu
.Utils
.FormatError(_('Error while reading backup'), info
),
1396 title
= _('Error Occured'),
1397 errortype
= 'gammu',
1398 type = wx
.ICON_ERROR
)
1399 wx
.PostEvent(self
, evt
)
1401 return (filename
, backup
)
1403 def ReadData(self
, evt
):
1404 (filename
, backup
) = self
.ReadBackup('all', True)
1408 if len(backup
['PhonePhonebook']) > 0:
1409 self
.values
['contact']['ME'] = map(Wammu
.Utils
.ParseMemoryEntry
, backup
['PhonePhonebook'], [self
.cfg
] * len(backup
['PhonePhonebook']))
1410 if len(backup
['SIMPhonebook']) > 0:
1411 self
.values
['contact']['SM'] = map(Wammu
.Utils
.ParseMemoryEntry
, backup
['SIMPhonebook'], [self
.cfg
] * len(backup
['SIMPhonebook']))
1412 if len(backup
['ToDo']) > 0:
1413 self
.values
['todo'][' '] = map(Wammu
.Utils
.ParseTodo
, backup
['ToDo'])
1414 if len(backup
['Calendar']) > 0:
1415 self
.values
['calendar'][' '] = map(Wammu
.Utils
.ParseCalendar
, backup
['Calendar'])
1417 self
.ActivateView('contact', ' ')
1419 self
.SetStatusText(_('Data has been read from file "%s"') % filename
)
1421 def ReadSMSData(self
, evt
):
1422 (filename
, backup
) = self
.ReadBackup('message', True)
1426 res
= Wammu
.Utils
.ProcessMessages(map(lambda x
:[x
], backup
), False)
1428 self
.values
['message']['Sent'] = res
['sent']
1429 self
.values
['message']['UnSent'] = res
['unsent']
1430 self
.values
['message']['Read'] = res
['read']
1431 self
.values
['message']['UnRead'] = res
['unread']
1433 self
.ActivateView('message', ' ')
1435 self
.SetStatusText(_('Data has been read from file "%s"') % filename
)
1437 def ImportSMS(self
, evt
):
1438 (filename
, backup
) = self
.ReadBackup('message')
1444 values
.append('message')
1445 choices
.append(_('%d messages') % len(backup
))
1447 if len(values
) == 0:
1448 wx
.MessageDialog(self
,
1449 _('No importable data were found in file "%s"') % filename
,
1450 _('No data to import'),
1451 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1454 dlg
= wx
.lib
.dialogs
.MultipleChoiceDialog(self
, _('Following data was found in backup, select which of these do you want to be added into phone.'), _('Select what to import'),
1455 choices
,style
= wx
.CHOICEDLG_STYLE | wx
.RESIZE_BORDER
,
1457 if dlg
.ShowModal() != wx
.ID_OK
:
1460 lst
= dlg
.GetValue()
1465 busy
= wx
.BusyInfo(_('Importing data...'))
1469 datatype
= values
[i
]
1470 if datatype
== 'message':
1473 v
['Folder'] = 2 # FIXME: this should be configurable
1474 v
['SMSC']['Location'] = 1
1475 (v
['Location'], v
['Folder']) = self
.sm
.AddSMS(v
)
1476 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1477 v
= self
.sm
.GetSMS(0, v
['Location'])
1480 res
= Wammu
.Utils
.ProcessMessages(smsl
, True)
1482 self
.values
['message']['Sent'] += res
['sent']
1483 self
.values
['message']['UnSent'] += res
['unsent']
1484 self
.values
['message']['Read'] += res
['read']
1485 self
.values
['message']['UnRead'] += res
['unread']
1487 self
.ActivateView('message', ' ')
1489 except gammu
.GSMError
, val
:
1490 self
.ShowError(val
[0])
1492 wx
.MessageDialog(self
,
1493 _('Backup has been imported from file "%s"') % filename
,
1494 _('Backup imported'),
1495 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1497 def Import(self
, evt
):
1498 (filename
, backup
) = self
.ReadBackup('all')
1503 if len(backup
['PhonePhonebook']) > 0:
1504 values
.append('PhonePhonebook')
1505 choices
.append(_('%d phone contact entries') % len(backup
['PhonePhonebook']))
1506 if len(backup
['SIMPhonebook']) > 0:
1507 values
.append('SIMPhonebook')
1508 choices
.append(_('%d SIM contact entries') % len(backup
['SIMPhonebook']))
1509 if len(backup
['ToDo']) > 0:
1510 values
.append('ToDo')
1511 choices
.append(_('%d to do entries') % len(backup
['ToDo']))
1512 if len(backup
['Calendar']) > 0:
1513 values
.append('Calendar')
1514 choices
.append(_('%d calendar entries') % len(backup
['Calendar']))
1516 if len(values
) == 0:
1517 wx
.MessageDialog(self
,
1518 _('No importable data were found in file "%s"') % filename
,
1519 _('No data to import'),
1520 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1524 if backup
['Model'] != '':
1525 msg
= '\n \n' + _('Backup saved from phone %s') % backup
['Model']
1526 if backup
['IMEI'] != '':
1527 msg
+= _(', serial number %s') % backup
['IMEI']
1528 if backup
['Creator'] != '':
1529 msg
+= '\n \n' + _('Backup was created by %s') % backup
['Creator']
1530 if backup
['DateTime'] != None:
1531 msg
+= '\n \n' + _('Backup saved on %s') % str(backup
['DateTime'])
1533 dlg
= wx
.lib
.dialogs
.MultipleChoiceDialog(self
, _('Following data was found in backup, select which of these do you want to be added into phone.') + msg
, _('Select what to import'),
1534 choices
,style
= wx
.CHOICEDLG_STYLE | wx
.RESIZE_BORDER
,
1536 if dlg
.ShowModal() != wx
.ID_OK
:
1539 lst
= dlg
.GetValue()
1544 busy
= wx
.BusyInfo(_('Importing data...'))
1548 datatype
= values
[i
]
1549 if datatype
== 'PhonePhonebook':
1550 for v
in backup
['PhonePhonebook']:
1551 v
['Location'] = self
.sm
.AddMemory(v
)
1552 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1553 v
= self
.sm
.GetMemory(v
['MemoryType'], v
['Location'])
1554 Wammu
.Utils
.ParseMemoryEntry(v
, self
.cfg
)
1556 # append new value to list
1557 self
.values
['contact'][v
['MemoryType']].append(v
)
1558 self
.ActivateView('contact', 'ME')
1559 elif datatype
== 'SIMPhonebook':
1560 for v
in backup
['SIMPhonebook']:
1561 v
['Location'] = self
.sm
.AddMemory(v
)
1562 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1563 v
= self
.sm
.GetMemory(v
['MemoryType'], v
['Location'])
1564 Wammu
.Utils
.ParseMemoryEntry(v
, self
.cfg
)
1566 # append new value to list
1567 self
.values
['contact'][v
['MemoryType']].append(v
)
1568 self
.ActivateView('contact', 'SM')
1569 elif datatype
== 'ToDo':
1570 for v
in backup
['ToDo']:
1571 v
['Location'] = self
.sm
.AddToDo(v
)
1572 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1573 v
= self
.sm
.GetToDo(v
['Location'])
1574 Wammu
.Utils
.ParseTodo(v
)
1576 # append new value to list
1577 self
.values
['todo'][' '].append(v
)
1578 self
.ActivateView('todo', ' ')
1579 elif datatype
== 'Calendar':
1580 for v
in backup
['Calendar']:
1581 v
['Location'] = self
.sm
.AddCalendar(v
)
1582 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1583 v
= self
.sm
.GetCalendar(v
['Location'])
1584 Wammu
.Utils
.ParseCalendar(v
)
1586 # append new value to list
1587 self
.values
['calendar'][' '].append(v
)
1588 self
.ActivateView('calendar', ' ')
1589 except gammu
.GSMError
, val
:
1590 self
.ShowError(val
[0])
1592 wx
.MessageDialog(self
,
1593 _('Backup has been imported from file "%s"') % filename
,
1594 _('Backup imported'),
1595 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1597 def WriteData(self
, evt
):
1598 self
.DoBackup(True, 'all')
1600 def WriteSMSData(self
, evt
):
1601 self
.DoBackup(True, 'message')
1603 def Backup(self
, evt
):
1604 self
.DoBackup(False, 'all')
1606 def BackupSMS(self
, evt
):
1607 self
.DoBackup(False, 'message')
1609 def PrepareBackup(self
):
1611 backup
['Creator'] = 'Wammu ' + Wammu
.__version
__
1612 backup
['IMEI'] = self
.IMEI
1613 backup
['Model'] = '%s %s %s' % ( self
.Manufacturer
, self
.Model
, self
.Version
)
1616 def WriteBackup(self
, filename
, type, backup
, data
= False):
1618 if type == 'message':
1619 # Backup is here our internal SMS list: [{'SMS':[{sms1}, {sms2}]}, ...]
1620 data
= map(lambda x
:x
['SMS'], backup
)
1624 gammu
.SaveSMSBackup(filename
, backup
)
1626 gammu
.SaveBackup(filename
, backup
)
1628 self
.SetStatusText(_('Backup has been saved to file "%s"') % filename
)
1630 self
.SetStatusText(_('Data has been saved to file "%s"') % filename
)
1631 except gammu
.GSMError
, val
:
1633 evt
= Wammu
.Events
.ShowMessageEvent(
1634 message
= Wammu
.Utils
.FormatError(_('Error while saving backup'), info
),
1635 title
= _('Error Occured'),
1636 errortype
= 'gammu',
1637 type = wx
.ICON_ERROR
)
1638 wx
.PostEvent(self
, evt
)
1639 except MemoryError, val
:
1641 evt
= Wammu
.Events
.ShowMessageEvent(
1642 message
= _('Error while saving backup, probably some limit inside of Gammu exceeded.\n%s') % str(info
),
1643 title
= _('Error Occured'),
1644 type = wx
.ICON_ERROR
)
1645 wx
.PostEvent(self
, evt
)
1647 def DoBackup(self
, data
, type):
1648 filename
= self
.SelectBackupFile(type, data
= data
)
1649 if filename
== None:
1651 ext
= os
.path
.splitext(filename
)[1].lower()
1653 if type == 'message':
1654 backup
= self
.values
['message']['Read'] + self
.values
['message']['UnRead'] + self
.values
['message']['Sent'] + self
.values
['message']['UnSent']
1656 backup
= self
.PrepareBackup()
1657 if ext
in ['.vcf', '.ldif']:
1658 # these support only one phonebook, so merged it
1659 backup
['PhonePhonebook'] = self
.values
['contact']['ME'] + self
.values
['contact']['SM']
1661 backup
['PhonePhonebook'] = self
.values
['contact']['ME']
1662 backup
['SIMPhonebook'] = self
.values
['contact']['SM']
1664 backup
['ToDo'] = self
.values
['todo'][' ']
1665 backup
['Calendar'] = self
.values
['calendar'][' ']
1666 self
.WriteBackup(filename
, type, backup
, data
)
1669 def OnBackup(self
, evt
):
1670 filename
= self
.SelectBackupFile(self
.type[0])
1671 if filename
== None:
1673 ext
= os
.path
.splitext(filename
)[1].lower()
1675 if self
.type[0] == 'message':
1678 backup
= self
.PrepareBackup()
1679 if self
.type[0] == 'contact':
1680 if ext
in ['.vcf', '.ldif']:
1681 # these support only one phonebook, so keep it merged
1682 backup
['PhonePhonebook'] = lst
1687 if item
['MemoryType'] == 'SM':
1689 elif item
['MemoryType'] == 'ME':
1691 backup
['PhonePhonebook'] = phone
1692 backup
['SIMPhonebook'] = sim
1693 elif self
.type[0] == 'todo':
1694 backup
['ToDo'] = lst
1695 elif self
.type[0] == 'calendar':
1696 backup
['Calendar'] = lst
1698 self
.WriteBackup(filename
, self
.type[0], backup
)
1700 def OnDelete(self
, evt
):
1701 # first check on supported types
1702 if not self
.type[0] in ['contact', 'call', 'message', 'todo', 'calendar']:
1703 print 'Delete not yet implemented! (items to delete = %s, type = %s)' % (str(evt
.lst
), self
.type[0])
1712 if not lst
[0]['Synced']:
1713 wx
.MessageDialog(self
, _('You can not work on this data, please retrieve it first from phone'), _('Data not up to date'), wx
.OK | wx
.ICON_ERROR
).ShowModal()
1716 # check for confirmation
1717 if self
.cfg
.Read('/Wammu/ConfirmDelete') == 'yes':
1721 if self
.type[0] == 'contact':
1722 txt
= _('Are you sure you want to delete contact "%s"?') % v
['Name']
1723 elif self
.type[0] == 'call':
1724 txt
= _('Are you sure you want to delete call from "%s"?') % v
['Name']
1725 elif self
.type[0] == 'message':
1726 txt
= _('Are you sure you want to delete message from "%s"?') % v
['Number']
1727 elif self
.type[0] == 'todo':
1728 txt
= _('Are you sure you want to delete todo entry "%s"?') % v
['Text']
1729 elif self
.type[0] == 'calendar':
1730 txt
= _('Are you sure you want to delete calendar entry "%s"?') % v
['Text']
1732 if self
.type[0] == 'contact':
1733 txt
= Wammu
.Locales
.ngettext(
1734 'Are you sure you want to delete %d contact?',
1735 'Are you sure you want to delete %d contacts?',
1737 elif self
.type[0] == 'call':
1738 txt
= Wammu
.Locales
.ngettext(
1739 'Are you sure you want to delete %d call?',
1740 'Are you sure you want to delete %d calls?',
1742 elif self
.type[0] == 'message':
1743 txt
= Wammu
.Locales
.ngettext(
1744 'Are you sure you want to delete %d message?',
1745 'Are you sure you want to delete %d messages?',
1747 elif self
.type[0] == 'todo':
1748 txt
= Wammu
.Locales
.ngettext(
1749 'Are you sure you want to delete %d todo entry?',
1750 'Are you sure you want to delete %d todo entries?',
1752 elif self
.type[0] == 'calendar':
1753 txt
= Wammu
.Locales
.ngettext(
1754 'Are you sure you want to delete %d calendar entry?',
1755 'Are you sure you want to delete %d calendar entries?',
1757 dlg
= wx
.MessageDialog(self
,
1759 _('Confirm deleting'),
1760 wx
.OK | wx
.CANCEL | wx
.ICON_WARNING
)
1761 if dlg
.ShowModal() != wx
.ID_OK
:
1766 if self
.type[0] == 'contact' or self
.type[0] == 'call':
1767 busy
= wx
.BusyInfo(_('Deleting contact(s)...'))
1771 self
.sm
.DeleteMemory(v
['MemoryType'], v
['Location'])
1772 for idx
in range(len(self
.values
[self
.type[0]][v
['MemoryType']])):
1773 if self
.values
[self
.type[0]][v
['MemoryType']][idx
] == v
:
1774 del self
.values
[self
.type[0]][v
['MemoryType']][idx
]
1776 elif self
.type[0] == 'message':
1777 busy
= wx
.BusyInfo(_('Deleting message(s)...'))
1781 for loc
in v
['Location'].split(', '):
1782 self
.sm
.DeleteSMS(0, int(loc
))
1783 for idx
in range(len(self
.values
[self
.type[0]][v
['State']])):
1784 if self
.values
[self
.type[0]][v
['State']][idx
] == v
:
1785 del self
.values
[self
.type[0]][v
['State']][idx
]
1787 elif self
.type[0] == 'todo':
1788 busy
= wx
.BusyInfo(_('Deleting todo(s)...'))
1792 self
.sm
.DeleteToDo(v
['Location'])
1793 for idx
in range(len(self
.values
[self
.type[0]][' '])):
1794 if self
.values
[self
.type[0]][' '][idx
] == v
:
1795 del self
.values
[self
.type[0]][' '][idx
]
1797 elif self
.type[0] == 'calendar':
1798 busy
= wx
.BusyInfo(_('Deleting calendar event(s)...'))
1802 self
.sm
.DeleteCalendar(v
['Location'])
1803 for idx
in range(len(self
.values
[self
.type[0]][' '])):
1804 if self
.values
[self
.type[0]][' '][idx
] == v
:
1805 del self
.values
[self
.type[0]][' '][idx
]
1807 except gammu
.GSMError
, val
:
1811 self
.ShowError(val
[0])
1813 self
.ActivateView(self
.type[0], self
.type[1])
1815 def OnLink(self
, evt
):
1816 v
= evt
.link
.split('://')
1820 if v
[0] == 'memory':
1826 if t
[0] in ['ME', 'SM']:
1827 self
.ActivateView('contact', t
[0])
1829 self
.browser
.ShowLocation(int(t
[1]))
1833 elif t
[0] in ['MC', 'RC', 'DC']:
1834 self
.ActivateView('call', t
[0])
1836 self
.browser
.ShowLocation(int(t
[1]))
1841 print 'Not supported memory type "%s"' % t
[0]
1844 print 'This link not yet implemented: "%s"' % evt
.link
1846 def OnShowMessage(self
, evt
):
1848 if self
.progress
.IsShown():
1849 parent
= self
.progress
1855 # Is is Gammu error?
1856 if hasattr(evt
, 'errortype') and evt
.errortype
== 'gammu':
1857 Wammu
.ErrorMessage
.ErrorMessage(parent
,
1858 StrConv(evt
.message
),
1859 StrConv(evt
.title
)).ShowModal()
1861 wx
.MessageDialog(parent
,
1862 StrConv(evt
.message
),
1864 wx
.OK | evt
.type).ShowModal()
1866 if hasattr(evt
, 'lock'):
1869 def ShowInfo(self
, event
):
1870 self
.ShowProgress(_('Reading phone information'))
1871 Wammu
.Info
.GetInfo(self
, self
.sm
).start()
1872 self
.nextfun
= self
.ActivateView
1873 self
.nextarg
= ('info', ' ')
1879 def ShowCalls(self
, event
):
1880 self
.GetCallsType('MC')
1881 self
.nextfun
= self
.ShowCalls2
1884 def ShowCalls2(self
):
1885 self
.GetCallsType('DC')
1886 self
.nextfun
= self
.ShowCalls3
1889 def ShowCalls3(self
):
1890 self
.GetCallsType('RC')
1891 self
.nextfun
= self
.ActivateView
1892 self
.nextarg
= ('call', ' ')
1894 def GetCallsType(self
, type):
1895 self
.ShowProgress(_('Reading calls of type %s') % type)
1896 Wammu
.Memory
.GetMemory(self
, self
.sm
, 'call', type).start()
1902 def ShowContacts(self
, event
):
1903 self
.GetContactsType('SM')
1904 self
.nextfun
= self
.ShowContacts2
1907 def ShowContacts2(self
):
1908 self
.GetContactsType('ME')
1909 self
.nextfun
= self
.ActivateView
1910 self
.nextarg
= ('contact', ' ')
1912 def ShowContactsME(self
, event
):
1913 self
.GetContactsType('ME')
1914 self
.nextfun
= self
.ActivateView
1915 self
.nextarg
= ('contact', 'ME')
1917 def ShowContactsSM(self
, event
):
1918 self
.GetContactsType('SM')
1919 self
.nextfun
= self
.ActivateView
1920 self
.nextarg
= ('contact', 'SM')
1922 def GetContactsType(self
, type):
1923 self
.ShowProgress(_('Reading contacts from %s') % type)
1924 Wammu
.Memory
.GetMemory(self
, self
.sm
, 'contact', type).start()
1930 def ShowMessages(self
, event
):
1931 self
.ShowProgress(_('Reading messages'))
1932 Wammu
.Message
.GetMessage(self
, self
.sm
).start()
1933 self
.nextfun
= self
.ActivateView
1934 self
.nextarg
= ('message', ' ')
1940 def ShowTodos(self
, event
):
1941 self
.ShowProgress(_('Reading todos'))
1942 Wammu
.Todo
.GetTodo(self
, self
.sm
).start()
1943 self
.nextfun
= self
.ActivateView
1944 self
.nextarg
= ('todo', ' ')
1950 def ShowCalendar(self
, event
):
1951 self
.ShowProgress(_('Reading calendar'))
1952 Wammu
.Calendar
.GetCalendar(self
, self
.sm
).start()
1953 self
.nextfun
= self
.ActivateView
1954 self
.nextarg
= ('calendar', ' ')
1960 def SyncTime(self
, event
):
1961 busy
= wx
.BusyInfo(_('Setting time in phone...'))
1965 self
.sm
.SetDateTime(datetime
.datetime
.now())
1966 except gammu
.GSMError
, val
:
1968 self
.ShowError(val
[0])
1974 def SendFile(self
, event
):
1976 Sends file to phone.
1978 @todo: Maybe we could add some wildcards for commonly used file types.
1980 dlg
= wx
.FileDialog(self
, _('Send file to phone'), os
.getcwd(), '', _('All files') + ' (*.*)|*.*', wx
.OPEN|wx
.CHANGE_DIR
)
1981 if dlg
.ShowModal() == wx
.ID_OK
:
1982 path
= dlg
.GetPath()
1984 file_data
= open(path
, 'r').read()
1987 'Name': os
.path
.basename(path
),
1990 'Used': len(file_data
),
1991 'Buffer': file_data
,
2001 busy
= wx
.BusyInfo(_('Sending file to phone...'))
2005 while (not file_f
['Finished']):
2006 file_f
= self
.sm
.SendFilePart(file_f
)
2007 except gammu
.ERR_PERMISSION
:
2008 wx
.MessageDialog(self
,
2009 _('Transfer has been rejected by phone.'),
2010 _('Transfer rejected!'),
2011 wx
.OK | wx
.ICON_ERROR
).ShowModal()
2012 except gammu
.GSMError
, val
:
2014 self
.ShowError(val
[0])
2016 wx
.MessageDialog(self
,
2017 _('Selected file "%s" was not found, no data read.') % path
,
2018 _('File not found!'),
2019 wx
.OK | wx
.ICON_ERROR
).ShowModal()
2022 # Connecting / Disconnecting
2025 def PhoneConnect(self
, event
= None):
2026 busy
= wx
.BusyInfo(_('One moment please, connecting to phone...'))
2029 section
= self
.cfg
.ReadInt('/Gammu/Section')
2030 config
= self
.cfg
.gammu
.GetConfig(section
)
2031 if config
['Connection'] == '' or config
['Device'] == '':
2032 wx
.MessageDialog(self
,
2033 _('Phone connection is not properly configured, can not connect to phone.'),
2034 _('Connection not configured!'),
2035 wx
.OK | wx
.ICON_ERROR
).ShowModal()
2038 'StartInfo': self
.cfg
.Read('/Gammu/StartInfo'),
2039 'UseGlobalDebugFile': 1,
2040 'DebugFile': None, # Set on other place
2041 'SyncTime': self
.cfg
.Read('/Gammu/SyncTime'),
2042 'Connection': config
['Connection'],
2043 'LockDevice': self
.cfg
.Read('/Gammu/LockDevice'),
2044 'DebugLevel': 'textalldate', # Set on other place
2045 'Device': config
['Device'],
2046 'Localize': None, # Set automatically by python-gammu
2047 'Model': config
['Model'],
2049 if cfg
['Model'] == 'auto':
2051 self
.sm
.SetConfig(0, cfg
)
2054 self
.sm
.SetIncomingCallback(self
.IncomingEvent
)
2056 self
.sm
.SetIncomingCall(True)
2057 except gammu
.GSMError
:
2059 self
.TogglePhoneMenus(True)
2060 self
.SetupNumberPrefix()
2062 self
.IMEI
= self
.sm
.GetIMEI()
2063 except gammu
.GSMError
:
2066 self
.Manufacturer
= self
.sm
.GetManufacturer()
2067 self
.cfg
.Write('/Phone-0/Manufacturer', self
.Manufacturer
)
2068 except gammu
.GSMError
:
2071 m
= self
.sm
.GetModel()
2072 if m
[0] == '' or m
[0] == 'unknown':
2076 self
.cfg
.Write('/Phone-0/Model', self
.Model
)
2077 except gammu
.GSMError
:
2080 self
.Version
= self
.sm
.GetFirmware()[0]
2084 except gammu
.GSMError
, val
:
2086 self
.ShowError(val
[0])
2089 except gammu
.GSMError
, val
:
2092 def DBUSActionCallback(self
, id, action
):
2094 Called when user does something on notification.
2096 self
.dbus_notify
.CloseNotification(self
.last_dbus_id
)
2097 if action
== 'accept-call':
2098 self
.sm
.AnswerCall(0, True)
2099 elif action
== 'reject-call':
2100 self
.sm
.CancelCall(0, True)
2102 print 'Unknown DBUS event: %s' % action
2104 def DBUSNotify(self
, title
, message
, actions
):
2106 Performs D-Bus notification if available.
2108 if self
.dbus_notify
is not None:
2109 self
.last_dbus_id
= self
.dbus_notify
.Notify(
2110 'Wammu', self
.last_dbus_id
, 'wammu',
2111 title
, message
, actions
, {}, -1)
2114 def IncomingEvent(self
, sm
, type, data
):
2116 Called on incoming event from phone.
2120 if data
['Status'] != 'IncomingCall':
2121 # We care only about incoming calls
2123 if data
['Number'] == '':
2124 msg
= _('Your phone has just received incoming call')
2126 msg
= _('Your phone has just received incoming call from %s') % data
['Number']
2127 self
.DBUSNotify(_('Incoming call'), msg
,
2128 ['reject-call', _('Reject'), 'accept-call', _('Accept')])
2130 def PhoneDisconnect(self
, event
= None):
2131 busy
= wx
.BusyInfo(_('One moment please, disconnecting from phone...'))
2136 except gammu
.ERR_NOTCONNECTED
:
2138 except gammu
.GSMError
, val
:
2140 self
.ShowError(val
[0])
2141 self
.TogglePhoneMenus(False)
2143 def SearchMessage(self
, text
):
2145 This has to send message as it is called from different thread.
2147 evt
= Wammu
.Events
.TextEvent(text
= text
+ '\n')
2148 wx
.PostEvent(self
.searchlog
, evt
)
2150 def SearchDone(self
, lst
):
2152 This has to send message as it is called from different thread.
2154 self
.founddevices
= lst
2155 evt
= Wammu
.Events
.DoneEvent()
2156 wx
.PostEvent(self
.searchlog
, evt
)
2158 def SearchPhone(self
, evt
= None):
2159 index
= self
.cfg
.gammu
.FirstFree()
2160 result
= Wammu
.PhoneWizard
.RunConfigureWizard(self
, index
)
2161 if result
is not None:
2162 self
.cfg
.gammu
.SetConfig(result
['Position'], result
['Device'], result
['Connection'], result
['Name'])
2163 self
.cfg
.WriteInt('/Gammu/Section', index
)
2165 def About(self
, evt
= None):
2166 Wammu
.About
.AboutBox(self
).ShowModal()
2168 def Website(self
, evt
= None):
2169 Wammu
.Webbrowser
.Open("http://%swammu.eu/?version=%s" % (Wammu
.Utils
.GetWebsiteLang(), Wammu
.__version
__))
2171 def Support(self
, evt
= None):
2172 Wammu
.Webbrowser
.Open("http://%swammu.eu/support?version=%s" % (Wammu
.Utils
.GetWebsiteLang(), Wammu
.__version
__))
2174 def ReportBug(self
, evt
= None):
2175 Wammu
.Webbrowser
.Open("http://bugs.cihar.com/set_project.php?ref=bug_report_page.php&project_id=1")
2177 def PhoneDB(self
, evt
= None):
2178 Wammu
.Webbrowser
.Open("http://%scihar.com/gammu/phonedb" % Wammu
.Utils
.GetWebsiteLang())
2180 def Talkback(self
, evt
= None):
2181 Wammu
.TalkbackDialog
.DoTalkback(self
, self
.cfg
, 0)
2183 def Donate(self
, evt
= None):
2184 Wammu
.Webbrowser
.Open("http://%swammu.eu/donate?src=wammu" % Wammu
.Utils
.GetWebsiteLang())
2186 def SaveLog(self
, evt
= None):
2188 Saves debug log to file.
2190 dlg
= wx
.FileDialog(self
,
2191 _('Save debug log as...'),
2195 wx
.SAVE | wx
.OVERWRITE_PROMPT | wx
.CHANGE_DIR
)
2196 if dlg
.ShowModal() == wx
.ID_OK
:
2197 Wammu
.ErrorLog
.SaveLog(filename
= dlg
.GetPath())