Beispiel #1
0
    def show_devices(self):
        self._label.hide()

        if self.devicesview == None:
            self.devicesview = Gtk.TreeView.new_with_model(self.deviceslist)
            self.devicesview.get_selection().connect("changed",
                self.on_device_selection_changed)

            cell_name = Gtk.CellRendererText()
            col_name = Gtk.TreeViewColumn(_("Name"))
            col_name.pack_start(cell_name, True)
            col_name.set_cell_data_func(cell_name, self.name_data_func, None)
            self.devicesview.append_column(col_name)

            cell_type = Gtk.CellRendererText()
            col_type = Gtk.TreeViewColumn(_("Type"))
            col_type.pack_start(cell_type, True)
            col_type.add_attribute(cell_type, "text", 1)
            self.devicesview.append_column(col_type)

            scrolledview = Gtk.ScrolledWindow()
            scrolledview.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
            scrolledview.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
            scrolledview.add(self.devicesview)
            scrolledview.show_all()

            text = "<b>%s</b>" % _("Select the device you want to configure.")
            self.frame = BaseFrame(text, scrolledview)
            self.frame.show()
            self.pack_start(self.frame, True, True, 0)

        self.devicesview.grab_focus()

        if len(self.deviceslist) == 1:
            self.emit("next-page")
Beispiel #2
0
    def __init__(self, parent, model, device_type):
        Gtk.Dialog.__init__(self,
                            title=_("Add to Group"),
                            parent=parent,
                            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
                                     Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.__selected_group = None
        self.set_border_width(5)

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=12)
        self.vbox_main.set_border_width(5)
        self.vbox_main.show()
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        groupbox = Gtk.Box(spacing=18)
        groupbox.show()

        group_frame = BaseFrame("<b>%s</b>" % _("Add Device to Group"),
                                groupbox)
        group_frame.show()
        self.vbox_main.pack_start(group_frame, True, True, 0)

        group_label = TextFieldLabel()
        group_label.show()
        group_label.set_markup_with_mnemonic(_("_Group:"))
        groupbox.pack_start(group_label, False, False, 0)

        self.groups = Gtk.ListStore(str, GObject.TYPE_PYOBJECT)

        combo = Gtk.ComboBox.new_with_model(self.groups)
        combo.connect("changed", self.on_combo_changed)
        cell = Gtk.CellRendererText()
        combo.pack_start(cell, True)
        combo.add_attribute(cell, "text", 0)
        combo.show()
        group_label.set_mnemonic_widget(combo)
        groupbox.pack_start(combo, True, True, 0)

        def append_groups(groups):
            for group in groups:
                if group.get_type() == device_type:
                    name = group["name"]
                    if name == "":
                        name = "Group %d" % group["id"]
                    self.groups.append([name, group])

        model.get_registered_device_groups(result_handler=append_groups)
