Example #1
0
    def on_connect_button_toggled(self, widget):
        dialmanager = self.model.get_dialer_manager()

        if widget.get_active():
            # user wants to connect
            if not self.model.device:
                widget.set_active(False)
                show_warning_dialog(
                    _("No device found"),
                    _("No device has been found. Insert one and try again."))
                return


            profiles_model = self.model.preferences_model.profiles_model
            if not profiles_model.has_active_profile():
                widget.set_active(False)
                show_warning_dialog(
                    _("Profile needed"),
                    _("You need to create a profile for connecting."))
                self.ask_for_new_profile()
                return

            active_profile = profiles_model.get_active_profile()

            dialmanager.ActivateConnection(active_profile.profile_path,
                                           self.model.device_opath,
                                           timeout=40,
                                           reply_handler=self._on_connect_cb,
                                           error_handler=self._on_connect_eb)

            self._setup_connection_signals()

            def cancel_cb():
                self.view.set_disconnected()
                self.model.dial_path = None

            def stop_connection_attempt():
                self._ignore_no_reply = True
                dialmanager.StopConnection(self.model.device_opath,
                                           reply_handler=cancel_cb,
                                           error_handler=logger.error)

            self.apb = ActivityProgressBar(_("Connecting"), self)
            self.apb.set_cancel_cb(stop_connection_attempt)
            self.apb.init()
            logger.info("Connecting...")
        else:
            # user wants to disconnect
            if not self.model.dial_path:
                return

            self.apb = ActivityProgressBar(_("Disconnecting"), self,
                                           disable_cancel=True)
            dialmanager.DeactivateConnection(self.model.dial_path,
                                        reply_handler=self._on_disconnect_cb,
                                        error_handler=self._on_disconnect_eb)

            self.apb.init()
            self.model.dial_path = None
