Beispiel #1
0
def get_backend(instance_id=None):
    '''Get the cache configuration information.'''
    config = Config(instance_id)
    config.set_schema('cache', {'backend': str, 'hostname': str, 'port': int})
    cache_config = config.get('cache')

    retval = cache_config.get('backend', 'none')
    return retval
Beispiel #2
0
def get_db(instance_id=None):
    if not instance_id:
        instance_id = getInstanceId()
    # FIXME: USE LOCKING!
    if instance_id not in databases:
        config = Config(instance_id)
        config.set_schema('database', {'dsn': str})
        dsn = config.get('database')['dsn']

        top = time()
        databases[instance_id] = init_db(dsn)
        bottom = time()
        log.info("Initialised database for instance %s in %.2fs" %
                 (instance_id, (bottom - top)))
    return databases[instance_id]
Beispiel #3
0
def get_db(instance_id=None):
    if not instance_id:
        instance_id = getInstanceId()
    # FIXME: USE LOCKING!
    if instance_id not in databases:
        config = Config(instance_id)
        config.set_schema('database', {'dsn': str})
        dsn = config.get('database')['dsn']

        top = time()
        databases[instance_id] = init_db(dsn)
        bottom = time()
        log.info("Initialised database for instance %s in %.2fs" %
                 (instance_id, (bottom - top)))
    return databases[instance_id]
Beispiel #4
0
def get_relay_address_prefix_from_config(configSet, configFileName):
    '''Get the prefix used to mark email addresses to relay from the config.

:param str configSet: The name of the configuration set to look up (see
                      :class:`gs.config.Config`)
:param str configFileName: The name of the configuration file that contains
                           the token.
:return: The address prefix for ``configSet`` in ``configFileName``, or 'p-'
         if absent.
:rtype: ``str``
'''
    config = Config(configSet, configFileName)
    config.set_schema('smtp', {'relay-address-prefix': str})
    ws = config.get('smtp', strict=False)
    retval = ws.get('relay-address-prefix', 'p-')
    return retval
def get_relay_address_prefix_from_config(configSet, configFileName):
    '''Get the prefix used to mark email addresses to relay from the config.

:param str configSet: The name of the configuration set to look up (see
                      :class:`gs.config.Config`)
:param str configFileName: The name of the configuration file that contains
                           the token.
:return: The address prefix for ``configSet`` in ``configFileName``, or 'p-'
         if absent.
:rtype: ``str``
'''
    config = Config(configSet, configFileName)
    config.set_schema('smtp', {'relay-address-prefix': str})
    ws = config.get('smtp', strict=False)
    retval = ws.get('relay-address-prefix', 'p-')
    return retval
Beispiel #6
0
def get_token_from_config(configSet, configFileName):
    '''Get the authentication token from the config.

:param str configSet: The name of the configuration set to look up (see
                      :class:`gs.config.Config`)
:param str configFileName: The name of the configuration file that contains
                           the token.
:return: The authentication token for ``configSet`` in ``configFileName``
:rtype: ``str``
:raises ValueError: The token was not present in ``configSet``.
'''
    config = Config(configSet, configFileName)
    config.set_schema('webservice', {'token': str})
    ws = config.get('webservice')
    retval = ws['token']
    if not retval:
        m = 'The token was not set.'
        raise ValueError(m)
    return retval
def get_token_from_config(configSet, configFileName):
    '''Get the authentication token from the config.

:param str configSet: The name of the configuration set to look up (see
                      :class:`gs.config.Config`)
:param str configFileName: The name of the configuration file that contains
                           the token.
:return: The authentication token for ``configSet`` in ``configFileName``
:rtype: ``str``
:raises ValueError: The token was not present in ``configSet``.
'''
    config = Config(configSet, configFileName)
    config.set_schema('webservice', {'token': str})
    ws = config.get('webservice')
    retval = ws['token']
    if not retval:
        m = 'The token was not set.'
        raise ValueError(m)
    return retval