Beispiel #3
0
    def __init__(self, parent, model, device_type):
        Gtk.Dialog.__init__(self, title=_("Add to Group"), parent=parent,
            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
                      Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.__selected_group = None
        self.set_border_width(5)

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        self.vbox_main.set_border_width(5)
        self.vbox_main.show()
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        groupbox = Gtk.Box(spacing=18)
        groupbox.show()

        group_frame = BaseFrame("<b>%s</b>" % _("Add Device to Group"), groupbox)
        group_frame.show()
        self.vbox_main.pack_start(group_frame, True, True, 0)

        group_label = TextFieldLabel()
        group_label.show()
        group_label.set_markup_with_mnemonic(_("_Group:"))
        groupbox.pack_start(group_label, False, False, 0)

        self.groups = Gtk.ListStore(str, GObject.TYPE_PYOBJECT)

        combo = Gtk.ComboBox.new_with_model(self.groups)
        combo.connect("changed", self.on_combo_changed)
        cell = Gtk.CellRendererText()
        combo.pack_start(cell, True)
        combo.add_attribute(cell, "text", 0)
        combo.show()
        group_label.set_mnemonic_widget(combo)
        groupbox.pack_start(combo, True, True, 0)

        def append_groups(groups):
            for group in groups:
                if group.get_type() == device_type:
                    name = group["name"]
                    if name == "":
                        name = "Group %d" % group["id"]
                    self.groups.append([name, group])
        model.get_registered_device_groups(result_handler=append_groups)
Beispiel #4
0
    def __init__(self, parent):
        Gtk.Dialog.__init__(self, title=_("Create new Group"),
            parent=parent,
            flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
                      Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.set_default_size(400, 150)
        self.set_border_width(5)

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        self.vbox_main.set_border_width(5)
        self.vbox_main.show()
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        self.table = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL)
        self.table.set_column_spacing(18)
        self.table.set_row_spacing(6)
        self.table.show()

        general_frame = BaseFrame("<b>%s</b>" % _("General"), self.table)
        general_frame.show()
        self.vbox_main.pack_start(general_frame, True, True, 0)

        name = TextFieldLabel()
        name.set_markup_with_mnemonic(_("_Name:"))
        name.show()

        self.name_entry = Gtk.Entry(hexpand=True)
        self.name_entry.show()
        name.set_mnemonic_widget(self.name_entry)

        self.table.add(name)
        self.table.attach_next_to(self.name_entry, name, Gtk.PositionType.RIGHT, 1, 1)

        self.channels = TextFieldLabel()
        self.channels.set_markup_with_mnemonic(_("Channels _file:"))
        self.channels.show()

        self.channelsbox = Gtk.Box(spacing=6, hexpand=True)
        self.channelsbox.show()

        self.channels_entry = Gtk.Entry()
        self.channels_entry.set_editable(False)
        self.channels_entry.show()
        self.channelsbox.pack_start(self.channels_entry, True, True, 0)
        self.channels.set_mnemonic_widget(self.channels_entry)

        channels_open = Gtk.Button(stock=Gtk.STOCK_OPEN)
        channels_open.connect("clicked", self._on_channels_open_clicked)
        channels_open.show()
        self.channelsbox.pack_start(channels_open, False, False, 0)

        self.table.add(self.channels)
        self.table.attach_next_to(self.channelsbox, self.channels, Gtk.PositionType.RIGHT, 1, 1)

        recbox = Gtk.Box(spacing=18)
        recbox.show()

        recordings_frame = BaseFrame("<b>%s</b>" % _("Recordings"), recbox)
        recordings_frame.show()
        self.vbox_main.pack_start(recordings_frame, True, True, 0)

        recordings = TextFieldLabel()
        recordings.set_markup_with_mnemonic(_("_Directory:"))
        recordings.show()
        recbox.pack_start(recordings, False, True, 0)

        recentrybox = Gtk.Box(spacing=6)
        recentrybox.show()
        recbox.pack_start(recentrybox, True, True, 0)

        self.recordings_entry = Gtk.Entry()
        self.recordings_entry.set_editable(False)
        self.recordings_entry.show()
        recentrybox.pack_start(self.recordings_entry, True, True, 0)
        recordings.set_mnemonic_widget(self.recordings_entry)

        recordings_open = Gtk.Button(stock=Gtk.STOCK_OPEN)
        recordings_open.connect("clicked", self._on_recordings_open_clicked)
        recordings_open.show()
        recentrybox.pack_start(recordings_open, False, False, 0)
Beispiel #5
0
class AdaptersPage(BasePage):

    __gsignals__ = {
        "finished": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, [bool]),
        "next-page": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, []),
    }

    def __init__(self, model):
        BasePage.__init__(self)

        self.__adapter_info = None
        self.__use_configured = True
        self.__model = model
        self._progressbar = None
        self._progressbar_timer = None
        self.devicesview = None
        self.frame = None

        # Name, Type Name, Type, adapter, frontend, registered
        self.deviceslist = Gtk.ListStore(str, str, int, int, int, bool)

    def show_no_devices(self):
        if self.frame:
            self.frame.hide()

        text = "<big><span weight=\"bold\">%s</span></big>" % _('No devices have been found.')
        text += "\n\n"
        text += _('Either no DVB cards are installed or all cards are busy. In the latter case make sure you close all programs such as video players that access your DVB card.')
        self._label.set_markup (text)
        self._label.show()

    def show_devices(self):
        self._label.hide()

        if self.devicesview == None:
            self.devicesview = Gtk.TreeView.new_with_model(self.deviceslist)
            self.devicesview.get_selection().connect("changed",
                self.on_device_selection_changed)

            cell_name = Gtk.CellRendererText()
            col_name = Gtk.TreeViewColumn(_("Name"))
            col_name.pack_start(cell_name, True)
            col_name.set_cell_data_func(cell_name, self.name_data_func, None)
            self.devicesview.append_column(col_name)

            cell_type = Gtk.CellRendererText()
            col_type = Gtk.TreeViewColumn(_("Type"))
            col_type.pack_start(cell_type, True)
            col_type.add_attribute(cell_type, "text", 1)
            self.devicesview.append_column(col_type)

            scrolledview = Gtk.ScrolledWindow()
            scrolledview.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
            scrolledview.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
            scrolledview.add(self.devicesview)
            scrolledview.show_all()

            text = "<b>%s</b>" % _("Select the device you want to configure.")
            self.frame = BaseFrame(text, scrolledview)
            self.frame.show()
            self.pack_start(self.frame, True, True, 0)

        self.devicesview.grab_focus()

        if len(self.deviceslist) == 1:
            self.emit("next-page")

    def show_all_configured(self):
        if self.frame:
            self.frame.hide()

        text = "<big><span weight=\"bold\">%s</span></big>" % _('All devices are already configured.')
        text += "\n\n"
        text += _('Go to the control center if you want to alter the settings of already configured devices.')
        self._label.set_markup (text)
        self._label.show()

    def show_error(self, error):
        if self.frame:
            self.frame.hide()

        text = "<big><span weight=\"bold\">%s</span></big>" % _('An error occurred while retrieving devices.')
        text += "\n\n"
        text += _("Make sure other applications don't access DVB devices and you have permissions to access them.")
        text += "\n\n"
        text += _('The detailed error message is:')
        text += "\n<i>%s</i>" % error
        self._label.set_selectable(True)
        self._label.set_markup (text)
        self._label.show()

    def show_progressbar(self):
        self._label.hide()
        self._progressbar = Gtk.ProgressBar()
        self._progressbar.set_text(_("Searching for devices"))
        self._progressbar.set_fraction(0.1)
        self._progressbar.show()
        self.pack_start(self._progressbar, False, True, 0)
        self._progressbar_timer = GLib.timeout_add(100, self.progressbar_pulse, None)

    def destroy_progressbar(self):
        GLib.source_remove(self._progressbar_timer)
        self._progressbar_timer = None
        self._progressbar.destroy()

    def progressbar_pulse(self, user_data):
        self._progressbar.pulse()
        return True

    def get_page_title(self):
        return _("Device selection")

    def display_configured(self, val):
        self.__use_configured = val

    def get_selected_device(self):
        model, aiter = self.devicesview.get_selection().get_selected()
        if aiter != None:
            return None
        else:
            return model[aiter]

    def get_adapter_info(self):
        if self.__adapter_info == None and len(self.deviceslist) == 1:
            aiter = self.deviceslist.get_iter_first()
            self.__adapter_info = {"name": self.deviceslist[aiter][0],
                                   "type": self.deviceslist[aiter][2],
                                   "adapter": self.deviceslist[aiter][3],
                                   "frontend": self.deviceslist[aiter][4],
                                   "registered": self.deviceslist[aiter][5],}
        return self.__adapter_info

    def run(self):
        """
        Retrieves registered and unregistered devices
        and sets the contents of the page
        """
        def registered_handler(devgroups):
            for group in devgroups:
                for dev in group["devices"]:
                    dev.type_name = DVB_TYPE_TO_DESC[dev.type]
                    dev.registered = True
                    registered.add(dev)
            self.__model.get_all_devices(result_handler=devices_handler)

        def devices_handler(devices):
            error = None
            for dev in devices:
                if dev not in registered:
                    success, info = gnomedvb.get_adapter_info(dev.adapter,
                        dev.frontend)
                    if success:
                        if info["type_t"]:
                            dev_t = copy.copy(dev)
                            dev_t.name = info["name"]
                            dev_t.type = GROUP_TERRESTRIAL
                            if dev_t.type in DVB_TYPE_TO_DESC:
                                dev_t.type_name = DVB_TYPE_TO_DESC[dev_t.type]
                            else:
                                dev_t.type_name = "Unknown"
                            dev_t.registered = False
                            unregistered.add(dev_t)
                        if info["type_s"]:
                            dev_s = copy.copy(dev)
                            dev_s.name = info["name"]
                            dev_s.type = GROUP_SATELLITE
                            if dev_s.type in DVB_TYPE_TO_DESC:
                                dev_s.type_name = DVB_TYPE_TO_DESC[dev_s.type]
                            else:
                                dev_s.type_name = "Unknown"
                            dev_s.registered = False
                            unregistered.add(dev_s)
                        if info["type_c"]:
                            dev_c = copy.copy(dev)
                            dev_c.name = info["name"]
                            dev_c.type = GROUP_CABLE
                            if dev_c.type in DVB_TYPE_TO_DESC:
                                dev_c.type_name = DVB_TYPE_TO_DESC[dev_c.type]
                            else:
                                dev_c.type_name = "Unknown"
                            dev_c.registered = False
                            unregistered.add(dev_c)
                    else:
                        error = info

            all_devs = registered | unregistered
            has_device = len(all_devs) > 0
            if self.__use_configured:
                devs = all_devs
            else:
                devs = unregistered

            self.deviceslist.clear()
            for dev in devs:
                self.deviceslist.append([dev.name, dev.type_name,
                    dev.type, dev.adapter, dev.frontend, dev.registered])

            self.destroy_progressbar()

            if error != None:
                self.show_error(error)
            elif len(devs) == 0:
                if not has_device:
                    self.show_no_devices()
                else:
                    self.show_all_configured()
            else:
                self.show_devices()

        registered = set()
        unregistered = set()
        self.__adapter_info = None
        self.show_progressbar()

        self.__model.get_registered_device_groups(result_handler=registered_handler)

    def on_device_selection_changed(self, treeselection):
        model, aiter = treeselection.get_selected()
        if aiter != None:
            self.__adapter_info = {"name": model[aiter][0],
                                   "type": model[aiter][2],
                                   "adapter": model[aiter][3],
                                   "frontend": model[aiter][4],
                                   "registered": model[aiter][5],}
            self.emit("finished", True)
        else:
            self.emit("finished", False)

    def name_data_func(self, column, cell, model, aiter, user_data):
        name = model[aiter][0]
        adapter = model[aiter][3]
        frontend = model[aiter][4]

        text = _("<b>%s</b>\n") % name
        text += "<small>%s</small>" % (_("Adapter: %d, Frontend: %d") % (adapter, frontend))

        cell.set_property("markup", text)
    def __init__(self, model, parent=None):
        Gtk.Dialog.__init__(self, title=_("Edit Channel Lists"),
            parent=parent)

        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.model = model
        self.devgroup = None
        self.channel_list = None

        self.set_default_size(600, 500)
        self.set_border_width(5)

        close_button = self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
        close_button.grab_default()

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        self.vbox_main.set_border_width(5)
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        # channel groups
        groups_box = Gtk.Box(spacing=6)
        groups_frame = BaseFrame("<b>%s</b>" % _("Channel groups"),
            groups_box)
        self.vbox_main.pack_start(groups_frame, False, True, 0)

        self.channel_groups = ChannelGroupsStore()
        self.channel_groups_view = ChannelGroupsView(self.channel_groups)
        self.channel_groups_view.set_headers_visible(False)
        self.channel_groups_view.get_selection().connect("changed",
            self.on_group_changed)
        self.channel_groups_view.get_renderer().connect("edited",
            self.on_channel_group_edited)

        scrolledgroups = Gtk.ScrolledWindow()
        scrolledgroups.add(self.channel_groups_view)
        scrolledgroups.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scrolledgroups.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        groups_box.pack_start(scrolledgroups, True, True, 0)

        groups_buttonbox = Gtk.ButtonBox(orientation=Gtk.Orientation.VERTICAL)
        groups_buttonbox.set_spacing(6)
        groups_buttonbox.set_layout(Gtk.ButtonBoxStyle.START)
        groups_box.pack_end(groups_buttonbox, False, False, 0)

        new_group_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        new_group_button.connect("clicked", self.on_new_group_clicked)
        groups_buttonbox.pack_start(new_group_button, True, True, 0)

        self.del_group_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.del_group_button.connect("clicked", self.on_delete_group_clicked)
        groups_buttonbox.pack_start(self.del_group_button, True, True, 0)

        # device groups
        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(self.devgroupslist)
        self.devgroupscombo.connect("changed", self.on_devgroupscombo_changed)
        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)

        groups_label = Gtk.Label()
        groups_label.set_markup_with_mnemonic(_("_Group:"))
        groups_label.set_mnemonic_widget(self.devgroupscombo)

        groups_box = Gtk.Box(spacing=6)
        groups_box.pack_start(groups_label, False, True, 0)
        groups_box.pack_start(self.devgroupscombo, True, True, 0)

        self.devgroups_frame = BaseFrame("<b>%s</b>" % _("Device groups"),
            groups_box, False, False)
        self.vbox_main.pack_start(self.devgroups_frame, False, True, 0)

        # channels
        channels_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.vbox_main.pack_start(channels_box, True, True, 0)

        cbox = Gtk.Box(spacing=6)
        channels_box.pack_start(cbox, True, True, 0)

        # all channels
        self.channels_store = None
        self.channels_view = ChannelsView(self.channels_store)
        self.channels_view.set_headers_visible(False)
        self.channels_view.connect("row-activated",
            self.on_channels_view_activated)
        treesel = self.channels_view.get_selection()
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        treesel.connect("changed",
            self.on_channel_store_selected)

        left_frame = Frame("<b>%s</b>" % _("All channels"), self.channels_view)
        cbox.pack_start(left_frame, True, True, 0)

        # selected channels
        self.selected_channels_store = Gtk.ListStore(str, int) # Name, sid
        self.selected_channels_view = Gtk.TreeView.new_with_model(self.selected_channels_store)
        self.selected_channels_view.set_reorderable(True)
        self.selected_channels_view.set_headers_visible(False)
        self.selected_channels_view.connect("row-activated",
            self.on_selected_channels_view_activated)
        treesel = self.selected_channels_view.get_selection()
        treesel.connect("changed",
            self.on_selected_channels_changed)
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        col_name = Gtk.TreeViewColumn(_("Channel"))
        cell_name = Gtk.CellRendererText()
        col_name.pack_start(cell_name, True)
        col_name.add_attribute(cell_name, "markup", 0)
        self.selected_channels_view.append_column(col_name)
        self.selected_channels_view.show()

        self.scrolled_selected_channels = Gtk.ScrolledWindow()
        self.scrolled_selected_channels.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        self.scrolled_selected_channels.set_policy(Gtk.PolicyType.AUTOMATIC,
            Gtk.PolicyType.AUTOMATIC)
        self.scrolled_selected_channels.add(self.selected_channels_view)

        self.select_group_helpbox = HelpBox()
        self.select_group_helpbox.set_markup(_("Choose a channel group"))
        self.right_frame = BaseFrame("<b>%s</b>" % _("Channels of group"),
            self.select_group_helpbox)
        cbox.pack_start(self.right_frame, True, True, 0)

        buttonbox = Gtk.ButtonBox()
        buttonbox.set_spacing(6)
        buttonbox.set_layout(Gtk.ButtonBoxStyle.SPREAD)
        self.add_channel_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        self.add_channel_button.connect("clicked", self.on_add_channel_clicked)
        buttonbox.pack_start(self.add_channel_button, True, True, 0)
        self.remove_channel_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.remove_channel_button.connect("clicked", self.on_remove_channel_clicked)
        buttonbox.pack_start(self.remove_channel_button, True, True, 0)
        channels_box.pack_start(buttonbox, False, False, 0)

        self.del_group_button.set_sensitive(False)
        self.add_channel_button.set_sensitive(False)
        self.remove_channel_button.set_sensitive(False)

        self.fill_device_groups()
        self.fill_channel_groups()

        self.show_all()
