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
81 from Wammu
.Locales
import StrConv
, ConsoleStrConv
86 def SortDataKeys(a
, b
):
94 def SortDataSubKeys(a
, b
):
103 displaydata
['info'] = {}
104 displaydata
['call'] = {}
105 displaydata
['contact'] = {}
106 displaydata
['message'] = {}
107 displaydata
['todo'] = {}
108 displaydata
['calendar'] = {}
111 displaydata
['info'][' '] = ('', _('Phone'), _('Phone Information'), 'phone', [
112 {'Name':_('Wammu version'), 'Value':Wammu
.__version
__, 'Synced': True},
114 if Wammu
.gammu_error
== None:
115 displaydata
['info'][' '][4].append({'Name':_('Gammu version'), 'Value':gammu
.Version()[0], 'Synced': True})
116 displaydata
['info'][' '][4].append({'Name':_('python-gammu version'), 'Value':gammu
.Version()[1], 'Synced': True})
119 displaydata
['call'][' '] = ('info', _('Calls'), _('All Calls'), 'call', [])
120 displaydata
['call']['RC'] = ('call', _('Received'), _('Received Calls'), 'call-received', [])
121 displaydata
['call']['MC'] = ('call', _('Missed'), _('Missed Calls'), 'call-missed', [])
122 displaydata
['call']['DC'] = ('call', _('Outgoing'), _('Outgoing Calls'), 'call-outgoing', [])
125 displaydata
['contact'][' '] = ('info', _('Contacts'), _('All Contacts'), 'contact', [])
126 displaydata
['contact']['SM'] = ('contact', _('SIM'), _('SIM Contacts'), 'contact-sim', [])
127 displaydata
['contact']['ME'] = ('contact', _('Phone'), _('Phone Contacts'), 'contact-phone', [])
130 displaydata
['message'][' '] = ('info', _('Messages'), _('All Messages'), 'message', [])
131 displaydata
['message']['Read'] = ('message', _('Read'), _('Read Messages'), 'message-read', [])
132 displaydata
['message']['UnRead'] = ('message', _('Unread'), _('Unread Messages'), 'message-unread', [])
133 displaydata
['message']['Sent'] = ('message', _('Sent'), _('Sent Messages'), 'message-sent', [])
134 displaydata
['message']['UnSent'] = ('message', _('Unsent'), _('Unsent Messages'), 'message-unsent', [])
137 displaydata
['todo'][' '] = ('info', _('Todos'), _('All Todo Items'), 'todo', [])
140 displaydata
['calendar'][' '] = ('info', _('Calendar'), _('All Calendar Events'), 'calendar', [])
143 ## Create a new frame class, derived from the wxPython Frame.
144 class WammuFrame(wx
.Frame
):
146 def __init__(self
, parent
, id):
147 self
.cfg
= Wammu
.WammuSettings
.WammuConfig()
148 Wammu
.configuration
= self
.cfg
149 if self
.cfg
.HasEntry('/Main/X') and self
.cfg
.HasEntry('/Main/Y'):
150 pos
= wx
.Point(self
.cfg
.ReadInt('/Main/X'), self
.cfg
.ReadInt('/Main/Y'))
152 pos
=wx
.DefaultPosition
153 size
= wx
.Size(self
.cfg
.ReadInt('/Main/Width'), self
.cfg
.ReadInt('/Main/Height'))
155 wx
.Frame
.__init
__(self
, parent
, id, 'Wammu', pos
, size
, wx
.DEFAULT_FRAME_STYLE
)
157 if sys
.platform
== 'win32':
158 img
= wx
.Image(AppIconPath('wammu'), wx
.BITMAP_TYPE_ICO
)
160 img
= wx
.Image(AppIconPath('wammu'), wx
.BITMAP_TYPE_PNG
)
162 self
.icon
= wx
.EmptyIcon()
163 self
.icon
.CopyFromBitmap(wx
.BitmapFromImage(img
))
165 if self
.icon
.GetWidth() == 16 and self
.icon
.GetHeight() == 16:
166 self
.icon16
= self
.icon
169 self
.icon16
= wx
.EmptyIcon()
170 self
.icon16
.CopyFromBitmap(wx
.BitmapFromImage(img
))
172 self
.SetIcon(self
.icon
)
174 self
.CreateStatusBar(2)
175 self
.SetStatusWidths([-1,400])
177 # Associate some events with methods of this class
178 wx
.EVT_CLOSE(self
, self
.CloseWindow
)
179 Wammu
.Events
.EVT_PROGRESS(self
, self
.OnProgress
)
180 Wammu
.Events
.EVT_SHOW_MESSAGE(self
, self
.OnShowMessage
)
181 Wammu
.Events
.EVT_LINK(self
, self
.OnLink
)
182 Wammu
.Events
.EVT_DATA(self
, self
.OnData
)
183 Wammu
.Events
.EVT_SHOW(self
, self
.OnShow
)
184 Wammu
.Events
.EVT_EDIT(self
, self
.OnEdit
)
185 Wammu
.Events
.EVT_SEND(self
, self
.OnSend
)
186 Wammu
.Events
.EVT_CALL(self
, self
.OnCall
)
187 Wammu
.Events
.EVT_MESSAGE(self
, self
.OnMessage
)
188 Wammu
.Events
.EVT_DUPLICATE(self
, self
.OnDuplicate
)
189 Wammu
.Events
.EVT_REPLY(self
, self
.OnReply
)
190 Wammu
.Events
.EVT_DELETE(self
, self
.OnDelete
)
191 Wammu
.Events
.EVT_BACKUP(self
, self
.OnBackup
)
192 Wammu
.Events
.EVT_EXCEPTION(self
, self
.OnException
)
194 self
.splitter
= wx
.SplitterWindow(self
, -1)
195 il
= wx
.ImageList(16, 16)
197 self
.tree
= wx
.TreeCtrl(self
.splitter
)
198 self
.tree
.AssignImageList(il
)
203 keys
= displaydata
.keys()
204 keys
.sort(SortDataKeys
)
206 self
.treei
[type] = {}
207 self
.values
[type] = {}
208 subkeys
= displaydata
[type].keys()
209 subkeys
.sort(SortDataSubKeys
)
210 for subtype
in subkeys
:
211 self
.values
[type][subtype
] = displaydata
[type][subtype
][4]
212 if displaydata
[type][subtype
][0] == '':
213 self
.treei
[type][subtype
] = self
.tree
.AddRoot(
214 displaydata
[type][subtype
][1],
215 il
.Add(wx
.Bitmap(IconPath(displaydata
[type][subtype
][3]))))
217 self
.treei
[type][subtype
] = self
.tree
.AppendItem(
218 self
.treei
[displaydata
[type][subtype
][0]][' '],
219 displaydata
[type][subtype
][1],
220 il
.Add(wx
.Bitmap(IconPath(displaydata
[type][subtype
][3]))))
223 self
.tree
.Expand(self
.treei
[type][' '])
225 wx
.EVT_TREE_SEL_CHANGED(self
, self
.tree
.GetId(), self
.OnTreeSel
)
227 # common border sizes (Gnome HIG)
228 self
.separatorHalf
= 3
229 self
.separatorNormal
= 6
230 self
.separatorTwice
= 12
233 self
.rightsplitter
= wx
.SplitterWindow(self
.splitter
, -1)
234 self
.rightwin
= wx
.Panel(self
.rightsplitter
, -1)
235 self
.rightwin
.sizer
= wx
.BoxSizer(wx
.VERTICAL
)
238 self
.righttitle
= wx
.StaticText(self
.rightwin
, -1, 'Wammu')
239 self
.rightwin
.sizer
.Add(self
.righttitle
, 0, wx
.LEFT|wx
.ALL|wx
.EXPAND
, self
.separatorNormal
)
242 self
.rightwin
.sizer
.Add(wx
.StaticLine(self
.rightwin
, -1), 0 , wx
.EXPAND
)
245 self
.searchpanel
= wx
.Panel(self
.rightwin
, -1)
246 self
.searchpanel
.sizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
247 self
.searchpanel
.sizer
.Add(wx
.StaticText(self
.searchpanel
, -1, _('Search: ')), 0, wx
.LEFT | wx
.CENTER
)
248 self
.searchinput
= wx
.TextCtrl(self
.searchpanel
, -1)
249 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.'))
250 self
.searchpanel
.sizer
.Add(self
.searchinput
, 1, wx
.CENTER | wx
.ALIGN_CENTER_VERTICAL
)
251 self
.searchchoice
= wx
.Choice(self
.searchpanel
, choices
= [_('Text'), _('Regexp'), _('Wildcard')])
252 self
.searchchoice
.SetToolTipString(_('Select search type'))
253 self
.searchchoice
.SetSelection(self
.cfg
.ReadInt('/Defaults/SearchType'))
254 self
.searchpanel
.sizer
.Add(self
.searchchoice
, 0, wx
.LEFT | wx
.CENTER | wx
.EXPAND
, self
.separatorNormal
)
255 self
.searchclear
= wx
.Button(self
.searchpanel
, wx
.ID_CLEAR
)
256 self
.searchpanel
.sizer
.Add(self
.searchclear
, 0, wx
.LEFT | wx
.CENTER | wx
.EXPAND
, self
.separatorNormal
)
257 self
.searchpanel
.SetSizer(self
.searchpanel
.sizer
)
258 self
.rightwin
.sizer
.Add(self
.searchpanel
, 0, wx
.LEFT | wx
.ALL | wx
.EXPAND
, self
.separatorNormal
)
260 self
.Bind(wx
.EVT_CHOICE
, self
.OnSearch
, self
.searchchoice
)
261 self
.Bind(wx
.EVT_TEXT
, self
.OnSearch
, self
.searchinput
)
262 self
.Bind(wx
.EVT_BUTTON
, self
.ClearSearch
, self
.searchclear
)
265 self
.browser
= Wammu
.Browser
.Browser(self
.rightwin
, self
, self
.cfg
)
266 self
.rightwin
.sizer
.Add(self
.browser
, 1, wx
.EXPAND
)
267 self
.rightwin
.SetSizer(self
.rightwin
.sizer
)
270 self
.content
= Wammu
.Displayer
.Displayer(self
.rightsplitter
, self
)
272 self
.splitter
.SplitVertically(self
.tree
, self
.rightsplitter
, self
.cfg
.ReadInt('/Main/Split'))
273 self
.rightsplitter
.SplitHorizontally(self
.rightwin
, self
.content
, self
.cfg
.ReadInt('/Main/SplitRight'))
276 self
.content
.SetContent('<font size=+1><b>%s</b></font>' % (_('Welcome to Wammu %s') % Wammu
.__version
__))
278 # Prepare the menu bar
279 self
.menuBar
= wx
.MenuBar()
282 menu1
.Append(100, _('&Write data'), _('Write data (except messages) to file.'))
283 menu1
.Append(101, _('W&rite message'), _('Write messages to file.'))
284 menu1
.Append(102, _('&Read data'), _('Read data (except messages) from file (does not import to the phone).'))
285 menu1
.Append(103, _('R&ead messages'), _('Read messages from file (does not import to the phone).'))
286 menu1
.AppendSeparator()
287 menu1
.Append(150, _('&Phone wizard'), _('Search for phone or configure it using guided wizard.'))
288 menu1
.Append(151, _('Se&ttings'), _('Change Wammu settings.'))
289 menu1
.AppendSeparator()
290 menu1
.Append(199, '%s\tCtrl+Q' % _('E&xit'), _('Terminate Wammu.'))
291 # Add menu to the menu bar
292 self
.menuBar
.Append(menu1
, _('&Wammu'))
295 menu2
.Append(201, _('&Connect'), _('Connect the device.'))
296 menu2
.Append(202, _('&Disconnect'), _('Disconnect the device.'))
297 menu2
.AppendSeparator()
298 menu2
.Append(210, _('&Synchronise time'), _('Synchronise time in mobile with PC.'))
299 menu2
.AppendSeparator()
300 menu2
.Append(250, _('Send &file'), _('Send file to phone.'))
301 # Add menu to the menu bar
302 self
.menuBar
.Append(menu2
, _('&Phone'))
305 menu3
.Append(301, '%s\tCtrl+I' % _('&Info'), _('Retrieve phone information.'))
306 menu3
.AppendSeparator()
307 menu3
.Append(310, _('Contacts (&SIM)'), _('Retrieve contacts from SIM.'))
308 menu3
.Append(311, _('Contacts (&phone)'), _('Retrieve contacts from phone memory.'))
309 menu3
.Append(312, _('&Contacts (All)'), _('Retrieve contacts from phone and SIM memory.'))
310 menu3
.AppendSeparator()
311 menu3
.Append(320, _('C&alls'), _('Retrieve call history.'))
312 menu3
.AppendSeparator()
313 menu3
.Append(330, _('&Messages'), _('Retrieve messages.'))
314 menu3
.AppendSeparator()
315 menu3
.Append(340, _('&Todos'), _('Retrieve todos.'))
316 menu3
.AppendSeparator()
317 menu3
.Append(350, _('Calenda&r'), _('Retrieve calendar events.'))
318 # Add menu to the menu bar
319 self
.menuBar
.Append(menu3
, _('&Retrieve'))
322 menu4
.Append(401, '%s\tCtrl+N' % _('&Contact'), _('Create new contact.'))
323 menu4
.Append(402, '%s\tCtrl+E' % _('Calendar &event'), _('Create new calendar event.'))
324 menu4
.Append(403, '%s\tCtrl+T' % _('&Todo'), _('Create new todo.'))
325 menu4
.Append(404, '%s\tCtrl+M' % _('&Message'), _('Create new message.'))
326 # Add menu to the menu bar
327 self
.menuBar
.Append(menu4
, _('&Create'))
330 menu5
.Append(501, _('&Save'), _('Save currently retrieved data (except messages) to backup.'))
331 menu5
.Append(502, _('S&ave messages'), _('Save currently retrieved messages to backup.'))
332 menu5
.Append(503, _('&Import'), _('Import data from backup to phone.'))
333 menu5
.Append(504, _('I&mport messages'), _('Import messages from backup to phone.'))
334 menu5
.AppendSeparator()
335 menu5
.Append(510, _('Export messages to &emails'), _('Export messages to emails in storage you choose.'))
336 menu5
.Append(511, _('Export messages to &XML'), _('Export messages to XML file you choose.'))
337 # Add menu to the menu bar
338 self
.menuBar
.Append(menu5
, _('&Backups'))
341 menuhelp
.Append(1001, _('&Website'), _('Visit Wammu website.'))
342 menuhelp
.Append(1002, _('&Support'), _('Visit Wammu support website.'))
343 menuhelp
.Append(1003, _('&Report bug'), _('Report bug in Wammu, please include saved debug log if possible.'))
344 menuhelp
.Append(1004, _('&Save debug log'), _('Save a copy of debug log, please include this in bug report.'))
345 menuhelp
.AppendSeparator()
346 menuhelp
.Append(1010, _('&Gammu Phone Database'), _('Visit database of user experiences with phones.'))
347 menuhelp
.Append(1011, _('&Talkback'), _('Report your experiences into Gammu Phone Database.'))
348 menuhelp
.AppendSeparator()
349 menuhelp
.Append(1020, _('&Donate'), _('Donate to Wammu project.'))
350 menuhelp
.AppendSeparator()
351 menuhelp
.Append(1100, _('&About'), _('Information about program.'))
352 # Add menu to the menu bar
353 self
.menuBar
.Append(menuhelp
, _('&Help'))
356 self
.SetMenuBar(self
.menuBar
)
359 wx
.EVT_MENU(self
, 100, self
.WriteData
)
360 wx
.EVT_MENU(self
, 101, self
.WriteSMSData
)
361 wx
.EVT_MENU(self
, 102, self
.ReadData
)
362 wx
.EVT_MENU(self
, 103, self
.ReadSMSData
)
363 wx
.EVT_MENU(self
, 150, self
.SearchPhone
)
364 wx
.EVT_MENU(self
, 151, self
.Settings
)
365 wx
.EVT_MENU(self
, 199, self
.CloseWindow
)
367 wx
.EVT_MENU(self
, 201, self
.PhoneConnect
)
368 wx
.EVT_MENU(self
, 202, self
.PhoneDisconnect
)
369 wx
.EVT_MENU(self
, 210, self
.SyncTime
)
370 wx
.EVT_MENU(self
, 250, self
.SendFile
)
372 wx
.EVT_MENU(self
, 301, self
.ShowInfo
)
373 wx
.EVT_MENU(self
, 310, self
.ShowContactsSM
)
374 wx
.EVT_MENU(self
, 311, self
.ShowContactsME
)
375 wx
.EVT_MENU(self
, 312, self
.ShowContacts
)
376 wx
.EVT_MENU(self
, 320, self
.ShowCalls
)
377 wx
.EVT_MENU(self
, 330, self
.ShowMessages
)
378 wx
.EVT_MENU(self
, 340, self
.ShowTodos
)
379 wx
.EVT_MENU(self
, 350, self
.ShowCalendar
)
381 wx
.EVT_MENU(self
, 401, self
.NewContact
)
382 wx
.EVT_MENU(self
, 402, self
.NewCalendar
)
383 wx
.EVT_MENU(self
, 403, self
.NewTodo
)
384 wx
.EVT_MENU(self
, 404, self
.NewMessage
)
386 wx
.EVT_MENU(self
, 501, self
.Backup
)
387 wx
.EVT_MENU(self
, 502, self
.BackupSMS
)
388 wx
.EVT_MENU(self
, 503, self
.Import
)
389 wx
.EVT_MENU(self
, 504, self
.ImportSMS
)
390 wx
.EVT_MENU(self
, 510, self
.SMSToMails
)
391 wx
.EVT_MENU(self
, 511, self
.SMSToXML
)
394 wx
.EVT_MENU(self
, 1001, self
.Website
)
395 wx
.EVT_MENU(self
, 1002, self
.Support
)
396 wx
.EVT_MENU(self
, 1003, self
.ReportBug
)
397 wx
.EVT_MENU(self
, 1004, self
.SaveLog
)
398 wx
.EVT_MENU(self
, 1010, self
.PhoneDB
)
399 wx
.EVT_MENU(self
, 1011, self
.Talkback
)
400 wx
.EVT_MENU(self
, 1020, self
.Donate
)
401 wx
.EVT_MENU(self
, 1100, self
.About
)
404 self
.TogglePhoneMenus(False)
406 self
.type = ['info',' ']
408 self
.TimerId
= wx
.NewId()
410 if Wammu
.gammu_error
== None:
411 # create state machine
412 self
.sm
= gammu
.StateMachine()
414 # create temporary file for logs
415 fd
, self
.logfilename
= tempfile
.mkstemp('.log', 'wammu')
417 # set filename to be used for error reports
418 Wammu
.ErrorLog
.DEBUG_LOG_FILENAME
= self
.logfilename
420 if sys
.platform
!= 'win32':
421 print ConsoleStrConv(
422 _('Debug log created in temporary file <%s>. In case of crash please include it in bugreport!') % self
.logfilename
425 self
.logfilefd
= os
.fdopen(fd
, 'w+')
426 # use temporary file for logs
427 gammu
.SetDebugFile(self
.logfilefd
)
428 gammu
.SetDebugLevel('textalldate')
431 self
.loggerdebug
= Wammu
.Logger
.LoggerDebug(self
.logfilename
)
432 self
.loggerdebug
.start()
434 # initialize variables
437 self
.Manufacturer
= ''
442 def HandleGammuError(self
):
444 Show error about gammu import failure. Try to help user with various
445 situation which could happened, so that he can solve this problem.
447 error
= str(Wammu
.gammu_error
)
448 if error
.find('Runtime libGammu version does not match compile time version') != -1:
449 result
= re
.match('Runtime libGammu version does not match compile time version \(runtime: (\S+), compiletime: (\S+)\)', error
)
451 wx
.MessageDialog(self
,
452 _('Wammu could not import gammu module, program will be terminated.') + '\n\n' +
453 _('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' +
454 _('You can fix it by recompiling python-gammu against gammu library you are currently using.'),
455 _('Gammu module not working!'),
456 wx
.OK | wx
.ICON_ERROR
).ShowModal()
457 elif error
.find('No module named gammu') != -1:
458 wx
.MessageDialog(self
,
459 _('Wammu could not import gammu module, program will be terminated.') + '\n\n' +
460 _('Gammu module was not found, you probably don\'t have properly installed python-gammu for current python version.'),
461 _('Gammu module not working!'),
462 wx
.OK | wx
.ICON_ERROR
).ShowModal()
464 wx
.MessageDialog(self
,
465 _('Wammu could not import gammu module, program will be terminated.') + '\n\n' +
466 _('The import failed with following error:') + '\n\n%s' % error
,
467 _('Gammu module not working!'),
468 wx
.OK | wx
.ICON_ERROR
).ShowModal()
471 def InitConfiguration(self
):
473 Binds Wammu configuration to Gammu one. If at least one section
474 exists, use first one (same as Gammu), otherwise we suggest search to
477 gammucfg
= self
.cfg
.gammu
.GetConfigs()
478 if len(gammucfg
) == 0:
479 dlg
= wx
.MessageDialog(self
,
480 _('Wammu configuration was not found and Gammu settings couldn\'t be read.') + '\n\n' +
481 _('Do you want to configure phone connection now?') + '\n',
482 _('Configuration not found'),
483 wx
.YES_NO | wx
.YES_DEFAULT | wx
.ICON_WARNING
)
484 if dlg
.ShowModal() == wx
.ID_YES
:
486 elif not self
.cfg
.HasEntry('/Gammu/Section'):
488 self
.cfg
.WriteInt('/Gammu/Section', 0)
490 def TalkbackCheck(self
):
492 Do ask for talkback after month of usage and at least 30 executions.
494 firstrun
= self
.cfg
.ReadFloat('/Wammu/FirstRun')
496 firstrun
= time
.time()
497 self
.cfg
.WriteFloat('/Wammu/FirstRun', firstrun
)
498 runs
= self
.cfg
.ReadInt('/Wammu/RunCounter')
499 self
.cfg
.WriteInt('/Wammu/RunCounter', runs
+ 1)
500 if self
.cfg
.Read('/Wammu/TalkbackDone') == 'no':
501 if (firstrun
+ (3600 * 24 * TALKBACK_DAYS
) < time
.time()
502 and runs
> TALKBACK_COUNT
):
503 dlg
= wx
.MessageDialog(self
,
504 _('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?') +
505 '\n\n' + _('Press Cancel to never show this question again.'),
506 _('Thanks for using Wammu'),
507 wx
.YES_NO | wx
.CANCEL | wx
.ICON_INFORMATION
)
508 ret
= dlg
.ShowModal()
511 elif ret
== wx
.ID_CANCEL
:
512 self
.cfg
.Write('/Wammu/TalkbackDone', 'skipped')
514 def MigrateConfiguration(self
):
516 Migrate configuration from pre-0.18 style one (Gammu was configured
517 inside Wammu configuration) to using .gammurc.
519 connection
= self
.cfg
.Read('/Gammu/Connection')
520 device
= self
.cfg
.Read('/Gammu/Device')
521 model
= self
.cfg
.Read('/Gammu/Model')
522 gammucfg
= self
.cfg
.gammu
.GetConfigs()
523 if len(gammucfg
) > 0:
525 cfg
= self
.cfg
.gammu
.GetConfig(i
['Id'])
526 if cfg
['Model'] == model
and cfg
['Connection'] == connection
and cfg
['Device'] == device
:
527 self
.cfg
.WriteInt('/Gammu/Section', i
['Id'])
529 if not self
.cfg
.HasEntry('/Gammu/Section'):
530 index
= self
.cfg
.gammu
.FirstFree()
531 self
.cfg
.gammu
.SetConfig(index
, device
, connection
, _('Migrated from older Wammu'), model
)
532 self
.cfg
.WriteInt('/Gammu/Section', index
)
534 def PostInit(self
, appparent
):
536 Do things which need window opened to behave correctly.
538 - Activate initial view.
539 - Show if something wrong has happened on gammu import.
540 - Initialize or migrate Gammu configuration.
541 - Connect to phone if required.
543 - Setup internal information.
545 self
.ActivateView('info', ' ')
546 self
.appparent
= appparent
548 if Wammu
.gammu_error
!= None:
549 self
.HandleGammuError()
551 if not self
.cfg
.HasEntry('/Gammu/Section') and self
.cfg
.HasEntry('/Gammu/Connection'):
552 self
.MigrateConfiguration()
554 self
.InitConfiguration()
556 self
.DoDebug(self
.cfg
.Read('/Debug/Show'))
558 if (self
.cfg
.Read('/Wammu/AutoConnect') == 'yes'):
563 self
.SetupNumberPrefix()
565 self
.SetupStatusRefresh()
573 Initializes DBUS handlers if available.
575 self
.dbus_notify
= None
576 self
.last_dbus_id
= 0
579 bus
= dbus
.SessionBus() #mainloop = self.appparent.MainLoop)
580 interface
= 'org.freedesktop.Notifications'
581 path
= '/org/freedesktop/Notifications'
582 if Wammu
.Utils
.DBUSServiceAvailable(bus
, interface
, True):
583 obj
= bus
.get_object(interface
, path
)
584 self
.dbus_notify
= dbus
.Interface(obj
, interface
)
585 self
.dbus_notify
.connect_to_signal('ActionInvoked', self
.DBUSActionCallback
)
586 except dbus
.DBusException
:
587 self
.dbus_notify
= None
588 self
.last_dbus_id
= 0
590 def SetupTrayIcon(self
):
591 if self
.cfg
.Read('/Wammu/TaskBarIcon') != 'yes':
592 if self
.tbicon
is not None:
593 self
.tbicon
.Destroy()
595 if self
.tbicon
is not None:
598 self
.tbicon
= wx
.TaskBarIcon()
599 self
.tbicon
.SetIcon(self
.icon16
, 'Wammu')
600 self
.tbicon
.Bind(wx
.EVT_TASKBAR_RIGHT_UP
, self
.OnTaskBarRightClick
)
601 self
.tbicon
.Bind(wx
.EVT_TASKBAR_LEFT_UP
, self
.OnTaskBarLeftClick
)
602 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.Settings
, id=151)
603 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.PhoneConnect
, id=201)
604 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.PhoneDisconnect
, id=202)
605 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRestore
, id=100000)
606 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarMinimize
, id=100001)
607 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=100002)
609 def OnTaskBarRightClick(self
, evt
):
610 menutaskbar
= wx
.Menu()
611 menutaskbar
.Append(201, _('Connect'))
612 menutaskbar
.Append(202, _('Disconnect'))
613 menutaskbar
.AppendSeparator()
614 menutaskbar
.Append(151, _('Settings'))
615 menutaskbar
.AppendSeparator()
616 menutaskbar
.Append(100000, _('Restore'))
617 menutaskbar
.Append(100001, _('Minimize'))
618 menutaskbar
.AppendSeparator()
619 menutaskbar
.Append(100002, _('Close'))
620 self
.tbicon
.PopupMenu(menutaskbar
)
621 menutaskbar
.Destroy()
623 def OnTaskBarLeftClick(self
, evt
):
629 def OnTaskBarRestore(self
, evt
):
632 def OnTaskBarMinimize(self
, evt
):
635 def OnTaskBarClose(self
, evt
):
636 self
.CloseWindow(evt
)
638 def OnTimer(self
, evt
= None):
641 s
= self
.sm
.GetSignalQuality()
642 b
= self
.sm
.GetBatteryCharge()
643 d
= self
.sm
.GetDateTime()
647 if b
['ChargeState'] == 'BatteryPowered':
649 elif b
['ChargeState'] == 'BatteryConnected':
651 elif b
['ChargeState'] == 'BatteryNotConnected':
652 power
= _('no battery')
653 elif b
['ChargeState'] == 'PowerFault':
655 elif b
['ChargeState'] == 'BatteryCharging':
656 power
= _('charging')
657 elif b
['ChargeState'] == 'BatteryFull':
660 # Time might be None if it is invalid (eg. 0.0.0000 date)
664 time
= StrConv(d
.strftime('%c'))
666 # Detect unknown signal quality
667 if s
['SignalPercent'] == -1:
668 signal
= _('Unknown')
670 # l10n: Formatting of signal percentage, usually you can keep this as it is.
671 signal
= _('%d %%') % s
['SignalPercent']
673 self
.SetStatusText(_('Bat: %(battery_percent)d %% (%(power_source)s), Sig: %(signal_level)s, Time: %(time)s') %
675 'battery_percent':b
['BatteryPercent'],
676 'power_source':power
,
677 'signal_level':signal
,
680 except gammu
.GSMError
:
683 def SetupNumberPrefix(self
):
684 self
.prefix
= self
.cfg
.Read('/Wammu/PhonePrefix')
685 if self
.prefix
== 'Auto':
689 on
= Wammu
.Utils
.ParseMemoryEntry(self
.sm
.GetMemory(Location
= 1, Type
= 'ON'), self
.cfg
)['Number']
690 self
.prefix
= Wammu
.Utils
.GrabNumberPrefix(on
, Wammu
.Data
.InternationalPrefixes
)
691 except gammu
.GSMError
:
693 if self
.prefix
is None:
695 smsc
= self
.sm
.GetSMSC()['Number']
696 self
.prefix
= Wammu
.Utils
.GrabNumberPrefix(smsc
, Wammu
.Data
.InternationalPrefixes
)
697 except gammu
.GSMError
:
699 if self
.prefix
is None:
700 self
.prefix
= self
.cfg
.Read('/Wammu/LastPhonePrefix')
702 self
.cfg
.Write('/Wammu/LastPhonePrefix', self
.prefix
)
704 self
.prefix
= self
.cfg
.Read('/Wammu/LastPhonePrefix')
705 Wammu
.Utils
.NumberPrefix
= self
.prefix
707 def SetupStatusRefresh(self
):
708 repeat
= self
.cfg
.ReadInt('/Wammu/RefreshState')
713 self
.timer
= wx
.Timer(self
, self
.TimerId
)
714 wx
.EVT_TIMER(self
, self
.TimerId
, self
.OnTimer
)
715 self
.timer
.Start(repeat
)
717 def DoDebug(self
, newdebug
):
718 if newdebug
!= self
.showdebug
:
719 self
.showdebug
= newdebug
720 if self
.showdebug
== 'yes':
721 self
.logwin
= Wammu
.Logger
.LogFrame(self
, self
.cfg
)
722 self
.logwin
.Show(True)
723 wx
.EVT_CLOSE(self
.logwin
, self
.LogClose
)
724 self
.logger
= Wammu
.Logger
.Logger(self
.logwin
, self
.logfilename
)
727 self
.CloseLogWindow()
729 def SaveWinSize(self
, win
, key
):
730 x
,y
= win
.GetPositionTuple()
731 w
,h
= win
.GetSizeTuple()
733 self
.cfg
.WriteInt('/%s/X' % key
, x
)
734 self
.cfg
.WriteInt('/%s/Y' % key
, y
)
735 self
.cfg
.WriteInt('/%s/Width' % key
, w
)
736 self
.cfg
.WriteInt('/%s/Height' % key
, h
)
738 def CloseLogWindow(self
):
739 if hasattr(self
, 'logwin'):
740 self
.SaveWinSize(self
.logwin
, 'Debug')
741 if hasattr(self
, 'logger'):
742 self
.logger
.canceled
= True
744 if hasattr(self
, 'logwin'):
745 self
.logwin
.Destroy()
749 def LogClose(self
, evt
= None):
750 self
.cfg
.Write('/Debug/Show', 'no')
751 self
.CloseLogWindow()
753 def TogglePhoneMenus(self
, enable
):
754 self
.connected
= enable
756 self
.SetStatusText(_('Connected'), 1)
757 if self
.timer
!= None:
760 self
.SetStatusText(_('Disconnected'), 1)
763 mb
.Enable(201, not enable
);
764 mb
.Enable(202, enable
);
766 mb
.Enable(210, enable
);
768 mb
.Enable(250, enable
);
770 mb
.Enable(301, enable
);
772 mb
.Enable(310, enable
);
773 mb
.Enable(311, enable
);
774 mb
.Enable(312, enable
);
776 mb
.Enable(320, enable
);
778 mb
.Enable(330, enable
);
780 mb
.Enable(340, enable
);
782 mb
.Enable(350, enable
);
784 mb
.Enable(401, enable
);
785 mb
.Enable(402, enable
);
786 mb
.Enable(403, enable
);
787 mb
.Enable(404, enable
);
789 mb
.Enable(501, enable
);
790 mb
.Enable(502, enable
);
791 mb
.Enable(503, enable
);
792 mb
.Enable(504, enable
);
794 mb
.Enable(510, enable
);
795 mb
.Enable(511, enable
);
797 def ActivateView(self
, k1
, k2
):
798 self
.tree
.SelectItem(self
.treei
[k1
][k2
])
799 self
.ChangeView(k1
, k2
)
801 def ChangeView(self
, k1
, k2
):
802 self
.ChangeBrowser(k1
, k2
)
803 self
.righttitle
.SetLabel(displaydata
[k1
][k2
][2])
805 def ChangeBrowser(self
, k1
, k2
):
809 for k3
, v3
in self
.values
[k1
].iteritems():
812 self
.values
[k1
]['__'] = data
813 self
.browser
.Change(k1
, data
)
815 self
.browser
.Change(k1
, self
.values
[k1
][k2
])
816 self
.browser
.ShowRow(0)
818 def OnTreeSel(self
, event
):
819 item
= event
.GetItem()
820 for k1
, v1
in self
.treei
.iteritems():
821 for k2
, v2
in v1
.iteritems():
823 self
.ChangeView(k1
, k2
)
826 def OnSearch(self
, event
):
827 text
= self
.searchinput
.GetValue()
828 type = self
.searchchoice
.GetSelection()
830 self
.browser
.Filter(text
, type)
831 self
.searchinput
.SetBackgroundColour(wx
.NullColour
)
832 except Wammu
.Browser
.FilterException
:
833 self
.searchinput
.SetBackgroundColour(wx
.RED
)
835 def ClearSearch(self
, event
= None):
836 self
.searchinput
.SetValue('')
838 def Settings(self
, event
= None):
840 connection_settings
= {
841 'Connection': self
.cfg
.Read('/Gammu/Connection'),
842 'LockDevice': self
.cfg
.Read('/Gammu/LockDevice'),
843 'Device': self
.cfg
.Read('/Gammu/Device'),
844 'Model': self
.cfg
.Read('/Gammu/Model')
847 result
= Wammu
.Settings
.Settings(self
, self
.cfg
).ShowModal()
848 if result
== wx
.ID_OK
:
850 connection_settings_new
= {
851 'Connection': self
.cfg
.Read('/Gammu/Connection'),
852 'LockDevice': self
.cfg
.Read('/Gammu/LockDevice'),
853 'Device': self
.cfg
.Read('/Gammu/Device'),
854 'Model': self
.cfg
.Read('/Gammu/Model')
857 if connection_settings
!= connection_settings_new
:
858 wx
.MessageDialog(self
,
859 _('You changed parameters affecting phone connection, they will be used next time you connect to phone.'),
861 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
862 self
.DoDebug(self
.cfg
.Read('/Debug/Show'))
863 self
.SetupNumberPrefix()
864 self
.SetupStatusRefresh()
867 def CloseWindow(self
, event
):
868 self
.SaveWinSize(self
, 'Main')
869 if hasattr(self
, 'logwin'):
870 self
.CloseLogWindow()
871 self
.cfg
.WriteInt('/Main/Split', self
.splitter
.GetSashPosition())
872 self
.cfg
.WriteInt('/Main/SplitRight', self
.rightsplitter
.GetSashPosition())
873 self
.cfg
.WriteInt('/Defaults/SearchType', self
.searchchoice
.GetCurrentSelection())
875 gammu
.SetDebugFile(None)
876 gammu
.SetDebugLevel('nothing')
878 self
.logfilefd
.close()
880 if hasattr(self
, 'logger'):
881 self
.logger
.canceled
= True
884 if hasattr(self
, 'loggerdebug'):
885 self
.loggerdebug
.canceled
= True
886 self
.loggerdebug
.join()
888 if self
.tbicon
is not None:
889 self
.tbicon
.Destroy()
891 if sys
.platform
!= 'win32':
892 print ConsoleStrConv(
893 _('Looks like normal program termination, deleting log file.')
896 os
.unlink(self
.logfilename
)
898 print ConsoleStrConv(
899 _('Failed to unlink temporary log file, please delete it yourself.')
901 print ConsoleStrConv(
902 _('Filename: %s') % self
.logfilename
905 # Forcibily save configuration
908 # tell the window to kill itself
911 def ShowError(self
, info
):
912 evt
= Wammu
.Events
.ShowMessageEvent(
913 message
= Wammu
.Utils
.FormatError(_('Error while communicating with phone'), info
),
914 title
= _('Error Occured'),
916 type = wx
.ICON_ERROR
)
917 wx
.PostEvent(self
, evt
)
919 def ShowProgress(self
, text
):
920 self
.progress
= wx
.ProgressDialog(
921 _('Operation in progress'),
925 wx
.PD_CAN_ABORT | wx
.PD_APP_MODAL | wx
.PD_AUTO_HIDE | wx
.PD_ELAPSED_TIME | wx
.PD_REMAINING_TIME | wx
.PD_ESTIMATED_TIME
)
927 def OnProgress(self
, evt
):
928 if hasattr(self
, 'progress'):
929 if not self
.progress
.Update(evt
.progress
):
934 if (evt
.progress
== 100):
936 if hasattr(evt
, 'lock'):
939 def OnException(self
, evt
):
940 Wammu
.Error
.Handler(*evt
.data
)
942 def OnData(self
, evt
):
943 self
.values
[evt
.type[0]][evt
.type[1]] = evt
.data
945 if hasattr(self
, 'progress'):
946 self
.progress
.Update(100)
949 if hasattr(self
, 'nextfun'):
956 def ShowData(self
, data
):
961 text
+= u
'<b>%s</b>: %s<br>' % (d
[0], d
[1])
963 text
+= u
'<br>%s' % d
[0]
964 self
.content
.SetContent(text
)
966 def OnShow(self
, evt
):
970 elif self
.type == ['info',' ']:
971 data
= [(evt
.data
['Name'], evt
.data
['Value'])]
972 elif self
.type[0] == 'contact' or self
.type[0] == 'call':
974 (_('Location'), str(v
['Location'])),
975 (_('Memory type'), v
['MemoryType'])]
976 for i
in v
['Entries']:
977 s
= Wammu
.Utils
.GetTypeString(i
['Type'], i
['Value'], self
.values
, linkphone
= False)
980 s
+= ', ' + (_('voice tag %x') % i
['VoiceTag'])
983 data
.append((i
['Type'], s
))
984 elif self
.type[0] == 'message':
986 (_('Number'), Wammu
.Utils
.GetNumberLink([] + self
.values
['contact']['ME'] + self
.values
['contact']['SM'], v
['Number'])),
987 (_('Date'), StrConv(v
['DateTime'])),
988 (_('Location'), StrConv(v
['Location'])),
989 (_('Folder'), StrConv(v
['SMS'][0]['Folder'])),
990 (_('Memory'), StrConv(v
['SMS'][0]['Memory'])),
991 (_('SMSC'), Wammu
.Utils
.GetNumberLink([] + self
.values
['contact']['ME'] + self
.values
['contact']['SM'], v
['SMS'][0]['SMSC']['Number'])),
992 (_('State'), StrConv(v
['State']))]
994 data
.append((_('Name'), StrConv(v
['Name'])))
995 data
.append((Wammu
.MessageDisplay
.SmsToHtml(self
.cfg
, v
),))
996 elif self
.type[0] == 'todo':
998 (_('Location'), str(v
['Location'])),
999 (_('Priority'), v
['Priority']),
1000 (_('Type'), v
['Type']),
1002 for i
in v
['Entries']:
1003 data
.append((i
['Type'], Wammu
.Utils
.GetTypeString(i
['Type'], i
['Value'], self
.values
)))
1004 elif self
.type[0] == 'calendar':
1006 (_('Location'), str(v
['Location'])),
1007 (_('Type'), v
['Type']),
1009 for i
in v
['Entries']:
1010 data
.append((i
['Type'], Wammu
.Utils
.GetTypeString(i
['Type'], i
['Value'], self
.values
)))
1012 data
= [('Show not yet implemented! (type = %s)' % self
.type[0])]
1015 def NewContact(self
, evt
):
1016 self
.EditContact({})
1018 def NewCalendar(self
, evt
):
1019 self
.EditCalendar({})
1021 def NewTodo(self
, evt
):
1024 def NewMessage(self
, evt
):
1025 self
.ComposeMessage({})
1027 def ComposeMessage(self
, v
, action
= 'save'):
1028 if Wammu
.Composer
.SMSComposer(self
, self
.cfg
, v
, self
.values
, action
).ShowModal() == wx
.ID_OK
:
1030 if len(v
['Numbers']) == 0:
1031 v
['Numbers'] = ['Wammu']
1033 for number
in v
['Numbers']:
1034 busy
= wx
.BusyInfo(_('Writing message(s)...'))
1037 v
['Number'] = number
1038 v
['SMS'] = gammu
.EncodeSMS(v
['SMSInfo'])
1045 for msg
in v
['SMS']:
1046 msg
['SMSC']['Location'] = 1
1048 msg
['Folder'] = v
['Folder']
1049 msg
['Number'] = v
['Number']
1050 msg
['Type'] = v
['Type']
1051 msg
['State'] = v
['State']
1054 (msg
['Location'], msg
['Folder']) = self
.sm
.AddSMS(msg
)
1056 # When sending of saved message fails, send it directly:
1058 msg
['MessageReference'] = self
.sm
.SendSavedSMS(0, msg
['Location'])
1059 except gammu
.GSMError
:
1060 msg
['MessageReference'] = self
.sm
.SendSMS(msg
)
1062 result
['SMS'].append(self
.sm
.GetSMS(0, msg
['Location'])[0])
1063 except gammu
.ERR_EMPTY
:
1064 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()
1066 msg
['MessageReference'] = self
.sm
.SendSMS(msg
)
1069 info
= gammu
.DecodeSMS(result
['SMS'])
1071 result
['SMSInfo'] = info
1072 Wammu
.Utils
.ParseMessage(result
, (info
!= None))
1073 result
['Synced'] = True
1074 self
.values
['message'][result
['State']].append(result
)
1076 except gammu
.GSMError
, val
:
1078 self
.ShowError(val
[0])
1082 self
.ActivateView('message', result
['State'])
1083 self
.browser
.ShowLocation(result
['Location'])
1087 def EditContact(self
, v
):
1088 backup
= copy
.deepcopy(v
)
1089 shoulddelete
= (v
== {} or v
['Location'] == 0)
1090 if Wammu
.Editor
.ContactEditor(self
, self
.cfg
, self
.values
, v
).ShowModal() == wx
.ID_OK
:
1092 busy
= wx
.BusyInfo(_('Writing contact...'))
1095 # was entry moved => delete it from internal list
1096 if not shoulddelete
:
1097 for idx
in range(len(self
.values
['contact'][backup
['MemoryType']])):
1098 if self
.values
['contact'][backup
['MemoryType']][idx
] == v
:
1099 del self
.values
['contact'][backup
['MemoryType']][idx
]
1102 # have we specified location? => add or set
1103 if v
['Location'] == 0:
1104 v
['Location'] = self
.sm
.AddMemory(v
)
1107 v
['Location'] = self
.sm
.SetMemory(v
)
1108 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1109 v
['Location'] = self
.sm
.AddMemory(v
)
1111 # was entry moved => delete it from phone
1112 if not shoulddelete
:
1113 if v
['MemoryType'] != backup
['MemoryType'] or v
['Location'] != backup
['Location']:
1115 self
.sm
.DeleteMemory(backup
['MemoryType'], backup
['Location'])
1117 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1120 while attempts
< 10:
1122 v
= self
.sm
.GetMemory(v
['MemoryType'], v
['Location'])
1123 except gammu
.ERR_EMPTY
:
1124 # some phones need time till entry appears
1125 attempts
= attempts
+ 1
1127 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1128 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()
1129 Wammu
.Utils
.ParseMemoryEntry(v
, self
.cfg
)
1131 # append new value to list
1132 self
.values
['contact'][v
['MemoryType']].append(v
)
1134 except gammu
.GSMError
, val
:
1137 self
.ShowError(val
[0])
1139 if (self
.type[0] == 'contact' and self
.type[1] == ' ') or not v
.has_key('MemoryType'):
1140 self
.ActivateView('contact', ' ')
1142 self
.browser
.ShowLocation(v
['Location'], ('MemoryType', v
['MemoryType']))
1146 self
.ActivateView('contact', v
['MemoryType'])
1148 self
.browser
.ShowLocation(v
['Location'])
1152 def EditCalendar(self
, v
):
1153 backup
= copy
.deepcopy(v
)
1154 shoulddelete
= (v
== {} or v
['Location'] == 0)
1155 if Wammu
.Editor
.CalendarEditor(self
, self
.cfg
, self
.values
, v
).ShowModal() == wx
.ID_OK
:
1157 busy
= wx
.BusyInfo(_('Writing calendar...'))
1160 # was entry moved => delete it from internal list
1161 if not shoulddelete
:
1162 # delete from internal list
1163 for idx
in range(len(self
.values
['calendar'][' '])):
1164 if self
.values
['calendar'][' '][idx
] == v
:
1165 del self
.values
['calendar'][' '][idx
]
1168 # have we specified location? => add or set
1169 if v
['Location'] == 0:
1170 v
['Location'] = self
.sm
.AddCalendar(v
)
1173 v
['Location'] = self
.sm
.SetCalendar(v
)
1174 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1175 v
['Location'] = self
.sm
.AddCalendar(v
)
1177 # was entry moved => delete it from phone
1178 if not shoulddelete
:
1179 if v
['Location'] != backup
['Location']:
1181 self
.sm
.DeleteCalendar(backup
['Location'])
1183 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1185 v
= self
.sm
.GetCalendar(v
['Location'])
1186 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1187 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()
1188 Wammu
.Utils
.ParseCalendar(v
)
1190 # append new value to list
1191 self
.values
['calendar'][' '].append(v
)
1193 except gammu
.GSMError
, val
:
1196 self
.ShowError(val
[0])
1198 self
.ActivateView('calendar', ' ')
1200 self
.browser
.ShowLocation(v
['Location'])
1204 def EditTodo(self
, v
):
1205 backup
= copy
.deepcopy(v
)
1206 shoulddelete
= (v
== {} or v
['Location'] == 0)
1207 if Wammu
.Editor
.TodoEditor(self
, self
.cfg
, self
.values
, v
).ShowModal() == wx
.ID_OK
:
1209 busy
= wx
.BusyInfo(_('Writing todo...'))
1212 # was entry moved => delete it from internal list
1213 if not shoulddelete
:
1214 for idx
in range(len(self
.values
['todo'][' '])):
1215 if self
.values
['todo'][' '][idx
] == v
:
1216 del self
.values
['todo'][' '][idx
]
1219 # have we specified location? => add or set
1220 if v
['Location'] == 0:
1221 v
['Location'] = self
.sm
.AddToDo(v
)
1224 v
['Location'] = self
.sm
.SetToDo(v
)
1225 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1226 v
['Location'] = self
.sm
.AddToDo(v
)
1228 # was entry moved => delete it from phone
1229 if not shoulddelete
:
1230 if v
['Location'] != backup
['Location']:
1232 self
.sm
.DeleteToDo(backup
['Location'])
1234 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1236 v
= self
.sm
.GetToDo(v
['Location'])
1237 except (gammu
.ERR_NOTSUPPORTED
, gammu
.ERR_NOTIMPLEMENTED
):
1238 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()
1239 Wammu
.Utils
.ParseTodo(v
)
1241 # append new value to list
1242 self
.values
['todo'][' '].append(v
)
1243 except gammu
.GSMError
, val
:
1246 self
.ShowError(val
[0])
1248 self
.ActivateView('todo', ' ')
1250 self
.browser
.ShowLocation(v
['Location'])
1255 def OnEdit(self
, evt
):
1256 if evt
.data
!= {} and not evt
.data
['Synced']:
1257 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()
1259 if self
.type[0] == 'contact':
1260 self
.EditContact(evt
.data
)
1261 elif self
.type[0] == 'calendar':
1262 self
.EditCalendar(evt
.data
)
1263 elif self
.type[0] == 'todo':
1264 self
.EditTodo(evt
.data
)
1266 print 'Edit not yet implemented (type = %s)!' % self
.type[0]
1268 def OnReply(self
, evt
):
1269 if self
.type[0] == 'message':
1270 self
.ComposeMessage({'Number': evt
.data
['Number']}, action
= 'send')
1272 print 'Reply not yet implemented!'
1275 def OnCall(self
, evt
):
1276 if self
.type[0] in ['call', 'contact']:
1277 num
= Wammu
.Select
.SelectContactNumber(self
, evt
.data
)
1282 self
.sm
.DialVoice(num
)
1283 except gammu
.GSMError
, val
:
1284 self
.ShowError(val
[0])
1285 elif self
.type[0] == 'message':
1287 self
.sm
.DialVoice(evt
.data
['Number'])
1288 except gammu
.GSMError
, val
:
1289 self
.ShowError(val
[0])
1291 print 'Call not yet implemented (type = %s)!' % self
.type[0]
1293 def OnMessage(self
, evt
):
1294 if self
.type[0] in ['call', 'contact']:
1296 num
= Wammu
.Select
.SelectContactNumber(self
, evt
.data
)
1299 self
.ComposeMessage({'Number': num
}, action
= 'send')
1300 elif self
.type[0] == 'message':
1301 self
.ComposeMessage({'Number': evt
.data
['Number']}, action
= 'send')
1303 print 'Message send not yet implemented (type = %s)!' % self
.type[0]
1305 def OnDuplicate(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 v
= copy
.deepcopy(evt
.data
)
1310 if self
.type[0] == 'contact':
1313 elif self
.type[0] == 'calendar':
1315 self
.EditCalendar(v
)
1316 elif self
.type[0] == 'todo':
1319 elif self
.type[0] == 'message':
1320 self
.ComposeMessage(v
)
1322 print 'Duplicate not yet implemented (type = %s)!' % self
.type[0]
1325 def OnSend(self
, evt
):
1326 if evt
.data
!= {} and not evt
.data
['Synced']:
1327 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()
1329 if self
.type[0] == 'message':
1333 for loc
in v
['Location'].split(', '):
1334 self
.sm
.SendSavedSMS(0, int(loc
))
1335 except gammu
.ERR_NOTSUPPORTED
:
1336 for msg
in v
['SMS']:
1337 self
.sm
.SendSMS(msg
)
1338 except gammu
.GSMError
, val
:
1339 self
.ShowError(val
[0])
1341 def SMSToMails(self
, evt
):
1342 messages
= self
.values
['message']['Read'] + \
1343 self
.values
['message']['UnRead'] + \
1344 self
.values
['message']['Sent'] + \
1345 self
.values
['message']['UnSent']
1346 contacts
= self
.values
['contact']['ME'] + \
1347 self
.values
['contact']['SM']
1348 Wammu
.SMSExport
.SMSExport(self
, messages
, contacts
)
1350 def SMSToXML(self
, evt
):
1351 messages
= self
.values
['message']['Read'] + \
1352 self
.values
['message']['UnRead'] + \
1353 self
.values
['message']['Sent'] + \
1354 self
.values
['message']['UnSent']
1355 contacts
= self
.values
['contact']['ME'] + \
1356 self
.values
['contact']['SM']
1357 Wammu
.SMSXML
.SMSExportXML(self
, messages
, contacts
)
1359 def SelectBackupFile(self
, type, save
= True, data
= False):
1361 if type == 'message':
1362 wildcard
+= _('Gammu messages backup') + ' (*.smsbackup)|*.smsbackup|'
1363 exts
= ['smsbackup']
1366 wildcard
+= _('All backup formats') + '|*.backup;*.lmb;*.vcf;*.ldif;*.vcs;*.ics|'
1368 wildcard
+= _('Gammu backup [all data]') + ' (*.backup)|*.backup|'
1371 if type in ['contact', 'all']:
1372 wildcard
+= _('Nokia backup [contacts]') + ' (*.lmb)|*.lmb|'
1374 if type in ['contact', 'all']:
1375 wildcard
+= _('vCard [contacts]') + ' (*.vcf)|*.vcf|'
1377 if type in ['contact', 'all']:
1378 wildcard
+= _('LDIF [contacts]') + ' (*.ldif)|*.ldif|'
1380 if type in ['todo', 'calendar', 'all']:
1381 wildcard
+= _('vCalendar [todo,calendar]') + ' (*.vcs)|*.vcs|'
1383 if type in ['todo', 'calendar', 'all']:
1384 wildcard
+= _('iCalendar [todo,calendar]') + ' (*.ics)|*.ics|'
1387 wildcard
+= _('All files') + ' (*.*)|*.*'
1392 dlg
= wx
.FileDialog(self
, _('Save data as...'), os
.getcwd(), "", wildcard
, wx
.SAVE|wx
.OVERWRITE_PROMPT|wx
.CHANGE_DIR
)
1394 dlg
= wx
.FileDialog(self
, _('Read data'), os
.getcwd(), "", wildcard
, wx
.OPEN|wx
.CHANGE_DIR
)
1397 dlg
= wx
.FileDialog(self
, _('Save backup as...'), os
.getcwd(), "", wildcard
, wx
.SAVE|wx
.OVERWRITE_PROMPT|wx
.CHANGE_DIR
)
1399 dlg
= wx
.FileDialog(self
, _('Import backup'), os
.getcwd(), "", wildcard
, wx
.OPEN|wx
.CHANGE_DIR
)
1400 if dlg
.ShowModal() == wx
.ID_OK
:
1401 path
= dlg
.GetPath()
1403 ext
= exts
[dlg
.GetFilterIndex()]
1404 # Add automatic extension if we know one and file does not
1406 if (os
.path
.splitext(path
)[1] == '' and
1409 return Wammu
.Locales
.ConsoleStrConv(path
)
1412 def ReadBackup(self
, type, data
= False):
1413 filename
= self
.SelectBackupFile(type, save
= False, data
= data
)
1414 if filename
== None:
1417 if type == 'message':
1418 backup
= gammu
.ReadSMSBackup(filename
)
1420 backup
= gammu
.ReadBackup(filename
)
1421 except gammu
.GSMError
, val
:
1423 evt
= Wammu
.Events
.ShowMessageEvent(
1424 message
= Wammu
.Utils
.FormatError(_('Error while reading backup'), info
),
1425 title
= _('Error Occured'),
1426 errortype
= 'gammu',
1427 type = wx
.ICON_ERROR
)
1428 wx
.PostEvent(self
, evt
)
1430 return (filename
, backup
)
1432 def ReadData(self
, evt
):
1433 (filename
, backup
) = self
.ReadBackup('all', True)
1437 if len(backup
['PhonePhonebook']) > 0:
1438 self
.values
['contact']['ME'] = map(Wammu
.Utils
.ParseMemoryEntry
, backup
['PhonePhonebook'], [self
.cfg
] * len(backup
['PhonePhonebook']))
1439 if len(backup
['SIMPhonebook']) > 0:
1440 self
.values
['contact']['SM'] = map(Wammu
.Utils
.ParseMemoryEntry
, backup
['SIMPhonebook'], [self
.cfg
] * len(backup
['SIMPhonebook']))
1441 if len(backup
['ToDo']) > 0:
1442 self
.values
['todo'][' '] = map(Wammu
.Utils
.ParseTodo
, backup
['ToDo'])
1443 if len(backup
['Calendar']) > 0:
1444 self
.values
['calendar'][' '] = map(Wammu
.Utils
.ParseCalendar
, backup
['Calendar'])
1446 self
.ActivateView('contact', ' ')
1448 self
.SetStatusText(_('Data has been read from file "%s"') % filename
)
1450 def ReadSMSData(self
, evt
):
1451 (filename
, backup
) = self
.ReadBackup('message', True)
1455 res
= Wammu
.Utils
.ProcessMessages(map(lambda x
:[x
], backup
), False)
1457 self
.values
['message']['Sent'] = res
['sent']
1458 self
.values
['message']['UnSent'] = res
['unsent']
1459 self
.values
['message']['Read'] = res
['read']
1460 self
.values
['message']['UnRead'] = res
['unread']
1462 self
.ActivateView('message', ' ')
1464 self
.SetStatusText(_('Data has been read from file "%s"') % filename
)
1466 def ImportSMS(self
, evt
):
1467 (filename
, backup
) = self
.ReadBackup('message')
1473 values
.append('message')
1474 choices
.append(_('%d messages') % len(backup
))
1476 if len(values
) == 0:
1477 wx
.MessageDialog(self
,
1478 _('No importable data were found in file "%s"') % filename
,
1479 _('No data to import'),
1480 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1483 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'),
1484 choices
,style
= wx
.CHOICEDLG_STYLE | wx
.RESIZE_BORDER
,
1486 if dlg
.ShowModal() != wx
.ID_OK
:
1489 lst
= dlg
.GetValue()
1494 busy
= wx
.BusyInfo(_('Importing data...'))
1498 datatype
= values
[i
]
1499 if datatype
== 'message':
1502 v
['Folder'] = 2 # FIXME: this should be configurable
1503 v
['SMSC']['Location'] = 1
1504 (v
['Location'], v
['Folder']) = self
.sm
.AddSMS(v
)
1505 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1506 v
= self
.sm
.GetSMS(0, v
['Location'])
1509 res
= Wammu
.Utils
.ProcessMessages(smsl
, True)
1511 self
.values
['message']['Sent'] += res
['sent']
1512 self
.values
['message']['UnSent'] += res
['unsent']
1513 self
.values
['message']['Read'] += res
['read']
1514 self
.values
['message']['UnRead'] += res
['unread']
1516 self
.ActivateView('message', ' ')
1521 wx
.MessageDialog(self
,
1522 _('Backup has been imported from file "%s"') % filename
,
1523 _('Backup imported'),
1524 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1526 except gammu
.GSMError
, val
:
1527 self
.ShowError(val
[0])
1529 wx
.MessageDialog(self
,
1530 _('Restoring from file "%s" has failed, some parts of backup might have been stored to phone and some were not.') % filename
,
1531 _('Backup import failed'),
1532 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1534 def Import(self
, evt
):
1535 (filename
, backup
) = self
.ReadBackup('all')
1540 if len(backup
['PhonePhonebook']) > 0:
1541 values
.append('PhonePhonebook')
1542 choices
.append(_('%d phone contact entries') % len(backup
['PhonePhonebook']))
1543 if len(backup
['SIMPhonebook']) > 0:
1544 values
.append('SIMPhonebook')
1545 choices
.append(_('%d SIM contact entries') % len(backup
['SIMPhonebook']))
1546 if len(backup
['ToDo']) > 0:
1547 values
.append('ToDo')
1548 choices
.append(_('%d to do entries') % len(backup
['ToDo']))
1549 if len(backup
['Calendar']) > 0:
1550 values
.append('Calendar')
1551 choices
.append(_('%d calendar entries') % len(backup
['Calendar']))
1553 if len(values
) == 0:
1554 wx
.MessageDialog(self
,
1555 _('No importable data were found in file "%s"') % filename
,
1556 _('No data to import'),
1557 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1561 if backup
['Model'] != '':
1562 msg
= '\n \n' + _('Backup saved from phone %s') % backup
['Model']
1563 if backup
['IMEI'] != '':
1564 msg
+= _(', serial number %s') % backup
['IMEI']
1565 if backup
['Creator'] != '':
1566 msg
+= '\n \n' + _('Backup was created by %s') % backup
['Creator']
1567 if backup
['DateTime'] != None:
1568 msg
+= '\n \n' + _('Backup saved on %s') % str(backup
['DateTime'])
1570 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'),
1571 choices
,style
= wx
.CHOICEDLG_STYLE | wx
.RESIZE_BORDER
,
1573 if dlg
.ShowModal() != wx
.ID_OK
:
1576 lst
= dlg
.GetValue()
1581 busy
= wx
.BusyInfo(_('Importing data...'))
1585 datatype
= values
[i
]
1586 if datatype
== 'PhonePhonebook':
1587 for v
in backup
['PhonePhonebook']:
1588 v
['Location'] = self
.sm
.AddMemory(v
)
1589 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1590 v
= self
.sm
.GetMemory(v
['MemoryType'], v
['Location'])
1591 Wammu
.Utils
.ParseMemoryEntry(v
, self
.cfg
)
1593 # append new value to list
1594 self
.values
['contact'][v
['MemoryType']].append(v
)
1595 self
.ActivateView('contact', 'ME')
1596 elif datatype
== 'SIMPhonebook':
1597 for v
in backup
['SIMPhonebook']:
1598 v
['Location'] = self
.sm
.AddMemory(v
)
1599 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1600 v
= self
.sm
.GetMemory(v
['MemoryType'], v
['Location'])
1601 Wammu
.Utils
.ParseMemoryEntry(v
, self
.cfg
)
1603 # append new value to list
1604 self
.values
['contact'][v
['MemoryType']].append(v
)
1605 self
.ActivateView('contact', 'SM')
1606 elif datatype
== 'ToDo':
1607 for v
in backup
['ToDo']:
1608 v
['Location'] = self
.sm
.AddToDo(v
)
1609 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1610 v
= self
.sm
.GetToDo(v
['Location'])
1611 Wammu
.Utils
.ParseTodo(v
)
1613 # append new value to list
1614 self
.values
['todo'][' '].append(v
)
1615 self
.ActivateView('todo', ' ')
1616 elif datatype
== 'Calendar':
1617 for v
in backup
['Calendar']:
1618 v
['Location'] = self
.sm
.AddCalendar(v
)
1619 # reread entry (it doesn't have to contain exactly same data as entered, it depends on phone features)
1620 v
= self
.sm
.GetCalendar(v
['Location'])
1621 Wammu
.Utils
.ParseCalendar(v
)
1623 # append new value to list
1624 self
.values
['calendar'][' '].append(v
)
1625 self
.ActivateView('calendar', ' ')
1630 wx
.MessageDialog(self
,
1631 _('Backup has been imported from file "%s"') % filename
,
1632 _('Backup imported'),
1633 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1635 except gammu
.GSMError
, val
:
1636 self
.ShowError(val
[0])
1638 wx
.MessageDialog(self
,
1639 _('Restoring from file "%s" has failed, some parts of backup might have been stored to phone and some were not.') % filename
,
1640 _('Backup import failed'),
1641 wx
.OK | wx
.ICON_INFORMATION
).ShowModal()
1643 def WriteData(self
, evt
):
1644 self
.DoBackup(True, 'all')
1646 def WriteSMSData(self
, evt
):
1647 self
.DoBackup(True, 'message')
1649 def Backup(self
, evt
):
1650 self
.DoBackup(False, 'all')
1652 def BackupSMS(self
, evt
):
1653 self
.DoBackup(False, 'message')
1655 def PrepareBackup(self
):
1657 backup
['Creator'] = 'Wammu ' + Wammu
.__version
__
1658 backup
['IMEI'] = self
.IMEI
1659 backup
['Model'] = '%s %s %s' % ( self
.Manufacturer
, self
.Model
, self
.Version
)
1662 def WriteBackup(self
, filename
, type, backup
, data
= False):
1664 if type == 'message':
1665 # Backup is here our internal SMS list: [{'SMS':[{sms1}, {sms2}]}, ...]
1666 data
= map(lambda x
:x
['SMS'], backup
)
1670 gammu
.SaveSMSBackup(filename
, backup
)
1672 gammu
.SaveBackup(filename
, backup
)
1674 self
.SetStatusText(_('Backup has been saved to file "%s"') % filename
)
1676 self
.SetStatusText(_('Data has been saved to file "%s"') % filename
)
1677 except gammu
.GSMError
, val
:
1679 evt
= Wammu
.Events
.ShowMessageEvent(
1680 message
= Wammu
.Utils
.FormatError(_('Error while saving backup'), info
),
1681 title
= _('Error Occured'),
1682 errortype
= 'gammu',
1683 type = wx
.ICON_ERROR
)
1684 wx
.PostEvent(self
, evt
)
1685 except MemoryError, val
:
1687 evt
= Wammu
.Events
.ShowMessageEvent(
1688 message
= _('Error while saving backup, probably some limit inside of Gammu exceeded.\n%s') % str(info
),
1689 title
= _('Error Occured'),
1690 type = wx
.ICON_ERROR
)
1691 wx
.PostEvent(self
, evt
)
1693 def DoBackup(self
, data
, type):
1694 filename
= self
.SelectBackupFile(type, data
= data
)
1695 if filename
== None:
1697 ext
= os
.path
.splitext(filename
)[1].lower()
1699 if type == 'message':
1700 backup
= self
.values
['message']['Read'] + self
.values
['message']['UnRead'] + self
.values
['message']['Sent'] + self
.values
['message']['UnSent']
1702 backup
= self
.PrepareBackup()
1703 if ext
in ['.vcf', '.ldif']:
1704 # these support only one phonebook, so merged it
1705 backup
['PhonePhonebook'] = self
.values
['contact']['ME'] + self
.values
['contact']['SM']
1707 backup
['PhonePhonebook'] = self
.values
['contact']['ME']
1708 backup
['SIMPhonebook'] = self
.values
['contact']['SM']
1710 backup
['ToDo'] = self
.values
['todo'][' ']
1711 backup
['Calendar'] = self
.values
['calendar'][' ']
1712 self
.WriteBackup(filename
, type, backup
, data
)
1715 def OnBackup(self
, evt
):
1716 filename
= self
.SelectBackupFile(self
.type[0])
1717 if filename
== None:
1719 ext
= os
.path
.splitext(filename
)[1].lower()
1721 if self
.type[0] == 'message':
1724 backup
= self
.PrepareBackup()
1725 if self
.type[0] == 'contact':
1726 if ext
in ['.vcf', '.ldif']:
1727 # these support only one phonebook, so keep it merged
1728 backup
['PhonePhonebook'] = lst
1733 if item
['MemoryType'] == 'SM':
1735 elif item
['MemoryType'] == 'ME':
1737 backup
['PhonePhonebook'] = phone
1738 backup
['SIMPhonebook'] = sim
1739 elif self
.type[0] == 'todo':
1740 backup
['ToDo'] = lst
1741 elif self
.type[0] == 'calendar':
1742 backup
['Calendar'] = lst
1744 self
.WriteBackup(filename
, self
.type[0], backup
)
1746 def OnDelete(self
, evt
):
1747 # first check on supported types
1748 if not self
.type[0] in ['contact', 'call', 'message', 'todo', 'calendar']:
1749 print 'Delete not yet implemented! (items to delete = %s, type = %s)' % (str(evt
.lst
), self
.type[0])
1758 if not lst
[0]['Synced']:
1759 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()
1762 # check for confirmation
1763 if self
.cfg
.Read('/Wammu/ConfirmDelete') == 'yes':
1767 if self
.type[0] == 'contact':
1768 txt
= _('Are you sure you want to delete contact "%s"?') % v
['Name']
1769 elif self
.type[0] == 'call':
1770 txt
= _('Are you sure you want to delete call from "%s"?') % v
['Name']
1771 elif self
.type[0] == 'message':
1772 txt
= _('Are you sure you want to delete message from "%s"?') % v
['Number']
1773 elif self
.type[0] == 'todo':
1774 txt
= _('Are you sure you want to delete todo entry "%s"?') % v
['Text']
1775 elif self
.type[0] == 'calendar':
1776 txt
= _('Are you sure you want to delete calendar entry "%s"?') % v
['Text']
1778 if self
.type[0] == 'contact':
1779 txt
= Wammu
.Locales
.ngettext(
1780 'Are you sure you want to delete %d contact?',
1781 'Are you sure you want to delete %d contacts?',
1783 elif self
.type[0] == 'call':
1784 txt
= Wammu
.Locales
.ngettext(
1785 'Are you sure you want to delete %d call?',
1786 'Are you sure you want to delete %d calls?',
1788 elif self
.type[0] == 'message':
1789 txt
= Wammu
.Locales
.ngettext(
1790 'Are you sure you want to delete %d message?',
1791 'Are you sure you want to delete %d messages?',
1793 elif self
.type[0] == 'todo':
1794 txt
= Wammu
.Locales
.ngettext(
1795 'Are you sure you want to delete %d todo entry?',
1796 'Are you sure you want to delete %d todo entries?',
1798 elif self
.type[0] == 'calendar':
1799 txt
= Wammu
.Locales
.ngettext(
1800 'Are you sure you want to delete %d calendar entry?',
1801 'Are you sure you want to delete %d calendar entries?',
1803 dlg
= wx
.MessageDialog(self
,
1805 _('Confirm deleting'),
1806 wx
.OK | wx
.CANCEL | wx
.ICON_WARNING
)
1807 if dlg
.ShowModal() != wx
.ID_OK
:
1812 if self
.type[0] == 'contact' or self
.type[0] == 'call':
1813 busy
= wx
.BusyInfo(_('Deleting contact(s)...'))
1817 self
.sm
.DeleteMemory(v
['MemoryType'], v
['Location'])
1818 for idx
in range(len(self
.values
[self
.type[0]][v
['MemoryType']])):
1819 if self
.values
[self
.type[0]][v
['MemoryType']][idx
] == v
:
1820 del self
.values
[self
.type[0]][v
['MemoryType']][idx
]
1822 elif self
.type[0] == 'message':
1823 busy
= wx
.BusyInfo(_('Deleting message(s)...'))
1827 for loc
in v
['Location'].split(', '):
1828 self
.sm
.DeleteSMS(0, int(loc
))
1829 for idx
in range(len(self
.values
[self
.type[0]][v
['State']])):
1830 if self
.values
[self
.type[0]][v
['State']][idx
] == v
:
1831 del self
.values
[self
.type[0]][v
['State']][idx
]
1833 elif self
.type[0] == 'todo':
1834 busy
= wx
.BusyInfo(_('Deleting todo(s)...'))
1838 self
.sm
.DeleteToDo(v
['Location'])
1839 for idx
in range(len(self
.values
[self
.type[0]][' '])):
1840 if self
.values
[self
.type[0]][' '][idx
] == v
:
1841 del self
.values
[self
.type[0]][' '][idx
]
1843 elif self
.type[0] == 'calendar':
1844 busy
= wx
.BusyInfo(_('Deleting calendar event(s)...'))
1848 self
.sm
.DeleteCalendar(v
['Location'])
1849 for idx
in range(len(self
.values
[self
.type[0]][' '])):
1850 if self
.values
[self
.type[0]][' '][idx
] == v
:
1851 del self
.values
[self
.type[0]][' '][idx
]
1853 except gammu
.GSMError
, val
:
1857 self
.ShowError(val
[0])
1859 self
.ActivateView(self
.type[0], self
.type[1])
1861 def OnLink(self
, evt
):
1862 v
= evt
.link
.split('://')
1866 if v
[0] == 'memory':
1872 if t
[0] in ['ME', 'SM']:
1873 self
.ActivateView('contact', t
[0])
1875 self
.browser
.ShowLocation(int(t
[1]))
1879 elif t
[0] in ['MC', 'RC', 'DC']:
1880 self
.ActivateView('call', t
[0])
1882 self
.browser
.ShowLocation(int(t
[1]))
1887 print 'Not supported memory type "%s"' % t
[0]
1890 print 'This link not yet implemented: "%s"' % evt
.link
1892 def OnShowMessage(self
, evt
):
1894 if self
.progress
.IsShown():
1895 parent
= self
.progress
1901 # Is is Gammu error?
1902 if hasattr(evt
, 'errortype') and evt
.errortype
== 'gammu':
1903 Wammu
.ErrorMessage
.ErrorMessage(parent
,
1904 StrConv(evt
.message
),
1905 StrConv(evt
.title
)).ShowModal()
1907 wx
.MessageDialog(parent
,
1908 StrConv(evt
.message
),
1910 wx
.OK | evt
.type).ShowModal()
1912 if hasattr(evt
, 'lock'):
1915 def ShowInfo(self
, event
):
1916 self
.ShowProgress(_('Reading phone information'))
1917 Wammu
.Info
.GetInfo(self
, self
.sm
).start()
1918 self
.nextfun
= self
.ActivateView
1919 self
.nextarg
= ('info', ' ')
1925 def ShowCalls(self
, event
):
1926 self
.GetCallsType('MC')
1927 self
.nextfun
= self
.ShowCalls2
1930 def ShowCalls2(self
):
1931 self
.GetCallsType('DC')
1932 self
.nextfun
= self
.ShowCalls3
1935 def ShowCalls3(self
):
1936 self
.GetCallsType('RC')
1937 self
.nextfun
= self
.ActivateView
1938 self
.nextarg
= ('call', ' ')
1940 def GetCallsType(self
, type):
1941 self
.ShowProgress(_('Reading calls of type %s') % type)
1942 Wammu
.Memory
.GetMemory(self
, self
.sm
, 'call', type).start()
1948 def ShowContacts(self
, event
):
1949 self
.GetContactsType('SM')
1950 self
.nextfun
= self
.ShowContacts2
1953 def ShowContacts2(self
):
1954 self
.GetContactsType('ME')
1955 self
.nextfun
= self
.ActivateView
1956 self
.nextarg
= ('contact', ' ')
1958 def ShowContactsME(self
, event
):
1959 self
.GetContactsType('ME')
1960 self
.nextfun
= self
.ActivateView
1961 self
.nextarg
= ('contact', 'ME')
1963 def ShowContactsSM(self
, event
):
1964 self
.GetContactsType('SM')
1965 self
.nextfun
= self
.ActivateView
1966 self
.nextarg
= ('contact', 'SM')
1968 def GetContactsType(self
, type):
1969 self
.ShowProgress(_('Reading contacts from %s') % type)
1970 Wammu
.Memory
.GetMemory(self
, self
.sm
, 'contact', type).start()
1976 def ShowMessages(self
, event
):
1977 self
.ShowProgress(_('Reading messages'))
1978 Wammu
.Message
.GetMessage(self
, self
.sm
).start()
1979 self
.nextfun
= self
.ActivateView
1980 self
.nextarg
= ('message', ' ')
1986 def ShowTodos(self
, event
):
1987 self
.ShowProgress(_('Reading todos'))
1988 Wammu
.Todo
.GetTodo(self
, self
.sm
).start()
1989 self
.nextfun
= self
.ActivateView
1990 self
.nextarg
= ('todo', ' ')
1996 def ShowCalendar(self
, event
):
1997 self
.ShowProgress(_('Reading calendar'))
1998 Wammu
.Calendar
.GetCalendar(self
, self
.sm
).start()
1999 self
.nextfun
= self
.ActivateView
2000 self
.nextarg
= ('calendar', ' ')
2006 def SyncTime(self
, event
):
2007 busy
= wx
.BusyInfo(_('Setting time in phone...'))
2011 self
.sm
.SetDateTime(datetime
.datetime
.now())
2012 except gammu
.GSMError
, val
:
2014 self
.ShowError(val
[0])
2020 def SendFile(self
, event
):
2022 Sends file to phone.
2024 @todo: Maybe we could add some wildcards for commonly used file types.
2026 dlg
= wx
.FileDialog(self
, _('Send file to phone'), os
.getcwd(), '', _('All files') + ' (*.*)|*.*', wx
.OPEN|wx
.CHANGE_DIR
)
2027 if dlg
.ShowModal() == wx
.ID_OK
:
2028 path
= dlg
.GetPath()
2030 file_data
= open(path
, 'r').read()
2033 'Name': os
.path
.basename(path
),
2036 'Used': len(file_data
),
2037 'Buffer': file_data
,
2047 busy
= wx
.BusyInfo(_('Sending file to phone...'))
2051 while (not file_f
['Finished']):
2052 file_f
= self
.sm
.SendFilePart(file_f
)
2053 except gammu
.ERR_PERMISSION
:
2054 wx
.MessageDialog(self
,
2055 _('Transfer has been rejected by phone.'),
2056 _('Transfer rejected!'),
2057 wx
.OK | wx
.ICON_ERROR
).ShowModal()
2058 except gammu
.GSMError
, val
:
2060 self
.ShowError(val
[0])
2062 wx
.MessageDialog(self
,
2063 _('Selected file "%s" was not found, no data read.') % path
,
2064 _('File not found!'),
2065 wx
.OK | wx
.ICON_ERROR
).ShowModal()
2068 # Connecting / Disconnecting
2071 def PhoneConnect(self
, event
= None):
2072 busy
= wx
.BusyInfo(_('One moment please, connecting to phone...'))
2075 section
= self
.cfg
.ReadInt('/Gammu/Section')
2076 config
= self
.cfg
.gammu
.GetConfig(section
)
2077 if config
['Connection'] == '' or config
['Device'] == '':
2078 wx
.MessageDialog(self
,
2079 _('Phone connection is not properly configured, can not connect to phone.'),
2080 _('Connection not configured!'),
2081 wx
.OK | wx
.ICON_ERROR
).ShowModal()
2084 'StartInfo': self
.cfg
.Read('/Gammu/StartInfo'),
2085 'UseGlobalDebugFile': 1,
2086 'DebugFile': None, # Set on other place
2087 'SyncTime': self
.cfg
.Read('/Gammu/SyncTime'),
2088 'Connection': config
['Connection'],
2089 'LockDevice': self
.cfg
.Read('/Gammu/LockDevice'),
2090 'DebugLevel': 'textalldate', # Set on other place
2091 'Device': config
['Device'],
2092 'Localize': None, # Set automatically by python-gammu
2093 'Model': config
['Model'],
2095 if cfg
['Model'] == 'auto':
2097 self
.sm
.SetConfig(0, cfg
)
2100 self
.sm
.SetIncomingCallback(self
.IncomingEvent
)
2102 self
.sm
.SetIncomingCall(True)
2103 except gammu
.GSMError
:
2105 self
.TogglePhoneMenus(True)
2106 self
.SetupNumberPrefix()
2108 self
.IMEI
= self
.sm
.GetIMEI()
2109 except gammu
.GSMError
:
2112 self
.Manufacturer
= self
.sm
.GetManufacturer()
2113 self
.cfg
.Write('/Phone-0/Manufacturer', self
.Manufacturer
)
2114 except gammu
.GSMError
:
2117 m
= self
.sm
.GetModel()
2118 if m
[0] == '' or m
[0] == 'unknown':
2122 self
.cfg
.Write('/Phone-0/Model', self
.Model
)
2123 except gammu
.GSMError
:
2126 self
.Version
= self
.sm
.GetFirmware()[0]
2130 except gammu
.GSMError
, val
:
2132 self
.ShowError(val
[0])
2135 except gammu
.GSMError
, val
:
2138 def DBUSActionCallback(self
, id, action
):
2140 Called when user does something on notification.
2142 self
.dbus_notify
.CloseNotification(self
.last_dbus_id
)
2143 if action
== 'accept-call':
2144 self
.sm
.AnswerCall(0, True)
2145 elif action
== 'reject-call':
2146 self
.sm
.CancelCall(0, True)
2148 print 'Unknown DBUS event: %s' % action
2150 def DBUSNotify(self
, title
, message
, actions
):
2152 Performs D-Bus notification if available.
2154 if self
.dbus_notify
is not None:
2155 self
.last_dbus_id
= self
.dbus_notify
.Notify(
2156 'Wammu', self
.last_dbus_id
, 'wammu',
2157 title
, message
, actions
, {}, -1)
2160 def IncomingEvent(self
, sm
, type, data
):
2162 Called on incoming event from phone.
2166 if data
['Status'] != 'IncomingCall':
2167 # We care only about incoming calls
2169 if data
['Number'] == '':
2170 msg
= _('Your phone has just received incoming call')
2172 msg
= _('Your phone has just received incoming call from %s') % data
['Number']
2173 self
.DBUSNotify(_('Incoming call'), msg
,
2174 ['reject-call', _('Reject'), 'accept-call', _('Accept')])
2176 def PhoneDisconnect(self
, event
= None):
2177 busy
= wx
.BusyInfo(_('One moment please, disconnecting from phone...'))
2182 except gammu
.ERR_NOTCONNECTED
:
2184 except gammu
.GSMError
, val
:
2186 self
.ShowError(val
[0])
2187 self
.TogglePhoneMenus(False)
2189 def SearchMessage(self
, text
):
2191 This has to send message as it is called from different thread.
2193 evt
= Wammu
.Events
.TextEvent(text
= text
+ '\n')
2194 wx
.PostEvent(self
.searchlog
, evt
)
2196 def SearchDone(self
, lst
):
2198 This has to send message as it is called from different thread.
2200 self
.founddevices
= lst
2201 evt
= Wammu
.Events
.DoneEvent()
2202 wx
.PostEvent(self
.searchlog
, evt
)
2204 def SearchPhone(self
, evt
= None):
2205 index
= self
.cfg
.gammu
.FirstFree()
2206 result
= Wammu
.PhoneWizard
.RunConfigureWizard(self
, index
)
2207 if result
is not None:
2208 self
.cfg
.gammu
.SetConfig(result
['Position'], result
['Device'], result
['Connection'], result
['Name'])
2209 self
.cfg
.WriteInt('/Gammu/Section', index
)
2211 def About(self
, evt
= None):
2212 Wammu
.About
.AboutBox(self
).ShowModal()
2214 def Website(self
, evt
= None):
2215 Wammu
.Webbrowser
.Open("http://%swammu.eu/?version=%s" % (Wammu
.Utils
.GetWebsiteLang(), Wammu
.__version
__))
2217 def Support(self
, evt
= None):
2218 Wammu
.Webbrowser
.Open("http://%swammu.eu/support?version=%s" % (Wammu
.Utils
.GetWebsiteLang(), Wammu
.__version
__))
2220 def ReportBug(self
, evt
= None):
2221 Wammu
.Webbrowser
.Open("http://bugs.cihar.com/set_project.php?ref=bug_report_page.php&project_id=1")
2223 def PhoneDB(self
, evt
= None):
2224 Wammu
.Webbrowser
.Open("http://%scihar.com/gammu/phonedb" % Wammu
.Utils
.GetWebsiteLang())
2226 def Talkback(self
, evt
= None):
2227 Wammu
.TalkbackDialog
.DoTalkback(self
, self
.cfg
, 0)
2229 def Donate(self
, evt
= None):
2230 Wammu
.Webbrowser
.Open("http://%swammu.eu/donate?src=wammu" % Wammu
.Utils
.GetWebsiteLang())
2232 def SaveLog(self
, evt
= None):
2234 Saves debug log to file.
2236 dlg
= wx
.FileDialog(self
,
2237 _('Save debug log as...'),
2241 wx
.SAVE | wx
.OVERWRITE_PROMPT | wx
.CHANGE_DIR
)
2242 if dlg
.ShowModal() == wx
.ID_OK
:
2243 Wammu
.ErrorLog
.SaveLog(filename
= dlg
.GetPath())