Beispiel #8
0
    def __init__(self, options):
        
        prefsfile = os.path.abspath(options.preferences)
        messagesfile = os.path.abspath(options.messages)
        settingsfile = os.path.abspath(options.settings)
        plugindir = os.path.abspath(options.plugin_dir)
        disable_plugins = options.disable_plugins

        if not os.path.exists(messagesfile):
            message_dialog("Could not find messages.xml", None, secondary="%s does not exist." % messagesfile)
            sys.exit(1)
        if not os.path.exists(settingsfile):
            message_dialog("Could not find settings.xml", None, secondary="%s does not exist." % settingsfile)
            sys.exit(1)
    
        #connect our log buffer to the python logging subsystem
        self._logbuffer = LogBuffer()
        handler = logging.StreamHandler(self._logbuffer)
        defaultFormatter = logging.Formatter(self._logbuffer.FORMAT)
        handler.setFormatter(defaultFormatter)
        logging.root.addHandler(handler)

        LOG.info("Groundstation loading")
        LOG.info("Restored preferences: %s" % prefsfile)
        LOG.info("Messages file: %s" % messagesfile)
        LOG.info("Settings file: %s" % settingsfile)
        LOG.info("Installed: %d" % gs.IS_INSTALLED)
        LOG.info("Windows: %d" % gs.IS_WINDOWS)

        try:
            GtkBuilderWidget.__init__(self, "groundstation.ui")
        except Exception:
            LOG.critical("Error loading ui file", exc_info=True)
            sys.exit(1)

        icon = get_icon_pixbuf("rocket.svg")
        gtk.window_set_default_icon(icon)

        self._tried_to_connect = False
        self._home_lat = self.CONFIG_LAT_DEFAULT
        self._home_lon = self.CONFIG_LON_DEFAULT
        self._home_zoom = self.CONFIG_ZOOM_DEFAULT

        self.window = self.get_resource("main_window")
        self.window.set_title(gs.NAME)

        self._config = Config(filename=prefsfile)
        ConfigurableIface.__init__(self, self._config)

        self._messagesfile = MessagesFile(path=messagesfile, debug=False)
        self._messagesfile.parse()

        self._settingsfile = SettingsFile(path=settingsfile)

        self._source = UAVSource(self._config, self._messagesfile, options)
        self._source.connect("source-connected", self._on_source_connected)
        self._source.connect("uav-selected", self._on_uav_selected)

        #track the UAVs we have got data from
        self._source.connect("uav-detected", self._on_uav_detected)
        self._uav_detected_model = gtk.ListStore(str,int)
        self._uav_detected_model.append( ("All UAVs", wasp.ACID_ALL) )

        #track the state of a few key variables received from the plane
        self._state = {}
        self._source.register_interest(self._on_gps, 2, "GPS_LLH")

        #All the menus in the UI. Get them the first time a plugin tries to add a submenu
        #to the UI to save startup time.
        self._menus = {
                "File"      :   None,
                "Window"    :   None,
                "Map"       :   None,
                "UAV"       :   None,
                "Help"      :   None,
        }

        self._map = Map(self._config, self._source)
        self._msgarea = MsgAreaController()
        self._sb = StatusBar(self._source)
        self._info = InfoBox(self._source, self._settingsfile)
        self._statusicon = StatusIcon(icon, self._source)

        #raise the window when the status icon clicked
        self._statusicon.connect("activate", lambda si, win: win.present(), self.window)

        self.get_resource("main_left_vbox").pack_start(self._info.widget, False, False)
        self.get_resource("window_vbox").pack_start(self._msgarea, False, False)
        self.get_resource("window_vbox").pack_start(self._sb, False, False)

        #The telemetry tab page
        self.telemetrycontroller = TelemetryController(self._config, self._source, self._messagesfile, self.window)
        self.get_resource("telemetry_hbox").pack_start(self.telemetrycontroller.widget, True, True)

        #The settings tab page
        self.settingscontroller = SettingsController(self._source, self._settingsfile, self._messagesfile)
        self.get_resource("settings_hbox").pack_start(self.settingscontroller.widget, True, True)

        #The command and control tab page
        self.commandcontroller = CommandController(self._source, self._messagesfile, self._settingsfile)
        self.get_resource("command_hbox").pack_start(self.commandcontroller.widget, False, True)
        self.controlcontroller = ControlController(self._source, self._messagesfile, self._settingsfile)
        self.get_resource("control_hbox").pack_start(self.controlcontroller.widget, True, True)
        #Track ok/failed command messages
        self._source.connect("command-ok", self._on_command_ok)
        self._source.connect("command-fail", self._on_command_fail)
        #Track logging of source
        self._source.connect("logging-started", self._on_logging_started)

        #Lazy initialize the following when first needed
        self._plane_view = None
        self._horizon_view = None
        self._prefs_window = None

        #create the map
        self.get_resource("map_holder").add(self._map.get_widget())
        self._map.connect("notify::auto-center", self.on_map_autocenter_property_change)
        self._map.connect("notify::show-trip-history", self.on_map_show_trip_history_property_change)

        #initialize the plugins
        self._plugin_manager = PluginManager(plugindir)
        if not disable_plugins:
            self._plugin_manager.initialize_plugins(self._config, self._source, self._messagesfile, self._settingsfile, self)
    
        #Setup those items which are configurable, or depend on configurable
        #information, and implement config.ConfigurableIface
        self._configurable = [
            self,
            self._source,
            self._map,
            self.telemetrycontroller.graphmanager,
        ]
        #Add those plugins that can also be configured
        self._configurable += self._plugin_manager.get_plugins_implementing_interface(ConfigurableIface)

        for c in self._configurable:
            if c:
                c.update_state_from_config()

        self.get_resource("menu_item_disconnect").set_sensitive(False)
        self.get_resource("menu_item_autopilot_disable").set_sensitive(False)
        self.builder_connect_signals()

        self.window.show_all()