class ChannelListEditorDialog(Gtk.Dialog):

    def __init__(self, model, parent=None):
        Gtk.Dialog.__init__(self, title=_("Edit Channel Lists"),
            parent=parent)

        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.model = model
        self.devgroup = None
        self.channel_list = None

        self.set_default_size(600, 500)
        self.set_border_width(5)

        close_button = self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
        close_button.grab_default()

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        self.vbox_main.set_border_width(5)
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        # channel groups
        groups_box = Gtk.Box(spacing=6)
        groups_frame = BaseFrame("<b>%s</b>" % _("Channel groups"),
            groups_box)
        self.vbox_main.pack_start(groups_frame, False, True, 0)

        self.channel_groups = ChannelGroupsStore()
        self.channel_groups_view = ChannelGroupsView(self.channel_groups)
        self.channel_groups_view.set_headers_visible(False)
        self.channel_groups_view.get_selection().connect("changed",
            self.on_group_changed)
        self.channel_groups_view.get_renderer().connect("edited",
            self.on_channel_group_edited)

        scrolledgroups = Gtk.ScrolledWindow()
        scrolledgroups.add(self.channel_groups_view)
        scrolledgroups.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scrolledgroups.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        groups_box.pack_start(scrolledgroups, True, True, 0)

        groups_buttonbox = Gtk.ButtonBox(orientation=Gtk.Orientation.VERTICAL)
        groups_buttonbox.set_spacing(6)
        groups_buttonbox.set_layout(Gtk.ButtonBoxStyle.START)
        groups_box.pack_end(groups_buttonbox, False, False, 0)

        new_group_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        new_group_button.connect("clicked", self.on_new_group_clicked)
        groups_buttonbox.pack_start(new_group_button, True, True, 0)

        self.del_group_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.del_group_button.connect("clicked", self.on_delete_group_clicked)
        groups_buttonbox.pack_start(self.del_group_button, True, True, 0)

        # device groups
        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(self.devgroupslist)
        self.devgroupscombo.connect("changed", self.on_devgroupscombo_changed)
        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)

        groups_label = Gtk.Label()
        groups_label.set_markup_with_mnemonic(_("_Group:"))
        groups_label.set_mnemonic_widget(self.devgroupscombo)

        groups_box = Gtk.Box(spacing=6)
        groups_box.pack_start(groups_label, False, True, 0)
        groups_box.pack_start(self.devgroupscombo, True, True, 0)

        self.devgroups_frame = BaseFrame("<b>%s</b>" % _("Device groups"),
            groups_box, False, False)
        self.vbox_main.pack_start(self.devgroups_frame, False, True, 0)

        # channels
        channels_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.vbox_main.pack_start(channels_box, True, True, 0)

        cbox = Gtk.Box(spacing=6)
        channels_box.pack_start(cbox, True, True, 0)

        # all channels
        self.channels_store = None
        self.channels_view = ChannelsView(self.channels_store)
        self.channels_view.set_headers_visible(False)
        self.channels_view.connect("row-activated",
            self.on_channels_view_activated)
        treesel = self.channels_view.get_selection()
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        treesel.connect("changed",
            self.on_channel_store_selected)

        left_frame = Frame("<b>%s</b>" % _("All channels"), self.channels_view)
        cbox.pack_start(left_frame, True, True, 0)

        # selected channels
        self.selected_channels_store = Gtk.ListStore(str, int) # Name, sid
        self.selected_channels_view = Gtk.TreeView.new_with_model(self.selected_channels_store)
        self.selected_channels_view.set_reorderable(True)
        self.selected_channels_view.set_headers_visible(False)
        self.selected_channels_view.connect("row-activated",
            self.on_selected_channels_view_activated)
        treesel = self.selected_channels_view.get_selection()
        treesel.connect("changed",
            self.on_selected_channels_changed)
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        col_name = Gtk.TreeViewColumn(_("Channel"))
        cell_name = Gtk.CellRendererText()
        col_name.pack_start(cell_name, True)
        col_name.add_attribute(cell_name, "markup", 0)
        self.selected_channels_view.append_column(col_name)
        self.selected_channels_view.show()

        self.scrolled_selected_channels = Gtk.ScrolledWindow()
        self.scrolled_selected_channels.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        self.scrolled_selected_channels.set_policy(Gtk.PolicyType.AUTOMATIC,
            Gtk.PolicyType.AUTOMATIC)
        self.scrolled_selected_channels.add(self.selected_channels_view)

        self.select_group_helpbox = HelpBox()
        self.select_group_helpbox.set_markup(_("Choose a channel group"))
        self.right_frame = BaseFrame("<b>%s</b>" % _("Channels of group"),
            self.select_group_helpbox)
        cbox.pack_start(self.right_frame, True, True, 0)

        buttonbox = Gtk.ButtonBox()
        buttonbox.set_spacing(6)
        buttonbox.set_layout(Gtk.ButtonBoxStyle.SPREAD)
        self.add_channel_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        self.add_channel_button.connect("clicked", self.on_add_channel_clicked)
        buttonbox.pack_start(self.add_channel_button, True, True, 0)
        self.remove_channel_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.remove_channel_button.connect("clicked", self.on_remove_channel_clicked)
        buttonbox.pack_start(self.remove_channel_button, True, True, 0)
        channels_box.pack_start(buttonbox, False, False, 0)

        self.del_group_button.set_sensitive(False)
        self.add_channel_button.set_sensitive(False)
        self.remove_channel_button.set_sensitive(False)

        self.fill_device_groups()
        self.fill_channel_groups()

        self.show_all()

    def fill_channel_groups(self):
        def add_groups(proxy, groups, user_data):
            for gid, name in groups:
                self.channel_groups.append([gid, name, False]) # not editable

        self.model.get_channel_groups(result_handler=add_groups,
            error_handler=gnomedvb.global_error_handler)

    def fill_device_groups(self):
        def append_groups(groups):
            for group in groups:
                self.devgroupslist.append([group["name"], group["id"], group])
            if len(groups) == 1:
                self.devgroup = groups[0]
                self.devgroups_frame.hide()
            else:
                self.devgroups_frame.show()
            self.devgroupscombo.set_active(0)

        self.model.get_registered_device_groups(result_handler=append_groups,
            error_handler=gnomedvb.global_error_handler)

    def refill_channel_groups(self):
        self.channel_groups.clear()
        self.fill_channel_groups()

    def fill_group_members(self):
        def add_channels(proxy, data, user_data):
            channels, success = data
            if success:
                for channel_id in channels:
                    name, success = self.channel_list.get_channel_name(channel_id)
                    if success:
                        self.selected_channels_store.append([name, channel_id])

        self.selected_channels_store.clear()
        data = self.get_selected_channel_group()
        if data:
            group_id, group_name = data
            self.channel_list.get_channels_of_group(group_id,
                result_handler=add_channels,
                error_handler=gnomedvb.global_error_handler)

    def get_selected_channels_all(self):
        sel = self.channels_view.get_selection()
        model, paths = sel.get_selected_rows()
        return [model[path][ChannelsStore.COL_SID] for path in paths]

    def get_selected_channels_selected_group(self):
        sel = self.selected_channels_view.get_selection()
        model, paths = sel.get_selected_rows()
        return [model[path][1] for path in paths]

    def get_selected_channel_group(self):
        model, aiter = self.channel_groups_view.get_selection().get_selected()
        if aiter == None:
            return None
        else:
            return self.channel_groups[aiter][0], self.channel_groups[aiter][1]

    def on_new_group_clicked(self, button):
        aiter = self.channel_groups.append()
        self.channel_groups.set_value(aiter, self.channel_groups.COL_EDITABLE,
            True)
        self.channel_groups_view.grab_focus()
        path = self.channel_groups.get_path(aiter)
        self.channel_groups_view.set_cursor(path,
            self.channel_groups_view.get_column(0), True)
        self.channel_groups_view.scroll_to_cell(path)

    def on_add_channel_group_finished(self, proxy, data, user_data):
        group_id, success = data
        if success:
            self.refill_channel_groups()
        else:
            error_dialog = Gtk.MessageDialog(parent=self,
                flags=Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT,
                type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
            error_dialog.set_markup(
                "<big><span weight=\"bold\">%s</span></big>" % _("An error occured while adding the group"))
            error_dialog.run()
            error_dialog.destroy()

    def on_delete_group_clicked(self, button):
        dialog = Gtk.MessageDialog(parent=self,
            flags=Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT,
            type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO)
        group_id, group_name = self.get_selected_channel_group()
        msg = _("Are you sure you want to delete the group '%s'?") % group_name
        dialog.set_markup (
            "<big><span weight=\"bold\">%s</span></big>\n\n%s" %
            (msg, _("All assignments to this group will be lost.")))
        if dialog.run() == Gtk.ResponseType.YES:
            self.model.remove_channel_group(group_id,
                result_handler=self.on_remove_channel_group_finished,
                error_handler=gnomedvb.global_error_handler)
        dialog.destroy()

    def on_remove_channel_group_finished(self, proxy, success, user_data):
        if success:
            self.refill_channel_groups()
        else:
            error_dialog = Gtk.MessageDialog(parent=self,
                flags=Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT,
                type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
            error_dialog.set_markup(
                "<big><span weight=\"bold\">%s</span></big>" % _("An error occured while removing the group"))
            error_dialog.run()
            error_dialog.destroy()

    def on_add_channel_clicked(self, button):
        channel_ids = self.get_selected_channels_all()
        group_data = self.get_selected_channel_group()
        if group_data:
            for channel_id in channel_ids:
                self.channel_list.add_channel_to_group(channel_id, group_data[0])
            self.fill_group_members()

    def on_remove_channel_clicked(self, button):
        channel_ids = self.get_selected_channels_selected_group()
        group_data = self.get_selected_channel_group()
        if group_data:
            for channel_id in channel_ids:
                self.channel_list.remove_channel_from_group(channel_id, group_data[0])
            self.fill_group_members()

    def on_channel_store_selected(self, treeselection):
        model, paths = treeselection.get_selected_rows()
        val = (len(paths) > 0 and self.get_selected_channel_group() != None)
        self.add_channel_button.set_sensitive(val)

    def on_selected_channels_changed(self, treeselection):
        model, paths = treeselection.get_selected_rows()
        val = (len(paths) > 0)
        self.remove_channel_button.set_sensitive(val)

    def on_group_changed(self, treeselection):
        model, aiter = treeselection.get_selected()
        val = aiter != None
        self.del_group_button.set_sensitive(val)
        if val:
            self.fill_group_members()
            self.right_frame.set_aligned_child(self.scrolled_selected_channels)
        else:
            self.right_frame.set_aligned_child(self.select_group_helpbox)
            self.selected_channels_store.clear()

    def on_channel_group_edited(self, renderer, path, new_text):
        aiter = self.channel_groups.get_iter(path)
        if len(new_text) == 0:
            self.channel_groups.remove(aiter)
        else:
            self.model.add_channel_group(new_text,
                result_handler=self.on_add_channel_group_finished,
                error_handler=gnomedvb.global_error_handler)

    def get_selected_group(self):
        if self.devgroup != None:
            return self.devgroup
        aiter = self.devgroupscombo.get_active_iter()
        if aiter == None:
            return None
        else:
            return self.devgroupslist[aiter][2]

    def on_devgroupscombo_changed(self, combo):
        group = self.get_selected_group()
        if group != None:
            self.channel_list = group.get_channel_list()
            self.channels_store = ChannelsStore(group)
            self.channels_view.set_model(self.channels_store)

    def on_channels_view_activated(self, treeview, aiter, path):
        self.on_add_channel_clicked(None)

    def on_selected_channels_view_activated(self, treeview, aiter, path):
        self.on_remove_channel_clicked(None)
Beispiel #8
0
    def __init__(self, parent):
        Gtk.Dialog.__init__(
            self,
            title=_("Create new Group"),
            parent=parent,
            flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK,
                     Gtk.ResponseType.ACCEPT))
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.set_default_size(400, 150)
        self.set_border_width(5)

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=12)
        self.vbox_main.set_border_width(5)
        self.vbox_main.show()
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        self.table = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL)
        self.table.set_column_spacing(18)
        self.table.set_row_spacing(6)
        self.table.show()

        general_frame = BaseFrame("<b>%s</b>" % _("General"), self.table)
        general_frame.show()
        self.vbox_main.pack_start(general_frame, True, True, 0)

        name = TextFieldLabel()
        name.set_markup_with_mnemonic(_("_Name:"))
        name.show()

        self.name_entry = Gtk.Entry(hexpand=True)
        self.name_entry.show()
        name.set_mnemonic_widget(self.name_entry)

        self.table.add(name)
        self.table.attach_next_to(self.name_entry, name,
                                  Gtk.PositionType.RIGHT, 1, 1)

        self.channels = TextFieldLabel()
        self.channels.set_markup_with_mnemonic(_("Channels _file:"))
        self.channels.show()

        self.channelsbox = Gtk.Box(spacing=6, hexpand=True)
        self.channelsbox.show()

        self.channels_entry = Gtk.Entry()
        self.channels_entry.set_editable(False)
        self.channels_entry.show()
        self.channelsbox.pack_start(self.channels_entry, True, True, 0)
        self.channels.set_mnemonic_widget(self.channels_entry)

        channels_open = Gtk.Button(stock=Gtk.STOCK_OPEN)
        channels_open.connect("clicked", self._on_channels_open_clicked)
        channels_open.show()
        self.channelsbox.pack_start(channels_open, False, False, 0)

        self.table.add(self.channels)
        self.table.attach_next_to(self.channelsbox, self.channels,
                                  Gtk.PositionType.RIGHT, 1, 1)

        recbox = Gtk.Box(spacing=18)
        recbox.show()

        recordings_frame = BaseFrame("<b>%s</b>" % _("Recordings"), recbox)
        recordings_frame.show()
        self.vbox_main.pack_start(recordings_frame, True, True, 0)

        recordings = TextFieldLabel()
        recordings.set_markup_with_mnemonic(_("_Directory:"))
        recordings.show()
        recbox.pack_start(recordings, False, True, 0)

        recentrybox = Gtk.Box(spacing=6)
        recentrybox.show()
        recbox.pack_start(recentrybox, True, True, 0)

        self.recordings_entry = Gtk.Entry()
        self.recordings_entry.set_editable(False)
        self.recordings_entry.show()
        recentrybox.pack_start(self.recordings_entry, True, True, 0)
        recordings.set_mnemonic_widget(self.recordings_entry)

        recordings_open = Gtk.Button(stock=Gtk.STOCK_OPEN)
        recordings_open.connect("clicked", self._on_recordings_open_clicked)
        recordings_open.show()
        recentrybox.pack_start(recordings_open, False, False, 0)
    def __init__(self, model, parent=None):
        Gtk.Dialog.__init__(self, title=_("Edit Channel Lists"), parent=parent)

        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.model = model
        self.devgroup = None
        self.channel_list = None

        self.set_default_size(600, 500)
        self.set_border_width(5)

        close_button = self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
        close_button.grab_default()

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=12)
        self.vbox_main.set_border_width(5)
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        # channel groups
        groups_box = Gtk.Box(spacing=6)
        groups_frame = BaseFrame("<b>%s</b>" % _("Channel groups"), groups_box)
        self.vbox_main.pack_start(groups_frame, False, True, 0)

        self.channel_groups = ChannelGroupsStore()
        self.channel_groups_view = ChannelGroupsView(self.channel_groups)
        self.channel_groups_view.set_headers_visible(False)
        self.channel_groups_view.get_selection().connect(
            "changed", self.on_group_changed)
        self.channel_groups_view.get_renderer().connect(
            "edited", self.on_channel_group_edited)

        scrolledgroups = Gtk.ScrolledWindow()
        scrolledgroups.add(self.channel_groups_view)
        scrolledgroups.set_policy(Gtk.PolicyType.NEVER,
                                  Gtk.PolicyType.AUTOMATIC)
        scrolledgroups.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        groups_box.pack_start(scrolledgroups, True, True, 0)

        groups_buttonbox = Gtk.ButtonBox(orientation=Gtk.Orientation.VERTICAL)
        groups_buttonbox.set_spacing(6)
        groups_buttonbox.set_layout(Gtk.ButtonBoxStyle.START)
        groups_box.pack_end(groups_buttonbox, False, False, 0)

        new_group_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        new_group_button.connect("clicked", self.on_new_group_clicked)
        groups_buttonbox.pack_start(new_group_button, True, True, 0)

        self.del_group_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.del_group_button.connect("clicked", self.on_delete_group_clicked)
        groups_buttonbox.pack_start(self.del_group_button, True, True, 0)

        # device groups
        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(
            self.devgroupslist)
        self.devgroupscombo.connect("changed", self.on_devgroupscombo_changed)
        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)

        groups_label = Gtk.Label()
        groups_label.set_markup_with_mnemonic(_("_Group:"))
        groups_label.set_mnemonic_widget(self.devgroupscombo)

        groups_box = Gtk.Box(spacing=6)
        groups_box.pack_start(groups_label, False, True, 0)
        groups_box.pack_start(self.devgroupscombo, True, True, 0)

        self.devgroups_frame = BaseFrame("<b>%s</b>" % _("Device groups"),
                                         groups_box, False, False)
        self.vbox_main.pack_start(self.devgroups_frame, False, True, 0)

        # channels
        channels_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.vbox_main.pack_start(channels_box, True, True, 0)

        cbox = Gtk.Box(spacing=6)
        channels_box.pack_start(cbox, True, True, 0)

        # all channels
        self.channels_store = None
        self.channels_view = ChannelsView(self.channels_store)
        self.channels_view.set_headers_visible(False)
        self.channels_view.connect("row-activated",
                                   self.on_channels_view_activated)
        treesel = self.channels_view.get_selection()
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        treesel.connect("changed", self.on_channel_store_selected)

        left_frame = Frame("<b>%s</b>" % _("All channels"), self.channels_view)
        cbox.pack_start(left_frame, True, True, 0)

        # selected channels
        self.selected_channels_store = Gtk.ListStore(str, int)  # Name, sid
        self.selected_channels_view = Gtk.TreeView.new_with_model(
            self.selected_channels_store)
        self.selected_channels_view.set_reorderable(True)
        self.selected_channels_view.set_headers_visible(False)
        self.selected_channels_view.connect(
            "row-activated", self.on_selected_channels_view_activated)
        treesel = self.selected_channels_view.get_selection()
        treesel.connect("changed", self.on_selected_channels_changed)
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        col_name = Gtk.TreeViewColumn(_("Channel"))
        cell_name = Gtk.CellRendererText()
        col_name.pack_start(cell_name, True)
        col_name.add_attribute(cell_name, "markup", 0)
        self.selected_channels_view.append_column(col_name)
        self.selected_channels_view.show()

        self.scrolled_selected_channels = Gtk.ScrolledWindow()
        self.scrolled_selected_channels.set_shadow_type(
            Gtk.ShadowType.ETCHED_IN)
        self.scrolled_selected_channels.set_policy(Gtk.PolicyType.AUTOMATIC,
                                                   Gtk.PolicyType.AUTOMATIC)
        self.scrolled_selected_channels.add(self.selected_channels_view)

        self.select_group_helpbox = HelpBox()
        self.select_group_helpbox.set_markup(_("Choose a channel group"))
        self.right_frame = BaseFrame("<b>%s</b>" % _("Channels of group"),
                                     self.select_group_helpbox)
        cbox.pack_start(self.right_frame, True, True, 0)

        buttonbox = Gtk.ButtonBox()
        buttonbox.set_spacing(6)
        buttonbox.set_layout(Gtk.ButtonBoxStyle.SPREAD)
        self.add_channel_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        self.add_channel_button.connect("clicked", self.on_add_channel_clicked)
        buttonbox.pack_start(self.add_channel_button, True, True, 0)
        self.remove_channel_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.remove_channel_button.connect("clicked",
                                           self.on_remove_channel_clicked)
        buttonbox.pack_start(self.remove_channel_button, True, True, 0)
        channels_box.pack_start(buttonbox, False, False, 0)

        self.del_group_button.set_sensitive(False)
        self.add_channel_button.set_sensitive(False)
        self.remove_channel_button.set_sensitive(False)

        self.fill_device_groups()
        self.fill_channel_groups()

        self.show_all()
