8523ad530d7367e38b7bf42988892ad77d80d3f4
[gc-dialer] / src / dialcentral_qt.py
1 #!/usr/bin/env python
2 # -*- coding: UTF8 -*-
3
4 from __future__ import with_statement
5
6 import os
7 import base64
8 import ConfigParser
9 import functools
10 import logging
11
12 from PyQt4 import QtGui
13 from PyQt4 import QtCore
14
15 import constants
16 from util import qtpie
17 from util import qwrappers
18 from util import qui_utils
19 from util import misc as misc_utils
20
21 import session
22
23
24 _moduleLogger = logging.getLogger(__name__)
25
26
27 class LedWrapper(object):
28
29         def __init__(self):
30                 self._ledHandler = None
31                 self._init = False
32
33         def off(self):
34                 self._lazy_init()
35                 if self._ledHandler is not None:
36                         self._ledHandler.off()
37
38         def _lazy_init(self):
39                 if self._init:
40                         return
41                 self._init = True
42                 try:
43                         import led_handler
44                         self._ledHandler = led_handler.LedHandler()
45                 except Exception, e:
46                         _moduleLogger.exception('Unable to initialize LED Handling: "%s"' % str(e))
47                         self._ledHandler = None
48
49
50 class Dialcentral(qwrappers.ApplicationWrapper):
51
52         _DATA_PATHS = [
53                 os.path.join(os.path.dirname(__file__), "../share"),
54                 os.path.join(os.path.dirname(__file__), "../data"),
55         ]
56
57         def __init__(self, app):
58                 self._dataPath = None
59                 self._aboutDialog = None
60                 self._ledHandler = LedWrapper()
61                 self.notifyOnMissed = False
62                 self.notifyOnVoicemail = False
63                 self.notifyOnSms = False
64
65                 try:
66                         import alarm_handler
67                         if alarm_handler.AlarmHandler is not alarm_handler._NoneAlarmHandler:
68                                 self._alarmHandler = alarm_handler.AlarmHandler()
69                         else:
70                                 self._alarmHandler = None
71                 except (ImportError, OSError):
72                         self._alarmHandler = None
73                 except Exception:
74                         _moduleLogger.exception("Notification failure")
75                         self._alarmHandler = None
76                 if self._alarmHandler is None:
77                         _moduleLogger.info("No notification support")
78
79                 qwrappers.ApplicationWrapper.__init__(self, app, constants)
80
81         def load_settings(self):
82                 try:
83                         config = ConfigParser.SafeConfigParser()
84                         config.read(constants._user_settings_)
85                 except IOError, e:
86                         _moduleLogger.info("No settings")
87                         return
88                 except ValueError:
89                         _moduleLogger.info("Settings were corrupt")
90                         return
91                 except ConfigParser.MissingSectionHeaderError:
92                         _moduleLogger.info("Settings were corrupt")
93                         return
94                 except Exception:
95                         _moduleLogger.exception("Unknown loading error")
96
97                 blobs = "", ""
98                 isFullscreen = False
99                 isPortrait = qui_utils.screen_orientation() == QtCore.Qt.Vertical
100                 tabIndex = 0
101                 try:
102                         blobs = [
103                                 config.get(constants.__pretty_app_name__, "bin_blob_%i" % i)
104                                 for i in xrange(len(self._mainWindow.get_default_credentials()))
105                         ]
106                         isFullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
107                         tabIndex = config.getint(constants.__pretty_app_name__, "tab")
108                         isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
109                 except ConfigParser.NoOptionError, e:
110                         _moduleLogger.info(
111                                 "Settings file %s is missing option %s" % (
112                                         constants._user_settings_,
113                                         e.option,
114                                 ),
115                         )
116                 except ConfigParser.NoSectionError, e:
117                         _moduleLogger.info(
118                                 "Settings file %s is missing section %s" % (
119                                         constants._user_settings_,
120                                         e.section,
121                                 ),
122                         )
123                 except Exception:
124                         _moduleLogger.exception("Unknown loading error")
125
126                 if self._alarmHandler is not None:
127                         try:
128                                 self._alarmHandler.load_settings(config, "alarm")
129                                 self.notifyOnMissed = config.getboolean("2 - Account Info", "notifyOnMissed")
130                                 self.notifyOnVoicemail = config.getboolean("2 - Account Info", "notifyOnVoicemail")
131                                 self.notifyOnSms = config.getboolean("2 - Account Info", "notifyOnSms")
132                         except ConfigParser.NoOptionError, e:
133                                 _moduleLogger.info(
134                                         "Settings file %s is missing option %s" % (
135                                                 constants._user_settings_,
136                                                 e.option,
137                                         ),
138                                 )
139                         except ConfigParser.NoSectionError, e:
140                                 _moduleLogger.info(
141                                         "Settings file %s is missing section %s" % (
142                                                 constants._user_settings_,
143                                                 e.section,
144                                         ),
145                                 )
146                         except Exception:
147                                 _moduleLogger.exception("Unknown loading error")
148
149                 creds = (
150                         base64.b64decode(blob)
151                         for blob in blobs
152                 )
153                 self._mainWindow.set_default_credentials(*creds)
154                 self._fullscreenAction.setChecked(isFullscreen)
155                 self._orientationAction.setChecked(isPortrait)
156                 self._mainWindow.set_current_tab(tabIndex)
157                 self._mainWindow.load_settings(config)
158
159         def save_settings(self):
160                 _moduleLogger.info("Saving settings")
161                 config = ConfigParser.SafeConfigParser()
162
163                 config.add_section(constants.__pretty_app_name__)
164                 config.set(constants.__pretty_app_name__, "tab", str(self._mainWindow.get_current_tab()))
165                 config.set(constants.__pretty_app_name__, "fullscreen", str(self._fullscreenAction.isChecked()))
166                 config.set(constants.__pretty_app_name__, "portrait", str(self._orientationAction.isChecked()))
167                 for i, value in enumerate(self._mainWindow.get_default_credentials()):
168                         blob = base64.b64encode(value)
169                         config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob)
170
171                 if self._alarmHandler is not None:
172                         config.add_section("alarm")
173                         self._alarmHandler.save_settings(config, "alarm")
174                 config.add_section("2 - Account Info")
175                 config.set("2 - Account Info", "notifyOnMissed", repr(self.notifyOnMissed))
176                 config.set("2 - Account Info", "notifyOnVoicemail", repr(self.notifyOnVoicemail))
177                 config.set("2 - Account Info", "notifyOnSms", repr(self.notifyOnSms))
178
179                 self._mainWindow.save_settings(config)
180
181                 with open(constants._user_settings_, "wb") as configFile:
182                         config.write(configFile)
183
184         def get_icon(self, name):
185                 if self._dataPath is None:
186                         for path in self._DATA_PATHS:
187                                 if os.path.exists(os.path.join(path, name)):
188                                         self._dataPath = path
189                                         break
190                 if self._dataPath is not None:
191                         icon = QtGui.QIcon(os.path.join(self._dataPath, name))
192                         return icon
193                 else:
194                         return None
195
196         def _close_windows(self):
197                 qwrappers.ApplicationWrapper._close_windows(self)
198                 if self._aboutDialog  is not None:
199                         self._aboutDialog.close()
200
201         @property
202         def fsContactsPath(self):
203                 return os.path.join(constants._data_path_, "contacts")
204
205         @property
206         def alarmHandler(self):
207                 return self._alarmHandler
208
209         @property
210         def ledHandler(self):
211                 return self._ledHandler
212
213         def _new_main_window(self):
214                 return MainWindow(None, self)
215
216         @QtCore.pyqtSlot()
217         @QtCore.pyqtSlot(bool)
218         @misc_utils.log_exception(_moduleLogger)
219         def _on_about(self, checked = True):
220                 with qui_utils.notify_error(self._errorLog):
221                         if self._aboutDialog is None:
222                                 import dialogs
223                                 self._aboutDialog = dialogs.AboutDialog(self)
224                         response = self._aboutDialog.run(self._mainWindow.window)
225
226
227 class DelayedWidget(object):
228
229         def __init__(self, app, settingsNames):
230                 self._layout = QtGui.QVBoxLayout()
231                 self._layout.setContentsMargins(0, 0, 0, 0)
232                 self._widget = QtGui.QWidget()
233                 self._widget.setContentsMargins(0, 0, 0, 0)
234                 self._widget.setLayout(self._layout)
235                 self._settings = dict((name, "") for name in settingsNames)
236
237                 self._child = None
238                 self._isEnabled = True
239
240         @property
241         def toplevel(self):
242                 return self._widget
243
244         def has_child(self):
245                 return self._child is not None
246
247         def set_child(self, child):
248                 if self._child is not None:
249                         self._layout.removeWidget(self._child.toplevel)
250                 self._child = child
251                 if self._child is not None:
252                         self._layout.addWidget(self._child.toplevel)
253
254                 self._child.set_settings(self._settings)
255
256                 if self._isEnabled:
257                         self._child.enable()
258                 else:
259                         self._child.disable()
260
261         @property
262         def child(self):
263                 return self._child
264
265         def enable(self):
266                 self._isEnabled = True
267                 if self._child is not None:
268                         self._child.enable()
269
270         def disable(self):
271                 self._isEnabled = False
272                 if self._child is not None:
273                         self._child.disable()
274
275         def clear(self):
276                 if self._child is not None:
277                         self._child.clear()
278
279         def refresh(self, force=True):
280                 if self._child is not None:
281                         self._child.refresh(force)
282
283         def get_settings(self):
284                 if self._child is not None:
285                         return self._child.get_settings()
286                 else:
287                         return self._settings
288
289         def set_settings(self, settings):
290                 if self._child is not None:
291                         self._child.set_settings(settings)
292                 else:
293                         self._settings = settings
294
295
296 def _tab_factory(tab, app, session, errorLog):
297         import gv_views
298         return gv_views.__dict__[tab](app, session, errorLog)
299
300
301 class MainWindow(qwrappers.WindowWrapper):
302
303         KEYPAD_TAB = 0
304         RECENT_TAB = 1
305         MESSAGES_TAB = 2
306         CONTACTS_TAB = 3
307         MAX_TABS = 4
308
309         _TAB_TITLES = [
310                 "Dialpad",
311                 "History",
312                 "Messages",
313                 "Contacts",
314         ]
315         assert len(_TAB_TITLES) == MAX_TABS
316
317         _TAB_ICONS = [
318                 "dialpad.png",
319                 "history.png",
320                 "messages.png",
321                 "contacts.png",
322         ]
323         assert len(_TAB_ICONS) == MAX_TABS
324
325         _TAB_CLASS = [
326                 functools.partial(_tab_factory, "Dialpad"),
327                 functools.partial(_tab_factory, "History"),
328                 functools.partial(_tab_factory, "Messages"),
329                 functools.partial(_tab_factory, "Contacts"),
330         ]
331         assert len(_TAB_CLASS) == MAX_TABS
332
333         # Hack to allow delay importing/loading of tabs
334         _TAB_SETTINGS_NAMES = [
335                 (),
336                 ("filter", ),
337                 ("status", "type"),
338                 ("selectedAddressbook", ),
339         ]
340         assert len(_TAB_SETTINGS_NAMES) == MAX_TABS
341
342         def __init__(self, parent, app):
343                 qwrappers.WindowWrapper.__init__(self, parent, app)
344                 self._window.setWindowTitle("%s" % constants.__pretty_app_name__)
345                 #self._freezer = qwrappers.AutoFreezeWindowFeature(self._app, self._window)
346                 self._errorLog = self._app.errorLog
347
348                 self._session = session.Session(self._errorLog, constants._data_path_)
349                 self._session.error.connect(self._on_session_error)
350                 self._session.loggedIn.connect(self._on_login)
351                 self._session.loggedOut.connect(self._on_logout)
352                 self._session.draft.recipientsChanged.connect(self._on_recipients_changed)
353                 self._defaultCredentials = "", ""
354                 self._curentCredentials = "", ""
355                 self._currentTab = 0
356
357                 self._credentialsDialog = None
358                 self._smsEntryDialog = None
359                 self._accountDialog = None
360
361                 self._tabsContents = [
362                         DelayedWidget(self._app, self._TAB_SETTINGS_NAMES[i])
363                         for i in xrange(self.MAX_TABS)
364                 ]
365                 for tab in self._tabsContents:
366                         tab.disable()
367
368                 self._tabWidget = QtGui.QTabWidget()
369                 if qui_utils.screen_orientation() == QtCore.Qt.Vertical:
370                         self._tabWidget.setTabPosition(QtGui.QTabWidget.South)
371                 else:
372                         self._tabWidget.setTabPosition(QtGui.QTabWidget.West)
373                 defaultTabIconSize = self._tabWidget.iconSize()
374                 defaultTabIconWidth, defaultTabIconHeight = defaultTabIconSize.width(), defaultTabIconSize.height()
375                 for tabIndex, (tabTitle, tabIcon) in enumerate(
376                         zip(self._TAB_TITLES, self._TAB_ICONS)
377                 ):
378                         icon = self._app.get_icon(tabIcon)
379                         if constants.IS_MAEMO and icon is not None:
380                                 tabTitle = ""
381
382                         if icon is None:
383                                 self._tabWidget.addTab(self._tabsContents[tabIndex].toplevel, tabTitle)
384                         else:
385                                 iconSize = icon.availableSizes()[0]
386                                 defaultTabIconWidth = max(defaultTabIconWidth, iconSize.width())
387                                 defaultTabIconHeight = max(defaultTabIconHeight, iconSize.height())
388                                 self._tabWidget.addTab(self._tabsContents[tabIndex].toplevel, icon, tabTitle)
389                 defaultTabIconWidth = max(defaultTabIconWidth, 32)
390                 defaultTabIconHeight = max(defaultTabIconHeight, 32)
391                 self._tabWidget.setIconSize(QtCore.QSize(defaultTabIconWidth, defaultTabIconHeight))
392                 self._tabWidget.currentChanged.connect(self._on_tab_changed)
393                 self._tabWidget.setContentsMargins(0, 0, 0, 0)
394
395                 self._layout.addWidget(self._tabWidget)
396
397                 self._loginTabAction = QtGui.QAction(None)
398                 self._loginTabAction.setText("Login")
399                 self._loginTabAction.triggered.connect(self._on_login_requested)
400
401                 self._importTabAction = QtGui.QAction(None)
402                 self._importTabAction.setText("Import")
403                 self._importTabAction.triggered.connect(self._on_import)
404
405                 self._accountTabAction = QtGui.QAction(None)
406                 self._accountTabAction.setText("Account")
407                 self._accountTabAction.triggered.connect(self._on_account)
408
409                 self._refreshTabAction = QtGui.QAction(None)
410                 self._refreshTabAction.setText("Refresh")
411                 self._refreshTabAction.setShortcut(QtGui.QKeySequence("CTRL+r"))
412                 self._refreshTabAction.triggered.connect(self._on_refresh)
413
414                 fileMenu = self._window.menuBar().addMenu("&File")
415                 fileMenu.addAction(self._loginTabAction)
416                 fileMenu.addAction(self._refreshTabAction)
417
418                 toolsMenu = self._window.menuBar().addMenu("&Tools")
419                 toolsMenu.addAction(self._accountTabAction)
420                 toolsMenu.addAction(self._importTabAction)
421                 toolsMenu.addAction(self._app.aboutAction)
422
423                 self._initialize_tab(self._tabWidget.currentIndex())
424                 self.set_fullscreen(self._app.fullscreenAction.isChecked())
425                 self.set_orientation(self._app.orientationAction.isChecked())
426
427         def set_default_credentials(self, username, password):
428                 self._defaultCredentials = username, password
429
430         def get_default_credentials(self):
431                 return self._defaultCredentials
432
433         def walk_children(self):
434                 if self._smsEntryDialog is not None:
435                         return (self._smsEntryDialog, )
436                 else:
437                         return ()
438
439         def start(self):
440                 qwrappers.WindowWrapper.start(self)
441                 assert self._session.state == self._session.LOGGEDOUT_STATE, "Initialization messed up"
442                 if self._defaultCredentials != ("", ""):
443                         username, password = self._defaultCredentials[0], self._defaultCredentials[1]
444                         self._curentCredentials = username, password
445                         self._session.login(username, password)
446                 else:
447                         self._prompt_for_login()
448
449         def close(self):
450                 for diag in (
451                         self._credentialsDialog,
452                         self._accountDialog,
453                 ):
454                         if diag is not None:
455                                 diag.close()
456                 for child in self.walk_children():
457                         child.window.destroyed.disconnect(self._on_child_close)
458                         child.window.closed.disconnect(self._on_child_close)
459                         child.close()
460                 self._window.close()
461
462         def destroy(self):
463                 qwrappers.WindowWrapper.destroy(self)
464                 if self._session.state != self._session.LOGGEDOUT_STATE:
465                         self._session.logout()
466
467         def get_current_tab(self):
468                 return self._currentTab
469
470         def set_current_tab(self, tabIndex):
471                 self._tabWidget.setCurrentIndex(tabIndex)
472
473         def load_settings(self, config):
474                 backendId = 2 # For backwards compatibility
475                 for tabIndex, tabTitle in enumerate(self._TAB_TITLES):
476                         sectionName = "%s - %s" % (backendId, tabTitle)
477                         settings = self._tabsContents[tabIndex].get_settings()
478                         for settingName in settings.iterkeys():
479                                 try:
480                                         settingValue = config.get(sectionName, settingName)
481                                 except ConfigParser.NoOptionError, e:
482                                         _moduleLogger.info(
483                                                 "Settings file %s is missing section %s" % (
484                                                         constants._user_settings_,
485                                                         e.section,
486                                                 ),
487                                         )
488                                         return
489                                 except ConfigParser.NoSectionError, e:
490                                         _moduleLogger.info(
491                                                 "Settings file %s is missing section %s" % (
492                                                         constants._user_settings_,
493                                                         e.section,
494                                                 ),
495                                         )
496                                         return
497                                 except Exception:
498                                         _moduleLogger.exception("Unknown loading error")
499                                         return
500                                 settings[settingName] = settingValue
501                         self._tabsContents[tabIndex].set_settings(settings)
502
503         def save_settings(self, config):
504                 backendId = 2 # For backwards compatibility
505                 for tabIndex, tabTitle in enumerate(self._TAB_TITLES):
506                         sectionName = "%s - %s" % (backendId, tabTitle)
507                         config.add_section(sectionName)
508                         tabSettings = self._tabsContents[tabIndex].get_settings()
509                         for settingName, settingValue in tabSettings.iteritems():
510                                 config.set(sectionName, settingName, settingValue)
511
512         def set_orientation(self, isPortrait):
513                 qwrappers.WindowWrapper.set_orientation(self, isPortrait)
514                 if isPortrait:
515                         self._tabWidget.setTabPosition(QtGui.QTabWidget.South)
516                 else:
517                         self._tabWidget.setTabPosition(QtGui.QTabWidget.West)
518
519         def _initialize_tab(self, index):
520                 assert index < self.MAX_TABS, "Invalid tab"
521                 if not self._tabsContents[index].has_child():
522                         tab = self._TAB_CLASS[index](self._app, self._session, self._errorLog)
523                         self._tabsContents[index].set_child(tab)
524                 self._tabsContents[index].refresh(force=False)
525
526         def _prompt_for_login(self):
527                 if self._credentialsDialog is None:
528                         import dialogs
529                         self._credentialsDialog = dialogs.CredentialsDialog(self._app)
530                 credentials = self._credentialsDialog.run(
531                         self._defaultCredentials[0], self._defaultCredentials[1], self.window
532                 )
533                 if credentials is None:
534                         return
535                 username, password = credentials
536                 self._curentCredentials = username, password
537                 self._session.login(username, password)
538
539         def _show_account_dialog(self):
540                 if self._accountDialog is None:
541                         import dialogs
542                         self._accountDialog = dialogs.AccountDialog(self._app)
543                         if self._app.alarmHandler is None:
544                                 self._accountDialog.setIfNotificationsSupported(False)
545                 if self._app.alarmHandler is not None:
546                         self._accountDialog.notifications = self._app.alarmHandler.isEnabled
547                         self._accountDialog.notificationTime = self._app.alarmHandler.recurrence
548                         self._accountDialog.notifyOnMissed = self._app.notifyOnMissed
549                         self._accountDialog.notifyOnVoicemail = self._app.notifyOnVoicemail
550                         self._accountDialog.notifyOnSms = self._app.notifyOnSms
551                 self._accountDialog.set_callbacks(
552                         self._session.get_callback_numbers(), self._session.get_callback_number()
553                 )
554                 accountNumberToDisplay = self._session.get_account_number()
555                 if not accountNumberToDisplay:
556                         accountNumberToDisplay = "Not Available (%s)" % self._session.state
557                 self._accountDialog.set_account_number(accountNumberToDisplay)
558                 response = self._accountDialog.run(self.window)
559                 if response == QtGui.QDialog.Accepted:
560                         if self._accountDialog.doClear:
561                                 self._session.logout_and_clear()
562                                 self._defaultCredentials = "", ""
563                                 self._curentCredentials = "", ""
564                                 for tab in self._tabsContents:
565                                         tab.disable()
566                         else:
567                                 callbackNumber = self._accountDialog.selectedCallback
568                                 self._session.set_callback_number(callbackNumber)
569                         if self._app.alarmHandler is not None:
570                                 self._app.alarmHandler.apply_settings(self._accountDialog.notifications, self._accountDialog.notificationTime)
571                                 self._app.notifyOnMissed = self._accountDialog.notifyOnMissed
572                                 self._app.notifyOnVoicemail = self._accountDialog.notifyOnVoicemail
573                                 self._app.notifyOnSms = self._accountDialog.notifyOnSms
574                                 self._app.save_settings()
575                 elif response == QtGui.QDialog.Rejected:
576                         _moduleLogger.info("Cancelled")
577                 else:
578                         _moduleLogger.info("Unknown response")
579
580         @QtCore.pyqtSlot(str)
581         @misc_utils.log_exception(_moduleLogger)
582         def _on_session_error(self, message):
583                 with qui_utils.notify_error(self._errorLog):
584                         self._errorLog.push_error(message)
585
586         @QtCore.pyqtSlot()
587         @misc_utils.log_exception(_moduleLogger)
588         def _on_login(self):
589                 with qui_utils.notify_error(self._errorLog):
590                         changedAccounts = self._defaultCredentials != self._curentCredentials
591                         noCallback = not self._session.get_callback_number()
592                         if changedAccounts or noCallback:
593                                 self._show_account_dialog()
594
595                         self._defaultCredentials = self._curentCredentials
596
597                         for tab in self._tabsContents:
598                                 tab.enable()
599                         self._initialize_tab(self._currentTab)
600
601         @QtCore.pyqtSlot()
602         @misc_utils.log_exception(_moduleLogger)
603         def _on_logout(self):
604                 with qui_utils.notify_error(self._errorLog):
605                         for tab in self._tabsContents:
606                                 tab.disable()
607
608         @QtCore.pyqtSlot()
609         @misc_utils.log_exception(_moduleLogger)
610         def _on_recipients_changed(self):
611                 with qui_utils.notify_error(self._errorLog):
612                         if self._session.draft.get_num_contacts() == 0:
613                                 return
614
615                         if self._smsEntryDialog is None:
616                                 import dialogs
617                                 self._smsEntryDialog = dialogs.SMSEntryWindow(self.window, self._app, self._session, self._errorLog)
618                                 self._smsEntryDialog.window.destroyed.connect(self._on_child_close)
619                                 self._smsEntryDialog.window.closed.connect(self._on_child_close)
620                                 self._smsEntryDialog.window.show()
621
622         @misc_utils.log_exception(_moduleLogger)
623         def _on_child_close(self, obj = None):
624                 self._smsEntryDialog = None
625
626         @QtCore.pyqtSlot()
627         @QtCore.pyqtSlot(bool)
628         @misc_utils.log_exception(_moduleLogger)
629         def _on_login_requested(self, checked = True):
630                 with qui_utils.notify_error(self._errorLog):
631                         self._prompt_for_login()
632
633         @QtCore.pyqtSlot(int)
634         @misc_utils.log_exception(_moduleLogger)
635         def _on_tab_changed(self, index):
636                 with qui_utils.notify_error(self._errorLog):
637                         self._currentTab = index
638                         self._initialize_tab(index)
639
640         @QtCore.pyqtSlot()
641         @QtCore.pyqtSlot(bool)
642         @misc_utils.log_exception(_moduleLogger)
643         def _on_refresh(self, checked = True):
644                 with qui_utils.notify_error(self._errorLog):
645                         self._tabsContents[self._currentTab].refresh(force=True)
646
647         @QtCore.pyqtSlot()
648         @QtCore.pyqtSlot(bool)
649         @misc_utils.log_exception(_moduleLogger)
650         def _on_import(self, checked = True):
651                 with qui_utils.notify_error(self._errorLog):
652                         csvName = QtGui.QFileDialog.getOpenFileName(self._window, caption="Import", filter="CSV Files (*.csv)")
653                         csvName = unicode(csvName)
654                         if not csvName:
655                                 return
656                         import shutil
657                         shutil.copy2(csvName, self._app.fsContactsPath)
658                         if self._tabsContents[self.CONTACTS_TAB].has_child:
659                                 self._tabsContents[self.CONTACTS_TAB].child.update_addressbooks()
660
661         @QtCore.pyqtSlot()
662         @QtCore.pyqtSlot(bool)
663         @misc_utils.log_exception(_moduleLogger)
664         def _on_account(self, checked = True):
665                 with qui_utils.notify_error(self._errorLog):
666                         assert self._session.state == self._session.LOGGEDIN_STATE, "Must be logged in for settings"
667                         self._show_account_dialog()
668
669
670 def run():
671         app = QtGui.QApplication([])
672         handle = Dialcentral(app)
673         qtpie.init_pies()
674         return app.exec_()
675
676
677 if __name__ == "__main__":
678         import sys
679
680         logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
681         logging.basicConfig(level=logging.DEBUG, format=logFormat)
682         try:
683                 os.makedirs(constants._data_path_)
684         except OSError, e:
685                 if e.errno != 17:
686                         raise
687
688         val = run()
689         sys.exit(val)