Beispiel #9
0
class Groundstation(GtkBuilderWidget, ConfigurableIface):
    """ The main groundstation window """

    CONFIG_SECTION = "MAIN"

    CONFIG_CONNECT_NAME = "Connect_to_UAV_automatically"
    CONFIG_CONNECT_DEFAULT = "1"
    CONFIG_LAT_DEFAULT = wasp.HOME_LAT
    CONFIG_LON_DEFAULT = wasp.HOME_LON
    CONFIG_ZOOM_DEFAULT = 12

    def __init__(self, options):
        
        prefsfile = os.path.abspath(options.preferences)
        messagesfile = os.path.abspath(options.messages)
        settingsfile = os.path.abspath(options.settings)
        plugindir = os.path.abspath(options.plugin_dir)
        disable_plugins = options.disable_plugins

        if not os.path.exists(messagesfile):
            message_dialog("Could not find messages.xml", None, secondary="%s does not exist." % messagesfile)
            sys.exit(1)
        if not os.path.exists(settingsfile):
            message_dialog("Could not find settings.xml", None, secondary="%s does not exist." % settingsfile)
            sys.exit(1)
    
        #connect our log buffer to the python logging subsystem
        self._logbuffer = LogBuffer()
        handler = logging.StreamHandler(self._logbuffer)
        defaultFormatter = logging.Formatter(self._logbuffer.FORMAT)
        handler.setFormatter(defaultFormatter)
        logging.root.addHandler(handler)

        LOG.info("Groundstation loading")
        LOG.info("Restored preferences: %s" % prefsfile)
        LOG.info("Messages file: %s" % messagesfile)
        LOG.info("Settings file: %s" % settingsfile)
        LOG.info("Installed: %d" % gs.IS_INSTALLED)
        LOG.info("Windows: %d" % gs.IS_WINDOWS)

        try:
            GtkBuilderWidget.__init__(self, "groundstation.ui")
        except Exception:
            LOG.critical("Error loading ui file", exc_info=True)
            sys.exit(1)

        icon = get_icon_pixbuf("rocket.svg")
        gtk.window_set_default_icon(icon)

        self._tried_to_connect = False
        self._home_lat = self.CONFIG_LAT_DEFAULT
        self._home_lon = self.CONFIG_LON_DEFAULT
        self._home_zoom = self.CONFIG_ZOOM_DEFAULT

        self.window = self.get_resource("main_window")
        self.window.set_title(gs.NAME)

        self._config = Config(filename=prefsfile)
        ConfigurableIface.__init__(self, self._config)

        self._messagesfile = MessagesFile(path=messagesfile, debug=False)
        self._messagesfile.parse()

        self._settingsfile = SettingsFile(path=settingsfile)

        self._source = UAVSource(self._config, self._messagesfile, options)
        self._source.connect("source-connected", self._on_source_connected)
        self._source.connect("uav-selected", self._on_uav_selected)

        #track the UAVs we have got data from
        self._source.connect("uav-detected", self._on_uav_detected)
        self._uav_detected_model = gtk.ListStore(str,int)
        self._uav_detected_model.append( ("All UAVs", wasp.ACID_ALL) )

        #track the state of a few key variables received from the plane
        self._state = {}
        self._source.register_interest(self._on_gps, 2, "GPS_LLH")

        #All the menus in the UI. Get them the first time a plugin tries to add a submenu
        #to the UI to save startup time.
        self._menus = {
                "File"      :   None,
                "Window"    :   None,
                "Map"       :   None,
                "UAV"       :   None,
                "Help"      :   None,
        }

        self._map = Map(self._config, self._source)
        self._msgarea = MsgAreaController()
        self._sb = StatusBar(self._source)
        self._info = InfoBox(self._source, self._settingsfile)
        self._statusicon = StatusIcon(icon, self._source)

        #raise the window when the status icon clicked
        self._statusicon.connect("activate", lambda si, win: win.present(), self.window)

        self.get_resource("main_left_vbox").pack_start(self._info.widget, False, False)
        self.get_resource("window_vbox").pack_start(self._msgarea, False, False)
        self.get_resource("window_vbox").pack_start(self._sb, False, False)

        #The telemetry tab page
        self.telemetrycontroller = TelemetryController(self._config, self._source, self._messagesfile, self.window)
        self.get_resource("telemetry_hbox").pack_start(self.telemetrycontroller.widget, True, True)

        #The settings tab page
        self.settingscontroller = SettingsController(self._source, self._settingsfile, self._messagesfile)
        self.get_resource("settings_hbox").pack_start(self.settingscontroller.widget, True, True)

        #The command and control tab page
        self.commandcontroller = CommandController(self._source, self._messagesfile, self._settingsfile)
        self.get_resource("command_hbox").pack_start(self.commandcontroller.widget, False, True)
        self.controlcontroller = ControlController(self._source, self._messagesfile, self._settingsfile)
        self.get_resource("control_hbox").pack_start(self.controlcontroller.widget, True, True)
        #Track ok/failed command messages
        self._source.connect("command-ok", self._on_command_ok)
        self._source.connect("command-fail", self._on_command_fail)
        #Track logging of source
        self._source.connect("logging-started", self._on_logging_started)

        #Lazy initialize the following when first needed
        self._plane_view = None
        self._horizon_view = None
        self._prefs_window = None

        #create the map
        self.get_resource("map_holder").add(self._map.get_widget())
        self._map.connect("notify::auto-center", self.on_map_autocenter_property_change)
        self._map.connect("notify::show-trip-history", self.on_map_show_trip_history_property_change)

        #initialize the plugins
        self._plugin_manager = PluginManager(plugindir)
        if not disable_plugins:
            self._plugin_manager.initialize_plugins(self._config, self._source, self._messagesfile, self._settingsfile, self)
    
        #Setup those items which are configurable, or depend on configurable
        #information, and implement config.ConfigurableIface
        self._configurable = [
            self,
            self._source,
            self._map,
            self.telemetrycontroller.graphmanager,
        ]
        #Add those plugins that can also be configured
        self._configurable += self._plugin_manager.get_plugins_implementing_interface(ConfigurableIface)

        for c in self._configurable:
            if c:
                c.update_state_from_config()

        self.get_resource("menu_item_disconnect").set_sensitive(False)
        self.get_resource("menu_item_autopilot_disable").set_sensitive(False)
        self.builder_connect_signals()

        self.window.show_all()

    def _on_command_ok(self, source, msgid):
        LOG.debug("COMMAND OK (ID: %d)", msgid)

    def _on_command_fail(self, source, msgid, error_msg):
        msg = self._messagesfile.get_message_by_id(msgid)
        self._msgarea.new_from_text_and_icon(
                        "Command Error",
                        "Message %s, %s" % (msg.name, error_msg),
                        message_type=gtk.MESSAGE_ERROR,
                        timeout=5).show_all()

    def _on_uav_detected(self, source, acid):
        self._uav_detected_model.append( ("0x%X" % acid, acid) )

    def _on_uav_selected(self, source, acid):
        self.window.set_title("%s - UAV: 0x%X" % (gs.NAME, acid))

    def _on_gps(self, msg, header, payload):
        fix,sv,lat,lon,hsl,hacc,vacc = msg.unpack_scaled_values(payload)
        if fix:
            self._state["lat"] = lat
            self._state["lon"] = lon
            #convert from mm to m
            self._state["hsl"] = hsl/1000.0

    def _on_source_connected(self, source, connected):
        conn_menu = self.get_resource("menu_item_connect")
        disconn_menu = self.get_resource("menu_item_disconnect")

        if connected:
            conn_menu.set_sensitive(False)
            disconn_menu.set_sensitive(True)

            #request UAV info once connected
            gobject.timeout_add(500, lambda: self._source.refresh_uav_info())
        else:
            disconn_menu.set_sensitive(False)
            conn_menu.set_sensitive(True)

    def _connect(self):
        self._tried_to_connect = True
        self._source.connect_to_uav()

    def _disconnect(self):
        self._source.disconnect_from_uav()

    def _add_submenu(self, name, parent_menu):
        """ adds a submenu of name to parent_menu """
        if name not in self._menus:
            #add a new menu
            menuitem = gtk.MenuItem(name)
            parent_menu.append(menuitem)
            menu = gtk.Menu()
            menuitem.set_submenu(menu)
            self._menus[name] = menu
        return self._menus[name]

    def _get_toplevel_menu(self, name):
        """ gets, or creates a toplevel menu of name """
        if name in self._menus:
            menu = self._menus[name]
            if not menu:
                menu = self.get_resource("%s_menu" % name.lower())
        else:
            menu = self._add_submenu(name, self.get_resource("main_menubar"))

        return menu

    def add_menu_item(self, name, *item):
        """
        Adds an item to the main window menubar. 

        :param name: the name of the top-level menu to add to, e.g. "File". 
                     If a menu of that name does not exist, one is created
        :param item: One or more gtk.MenuItem to add
        """
        menu = self._get_toplevel_menu(name)
        for i in item:
            menu.append(i)

    def add_submenu_item(self, name, submenu_name, *item):
        """
        Adds a submenu and item to the main window menubar.

        :param name: the name of the top-level menu to add to, e.g. "File". 
                     If a menu of that name does not exist, one is created
        :param submenu_name: the name of the submenu to hold the item
        :param item: One or more gtk.MenuItem to add
        """
        menu = self._add_submenu(submenu_name, self._get_toplevel_menu(name))
        for i in item:
            menu.append(i)

    def add_control_widget(self, name, control_widget):
        """
        Adds a control widget to the Command and Control page

        :param name: the name, a string describing the control method, 
                     i.e. 'Joystick'
        :param control_widget: a `gs.ui.control.ControlWidgetIface` that gets placed
                     in the Command and control page of the GUI
        """
        self.controlcontroller.add_control_widget(name, control_widget)

    def update_state_from_config(self):
        self._c = self.config_get(self.CONFIG_CONNECT_NAME, self.CONFIG_CONNECT_DEFAULT)
        if self._c == "1" and not self._tried_to_connect:
            gobject.timeout_add(2000, self._connect)

        try:
            self._home_lat = float(self.config_get("home_lat", self.CONFIG_LAT_DEFAULT))
            self._home_lon = float(self.config_get("home_lon", self.CONFIG_LON_DEFAULT))
            self._home_zoom = float(self.config_get("home_zoom", self.CONFIG_ZOOM_DEFAULT))
        except Exception:
            LOG.critical("Config error reading home position", exc_info=True)

    def update_config_from_state(self):
        self.config_set(self.CONFIG_CONNECT_NAME, self._c)
        self.config_set("home_lat", self._home_lat)
        self.config_set("home_lon", self._home_lon)
        self.config_set("home_zoom", self._home_zoom)

    def get_preference_widgets(self):
        ck = self.build_checkbutton(self.CONFIG_CONNECT_NAME)
        e1 = self.build_entry("home_lat")
        e2 = self.build_entry("home_lon")
        e3 = self.build_entry("home_zoom")

        items = [ck, e1, e2, e3]

        sg = self.build_sizegroup()
        frame = self.build_frame(None, [
            ck,
            self.build_label("Home Latitude", e1, sg=sg),
            self.build_label("Home Longitude", e2, sg=sg),
            self.build_label("Home Zoom", e3, sg=sg)
        ])

        return "Main Window", frame, items

    def on_window_destroy(self, widget):
        for c in self._configurable:
            if c:
                c.update_config_from_state()
        self._config.save()
        self._source.quit()
        gtk.main_quit()

    def on_menu_item_edit_flightplan_activate(self, *args):
        self._map.edit_flightplan()

    def on_menu_item_uav_mark_home_activate(self, *args):
        #get lat, lon from state
        try:
            lat = self._state["lat"]
            lon = self._state["lon"]
            hsl = self._state["hsl"]
            self._map.mark_home(lat,lon)
            self._sb.mark_home(lat, lon)

            #tell the UAV where home is
            self._source.send_message(
                    self._messagesfile.get_message_by_name("MARK_HOME"),
                    (lat,lon,hsl)
            )
        except KeyError:
            msg = self._msgarea.new_from_text_and_icon(
                            "Mark Home Failed",
                            "A GPS location has not been received from the UAV yet",
                            message_type=gtk.MESSAGE_ERROR,
                            timeout=5)
            msg.show_all()

    def _on_logging_started(self, source, loggers):
        msg = self._msgarea.new_from_text_and_icon(
                    "Logging Data Enabled",
                    "Messages will be saved to %s in %s" % (
                        ", ".join(['<a href="file://%s">%s</a>' % (l.logfile,os.path.basename(l.logfile)) for l in loggers]),
                        '<a href="file://%s">%s</a>' % (os.path.dirname(loggers[0].logfile),os.path.basename(os.path.dirname(loggers[0].logfile)))),
                    timeout=5)
        msg.show_all()

    def on_menu_item_log_uav_data_activate(self, *args):
        sw = self.get_resource("log_message_scrolledwindow")
        tv = MessageTreeView(
                self._source.get_rx_message_treestore(),
                editable=False, show_dt=False, show_value=False)
        tv.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        tv.show()
        sw.add(tv)

        w = self.get_resource("logdatadialog")
        w.set_transient_for(self.window)
        w.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        resp = w.run()
        w.hide()

        if resp == gtk.RESPONSE_OK:
            csv = self.get_resource("log_csv_radiobutton")

            messages = [m.name for m in tv.get_all_selected_messages()]
            if messages:
                if csv.get_active():
                    self._source.register_csv_logger(None, *messages)
                else:
                    self._source.register_sqlite_logger(None, *messages)
            else:
                msg = self._msgarea.new_from_text_and_icon(
                            "Logging Data Failed",
                            "You must select messages to be logged",
                            message_type=gtk.MESSAGE_ERROR,
                            timeout=5)
                msg.show_all()

        sw.remove(tv)

    def on_menu_item_export_kml_activate(self, *args):
        path = self._map.save_kml()
        if path:
            msg = self._msgarea.new_from_text_and_icon(
                            "KML Export Successful",
                            'The file has been saved to <a href="file://%s">%s</a>' % (path, path),
                            timeout=5)
        else:
            msg = self._msgarea.new_from_text_and_icon(
                            "KML Export Failed",
                            "You must mark the home position of the flight first.",
                            message_type=gtk.MESSAGE_ERROR,
                            timeout=5)
        msg.show_all()

    def on_menu_item_select_uav_activate(self, *args):
        tv = self.get_resource("treeview_select_uav")
        tv.set_model(self._uav_detected_model)
        dlg = self.get_resource("dialog_select_uav")
        dlg.set_transient_for(self.window)
        dlg.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        resp = dlg.run()
        dlg.hide()

        if resp == gtk.RESPONSE_OK:
            model, iter_ = tv.get_selection().get_selected()
            if iter_:
                acid = model.get_value(iter_, 1)
                self._source.select_uav(acid)

    def on_menu_item_refresh_uav_activate(self, *args):
        self._source.refresh_uav_info()

    def on_menu_item_request_telemetry_activate(self, *args):
        self.telemetrycontroller.request_telemetry()

    def on_menu_item_log_activate(self, widget):
        w = LogWindow(self._logbuffer)
        w.connect("delete-event", gtk.Widget.hide_on_delete)
        w.set_transient_for(self.window)
        w.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        w.show_all()

    def on_menu_item_show_plugins_activate(self, widget):
        def make_model(plugins):
            m = gtk.ListStore(str, str)
            for name,ver in plugins:
                m.append((name,ver))
            return m
        loaded, failed = self._plugin_manager.get_plugin_summary()

        ptv = self.get_resource("plugintreeview")
        ptv.set_model( make_model(loaded) )
        pftv = self.get_resource("pluginfailedtreeview")
        pftv.set_model( make_model(failed) )

        w = self.get_resource("pluginwindow")
        w.connect("delete-event", gtk.Widget.hide_on_delete)
        w.set_transient_for(self.window)
        w.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        w.show_all()

    def on_menu_item_home_activate(self, widget):
        self._map.centre(self._home_lat, self._home_lon, self._home_zoom)

    def on_menu_item_centre_activate(self, widget):
        self._map.centre()

    def on_menu_item_zoom_in_activate(self, widget):
        self._map.set_zoom(self._map.props.zoom+1)

    def on_menu_item_zoom_out_activate(self, widget):
        self._map.set_zoom(self._map.props.zoom-1)    

    def on_menu_item_cache_map_activate(self, widget):
        self._map.show_cache_dialog(self._msgarea)

    def on_menu_item_preferences_activate(self, widget):
        if not self._prefs_window:
            self._prefs_window = ConfigWindow(self.window, self._configurable)

        resp = self._prefs_window.show(self._config)
        #If the user clicked ok to the dialog, update all 
        #objects which are configuration dependant
        if resp == gtk.RESPONSE_ACCEPT:
            for obj in self._configurable:
                obj.update_state_from_config()
            
    def on_menu_item_connect_activate(self, widget):
        self._connect()

    def on_menu_item_disconnect_activate(self, widget):
        self._disconnect()
        
    def on_autopilot_enable_activate(self, widget):
        self.get_resource("menu_item_autopilot_disable").set_sensitive(True)
        self.get_resource("menu_item_autopilot_enable").set_sensitive(False)
    
    def on_autopilot_disable_activate(self, widget):
        self.get_resource("menu_item_autopilot_disable").set_sensitive(False)
        self.get_resource("menu_item_autopilot_enable").set_sensitive(True)
        

    def on_menu_item_about_activate(self, widget):
        dlg = gtk.AboutDialog()
        dlg.set_name("UAV Groundstation")
        dlg.set_authors(("Mark Cottrell", "John Stowers"))
        dlg.set_version("0.2")
        dlg.run()
        dlg.destroy()
        
    def on_menu_item_show_previous_activate(self, widget):
        message_dialog("Not Implemented", self.window)

    def on_menu_item_plane_view_activate(self, widget):
        if self._plane_view == None:
            try:
                from gs.ui.plane import PlaneView
                self._plane_view = PlaneView(self._source)
            except:
                LOG.warning("Could not initialize plane view", exc_info=True)
                return

        self._plane_view.show_all()
        
    def on_menu_item_horizon_view_activate(self, widget):
        if self._horizon_view == None:
            try:
                from gs.ui.horizon import HorizonView
                self._horizon_view = HorizonView(self._source)
            except:
                LOG.warning("Could not initialize horizon view", exc_info=True)
                return

        self._horizon_view.show_all()

    def on_menu_item_clear_path_activate(self, widget):
        self._map.clear_gps()

    def on_menu_item_clear_previous_activate(self, widget):
        self._map.clear_tracks()

    def on_map_autocenter_property_change(self, osm, *args):
        self.get_resource("menu_item_auto_centre").set_active(osm.get_property("auto-center"))
        
    def on_menu_item_auto_centre_toggled(self, widget):
        self._map.props.auto_center = widget.get_active()

    def on_map_show_trip_history_property_change(self, osm, *args):
        self.get_resource("menu_item_show_path").set_active(osm.get_property("show-trip-history"))

    def on_menu_item_show_path_toggled(self, widget):
        self._map.props.show_trip_history = widget.get_active()

    def main(self):
        gtk.main()