class ChannelListEditorDialog(Gtk.Dialog):
    def __init__(self, model, parent=None):
        Gtk.Dialog.__init__(self, title=_("Edit Channel Lists"), parent=parent)

        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.model = model
        self.devgroup = None
        self.channel_list = None

        self.set_default_size(600, 500)
        self.set_border_width(5)

        close_button = self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
        close_button.grab_default()

        self.vbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=12)
        self.vbox_main.set_border_width(5)
        self.get_content_area().pack_start(self.vbox_main, True, True, 0)

        # channel groups
        groups_box = Gtk.Box(spacing=6)
        groups_frame = BaseFrame("<b>%s</b>" % _("Channel groups"), groups_box)
        self.vbox_main.pack_start(groups_frame, False, True, 0)

        self.channel_groups = ChannelGroupsStore()
        self.channel_groups_view = ChannelGroupsView(self.channel_groups)
        self.channel_groups_view.set_headers_visible(False)
        self.channel_groups_view.get_selection().connect(
            "changed", self.on_group_changed)
        self.channel_groups_view.get_renderer().connect(
            "edited", self.on_channel_group_edited)

        scrolledgroups = Gtk.ScrolledWindow()
        scrolledgroups.add(self.channel_groups_view)
        scrolledgroups.set_policy(Gtk.PolicyType.NEVER,
                                  Gtk.PolicyType.AUTOMATIC)
        scrolledgroups.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        groups_box.pack_start(scrolledgroups, True, True, 0)

        groups_buttonbox = Gtk.ButtonBox(orientation=Gtk.Orientation.VERTICAL)
        groups_buttonbox.set_spacing(6)
        groups_buttonbox.set_layout(Gtk.ButtonBoxStyle.START)
        groups_box.pack_end(groups_buttonbox, False, False, 0)

        new_group_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        new_group_button.connect("clicked", self.on_new_group_clicked)
        groups_buttonbox.pack_start(new_group_button, True, True, 0)

        self.del_group_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.del_group_button.connect("clicked", self.on_delete_group_clicked)
        groups_buttonbox.pack_start(self.del_group_button, True, True, 0)

        # device groups
        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(
            self.devgroupslist)
        self.devgroupscombo.connect("changed", self.on_devgroupscombo_changed)
        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)

        groups_label = Gtk.Label()
        groups_label.set_markup_with_mnemonic(_("_Group:"))
        groups_label.set_mnemonic_widget(self.devgroupscombo)

        groups_box = Gtk.Box(spacing=6)
        groups_box.pack_start(groups_label, False, True, 0)
        groups_box.pack_start(self.devgroupscombo, True, True, 0)

        self.devgroups_frame = BaseFrame("<b>%s</b>" % _("Device groups"),
                                         groups_box, False, False)
        self.vbox_main.pack_start(self.devgroups_frame, False, True, 0)

        # channels
        channels_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.vbox_main.pack_start(channels_box, True, True, 0)

        cbox = Gtk.Box(spacing=6)
        channels_box.pack_start(cbox, True, True, 0)

        # all channels
        self.channels_store = None
        self.channels_view = ChannelsView(self.channels_store)
        self.channels_view.set_headers_visible(False)
        self.channels_view.connect("row-activated",
                                   self.on_channels_view_activated)
        treesel = self.channels_view.get_selection()
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        treesel.connect("changed", self.on_channel_store_selected)

        left_frame = Frame("<b>%s</b>" % _("All channels"), self.channels_view)
        cbox.pack_start(left_frame, True, True, 0)

        # selected channels
        self.selected_channels_store = Gtk.ListStore(str, int)  # Name, sid
        self.selected_channels_view = Gtk.TreeView.new_with_model(
            self.selected_channels_store)
        self.selected_channels_view.set_reorderable(True)
        self.selected_channels_view.set_headers_visible(False)
        self.selected_channels_view.connect(
            "row-activated", self.on_selected_channels_view_activated)
        treesel = self.selected_channels_view.get_selection()
        treesel.connect("changed", self.on_selected_channels_changed)
        treesel.set_mode(Gtk.SelectionMode.MULTIPLE)
        col_name = Gtk.TreeViewColumn(_("Channel"))
        cell_name = Gtk.CellRendererText()
        col_name.pack_start(cell_name, True)
        col_name.add_attribute(cell_name, "markup", 0)
        self.selected_channels_view.append_column(col_name)
        self.selected_channels_view.show()

        self.scrolled_selected_channels = Gtk.ScrolledWindow()
        self.scrolled_selected_channels.set_shadow_type(
            Gtk.ShadowType.ETCHED_IN)
        self.scrolled_selected_channels.set_policy(Gtk.PolicyType.AUTOMATIC,
                                                   Gtk.PolicyType.AUTOMATIC)
        self.scrolled_selected_channels.add(self.selected_channels_view)

        self.select_group_helpbox = HelpBox()
        self.select_group_helpbox.set_markup(_("Choose a channel group"))
        self.right_frame = BaseFrame("<b>%s</b>" % _("Channels of group"),
                                     self.select_group_helpbox)
        cbox.pack_start(self.right_frame, True, True, 0)

        buttonbox = Gtk.ButtonBox()
        buttonbox.set_spacing(6)
        buttonbox.set_layout(Gtk.ButtonBoxStyle.SPREAD)
        self.add_channel_button = Gtk.Button(stock=Gtk.STOCK_ADD)
        self.add_channel_button.connect("clicked", self.on_add_channel_clicked)
        buttonbox.pack_start(self.add_channel_button, True, True, 0)
        self.remove_channel_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        self.remove_channel_button.connect("clicked",
                                           self.on_remove_channel_clicked)
        buttonbox.pack_start(self.remove_channel_button, True, True, 0)
        channels_box.pack_start(buttonbox, False, False, 0)

        self.del_group_button.set_sensitive(False)
        self.add_channel_button.set_sensitive(False)
        self.remove_channel_button.set_sensitive(False)

        self.fill_device_groups()
        self.fill_channel_groups()

        self.show_all()

    def fill_channel_groups(self):
        def add_groups(proxy, groups, user_data):
            for gid, name in groups:
                self.channel_groups.append([gid, name, False])  # not editable

        self.model.get_channel_groups(
            result_handler=add_groups,
            error_handler=gnomedvb.global_error_handler)

    def fill_device_groups(self):
        def append_groups(groups):
            for group in groups:
                self.devgroupslist.append([group["name"], group["id"], group])
            if len(groups) == 1:
                self.devgroup = groups[0]
                self.devgroups_frame.hide()
            else:
                self.devgroups_frame.show()
            self.devgroupscombo.set_active(0)

        self.model.get_registered_device_groups(
            result_handler=append_groups,
            error_handler=gnomedvb.global_error_handler)

    def refill_channel_groups(self):
        self.channel_groups.clear()
        self.fill_channel_groups()

    def fill_group_members(self):
        def add_channels(proxy, data, user_data):
            channels, success = data
            if success:
                for channel_id in channels:
                    name, success = self.channel_list.get_channel_name(
                        channel_id)
                    if success:
                        self.selected_channels_store.append([name, channel_id])

        self.selected_channels_store.clear()
        data = self.get_selected_channel_group()
        if data:
            group_id, group_name = data
            self.channel_list.get_channels_of_group(
                group_id,
                result_handler=add_channels,
                error_handler=gnomedvb.global_error_handler)

    def get_selected_channels_all(self):
        sel = self.channels_view.get_selection()
        model, paths = sel.get_selected_rows()
        return [model[path][ChannelsStore.COL_SID] for path in paths]

    def get_selected_channels_selected_group(self):
        sel = self.selected_channels_view.get_selection()
        model, paths = sel.get_selected_rows()
        return [model[path][1] for path in paths]

    def get_selected_channel_group(self):
        model, aiter = self.channel_groups_view.get_selection().get_selected()
        if aiter == None:
            return None
        else:
            return self.channel_groups[aiter][0], self.channel_groups[aiter][1]

    def on_new_group_clicked(self, button):
        aiter = self.channel_groups.append()
        self.channel_groups.set_value(aiter, self.channel_groups.COL_EDITABLE,
                                      True)
        self.channel_groups_view.grab_focus()
        path = self.channel_groups.get_path(aiter)
        self.channel_groups_view.set_cursor(
            path, self.channel_groups_view.get_column(0), True)
        self.channel_groups_view.scroll_to_cell(path)

    def on_add_channel_group_finished(self, proxy, data, user_data):
        group_id, success = data
        if success:
            self.refill_channel_groups()
        else:
            error_dialog = Gtk.MessageDialog(
                parent=self,
                flags=Gtk.DialogFlags.MODAL
                | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK)
            error_dialog.set_markup(
                "<big><span weight=\"bold\">%s</span></big>" %
                _("An error occurred while adding the group"))
            error_dialog.run()
            error_dialog.destroy()

    def on_delete_group_clicked(self, button):
        dialog = Gtk.MessageDialog(parent=self,
                                   flags=Gtk.DialogFlags.MODAL
                                   | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                   type=Gtk.MessageType.QUESTION,
                                   buttons=Gtk.ButtonsType.YES_NO)
        group_id, group_name = self.get_selected_channel_group()
        msg = _("Are you sure you want to delete the group '%s'?") % group_name
        dialog.set_markup(
            "<big><span weight=\"bold\">%s</span></big>\n\n%s" %
            (msg, _("All assignments to this group will be lost.")))
        if dialog.run() == Gtk.ResponseType.YES:
            self.model.remove_channel_group(
                group_id,
                result_handler=self.on_remove_channel_group_finished,
                error_handler=gnomedvb.global_error_handler)
        dialog.destroy()

    def on_remove_channel_group_finished(self, proxy, success, user_data):
        if success:
            self.refill_channel_groups()
        else:
            error_dialog = Gtk.MessageDialog(
                parent=self,
                flags=Gtk.DialogFlags.MODAL
                | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK)
            error_dialog.set_markup(
                "<big><span weight=\"bold\">%s</span></big>" %
                _("An error occurred while removing the group"))
            error_dialog.run()
            error_dialog.destroy()

    def on_add_channel_clicked(self, button):
        channel_ids = self.get_selected_channels_all()
        group_data = self.get_selected_channel_group()
        if group_data:
            for channel_id in channel_ids:
                self.channel_list.add_channel_to_group(channel_id,
                                                       group_data[0])
            self.fill_group_members()

    def on_remove_channel_clicked(self, button):
        channel_ids = self.get_selected_channels_selected_group()
        group_data = self.get_selected_channel_group()
        if group_data:
            for channel_id in channel_ids:
                self.channel_list.remove_channel_from_group(
                    channel_id, group_data[0])
            self.fill_group_members()

    def on_channel_store_selected(self, treeselection):
        model, paths = treeselection.get_selected_rows()
        val = (len(paths) > 0 and self.get_selected_channel_group() != None)
        self.add_channel_button.set_sensitive(val)

    def on_selected_channels_changed(self, treeselection):
        model, paths = treeselection.get_selected_rows()
        val = (len(paths) > 0)
        self.remove_channel_button.set_sensitive(val)

    def on_group_changed(self, treeselection):
        model, aiter = treeselection.get_selected()
        val = aiter != None
        self.del_group_button.set_sensitive(val)
        if val:
            self.fill_group_members()
            self.right_frame.set_aligned_child(self.scrolled_selected_channels)
        else:
            self.right_frame.set_aligned_child(self.select_group_helpbox)
            self.selected_channels_store.clear()

    def on_channel_group_edited(self, renderer, path, new_text):
        aiter = self.channel_groups.get_iter(path)
        if len(new_text) == 0:
            self.channel_groups.remove(aiter)
        else:
            self.model.add_channel_group(
                new_text,
                result_handler=self.on_add_channel_group_finished,
                error_handler=gnomedvb.global_error_handler)

    def get_selected_group(self):
        if self.devgroup != None:
            return self.devgroup
        aiter = self.devgroupscombo.get_active_iter()
        if aiter == None:
            return None
        else:
            return self.devgroupslist[aiter][2]

    def on_devgroupscombo_changed(self, combo):
        group = self.get_selected_group()
        if group != None:
            self.channel_list = group.get_channel_list()
            self.channels_store = ChannelsStore(group)
            self.channels_view.set_model(self.channels_store)

    def on_channels_view_activated(self, treeview, aiter, path):
        self.on_add_channel_clicked(None)

    def on_selected_channels_view_activated(self, treeview, aiter, path):
        self.on_remove_channel_clicked(None)