Example #2
0
class MainController(Controller):
    """
    I am the controller for the main window
    """

    def __init__(self, model, view):
        super(MainController, self).__init__(model, view)
        model.ctrl = self
        self.cid = None

        self.signal_matches = []

        # activity progress bar
        self.apb = None
        self.icon = None
        # ignore cancelled connection attempts errors
        self._ignore_no_reply = False

    def register_view(self, view):
        super(MainController, self).register_view(view)
        self._setup_icon()
        self.view.set_initialising(True)
        self.connect_to_signals()

    def _setup_icon(self):
        filename = os.path.join(GLADE_DIR, 'wader.png')
        self.icon = gtk.status_icon_new_from_file(filename)

    def connect_to_signals(self):
        self.view['window1'].connect('delete_event', self.close_application)
        self.cid = self.view['connect_button'].connect('toggled',
                                            self.on_connect_button_toggled)
        self.icon.connect('activate', self.on_icon_activated)
        self.icon.connect('popup-menu', self.on_icon_popup_menu)

    def close_application(self, *args):
        if self.model.dial_path:
            show_warning_dialog(_("Can not close application"),
                               _("Can not close while a connection is active"))
            window = self.view.get_top_widget()
            try:
                window.emit_stop_by_name('delete_event')
            except IOError:
                pass

            return True
        else:
            self.view.start_throbber()
            self.model.quit(self._close_application_cb)

    def ask_for_new_profile(self):
        model = self.model.preferences_model
        if self.model.device:
            self.model.get_imsi(lambda imsi:
                show_profile_window(model, imsi=imsi))
        else:
            show_profile_window(model)

    def ask_for_pin(self):
        pin = ask_pin_dialog(self.view)
        if pin:
            self.model.send_pin(pin, self.model.enable_device)

    def _close_application_cb(self, *args):
        try:
            os.unlink(GTK_LOCK)
        except OSError:
            pass

        self.view.stop_throbber()
        gtk.main_quit()

    def _setup_connection_signals(self):
        self.model.bus.add_signal_receiver(
                                self._on_disconnect_cb,
                                "Disconnected",
                                dbus_interface=consts.WADER_DIALUP_INTFACE)

    # properties

    def property_rssi_value_change(self, model, old, new):
        self.view.rssi_changed(new)

    def on_net_password_required(self, opath, tag):
        password = ask_password_dialog(self.view)

        if password:
            from wader.gtk.profiles import manager
            ret = {'gsm': {'passwd': password}}
            profile = manager.get_profile_by_object_path(opath)
            profile.set_secrets(tag, ret)

    def on_keyring_password_required(self, opath, callback=None):
        from wader.gtk.profiles import manager
        profile = manager.get_profile_by_object_path(opath)
        password = None

        if profile.secrets.manager.is_new():
            dialog = NewKeyringDialog(self.view.get_top_widget())
            response = dialog.run()
        elif not profile.secrets.manager.is_open():
            dialog = KeyringPasswordDialog(self.view.get_top_widget())
            response = dialog.run()

        if response == gtk.RESPONSE_OK:
            password = dialog.password_entry.get_text()

        dialog.destroy()

        if password is not None:
            try:
                profile.secrets.manager.open(password)
            except KeyringInvalidPassword:
                title = _("Invalid password")
                details = _("The supplied password is incorrect")
                show_error_dialog(title, details)
                # call ourselves again
                self.on_keyring_password_required(opath)
            else:
                if callback is not None:
                    uuid = profile.get_settings()['connection']['uuid']
                    callback(profile.secrets.manager.get_secrets(uuid))

    def property_operator_value_change(self, model, old, new):
        if new == _('Unknown Network'):
            logger.error("Unknown operator received, using profile name...")
            profiles_model = self.model.preferences_model.profiles_model
            try:
                profile = profiles_model.get_active_profile()
            except RuntimeError:
                self.view.operator_changed(new)
            else:
                self.view.operator_changed(profile.name)
        else:
            self.view.operator_changed(new)

    def property_tech_value_change(self, model, old, new):
        self.view.tech_changed(new)

    def property_device_value_change(self, model, old, new):
        if self.model.device is not None:
            sm = self.model.device.connect_to_signal("DeviceEnabled",
                                            self.on_device_enabled_cb)
            self.signal_matches.append(sm)
            # connect to SIG_SMS and display SMS
            sm = self.model.device.connect_to_signal(SIG_SMS,
                                                self.on_sms_received_cb)
            self.signal_matches.append(sm)
        else:
            while self.signal_matches:
                sm = self.signal_matches.pop()
                sm.remove()

    def property_profile_value_change(self, model, old, new):
        logger.info("A profile has been set for current model %s" % new)

    def property_status_value_change(self, model, old, new):
        self.view.set_status(new)
        if new == _('Initialising'):
            self.view.set_initialising(True)
        elif new == _('No device'):
            self.view.set_disconnected(device_present=False)
        elif new in [_('Registered'), _('Roaming')]:
            self.view.set_initialising(False)

    def property_sim_error_value_change(self, model, old, details):
        title = _('Unknown error while initting device')
        show_error_dialog(title, details)

    def property_net_error_value_change(self, model, old, new):
        title = _("Error while registering to home network")
        show_error_dialog(title, new)

    def property_pin_required_value_change(self, model, old, new):
        if new:
            self.ask_for_pin()

    def property_puk_required_value_change(self, model, old, new):
        if new:
            pukinfo = ask_puk_dialog(parent=self.view)
            if pukinfo:
                puk, pin = pukinfo
                model.send_puk(puk, pin, model.enable_device)

    def property_puk2_required_value_change(self, model, old, new):
        if new:
            pukinfo = ask_puk2_dialog(parent=self.view)
            if pukinfo:
                puk2, pin = pukinfo
                model.send_puk(puk2, pin, model.enable_device)

    def property_rx_bytes_value_change(self, model, old, new):
        if old != new:
            self.view['rx_bytes_label'].set_text(bytes_repr(new))
            logger.info("Bytes rx: %d", new)

    def property_tx_bytes_value_change(self, model, old, new):
        if old != new:
            self.view['tx_bytes_label'].set_text(bytes_repr(new))
            logger.info("Bytes tx: %d", new)

    def property_total_bytes_value_change(self, model, old, new):
        if old != new and new != '':
            self.view['total_bytes_label'].set_text(bytes_repr(new))
            logger.info("Total bytes: %d", new)

    def property_transfer_limit_exceeded_value_change(self, model, old, new):
        if not old and new:
            show_warning_dialog(_("Transfer limit exceeded"),
                                _("You have exceeded your transfer limit"))

    # callbacks
    def on_sms_received_cb(self, index, complete):
        """
        Executed whenever a new SMS is received

        Will read and show the SMS to the user
        """
        # XXX: handle complete argument

        def process_sms_eb(error):
            title = _("Error reading SMS %d") % index
            show_error_dialog(title, get_error_msg(error))

         # read the SMS and show it to the user
        self.model.device.Get(index,
                              dbus_interface=consts.SMS_INTFACE,
                              reply_handler=self.show_sms_notification,
                              error_handler=process_sms_eb)

    def show_sms_notification(self, sms):
        """
        Shows a notification when a SMS is received

        It will take care of looking up the number in the phonebook
        to show the name if its a known contact instead of its number
        """

        def find_by_number_cb(contacts):
            if not contacts:
                title = _("SMS received from %s") % sms['number']
            else:
                assert len(contacts) == 1, "More than one match for a number!"
                title = _("SMS received from %s") % contacts[0][1]

            n = new_notification(self.icon, title, sms['text'],
                                 stock=gtk.STOCK_INFO)
            n.show()

        self.model.device.FindByNumber(sms['number'],
                                       dbus_interface=consts.CTS_INTFACE,
                                       reply_handler=find_by_number_cb,
                                       error_handler=logger.error)

    def on_device_enabled_cb(self, opath):
        self.view['sms_menuitem'].set_sensitive(True)
        self.view['preferences_menu_item'].set_sensitive(True)

    def _on_connect_cb(self, dev_path):
        self.view.set_connected()
        self.model.start_stats_tracking()
        if self.apb:
            self.apb.close()
            self.apb = None

        self.model.dial_path = dev_path

    def _on_connect_eb(self, e):
        logger.error("_on_connect_eb: %s" % e)
        self.view.set_disconnected()
        if self.apb:
            self.apb.close()
            self.apb = None

        if 'NoReply' in get_error_msg(e) and self._ignore_no_reply:
            # do not show NoReply exception as we were expecting it
            self._ignore_no_reply = False
        elif 'TypeError' in get_error_msg(e) and self._ignore_no_reply:
            # do not show TypeError exception as we were expecting it
            # as ActivateConnection returns None instead of an object
            # path.
            self._ignore_no_reply = False
        else:
            title = _('Failed connection attempt')
            show_error_dialog(title, get_error_msg(e))

    def _on_disconnect_cb(self, *args):
        logger.info("Disconnected")
        self.model.stop_stats_tracking()
        self.view.set_disconnected()

        if self.apb:
            self.apb.close()
            self.apb = None

        if self.model.dial_path:
            # if dial_path is not None, it means that the connection was
            # deactivated externally to wader, either through nm-applet
            # or because pppd died or something.
            dialmanager = self.model.get_dialer_manager()
            dialmanager.DeactivateConnection(self.model.dial_path)
            self.model.dial_path = None

    def _on_disconnect_eb(self, e):
        logger.error("_on_disconnect_eb: %s" % e)
        self.model.stop_stats_tracking()
        if self.apb:
            self.apb.close()
            self.apb = None

    def on_icon_activated(self, icon):
        window = self.view.get_top_widget()
        if window.get_property('visible'):
            window.hide()
        else:
            window.present()

    def get_trayicon_menu(self):
        menu = gtk.Menu()

        item = gtk.ImageMenuItem(_("About"))
        img = gtk.image_new_from_stock(gtk.STOCK_ABOUT, gtk.ICON_SIZE_MENU)
        item.set_image(img)
        item.connect("activate", self.on_about_menuitem_activate)
        item.show()
        menu.append(item)

        item = gtk.ImageMenuItem(_("Preferences"))
        item.set_image(gtk.image_new_from_stock(gtk.STOCK_PREFERENCES,
                                                gtk.ICON_SIZE_MENU))
        item.connect("activate", self.on_preferences_menu_item_activate)
        if self.model.device is None:
            item.set_sensitive(False)
        else:
            item.set_sensitive(True)
        item.show()
        menu.append(item)

        item = gtk.ImageMenuItem(_("Quit"))
        img = gtk.image_new_from_stock(gtk.STOCK_QUIT, gtk.ICON_SIZE_MENU)
        item.set_image(img)
        item.connect("activate", self.close_application)
        item.show()
        menu.append(item)

        return menu

    def on_icon_popup_menu(self, icon, button, activate_time):
        menu = self.get_trayicon_menu()
        menu.popup(None, None, None, button, activate_time)

    def on_connect_button_toggled(self, widget):
        dialmanager = self.model.get_dialer_manager()

        if widget.get_active():
            # user wants to connect
            if not self.model.device:
                widget.set_active(False)
                show_warning_dialog(
                    _("No device found"),
                    _("No device has been found. Insert one and try again."))
                return


            profiles_model = self.model.preferences_model.profiles_model
            if not profiles_model.has_active_profile():
                widget.set_active(False)
                show_warning_dialog(
                    _("Profile needed"),
                    _("You need to create a profile for connecting."))
                self.ask_for_new_profile()
                return

            active_profile = profiles_model.get_active_profile()

            dialmanager.ActivateConnection(active_profile.profile_path,
                                           self.model.device_opath,
                                           timeout=40,
                                           reply_handler=self._on_connect_cb,
                                           error_handler=self._on_connect_eb)

            self._setup_connection_signals()

            def cancel_cb():
                self.view.set_disconnected()
                self.model.dial_path = None

            def stop_connection_attempt():
                self._ignore_no_reply = True
                dialmanager.StopConnection(self.model.device_opath,
                                           reply_handler=cancel_cb,
                                           error_handler=logger.error)

            self.apb = ActivityProgressBar(_("Connecting"), self)
            self.apb.set_cancel_cb(stop_connection_attempt)
            self.apb.init()
            logger.info("Connecting...")
        else:
            # user wants to disconnect
            if not self.model.dial_path:
                return

            self.apb = ActivityProgressBar(_("Disconnecting"), self,
                                           disable_cancel=True)
            dialmanager.DeactivateConnection(self.model.dial_path,
                                        reply_handler=self._on_disconnect_cb,
                                        error_handler=self._on_disconnect_eb)

            self.apb.init()
            self.model.dial_path = None

    def on_preferences_menu_item_activate(self, widget):
        from wader.gtk.views.preferences import PreferencesView
        from wader.gtk.controllers.preferences import PreferencesController

        view = PreferencesView()
        controller = PreferencesController(self.model.preferences_model, view,
                                           lambda: self.model.device)

        profiles_model = self.model.preferences_model.profiles_model
        if not profiles_model.has_active_profile():
            show_warning_dialog(
                _("Profile needed"),
                _("You need to create a profile to save preferences"))
            self.ask_for_new_profile()
            return
        view.show()

    def on_sms_menuitem_activate(self, widget):
        from wader.gtk.models.sms import SMSContactsModel
        from wader.gtk.controllers.sms import SMSContactsController
        from wader.gtk.views.sms import SMSContactsView

        model = SMSContactsModel(self.model.device)
        view = SMSContactsView(parent=self.view)
        ctrl = SMSContactsController(model, view, self)
        view.init_ui(ctrl)

        view.show()

    def on_log_menuitem_activate(self, widget):
        from wader.gtk.controllers.log import LogController
        from wader.gtk.views.log import LogView
        from wader.gtk.models.log import LogModel

        model = LogModel()
        view = LogView()
        ctrl = LogController(model, view)

        view.show()

    def on_about_menuitem_activate(self, widget):
        dlg = show_about_dialog()
        dlg.run()
        dlg.destroy()

    def on_exit_menu_item_activate(self, widget):
        self.close_application()