Beispiel #10
0
def create_emailUtilities(instance_id=None):
    '''Create the utilities to send the email messages

:param str instance_id: The indentifier for the GroupServer instance
:returns: ``None``

The :func:`create_emailUtilities` function loads the ``smtp`` section of the
configuration of the instance specified by ``instance_id``. If no instance
is specified then :func:`gs.config.getInstanceId` is used to determine the
current instance. It then loads the following configuration options:

* ``hostname``
* ``port``
* ``username``
* ``password``
* ``no_tls``
* ``force_tls``
* ``queuepath``
* ``processorthread``
* ``xverp``

If the XVERP option is ``True`` then
:class:`gs.email.mailer.XVERPSMTPMailer` is registered as the utility used
to connect to the SMTP host; otherwise
:class:`zope.sendmail.mailer.SMTPMailer` is used. In either case the mailer
is configured with the options in the config file.'''
    if not instance_id:
        instance_id = getInstanceId()

    config = Config(instance_id)
    config.set_schema('smtp', {'hostname': str, 'port': int,
                               'username': str, 'password': str,
                               'no_tls': bool_, 'force_tls': bool_,
                               'queuepath': str, 'processorthread': bool_,
                               'xverp': bool_})
    smtpconfig = config.get('smtp', strict=False)
    name = ''
    for key in ('hostname', 'port', 'username', 'password', 'no_tls',
                'force_tls'):
        name += '+%s+' % smtpconfig.get(key, None)

    gsm = getGlobalSiteManager()
    if not queryUtility(IMailer, 'gs.mailer.%s' % name):
        if smtpconfig.get('xverp', False):
            Mailer = XVERPSMTPMailer
        else:
            Mailer = SMTPMailer

        gsm.registerUtility(
            Mailer(
                hostname=smtpconfig.get('hostname', None),
                port=smtpconfig.get('port', None),
                username=smtpconfig.get('username', None),
                password=smtpconfig.get('password', None),
                no_tls=smtpconfig.get('no_tls', None),
                force_tls=smtpconfig.get('force_tls', None)),
            IMailer, name='gs.mailer.%s' % name)
    queuePath = smtpconfig.get('queuepath', '/tmp/mailqueue')
    if not queryUtility(IMailDelivery, name='gs.maildelivery'):
        delivery = QueuedMailDelivery(queuePath)
        gsm.registerUtility(delivery, IMailDelivery, name='gs.maildelivery')
        if smtpconfig.get('processorthread', True):
            mailerObject = getUtility(IMailer, 'gs.mailer.%s' % name)
            thread = QueueProcessorThread()
            thread.setMailer(mailerObject)
            thread.setQueuePath(queuePath)
            thread.start()
Beispiel #11
0
    def __init__(self, options, show_tabs=False):

        prefsfile = os.path.abspath(options.preferences)
        messagesfile = os.path.abspath(options.messages)
        settingsfile = os.path.abspath(options.settings)
        plugindir = os.path.abspath(options.plugin_dir)
        disable_plugins = options.disable_plugins

        if not os.path.exists(messagesfile):
            message_dialog("Could not find messages.xml", None, secondary=gs.CONFIG_DIR)
            sys.exit(1)
        if not os.path.exists(settingsfile):
            message_dialog("Could not find settings.xml", None, secondary=gs.CONFIG_DIR)
            sys.exit(1)

        LOG.info("Groundstation loading")
        LOG.info("Restored preferences: %s" % prefsfile)
        LOG.info("Messages file: %s" % messagesfile)
        LOG.info("Settings file: %s" % settingsfile)

        self._messagesfile = MessagesFile(path=messagesfile, debug=False)
        self._messagesfile.parse()

        self._settingsfile = SettingsFile(path=settingsfile)

        self._config = Config(filename=prefsfile)
        ConfigurableIface.__init__(self, self._config)
        self.autobind_config("command_button","enabled_plugins")

        self._source = UAVSource(self._config, self._messagesfile, options)
        self._tm = TabletGraphManager(self._config, self._source, self._messagesfile, self)

        self._plugin_manager = PluginManager(plugindir, plugin_whitelist=self._enabled_plugins)
        if not disable_plugins:
            self._plugin_manager.initialize_plugins(self._config, self._source, self._messagesfile, self._settingsfile, self)

        self._in_fullscreen = False

        if HILDON_AVAILABLE:
            self._win = hildon.Window()
            self._win.fullscreen()
            self._win.connect("key-press-event", self._on_hildon_key_press)
        else:
            self._win = gtk.Window()
            self._win.set_default_size(800, 480)

        self._win.set_title("Wasp Groundstation")
        self._win.connect("window-state-event", self._on_window_state_change)
        self._win.connect("destroy", self._on_close)

        vb = gtk.VBox(spacing=5)
        self._notebook = gtk.Notebook()
        if not show_tabs:
            self._notebook.set_show_tabs(False)

        self._bb = gtk.HBox()

        vb.pack_start(self._notebook, expand=True, fill=True)
        vb.pack_start(self._bb, expand=False, fill=True)
        self._win.add(vb)

        self.add_page(
                "Status",
                self.make_status_page(show_uav_info=True, show_build=True, show_comm_status=True))
        self.add_page(
                "Telemetry",
                self.make_telemetry_page())

        self._configurable = [
            self._source,
            self._tm,
        ]
        for c in self._configurable:
            if c:
                c.update_state_from_config()

        gobject.timeout_add(2000, lambda: self._source.connect_to_uav())
        gobject.timeout_add(3000, lambda: self._source.refresh_uav_info())

        self._win.show_all()
Beispiel #12
0
class UI(ConfigurableIface):

    CONFIG_SECTION = "MAIN"

    DEFAULT_COMMAND_BUTTON = "BOMB_DROP"
    DEFAULT_ENABLED_PLUGINS = "none"

    def __init__(self, options, show_tabs=False):

        prefsfile = os.path.abspath(options.preferences)
        messagesfile = os.path.abspath(options.messages)
        settingsfile = os.path.abspath(options.settings)
        plugindir = os.path.abspath(options.plugin_dir)
        disable_plugins = options.disable_plugins

        if not os.path.exists(messagesfile):
            message_dialog("Could not find messages.xml", None, secondary=gs.CONFIG_DIR)
            sys.exit(1)
        if not os.path.exists(settingsfile):
            message_dialog("Could not find settings.xml", None, secondary=gs.CONFIG_DIR)
            sys.exit(1)

        LOG.info("Groundstation loading")
        LOG.info("Restored preferences: %s" % prefsfile)
        LOG.info("Messages file: %s" % messagesfile)
        LOG.info("Settings file: %s" % settingsfile)

        self._messagesfile = MessagesFile(path=messagesfile, debug=False)
        self._messagesfile.parse()

        self._settingsfile = SettingsFile(path=settingsfile)

        self._config = Config(filename=prefsfile)
        ConfigurableIface.__init__(self, self._config)
        self.autobind_config("command_button","enabled_plugins")

        self._source = UAVSource(self._config, self._messagesfile, options)
        self._tm = TabletGraphManager(self._config, self._source, self._messagesfile, self)

        self._plugin_manager = PluginManager(plugindir, plugin_whitelist=self._enabled_plugins)
        if not disable_plugins:
            self._plugin_manager.initialize_plugins(self._config, self._source, self._messagesfile, self._settingsfile, self)

        self._in_fullscreen = False

        if HILDON_AVAILABLE:
            self._win = hildon.Window()
            self._win.fullscreen()
            self._win.connect("key-press-event", self._on_hildon_key_press)
        else:
            self._win = gtk.Window()
            self._win.set_default_size(800, 480)

        self._win.set_title("Wasp Groundstation")
        self._win.connect("window-state-event", self._on_window_state_change)
        self._win.connect("destroy", self._on_close)

        vb = gtk.VBox(spacing=5)
        self._notebook = gtk.Notebook()
        if not show_tabs:
            self._notebook.set_show_tabs(False)

        self._bb = gtk.HBox()

        vb.pack_start(self._notebook, expand=True, fill=True)
        vb.pack_start(self._bb, expand=False, fill=True)
        self._win.add(vb)

        self.add_page(
                "Status",
                self.make_status_page(show_uav_info=True, show_build=True, show_comm_status=True))
        self.add_page(
                "Telemetry",
                self.make_telemetry_page())

        self._configurable = [
            self._source,
            self._tm,
        ]
        for c in self._configurable:
            if c:
                c.update_state_from_config()

        gobject.timeout_add(2000, lambda: self._source.connect_to_uav())
        gobject.timeout_add(3000, lambda: self._source.refresh_uav_info())

        self._win.show_all()

    def main(self):
        gtk.main()

    def make_status_page(self, show_uav_info=True, show_build=False, show_comm_status=False):
        #hbox for info pages
        ihb = gtk.HBox(homogeneous=True, spacing=5)
        if show_uav_info:
            info = InfoBox(self._source, self._settingsfile, show_images=False, show_build=False, show_comm_status=False)
            ihb.pack_start(info.widget)
        if show_build or show_comm_status:
            vb = gtk.VBox(spacing=5)
            if show_build:
                info = InfoBox(self._source, self._settingsfile, show_images=False, show_uav_status=False, show_build=True, show_comm_status=False)
                vb.pack_start(info.widget, False, False)
            if show_comm_status:
                info = InfoBox(self._source, self._settingsfile, show_images=False, show_uav_status=False, show_build=False, show_comm_status=True)
                vb.pack_start(info.widget, False, False)
            ihb.pack_start(vb, False, True)

        #buttons
        vb = gtk.VButtonBox()
        vb.set_layout(gtk.BUTTONBOX_START)

        b = gtk.Button(stock=gtk.STOCK_CONNECT)
        b.connect("clicked", lambda btn,source: source.connect_to_uav(), self._source)
        vb.pack_start(b)
        b = gtk.Button(stock=gtk.STOCK_DISCONNECT)
        b.connect("clicked", lambda btn,source: source.disconnect_from_uav(), self._source)
        vb.pack_start(b)
        mb = RequestMessageButton(self._messagesfile, "BUILD_INFO", gtk.Button(stock=gtk.STOCK_REFRESH))
        mb.connect("send-message", lambda mb, msg, vals, source: source.send_message(msg, vals), self._source)
        vb.pack_start(mb)
        #custom command buttons
        for name in self._command_button.split(","):
            LOG.info("Adding custom command button: %s" % name)
            msg = self._messagesfile.get_message_by_name(name)
            b = gtk.Button(msg.pretty_name)
            b.connect("clicked", lambda b,s,c,: s.send_command(c, ()), self._source, msg)
            vb.pack_start(b)

        #hb contains info and buttons
        hb = gtk.HBox(spacing=5)
        hb.pack_start(ihb, True, True)
        hb.pack_start(vb, False, False)

        return hb

    def _on_graph_clicked(self, btn, rxtv):
        field = rxtv.get_selected_field()
        msg = rxtv.get_selected_message()
        if field and msg:
            self._tm.add_graph(msg, field)

    def _on_request_telemetry(self, btn):
        def _request_clicked(_rm, _msg, _vals, _source, _dlg):
            _source.send_message(_msg, _vals)
            _dlg.response(gtk.RESPONSE_OK)

        dlg = gtk.Dialog(
                    title="Requrest Telemetry",
                    parent=self._win)

        rm = RequestTelemetrySender(self._messagesfile)
        rm.connect("send-message", _request_clicked, self._source, dlg)
        dlg.vbox.pack_start(rm, False, False)

        dlg.show_all()
        dlg.run()
        dlg.destroy()

    def make_telemetry_page(self):
        rxts = self._source.get_rx_message_treestore()
        if not rxts:
            LOG.critical("Could not get RX treestore")
            return

        vb = gtk.VBox()
        rxtv = MessageTreeView(rxts, editable=False, show_dt=True)
        vb.pack_start(rxtv, expand=True, fill=True)

        b = gs.ui.get_button("Graph Selected", image_stock=gtk.STOCK_ADD)
        b.connect("clicked", self._on_graph_clicked, rxtv)
        vb.pack_start(b, expand=False, fill=True)

        b = gs.ui.get_button("Request Telemetry", image_stock=gtk.STOCK_INFO)
        b.connect("clicked", self._on_request_telemetry)
        vb.pack_start(b, expand=False, fill=True)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.add_with_viewport(vb)

        return sw

    def _on_close(self, *args):
        for c in self._configurable:
            if c:
                c.update_config_from_state()
        self._config.save()
        self._source.quit()
        gtk.main_quit()


    def _on_hildon_key_press(self, widget, event, *args):
        if event.keyval == gtk.keysyms.F6:
            # The "Full screen" hardware key has been pressed
            if self._in_fullscreen:
                self._win.unfullscreen()
            else:
                self._win.fullscreen()

    def _on_window_state_change(self, widget, event, *args):
        if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
            self._in_fullscreen = True
        else:
            self._in_fullscreen = False

    def _on_button_clicked(self, btn, page):
        self._notebook.set_current_page(
                self._notebook.page_num(page))

    def add_page(self, pagename, page):
        b = gtk.Button(label=pagename)
        b.connect("clicked", self._on_button_clicked, page)
        b.show()
        page.set_data("BUTTON", b)
        self._notebook.append_page(page)
        self._bb.pack_start(b)

    def remove_page(self, page):
        i = self._notebook.page_num(page)
        if i == -1:
            LOG.critical("Could not find page to remove")
            return

        self._notebook.remove_page(i)
        #remove the button too
        b = page.get_data("BUTTON")
        self._bb.remove(b)
        page.set_data("BUTTON", None)
        self._notebook.set_current_page(0)
Beispiel #13
0
    def __init__(self, options, show_tabs=False):

        prefsfile = os.path.abspath(options.preferences)
        messagesfile = os.path.abspath(options.messages)
        settingsfile = os.path.abspath(options.settings)
        plugindir = os.path.abspath(options.plugin_dir)
        disable_plugins = options.disable_plugins

        if not os.path.exists(messagesfile):
            message_dialog("Could not find messages.xml",
                           None,
                           secondary=gs.CONFIG_DIR)
            sys.exit(1)
        if not os.path.exists(settingsfile):
            message_dialog("Could not find settings.xml",
                           None,
                           secondary=gs.CONFIG_DIR)
            sys.exit(1)

        LOG.info("Groundstation loading")
        LOG.info("Restored preferences: %s" % prefsfile)
        LOG.info("Messages file: %s" % messagesfile)
        LOG.info("Settings file: %s" % settingsfile)

        self._messagesfile = MessagesFile(path=messagesfile, debug=False)
        self._messagesfile.parse()

        self._settingsfile = SettingsFile(path=settingsfile)

        self._config = Config(filename=prefsfile)
        ConfigurableIface.__init__(self, self._config)
        self.autobind_config("command_button", "enabled_plugins")

        self._source = UAVSource(self._config, self._messagesfile, options)
        self._tm = TabletGraphManager(self._config, self._source,
                                      self._messagesfile, self)

        self._plugin_manager = PluginManager(
            plugindir, plugin_whitelist=self._enabled_plugins)
        if not disable_plugins:
            self._plugin_manager.initialize_plugins(self._config, self._source,
                                                    self._messagesfile,
                                                    self._settingsfile, self)

        self._in_fullscreen = False

        if HILDON_AVAILABLE:
            self._win = hildon.Window()
            self._win.fullscreen()
            self._win.connect("key-press-event", self._on_hildon_key_press)
        else:
            self._win = gtk.Window()
            self._win.set_default_size(800, 480)

        self._win.set_title("Wasp Groundstation")
        self._win.connect("window-state-event", self._on_window_state_change)
        self._win.connect("destroy", self._on_close)

        vb = gtk.VBox(spacing=5)
        self._notebook = gtk.Notebook()
        if not show_tabs:
            self._notebook.set_show_tabs(False)

        self._bb = gtk.HBox()

        vb.pack_start(self._notebook, expand=True, fill=True)
        vb.pack_start(self._bb, expand=False, fill=True)
        self._win.add(vb)

        self.add_page(
            "Status",
            self.make_status_page(show_uav_info=True,
                                  show_build=True,
                                  show_comm_status=True))
        self.add_page("Telemetry", self.make_telemetry_page())

        self._configurable = [
            self._source,
            self._tm,
        ]
        for c in self._configurable:
            if c:
                c.update_state_from_config()

        gobject.timeout_add(2000, lambda: self._source.connect_to_uav())
        gobject.timeout_add(3000, lambda: self._source.refresh_uav_info())

        self._win.show_all()
Beispiel #14
0
class UI(ConfigurableIface):

    CONFIG_SECTION = "MAIN"

    DEFAULT_COMMAND_BUTTON = "BOMB_DROP"
    DEFAULT_ENABLED_PLUGINS = "none"

    def __init__(self, options, show_tabs=False):

        prefsfile = os.path.abspath(options.preferences)
        messagesfile = os.path.abspath(options.messages)
        settingsfile = os.path.abspath(options.settings)
        plugindir = os.path.abspath(options.plugin_dir)
        disable_plugins = options.disable_plugins

        if not os.path.exists(messagesfile):
            message_dialog("Could not find messages.xml",
                           None,
                           secondary=gs.CONFIG_DIR)
            sys.exit(1)
        if not os.path.exists(settingsfile):
            message_dialog("Could not find settings.xml",
                           None,
                           secondary=gs.CONFIG_DIR)
            sys.exit(1)

        LOG.info("Groundstation loading")
        LOG.info("Restored preferences: %s" % prefsfile)
        LOG.info("Messages file: %s" % messagesfile)
        LOG.info("Settings file: %s" % settingsfile)

        self._messagesfile = MessagesFile(path=messagesfile, debug=False)
        self._messagesfile.parse()

        self._settingsfile = SettingsFile(path=settingsfile)

        self._config = Config(filename=prefsfile)
        ConfigurableIface.__init__(self, self._config)
        self.autobind_config("command_button", "enabled_plugins")

        self._source = UAVSource(self._config, self._messagesfile, options)
        self._tm = TabletGraphManager(self._config, self._source,
                                      self._messagesfile, self)

        self._plugin_manager = PluginManager(
            plugindir, plugin_whitelist=self._enabled_plugins)
        if not disable_plugins:
            self._plugin_manager.initialize_plugins(self._config, self._source,
                                                    self._messagesfile,
                                                    self._settingsfile, self)

        self._in_fullscreen = False

        if HILDON_AVAILABLE:
            self._win = hildon.Window()
            self._win.fullscreen()
            self._win.connect("key-press-event", self._on_hildon_key_press)
        else:
            self._win = gtk.Window()
            self._win.set_default_size(800, 480)

        self._win.set_title("Wasp Groundstation")
        self._win.connect("window-state-event", self._on_window_state_change)
        self._win.connect("destroy", self._on_close)

        vb = gtk.VBox(spacing=5)
        self._notebook = gtk.Notebook()
        if not show_tabs:
            self._notebook.set_show_tabs(False)

        self._bb = gtk.HBox()

        vb.pack_start(self._notebook, expand=True, fill=True)
        vb.pack_start(self._bb, expand=False, fill=True)
        self._win.add(vb)

        self.add_page(
            "Status",
            self.make_status_page(show_uav_info=True,
                                  show_build=True,
                                  show_comm_status=True))
        self.add_page("Telemetry", self.make_telemetry_page())

        self._configurable = [
            self._source,
            self._tm,
        ]
        for c in self._configurable:
            if c:
                c.update_state_from_config()

        gobject.timeout_add(2000, lambda: self._source.connect_to_uav())
        gobject.timeout_add(3000, lambda: self._source.refresh_uav_info())

        self._win.show_all()

    def main(self):
        gtk.main()

    def make_status_page(self,
                         show_uav_info=True,
                         show_build=False,
                         show_comm_status=False):
        #hbox for info pages
        ihb = gtk.HBox(homogeneous=True, spacing=5)
        if show_uav_info:
            info = InfoBox(self._source,
                           self._settingsfile,
                           show_images=False,
                           show_build=False,
                           show_comm_status=False)
            ihb.pack_start(info.widget)
        if show_build or show_comm_status:
            vb = gtk.VBox(spacing=5)
            if show_build:
                info = InfoBox(self._source,
                               self._settingsfile,
                               show_images=False,
                               show_uav_status=False,
                               show_build=True,
                               show_comm_status=False)
                vb.pack_start(info.widget, False, False)
            if show_comm_status:
                info = InfoBox(self._source,
                               self._settingsfile,
                               show_images=False,
                               show_uav_status=False,
                               show_build=False,
                               show_comm_status=True)
                vb.pack_start(info.widget, False, False)
            ihb.pack_start(vb, False, True)

        #buttons
        vb = gtk.VButtonBox()
        vb.set_layout(gtk.BUTTONBOX_START)

        b = gtk.Button(stock=gtk.STOCK_CONNECT)
        b.connect("clicked", lambda btn, source: source.connect_to_uav(),
                  self._source)
        vb.pack_start(b)
        b = gtk.Button(stock=gtk.STOCK_DISCONNECT)
        b.connect("clicked", lambda btn, source: source.disconnect_from_uav(),
                  self._source)
        vb.pack_start(b)
        mb = RequestMessageButton(self._messagesfile, "BUILD_INFO",
                                  gtk.Button(stock=gtk.STOCK_REFRESH))
        mb.connect(
            "send-message",
            lambda mb, msg, vals, source: source.send_message(msg, vals),
            self._source)
        vb.pack_start(mb)
        #custom command buttons
        for name in self._command_button.split(","):
            LOG.info("Adding custom command button: %s" % name)
            msg = self._messagesfile.get_message_by_name(name)
            b = gtk.Button(msg.pretty_name)
            b.connect("clicked", lambda b, s, c, : s.send_command(c, ()),
                      self._source, msg)
            vb.pack_start(b)

        #hb contains info and buttons
        hb = gtk.HBox(spacing=5)
        hb.pack_start(ihb, True, True)
        hb.pack_start(vb, False, False)

        return hb

    def _on_graph_clicked(self, btn, rxtv):
        field = rxtv.get_selected_field()
        msg = rxtv.get_selected_message()
        if field and msg:
            self._tm.add_graph(msg, field)

    def _on_request_telemetry(self, btn):
        def _request_clicked(_rm, _msg, _vals, _source, _dlg):
            _source.send_message(_msg, _vals)
            _dlg.response(gtk.RESPONSE_OK)

        dlg = gtk.Dialog(title="Requrest Telemetry", parent=self._win)

        rm = RequestTelemetrySender(self._messagesfile)
        rm.connect("send-message", _request_clicked, self._source, dlg)
        dlg.vbox.pack_start(rm, False, False)

        dlg.show_all()
        dlg.run()
        dlg.destroy()

    def make_telemetry_page(self):
        rxts = self._source.get_rx_message_treestore()
        if not rxts:
            LOG.critical("Could not get RX treestore")
            return

        vb = gtk.VBox()
        rxtv = MessageTreeView(rxts, editable=False, show_dt=True)
        vb.pack_start(rxtv, expand=True, fill=True)

        b = gs.ui.get_button("Graph Selected", image_stock=gtk.STOCK_ADD)
        b.connect("clicked", self._on_graph_clicked, rxtv)
        vb.pack_start(b, expand=False, fill=True)

        b = gs.ui.get_button("Request Telemetry", image_stock=gtk.STOCK_INFO)
        b.connect("clicked", self._on_request_telemetry)
        vb.pack_start(b, expand=False, fill=True)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.add_with_viewport(vb)

        return sw

    def _on_close(self, *args):
        for c in self._configurable:
            if c:
                c.update_config_from_state()
        self._config.save()
        self._source.quit()
        gtk.main_quit()

    def _on_hildon_key_press(self, widget, event, *args):
        if event.keyval == gtk.keysyms.F6:
            # The "Full screen" hardware key has been pressed
            if self._in_fullscreen:
                self._win.unfullscreen()
            else:
                self._win.fullscreen()

    def _on_window_state_change(self, widget, event, *args):
        if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
            self._in_fullscreen = True
        else:
            self._in_fullscreen = False

    def _on_button_clicked(self, btn, page):
        self._notebook.set_current_page(self._notebook.page_num(page))

    def add_page(self, pagename, page):
        b = gtk.Button(label=pagename)
        b.connect("clicked", self._on_button_clicked, page)
        b.show()
        page.set_data("BUTTON", b)
        self._notebook.append_page(page)
        self._bb.pack_start(b)

    def remove_page(self, page):
        i = self._notebook.page_num(page)
        if i == -1:
            LOG.critical("Could not find page to remove")
            return

        self._notebook.remove_page(i)
        #remove the button too
        b = page.get_data("BUTTON")
        self._bb.remove(b)
        page.set_data("BUTTON", None)
        self._notebook.set_current_page(0)