Example #1
0
    def __init__(self,
                 parent,
                 device_group,
                 channel=None,
                 starttime=None,
                 duration=60):
        """
        @param parent: Parent window
        @type parent: Gtk.Window
        @param device_group: DeviceGroup instance
        """
        Gtk.Dialog.__init__(self, parent=parent)

        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.set_default_size(320, -1)

        self.device_group = device_group
        self.date_valid = False
        self.allowed_delta = datetime.timedelta(hours=1)

        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
        self.ok_button = self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)

        self.set_border_width(5)

        table = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL)
        table.set_column_spacing(18)
        table.set_row_spacing(6)
        table.set_border_width(5)
        self.get_content_area().pack_start(table, True, True, 0)

        label_channel = TextFieldLabel()
        table.add(label_channel)

        if channel == None:
            self.channel_selected = False
            self.set_title(_("Add Timer"))
            self.ok_button.set_sensitive(False)

            label_channel.set_markup_with_mnemonic(_("_Channel:"))
            self.channels = ChannelsStore(device_group)

            scrolledchannels = Gtk.ScrolledWindow(expand=True)
            scrolledchannels.set_policy(Gtk.PolicyType.AUTOMATIC,
                                        Gtk.PolicyType.AUTOMATIC)
            scrolledchannels.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
            table.attach_next_to(scrolledchannels, label_channel,
                                 Gtk.PositionType.BOTTOM, 2, 1)

            self.channelsview = ChannelsView(self.channels)
            self.channelsview.set_headers_visible(False)
            self.channelsview.get_selection().connect("changed",
                                                      self._on_channel_changed)
            scrolledchannels.add(self.channelsview)
            label_channel.set_mnemonic_widget(self.channelsview)
            self.channelsview.grab_focus()
        else:
            self.channel_selected = True
            self.set_title(_("Edit Timer"))
            self.ok_button.set_sensitive(True)

            label_channel.set_text(_("Channel:"))
            self.channels = None
            self.channelsview = None
            channel_label = TextFieldLabel(channel)
            table.attach_next_to(channel_label, label_channel,
                                 Gtk.PositionType.RIGHT, 1, 1)

        label_start = TextFieldLabel()
        label_start.set_markup_with_mnemonic(_("_Start time:"))
        table.add(label_start)

        hbox = Gtk.Box(spacing=6, hexpand=True)
        table.attach_next_to(hbox, label_start, Gtk.PositionType.RIGHT, 1, 1)

        if starttime == None:
            starttime = datetime.datetime.now()

        self.datetime_box = DateTimeBox(starttime)
        self.datetime_box.connect("changed", self._on_datetime_changed)
        hbox.pack_start(self.datetime_box, True, True, 0)
        label_start.set_mnemonic_widget(self.datetime_box)

        label_duration = TextFieldLabel()
        label_duration.set_markup_with_mnemonic(_("_Duration:"))
        table.add(label_duration)

        duration_hbox = Gtk.Box(spacing=6, hexpand=True)
        table.attach_next_to(duration_hbox, label_duration,
                             Gtk.PositionType.RIGHT, 1, 1)

        self.duration = Gtk.SpinButton()
        self.duration.set_range(1, 65535)
        self.duration.set_increments(1, 10)
        self.duration.set_width_chars(3)
        self.duration.set_value(60)
        duration_hbox.pack_start(self.duration, False, True, 0)
        label_duration.set_mnemonic_widget(self.duration)

        minutes_label = TextFieldLabel(_("minutes"))
        duration_hbox.pack_start(minutes_label, True, True, 0)

        self.set_start_time(starttime)
        self.set_duration(duration)

        table.show_all()
class ControlCenterWindow(Gtk.Window):

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

        self.runningnextstore = None
        self.scrolledrunningnext = None
        self.runningnextview = None
        self.__single_group = None

        self.channellists = {}
        self.manager = model
        self.manager.connect('group-added', self._on_manager_group_added)
        self.manager.connect('group-removed', self._on_manager_group_removed)

        self.connect('delete-event', Gtk.main_quit)
        self.connect('destroy-event', Gtk.main_quit)
        self.set_title(_("DVB Control Center"))
        self.set_default_size(800, 500)

        self.vbox_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.vbox_outer.show()
        self.add(self.vbox_outer)

        self.toolbar = None
        self.vbox_left  = None
        self.__create_menu()
        self.__create_toolbar()

        self.hbox = Gtk.Box(spacing=6)
        self.vbox_outer.pack_start(self.hbox, True, True, 0)

        self.hpaned = Gtk.Paned()
        self.hpaned.set_border_width(3)
        self.hpaned.set_position(175)
        self.hbox.pack_start(self.hpaned, True, True, 0)

        self.vbox_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.hpaned.pack1(self.vbox_left)

        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)
        self.devgroupslist.connect("row-inserted", self._on_devgroupslist_inserted)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(self.devgroupslist)

        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)
        self.devgroupscombo.connect("changed", self._on_devgroupscombo_changed)
        self.vbox_left.pack_start(self.devgroupscombo, False, True, 0)

        self.channelsstore = None

        self.channelsview = ChannelsView()
        self.channelsview.set_headers_visible(False)
        self.channelsview.get_selection().connect("changed", self._on_channel_selected)

        scrolledchannels = Gtk.ScrolledWindow()
        scrolledchannels.add(self.channelsview)
        scrolledchannels.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scrolledchannels.set_shadow_type(Gtk.ShadowType.IN)
        self.vbox_left.pack_start(scrolledchannels, True, True, 0)

        self.schedulestore = None

        self.help_eventbox = HelpBox()
        self.choose_group_text = _("Choose a device group and channel on the left to view the program guide")
        self.create_group_text = _("No devices are configured. Please go to preferences to configure them.")
        self.no_events_text = _("There is currently no schedule available for this channel")
        self.hpaned.pack2(self.help_eventbox)

        self.schedulepaned = SchedulePaned()
        self.schedulepaned.show()
        self.scheduleview = self.schedulepaned.get_treeview()
        self.scheduleview.connect("button-press-event", self._on_event_selected)

        self.get_device_groups()
        if len(self.devgroupslist) == 0:
            self.help_eventbox.set_markup(self.create_group_text)
        else:
            self._select_first_group()

        Gtk.Window.set_default_icon_name("gnome-dvb-daemon")

    def __create_menu(self):
        ui = '''
        <menubar name="MenuBar">
          <menu action="Timers">
            <menuitem action="EditTimers"/>
            <menuitem action="Recordings"/>
            <separator/>
            <menuitem action="Quit"/>
          </menu>
          <menu action="Edit">
            <menuitem action="EditChannelLists"/>
            <separator/>
            <menuitem action="Preferences"/>
          </menu>
          <menu action="View">
            <menuitem action="WhatsOnNow"/>
            <menuitem action="Refresh"/>
            <menuitem action="PrevDay"/>
            <menuitem action="NextDay"/>
            <separator/>
            <menuitem action="Channels"/>
            <menuitem action="Toolbar"/>
          </menu>
          <menu action="Help">
            <menuitem action="About"/>
          </menu>
        </menubar>'''

        uimanager = Gtk.UIManager()

        # Add the accelerator group to the toplevel window
        accelgroup = uimanager.get_accel_group()
        self.add_accel_group(accelgroup)

        # Create actions
        actiongroup = Gtk.ActionGroup(name='Root')
        actiongroup.add_actions([
            ('Timers', None, _('_Recording schedule')),
            ('Edit', None, _('_Edit')),
            ('View', None, _('_View')),
            ('Help', None, _('Help')),
        ])
        # Add the actiongroup to the uimanager
        uimanager.insert_action_group(actiongroup, 0)

        actiongroup = Gtk.ActionGroup(name='Timers')
        actiongroup.add_actions([
            ('EditTimers', None, _('_Manage'), '<Control>T',
             _('Manage recording schedule'), self._on_button_display_timers_clicked),
            ('Recordings', None, _('_Recordings'), '<Control>W',
             _('Manage recordings'), self._on_button_recordings_clicked),
            ('Quit', Gtk.STOCK_QUIT, _('_Quit'), None,
             _('Quit the Program'), Gtk.main_quit)])
        uimanager.insert_action_group(actiongroup, 1)

        actiongroup = Gtk.ActionGroup(name='Edit')
        actiongroup.add_actions([
            ('EditChannelLists', None, _('_Channel Lists'), None,
             _('Edit channel lists'), self._on_edit_channellists_clicked),
            ('Preferences', Gtk.STOCK_PREFERENCES, _('_Preferences'), None,
             _('Display preferences'), self._on_button_prefs_clicked),
        ])
        uimanager.insert_action_group(actiongroup, 2)

        actiongroup = Gtk.ActionGroup(name='View')
        actiongroup.add_actions([
            ('WhatsOnNow', None, _("_What's on now"), None,
             _("See what's currently on and is coming next"), self._on_whats_on_now_clicked),
            ('Refresh', Gtk.STOCK_REFRESH, _('_Refresh'), '<Control>R',
             _('Refresh program guide'), self._on_refresh_clicked),
            ('PrevDay', None, _('_Previous Day'), '<Alt>Left',
             _('Go to previous day'), self._on_button_prev_day_clicked),
            ('NextDay', None, _('_Next Day'), '<Alt>Right',
             _('Go to next day'), self._on_button_next_day_clicked),
        ])
        actiongroup.add_toggle_actions([
            ('Channels', None, _('_Channels'), None,
             _('View/Hide channels'), self._on_view_channels_clicked),
            ('Toolbar', None, _('_Toolbar'), None,
             _('View/Hide toolbar'), self._on_view_toolbar_clicked),
        ])
        action = actiongroup.get_action('Toolbar')
        action.set_active(True)
        action = actiongroup.get_action('Channels')
        action.set_active(True)
        uimanager.insert_action_group(actiongroup, 3)

        actiongroup = Gtk.ActionGroup(name='Help')
        actiongroup.add_actions([
            ('About', Gtk.STOCK_ABOUT, _('_About'), None,
             _('Display informations about the program'),
             self._on_about_clicked),
        ])
        uimanager.insert_action_group(actiongroup, 4)

        # Add a UI description
        uimanager.add_ui_from_string(ui)

        timers_image = Gtk.Image.new_from_icon_name("appointment-soon", Gtk.IconSize.MENU)
        timers_image.show()

        self.timersitem = uimanager.get_widget('/MenuBar/Timers/EditTimers')
        self.timersitem.set_image(timers_image)
        self.timersitem.set_sensitive(False)

        recordings_image = Gtk.Image.new_from_icon_name("video-x-generic", Gtk.IconSize.MENU)
        recordings_image.show()

        recordings = uimanager.get_widget('/MenuBar/Timers/Recordings')
        recordings.set_image(recordings_image)

        whatson_image = Gtk.Image.new_from_stock(Gtk.STOCK_INDEX, Gtk.IconSize.MENU)
        whatson_image.show()

        self.whatons_item = uimanager.get_widget('/MenuBar/View/WhatsOnNow')
        self.whatons_item.set_image(whatson_image)
        self.whatons_item.set_sensitive(False)

        self.refresh_menuitem = uimanager.get_widget('/MenuBar/View/Refresh')
        self.refresh_menuitem.set_sensitive(False)

        self.prev_day_menuitem = uimanager.get_widget('/MenuBar/View/PrevDay')
        prev_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_BACK, Gtk.IconSize.MENU)
        prev_image.show()
        self.prev_day_menuitem.set_image(prev_image)
        self.prev_day_menuitem.set_sensitive(False)

        self.next_day_menuitem = uimanager.get_widget('/MenuBar/View/NextDay')
        next_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_FORWARD, Gtk.IconSize.MENU)
        next_image.show()
        self.next_day_menuitem.set_image(next_image)
        self.next_day_menuitem.set_sensitive(False)

        # Create a MenuBar
        menubar = uimanager.get_widget('/MenuBar')
        menubar.show()
        self.vbox_outer.pack_start(menubar, False, True, 0)

    def __create_toolbar(self):
        self.toolbar = Gtk.Toolbar()
        self.toolbar.show()
        self.vbox_outer.pack_start(self.toolbar, False, True, 0)

        timers_image = Gtk.Image.new_from_icon_name("appointment-soon", Gtk.IconSize.MENU)
        timers_image.show()

        self.button_display_timers = Gtk.ToolButton(icon_widget=timers_image, label=_("Recording schedule"))
        self.button_display_timers.set_is_important(True)
        self.button_display_timers.set_sensitive(False)
        self.button_display_timers.connect("clicked", self._on_button_display_timers_clicked)
        self.button_display_timers.set_tooltip_markup(_("Manage recording schedule"))
        self.button_display_timers.show()
        self.toolbar.insert(self.button_display_timers, 0)

        recordings_image = Gtk.Image.new_from_icon_name("video-x-generic", Gtk.IconSize.MENU)
        recordings_image.show()

        button_recordings = Gtk.ToolButton(icon_widget=recordings_image, label=_("Recordings"))
        button_recordings.set_is_important(True)
        button_recordings.connect("clicked", self._on_button_recordings_clicked)
        button_recordings.show()
        self.toolbar.insert(button_recordings, 1)

        whatson_image = Gtk.Image.new_from_stock(Gtk.STOCK_INDEX, Gtk.IconSize.LARGE_TOOLBAR)
        whatson_image.show()

        self.button_whatson = Gtk.ToolButton(icon_widget=whatson_image, label=_("What's on now"))
        self.button_whatson.set_is_important(True)
        self.button_whatson.set_sensitive(False)
        self.button_whatson.connect("clicked", self._on_whats_on_now_clicked)
        self.button_whatson.show()
        self.toolbar.insert(self.button_whatson, 2)

        sep = Gtk.SeparatorToolItem()
        sep.show()
        self.toolbar.insert(sep, 3)

        self.refresh_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_REFRESH)
        self.refresh_button.connect("clicked", self._on_refresh_clicked)
        self.refresh_button.set_tooltip_markup(_("Refresh program guide"))
        self.refresh_button.show()
        self.toolbar.insert(self.refresh_button, 4)

        prev_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_BACK, Gtk.IconSize.LARGE_TOOLBAR)
        prev_image.show()
        self.button_prev_day = Gtk.ToolButton(icon_widget=prev_image, label=_("Previous Day"))
        self.button_prev_day.connect("clicked", self._on_button_prev_day_clicked)
        self.button_prev_day.set_tooltip_markup(_("Go to previous day"))
        self.button_prev_day.set_sensitive(False)
        self.button_prev_day.show()
        self.toolbar.insert(self.button_prev_day, 5)

        next_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_FORWARD, Gtk.IconSize.LARGE_TOOLBAR)
        next_image.show()
        self.button_next_day = Gtk.ToolButton(icon_widget=next_image, label=_("Next Day"))
        self.button_next_day.connect("clicked", self._on_button_next_day_clicked)
        self.button_next_day.set_tooltip_markup(_("Go to next day"))
        self.button_next_day.set_sensitive(False)
        self.button_next_day.show()
        self.toolbar.insert(self.button_next_day, 6)

    def get_device_groups(self):
        def append_groups(groups):
            for group in groups:
                self._append_group(group)
            self.check_single_group_mode()
        self.manager.get_registered_device_groups(result_handler=append_groups)

    def check_single_group_mode(self):
        val = len(self.devgroupslist) == 1
        if val:
            aiter = self.devgroupslist.get_iter_first()
            self.__single_group = self.devgroupslist[aiter][2]
            self.devgroupscombo.hide()
        else:
            self.__single_group = None
            self.devgroupscombo.show()

    def _select_first_group(self):
        self.devgroupscombo.set_active(0)
        self.channelsview.grab_focus()

    def _append_group(self, group):
        self.devgroupslist.append([group["name"], group["id"], group])
        self.channellists[group["id"]] = group.get_channel_list()

    def _remove_group(self, group_id):
        aiter = None
        for row in self.devgroupslist:
            if row[1] == group_id:
                aiter = row.iter

        if aiter != None:
            if self._get_selected_group()["id"] == group_id:
                # Select no group
                self.devgroupscombo.set_active(-1)

            self.devgroupslist.remove(aiter)
            del self.channellists[group_id]

    def _reset_ui(self):
        self.channelsstore = None
        self.channelsview.set_model(None)
        if len(self.devgroupslist) == 0:
            text = self.create_group_text
        else:
            text = self.choose_group_text
        self._display_help_message(text)
        self._set_timers_sensitive(False)

    def _reset_schedule_view(self):
        self.schedulestore = None
        self.scheduleview.set_model(None)
        self._display_running_next()

    def _on_manager_group_added(self, manager, group_id):
        group = self.manager.get_device_group(group_id)
        if group != None:
            self._append_group(group)
            self.check_single_group_mode()

    def _on_manager_group_removed(self, manager, group_id):
        self._remove_group(group_id)
        self.check_single_group_mode()
        self._select_first_group()

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

    def _get_selected_channel_sid(self):
        model, aiter = self.channelsview.get_selection().get_selected()
        if aiter != None:
            sid = model[aiter][model.COL_SID]
            return sid
        else:
            return None

    def _on_devgroupscombo_changed(self, combo):
        group = self._get_selected_group()
        if group != None:
            self._set_timers_sensitive(True)
            self._set_whatson_sensitive(True)

            self.channelsstore = ChannelsStore(group)
            self.channelsview.set_model(self.channelsstore)

            self._reset_schedule_view()
        else:
            self._reset_ui()

    def _on_devgroupslist_inserted(self, model, path, aiter):
        if len(model) == 1:
            # Delay the call otherwise we get DBus errors
            GLib.timeout_add(100, self._select_first_group)

    def _on_channel_selected(self, treeselection):
        model, aiter = treeselection.get_selected()
        child = self.hpaned.get_child2()
        if aiter != None:
            sid = model[aiter][model.COL_SID]
            group = self._get_selected_group()
            self.schedulestore = ScheduleStore(group, sid)
            self.schedulestore.connect("loading-finished",
                self._on_schedule_loading_finished)

            self.scheduleview.set_model(self.schedulestore)
            # Display schedule if it isn't already displayed
            if child != self.schedulepaned:
                self.hpaned.remove(child)
                self.hpaned.pack2(self.schedulepaned)
                self._set_previous_day_sensitive(True)
                self._set_next_day_sensitive(True)
                self._set_refresh_sensitive(True)
        else:
            # Display running/next if it isn't already displayed
            if child != self.scrolledrunningnext:
                self._display_running_next()

    def _on_schedule_loading_finished(self, schedulestore):
        if len(self.schedulestore) == 0:
            self._display_help_message(self.no_events_text)

    def _display_help_message(self, text):
        child = self.hpaned.get_child2()
        self.hpaned.remove(child)
        self.hpaned.pack2(self.help_eventbox)
        self._set_previous_day_sensitive(False)
        self._set_next_day_sensitive(False)
        self._set_refresh_sensitive(False)

        self.help_eventbox.set_markup(text)

    def _display_running_next(self):
        group = self._get_selected_group()

        self.runningnextstore = RunningNextStore(group)

        self.scrolledrunningnext = Gtk.ScrolledWindow()
        self.scrolledrunningnext.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.scrolledrunningnext.set_shadow_type(Gtk.ShadowType.IN)
        self.scrolledrunningnext.show()

        self.runningnextview = RunningNextView(self.runningnextstore)
        self.runningnextview.show()
        self.scrolledrunningnext.add(self.runningnextview)

        child = self.hpaned.get_child2()
        self.hpaned.remove(child)
        self.hpaned.pack2(self.scrolledrunningnext)
        self._set_previous_day_sensitive(False)
        self._set_next_day_sensitive(False)
        self._set_refresh_sensitive(False)

    def _set_next_day_sensitive(self, val):
        self.button_next_day.set_sensitive(val)
        self.next_day_menuitem.set_sensitive(val)

    def _set_previous_day_sensitive(self, val):
        self.button_prev_day.set_sensitive(val)
        self.prev_day_menuitem.set_sensitive(val)

    def _set_timers_sensitive(self, val):
        self.button_display_timers.set_sensitive(val)
        self.timersitem.set_sensitive(val)

    def _set_refresh_sensitive(self, val):
        self.refresh_button.set_sensitive(val)
        self.refresh_menuitem.set_sensitive(val)

    def _set_whatson_sensitive(self, val):
        self.whatons_item.set_sensitive(val)
        self.button_whatson.set_sensitive(val)

    def _on_event_selected(self, treeview, event):
        if event.type == getattr(Gdk.EventType, "2BUTTON_PRESS"):
            model, aiter = treeview.get_selection().get_selected()
            if aiter != None:
                dialog = Gtk.MessageDialog(parent=self,
                    flags=Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO)
                dialog.set_markup (
                    "<big><span weight=\"bold\">%s</span></big>" % _("Schedule recording for the selected event?"))

                success = True
                if dialog.run() == Gtk.ResponseType.YES:
                    event_id = model[aiter][model.COL_EVENT_ID]
                    group = self._get_selected_group()
                    channel_sid = self._get_selected_channel_sid()
                    recorder = group.get_recorder()
                    rec_id, success = recorder.add_timer_for_epg_event(event_id, channel_sid)
                dialog.destroy()

                if not success:
                    dialog = TimerFailureDialog(self)
                    dialog.run()
                    dialog.destroy()

    def _on_button_display_timers_clicked(self, button, user_data=None):
        group = self._get_selected_group()
        if group != None:
            edit = EditTimersDialog(group, self)
            edit.run()
            edit.destroy()

    def _on_whats_on_now_clicked(self, button, user_data=None):
        self._reset_schedule_view()

    def _on_refresh_clicked(self, button, user_data=None):
        self.schedulestore.reload_all()

    def _on_button_prev_day_clicked(self, button, user_data=None):
        if self.schedulestore != None:
            model, aiter = self.scheduleview.get_selection().get_selected()
            if aiter == None:
                path, col, x, y = self.scheduleview.get_path_at_pos(1, 1)
                aiter = model.get_iter(path)

            day_iter = self.schedulestore.get_previous_day_iter(aiter)
            if day_iter == None:
                self._set_previous_day_sensitive(False)
            else:
                self._set_next_day_sensitive(True)
                day_path = model.get_path(day_iter)
                self.scheduleview.scroll_to_cell(day_path, use_align=True)
                self.scheduleview.set_cursor(day_path, None, False)

    def _on_button_next_day_clicked(self, button, user_data=None):
        if self.schedulestore != None:
            model, aiter = self.scheduleview.get_selection().get_selected()
            if aiter == None:
                path, col, x, y = self.scheduleview.get_path_at_pos(1, 1)
                aiter = model.get_iter(path)

            day_iter = self.schedulestore.get_next_day_iter(aiter)
            if day_iter == None:
                self._set_next_day_sensitive(False)
            else:
                self._set_previous_day_sensitive(True)
                day_path = model.get_path(day_iter)
                self.scheduleview.scroll_to_cell(day_path, use_align=True)
                self.scheduleview.set_cursor(day_path, None, False)

    def _on_button_prefs_clicked(self, button, user_data=None):
        prefs = Preferences(self.manager, self)
        prefs.show()

    def _on_button_recordings_clicked(self, button, user_data=None):
        dialog = RecordingsDialog(self)
        dialog.run()
        dialog.destroy()

    def _on_view_channels_clicked(self, action, user_data=None):
        if self.vbox_left:
            if action.get_active():
                self.vbox_left.show()
            else:
                self.vbox_left.hide()

    def _on_view_toolbar_clicked(self, action, user_data=None):
        if self.toolbar:
            if action.get_active():
                self.toolbar.show()
            else:
                self.toolbar.hide()

    def _on_about_clicked(self, action, user_data=None):
        about = Gtk.AboutDialog()
        about.set_transient_for(self)
        #translators: These appear in the About dialog, usual format applies.
        about.set_translator_credits( _("translator-credits") )

        for prop, val in list(gnomedvb.INFOS.items()):
            about.set_property(prop, val)

        about.set_screen(self.get_screen())
        about.run()
        about.destroy()

    def _on_edit_channellists_clicked(self, action, user_data=None):
        dialog = ChannelListEditorDialog(self.manager, parent=self)
        dialog.run()
        dialog.destroy()
    def __init__(self, model):
        GObject.GObject.__init__(self)

        self.runningnextstore = None
        self.scrolledrunningnext = None
        self.runningnextview = None
        self.__single_group = None

        self.channellists = {}
        self.manager = model
        self.manager.connect('group-added', self._on_manager_group_added)
        self.manager.connect('group-removed', self._on_manager_group_removed)

        self.connect('delete-event', Gtk.main_quit)
        self.connect('destroy-event', Gtk.main_quit)
        self.set_title(_("DVB Control Center"))
        self.set_default_size(800, 500)

        self.vbox_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.vbox_outer.show()
        self.add(self.vbox_outer)

        self.toolbar = None
        self.vbox_left  = None
        self.__create_menu()
        self.__create_toolbar()

        self.hbox = Gtk.Box(spacing=6)
        self.vbox_outer.pack_start(self.hbox, True, True, 0)

        self.hpaned = Gtk.Paned()
        self.hpaned.set_border_width(3)
        self.hpaned.set_position(175)
        self.hbox.pack_start(self.hpaned, True, True, 0)

        self.vbox_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.hpaned.pack1(self.vbox_left)

        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)
        self.devgroupslist.connect("row-inserted", self._on_devgroupslist_inserted)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(self.devgroupslist)

        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)
        self.devgroupscombo.connect("changed", self._on_devgroupscombo_changed)
        self.vbox_left.pack_start(self.devgroupscombo, False, True, 0)

        self.channelsstore = None

        self.channelsview = ChannelsView()
        self.channelsview.set_headers_visible(False)
        self.channelsview.get_selection().connect("changed", self._on_channel_selected)

        scrolledchannels = Gtk.ScrolledWindow()
        scrolledchannels.add(self.channelsview)
        scrolledchannels.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scrolledchannels.set_shadow_type(Gtk.ShadowType.IN)
        self.vbox_left.pack_start(scrolledchannels, True, True, 0)

        self.schedulestore = None

        self.help_eventbox = HelpBox()
        self.choose_group_text = _("Choose a device group and channel on the left to view the program guide")
        self.create_group_text = _("No devices are configured. Please go to preferences to configure them.")
        self.no_events_text = _("There is currently no schedule available for this channel")
        self.hpaned.pack2(self.help_eventbox)

        self.schedulepaned = SchedulePaned()
        self.schedulepaned.show()
        self.scheduleview = self.schedulepaned.get_treeview()
        self.scheduleview.connect("button-press-event", self._on_event_selected)

        self.get_device_groups()
        if len(self.devgroupslist) == 0:
            self.help_eventbox.set_markup(self.create_group_text)
        else:
            self._select_first_group()

        Gtk.Window.set_default_icon_name("gnome-dvb-daemon")
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)
    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 __init__(self, model):
        GObject.GObject.__init__(self)

        self.runningnextstore = None
        self.scrolledrunningnext = None
        self.runningnextview = None
        self.__single_group = None

        self.channellists = {}
        self.manager = model
        self.manager.connect('group-added', self._on_manager_group_added)
        self.manager.connect('group-removed', self._on_manager_group_removed)

        self.connect('delete-event', Gtk.main_quit)
        self.connect('destroy-event', Gtk.main_quit)
        self.set_title(_("DVB Control Center"))
        self.set_default_size(800, 500)

        self.vbox_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.vbox_outer.show()
        self.add(self.vbox_outer)

        self.toolbar = None
        self.vbox_left = None
        self.__create_menu()
        self.__create_toolbar()

        self.hbox = Gtk.Box(spacing=6)
        self.vbox_outer.pack_start(self.hbox, True, True, 0)

        self.hpaned = Gtk.Paned()
        self.hpaned.set_border_width(3)
        self.hpaned.set_position(175)
        self.hbox.pack_start(self.hpaned, True, True, 0)

        self.vbox_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=6)
        self.hpaned.pack1(self.vbox_left)

        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)
        self.devgroupslist.connect("row-inserted",
                                   self._on_devgroupslist_inserted)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(
            self.devgroupslist)

        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)
        self.devgroupscombo.connect("changed", self._on_devgroupscombo_changed)
        self.vbox_left.pack_start(self.devgroupscombo, False, True, 0)

        self.channelsstore = None

        self.channelsview = ChannelsView()
        self.channelsview.set_headers_visible(False)
        self.channelsview.get_selection().connect("changed",
                                                  self._on_channel_selected)

        scrolledchannels = Gtk.ScrolledWindow()
        scrolledchannels.add(self.channelsview)
        scrolledchannels.set_policy(Gtk.PolicyType.AUTOMATIC,
                                    Gtk.PolicyType.AUTOMATIC)
        scrolledchannels.set_shadow_type(Gtk.ShadowType.IN)
        self.vbox_left.pack_start(scrolledchannels, True, True, 0)

        self.schedulestore = None

        self.help_eventbox = HelpBox()
        self.choose_group_text = _(
            "Choose a device group and channel on the left to view the program guide"
        )
        self.create_group_text = _(
            "No devices are configured. Please go to preferences to configure them."
        )
        self.no_events_text = _(
            "There is currently no schedule available for this channel")
        self.hpaned.pack2(self.help_eventbox)

        self.schedulepaned = SchedulePaned()
        self.schedulepaned.show()
        self.scheduleview = self.schedulepaned.get_treeview()
        self.scheduleview.connect("button-press-event",
                                  self._on_event_selected)

        self.get_device_groups()
        if len(self.devgroupslist) == 0:
            self.help_eventbox.set_markup(self.create_group_text)
        else:
            self._select_first_group()

        Gtk.Window.set_default_icon_name("gnome-dvb-daemon")
class ControlCenterWindow(Gtk.Window):
    def __init__(self, model):
        GObject.GObject.__init__(self)

        self.runningnextstore = None
        self.scrolledrunningnext = None
        self.runningnextview = None
        self.__single_group = None

        self.channellists = {}
        self.manager = model
        self.manager.connect('group-added', self._on_manager_group_added)
        self.manager.connect('group-removed', self._on_manager_group_removed)

        self.connect('delete-event', Gtk.main_quit)
        self.connect('destroy-event', Gtk.main_quit)
        self.set_title(_("DVB Control Center"))
        self.set_default_size(800, 500)

        self.vbox_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.vbox_outer.show()
        self.add(self.vbox_outer)

        self.toolbar = None
        self.vbox_left = None
        self.__create_menu()
        self.__create_toolbar()

        self.hbox = Gtk.Box(spacing=6)
        self.vbox_outer.pack_start(self.hbox, True, True, 0)

        self.hpaned = Gtk.Paned()
        self.hpaned.set_border_width(3)
        self.hpaned.set_position(175)
        self.hbox.pack_start(self.hpaned, True, True, 0)

        self.vbox_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=6)
        self.hpaned.pack1(self.vbox_left)

        self.devgroupslist = Gtk.ListStore(str, int, GObject.GObject)
        self.devgroupslist.connect("row-inserted",
                                   self._on_devgroupslist_inserted)

        self.devgroupscombo = Gtk.ComboBox.new_with_model_and_entry(
            self.devgroupslist)

        cell_adapter = Gtk.CellRendererText()
        self.devgroupscombo.pack_start(cell_adapter, True)
        self.devgroupscombo.set_entry_text_column(0)
        self.devgroupscombo.connect("changed", self._on_devgroupscombo_changed)
        self.vbox_left.pack_start(self.devgroupscombo, False, True, 0)

        self.channelsstore = None

        self.channelsview = ChannelsView()
        self.channelsview.set_headers_visible(False)
        self.channelsview.get_selection().connect("changed",
                                                  self._on_channel_selected)

        scrolledchannels = Gtk.ScrolledWindow()
        scrolledchannels.add(self.channelsview)
        scrolledchannels.set_policy(Gtk.PolicyType.AUTOMATIC,
                                    Gtk.PolicyType.AUTOMATIC)
        scrolledchannels.set_shadow_type(Gtk.ShadowType.IN)
        self.vbox_left.pack_start(scrolledchannels, True, True, 0)

        self.schedulestore = None

        self.help_eventbox = HelpBox()
        self.choose_group_text = _(
            "Choose a device group and channel on the left to view the program guide"
        )
        self.create_group_text = _(
            "No devices are configured. Please go to preferences to configure them."
        )
        self.no_events_text = _(
            "There is currently no schedule available for this channel")
        self.hpaned.pack2(self.help_eventbox)

        self.schedulepaned = SchedulePaned()
        self.schedulepaned.show()
        self.scheduleview = self.schedulepaned.get_treeview()
        self.scheduleview.connect("button-press-event",
                                  self._on_event_selected)

        self.get_device_groups()
        if len(self.devgroupslist) == 0:
            self.help_eventbox.set_markup(self.create_group_text)
        else:
            self._select_first_group()

        Gtk.Window.set_default_icon_name("gnome-dvb-daemon")

    def __create_menu(self):
        ui = '''
        <menubar name="MenuBar">
          <menu action="Timers">
            <menuitem action="EditTimers"/>
            <menuitem action="Recordings"/>
            <separator/>
            <menuitem action="Quit"/>
          </menu>
          <menu action="Edit">
            <menuitem action="EditChannelLists"/>
            <separator/>
            <menuitem action="Preferences"/>
          </menu>
          <menu action="View">
            <menuitem action="WhatsOnNow"/>
            <menuitem action="Refresh"/>
            <menuitem action="PrevDay"/>
            <menuitem action="NextDay"/>
            <separator/>
            <menuitem action="Channels"/>
            <menuitem action="Toolbar"/>
          </menu>
          <menu action="Help">
            <menuitem action="About"/>
          </menu>
        </menubar>'''

        uimanager = Gtk.UIManager()

        # Add the accelerator group to the toplevel window
        accelgroup = uimanager.get_accel_group()
        self.add_accel_group(accelgroup)

        # Create actions
        actiongroup = Gtk.ActionGroup(name='Root')
        actiongroup.add_actions([
            ('Timers', None, _('_Recording schedule')),
            ('Edit', None, _('_Edit')),
            ('View', None, _('_View')),
            ('Help', None, _('Help')),
        ])
        # Add the actiongroup to the uimanager
        uimanager.insert_action_group(actiongroup, 0)

        actiongroup = Gtk.ActionGroup(name='Timers')
        actiongroup.add_actions([
            ('EditTimers', None, _('_Manage'), '<Control>T',
             _('Manage recording schedule'),
             self._on_button_display_timers_clicked),
            ('Recordings', None, _('_Recordings'), '<Control>W',
             _('Manage recordings'), self._on_button_recordings_clicked),
            ('Quit', Gtk.STOCK_QUIT, _('_Quit'), None, _('Quit the Program'),
             Gtk.main_quit)
        ])
        uimanager.insert_action_group(actiongroup, 1)

        actiongroup = Gtk.ActionGroup(name='Edit')
        actiongroup.add_actions([
            ('EditChannelLists', None, _('_Channel Lists'), None,
             _('Edit channel lists'), self._on_edit_channellists_clicked),
            ('Preferences', Gtk.STOCK_PREFERENCES, _('_Preferences'), None,
             _('Display preferences'), self._on_button_prefs_clicked),
        ])
        uimanager.insert_action_group(actiongroup, 2)

        actiongroup = Gtk.ActionGroup(name='View')
        actiongroup.add_actions([
            ('WhatsOnNow', None, _("_What's on now"), None,
             _("See what's currently on and is coming next"),
             self._on_whats_on_now_clicked),
            ('Refresh', Gtk.STOCK_REFRESH, _('_Refresh'), '<Control>R',
             _('Refresh program guide'), self._on_refresh_clicked),
            ('PrevDay', None, _('_Previous Day'), '<Alt>Left',
             _('Go to previous day'), self._on_button_prev_day_clicked),
            ('NextDay', None, _('_Next Day'), '<Alt>Right',
             _('Go to next day'), self._on_button_next_day_clicked),
        ])
        actiongroup.add_toggle_actions([
            ('Channels', None, _('_Channels'), None, _('View/Hide channels'),
             self._on_view_channels_clicked),
            ('Toolbar', None, _('_Toolbar'), None, _('View/Hide toolbar'),
             self._on_view_toolbar_clicked),
        ])
        action = actiongroup.get_action('Toolbar')
        action.set_active(True)
        action = actiongroup.get_action('Channels')
        action.set_active(True)
        uimanager.insert_action_group(actiongroup, 3)

        actiongroup = Gtk.ActionGroup(name='Help')
        actiongroup.add_actions([
            ('About', Gtk.STOCK_ABOUT, _('_About'), None,
             _('Display informations about the program'),
             self._on_about_clicked),
        ])
        uimanager.insert_action_group(actiongroup, 4)

        # Add a UI description
        uimanager.add_ui_from_string(ui)

        timers_image = Gtk.Image.new_from_icon_name("appointment-soon",
                                                    Gtk.IconSize.MENU)
        timers_image.show()

        self.timersitem = uimanager.get_widget('/MenuBar/Timers/EditTimers')
        self.timersitem.set_image(timers_image)
        self.timersitem.set_sensitive(False)

        recordings_image = Gtk.Image.new_from_icon_name(
            "video-x-generic", Gtk.IconSize.MENU)
        recordings_image.show()

        recordings = uimanager.get_widget('/MenuBar/Timers/Recordings')
        recordings.set_image(recordings_image)

        whatson_image = Gtk.Image.new_from_stock(Gtk.STOCK_INDEX,
                                                 Gtk.IconSize.MENU)
        whatson_image.show()

        self.whatons_item = uimanager.get_widget('/MenuBar/View/WhatsOnNow')
        self.whatons_item.set_image(whatson_image)
        self.whatons_item.set_sensitive(False)

        self.refresh_menuitem = uimanager.get_widget('/MenuBar/View/Refresh')
        self.refresh_menuitem.set_sensitive(False)

        self.prev_day_menuitem = uimanager.get_widget('/MenuBar/View/PrevDay')
        prev_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_BACK,
                                              Gtk.IconSize.MENU)
        prev_image.show()
        self.prev_day_menuitem.set_image(prev_image)
        self.prev_day_menuitem.set_sensitive(False)

        self.next_day_menuitem = uimanager.get_widget('/MenuBar/View/NextDay')
        next_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_FORWARD,
                                              Gtk.IconSize.MENU)
        next_image.show()
        self.next_day_menuitem.set_image(next_image)
        self.next_day_menuitem.set_sensitive(False)

        # Create a MenuBar
        menubar = uimanager.get_widget('/MenuBar')
        menubar.show()
        self.vbox_outer.pack_start(menubar, False, True, 0)

    def __create_toolbar(self):
        self.toolbar = Gtk.Toolbar()
        self.toolbar.show()
        self.vbox_outer.pack_start(self.toolbar, False, True, 0)

        timers_image = Gtk.Image.new_from_icon_name("appointment-soon",
                                                    Gtk.IconSize.MENU)
        timers_image.show()

        self.button_display_timers = Gtk.ToolButton(
            icon_widget=timers_image, label=_("Recording schedule"))
        self.button_display_timers.set_is_important(True)
        self.button_display_timers.set_sensitive(False)
        self.button_display_timers.connect(
            "clicked", self._on_button_display_timers_clicked)
        self.button_display_timers.set_tooltip_markup(
            _("Manage recording schedule"))
        self.button_display_timers.show()
        self.toolbar.insert(self.button_display_timers, 0)

        recordings_image = Gtk.Image.new_from_icon_name(
            "video-x-generic", Gtk.IconSize.MENU)
        recordings_image.show()

        button_recordings = Gtk.ToolButton(icon_widget=recordings_image,
                                           label=_("Recordings"))
        button_recordings.set_is_important(True)
        button_recordings.connect("clicked",
                                  self._on_button_recordings_clicked)
        button_recordings.show()
        self.toolbar.insert(button_recordings, 1)

        whatson_image = Gtk.Image.new_from_stock(Gtk.STOCK_INDEX,
                                                 Gtk.IconSize.LARGE_TOOLBAR)
        whatson_image.show()

        self.button_whatson = Gtk.ToolButton(icon_widget=whatson_image,
                                             label=_("What's on now"))
        self.button_whatson.set_is_important(True)
        self.button_whatson.set_sensitive(False)
        self.button_whatson.connect("clicked", self._on_whats_on_now_clicked)
        self.button_whatson.show()
        self.toolbar.insert(self.button_whatson, 2)

        sep = Gtk.SeparatorToolItem()
        sep.show()
        self.toolbar.insert(sep, 3)

        self.refresh_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_REFRESH)
        self.refresh_button.connect("clicked", self._on_refresh_clicked)
        self.refresh_button.set_tooltip_markup(_("Refresh program guide"))
        self.refresh_button.show()
        self.toolbar.insert(self.refresh_button, 4)

        prev_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_BACK,
                                              Gtk.IconSize.LARGE_TOOLBAR)
        prev_image.show()
        self.button_prev_day = Gtk.ToolButton(icon_widget=prev_image,
                                              label=_("Previous Day"))
        self.button_prev_day.connect("clicked",
                                     self._on_button_prev_day_clicked)
        self.button_prev_day.set_tooltip_markup(_("Go to previous day"))
        self.button_prev_day.set_sensitive(False)
        self.button_prev_day.show()
        self.toolbar.insert(self.button_prev_day, 5)

        next_image = Gtk.Image.new_from_stock(Gtk.STOCK_GO_FORWARD,
                                              Gtk.IconSize.LARGE_TOOLBAR)
        next_image.show()
        self.button_next_day = Gtk.ToolButton(icon_widget=next_image,
                                              label=_("Next Day"))
        self.button_next_day.connect("clicked",
                                     self._on_button_next_day_clicked)
        self.button_next_day.set_tooltip_markup(_("Go to next day"))
        self.button_next_day.set_sensitive(False)
        self.button_next_day.show()
        self.toolbar.insert(self.button_next_day, 6)

    def get_device_groups(self):
        def append_groups(groups):
            for group in groups:
                self._append_group(group)
            self.check_single_group_mode()

        self.manager.get_registered_device_groups(result_handler=append_groups)

    def check_single_group_mode(self):
        val = len(self.devgroupslist) == 1
        if val:
            aiter = self.devgroupslist.get_iter_first()
            self.__single_group = self.devgroupslist[aiter][2]
            self.devgroupscombo.hide()
        else:
            self.__single_group = None
            self.devgroupscombo.show()

    def _select_first_group(self):
        self.devgroupscombo.set_active(0)
        self.channelsview.grab_focus()

    def _append_group(self, group):
        self.devgroupslist.append([group["name"], group["id"], group])
        self.channellists[group["id"]] = group.get_channel_list()

    def _remove_group(self, group_id):
        aiter = None
        for row in self.devgroupslist:
            if row[1] == group_id:
                aiter = row.iter

        if aiter != None:
            if self._get_selected_group()["id"] == group_id:
                # Select no group
                self.devgroupscombo.set_active(-1)

            self.devgroupslist.remove(aiter)
            del self.channellists[group_id]

    def _reset_ui(self):
        self.channelsstore = None
        self.channelsview.set_model(None)
        if len(self.devgroupslist) == 0:
            text = self.create_group_text
        else:
            text = self.choose_group_text
        self._display_help_message(text)
        self._set_timers_sensitive(False)

    def _reset_schedule_view(self):
        self.schedulestore = None
        self.scheduleview.set_model(None)
        self._display_running_next()

    def _on_manager_group_added(self, manager, group_id):
        group = self.manager.get_device_group(group_id)
        if group != None:
            self._append_group(group)
            self.check_single_group_mode()

    def _on_manager_group_removed(self, manager, group_id):
        self._remove_group(group_id)
        self.check_single_group_mode()
        self._select_first_group()

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

    def _get_selected_channel_sid(self):
        model, aiter = self.channelsview.get_selection().get_selected()
        if aiter != None:
            sid = model[aiter][model.COL_SID]
            return sid
        else:
            return None

    def _on_devgroupscombo_changed(self, combo):
        group = self._get_selected_group()
        if group != None:
            self._set_timers_sensitive(True)
            self._set_whatson_sensitive(True)

            self.channelsstore = ChannelsStore(group)
            self.channelsview.set_model(self.channelsstore)

            self._reset_schedule_view()
        else:
            self._reset_ui()

    def _on_devgroupslist_inserted(self, model, path, aiter):
        if len(model) == 1:
            # Delay the call otherwise we get DBus errors
            GLib.timeout_add(100, self._select_first_group)

    def _on_channel_selected(self, treeselection):
        model, aiter = treeselection.get_selected()
        child = self.hpaned.get_child2()
        if aiter != None:
            sid = model[aiter][model.COL_SID]
            group = self._get_selected_group()
            self.schedulestore = ScheduleStore(group, sid)
            self.schedulestore.connect("loading-finished",
                                       self._on_schedule_loading_finished)

            self.scheduleview.set_model(self.schedulestore)
            # Display schedule if it isn't already displayed
            if child != self.schedulepaned:
                self.hpaned.remove(child)
                self.hpaned.pack2(self.schedulepaned)
                self._set_previous_day_sensitive(True)
                self._set_next_day_sensitive(True)
                self._set_refresh_sensitive(True)
        else:
            # Display running/next if it isn't already displayed
            if child != self.scrolledrunningnext:
                self._display_running_next()

    def _on_schedule_loading_finished(self, schedulestore):
        if len(self.schedulestore) == 0:
            self._display_help_message(self.no_events_text)

    def _display_help_message(self, text):
        child = self.hpaned.get_child2()
        self.hpaned.remove(child)
        self.hpaned.pack2(self.help_eventbox)
        self._set_previous_day_sensitive(False)
        self._set_next_day_sensitive(False)
        self._set_refresh_sensitive(False)

        self.help_eventbox.set_markup(text)

    def _display_running_next(self):
        group = self._get_selected_group()

        self.runningnextstore = RunningNextStore(group)

        self.scrolledrunningnext = Gtk.ScrolledWindow()
        self.scrolledrunningnext.set_policy(Gtk.PolicyType.AUTOMATIC,
                                            Gtk.PolicyType.AUTOMATIC)
        self.scrolledrunningnext.set_shadow_type(Gtk.ShadowType.IN)
        self.scrolledrunningnext.show()

        self.runningnextview = RunningNextView(self.runningnextstore)
        self.runningnextview.show()
        self.scrolledrunningnext.add(self.runningnextview)

        child = self.hpaned.get_child2()
        self.hpaned.remove(child)
        self.hpaned.pack2(self.scrolledrunningnext)
        self._set_previous_day_sensitive(False)
        self._set_next_day_sensitive(False)
        self._set_refresh_sensitive(False)

    def _set_next_day_sensitive(self, val):
        self.button_next_day.set_sensitive(val)
        self.next_day_menuitem.set_sensitive(val)

    def _set_previous_day_sensitive(self, val):
        self.button_prev_day.set_sensitive(val)
        self.prev_day_menuitem.set_sensitive(val)

    def _set_timers_sensitive(self, val):
        self.button_display_timers.set_sensitive(val)
        self.timersitem.set_sensitive(val)

    def _set_refresh_sensitive(self, val):
        self.refresh_button.set_sensitive(val)
        self.refresh_menuitem.set_sensitive(val)

    def _set_whatson_sensitive(self, val):
        self.whatons_item.set_sensitive(val)
        self.button_whatson.set_sensitive(val)

    def _on_event_selected(self, treeview, event):
        if event.type == getattr(Gdk.EventType, "2BUTTON_PRESS"):
            model, aiter = treeview.get_selection().get_selected()
            if aiter != None:
                dialog = Gtk.MessageDialog(
                    parent=self,
                    flags=Gtk.DialogFlags.MODAL
                    | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    type=Gtk.MessageType.QUESTION,
                    buttons=Gtk.ButtonsType.YES_NO)
                dialog.set_markup(
                    "<big><span weight=\"bold\">%s</span></big>" %
                    _("Schedule recording for the selected event?"))

                success = True
                if dialog.run() == Gtk.ResponseType.YES:
                    event_id = model[aiter][model.COL_EVENT_ID]
                    group = self._get_selected_group()
                    channel_sid = self._get_selected_channel_sid()
                    recorder = group.get_recorder()
                    rec_id, success = recorder.add_timer_for_epg_event(
                        event_id, channel_sid)
                dialog.destroy()

                if not success:
                    dialog = TimerFailureDialog(self)
                    dialog.run()
                    dialog.destroy()

    def _on_button_display_timers_clicked(self, button, user_data=None):
        group = self._get_selected_group()
        if group != None:
            edit = EditTimersDialog(group, self)
            edit.run()
            edit.destroy()

    def _on_whats_on_now_clicked(self, button, user_data=None):
        self._reset_schedule_view()

    def _on_refresh_clicked(self, button, user_data=None):
        self.schedulestore.reload_all()

    def _on_button_prev_day_clicked(self, button, user_data=None):
        if self.schedulestore != None:
            model, aiter = self.scheduleview.get_selection().get_selected()
            if aiter == None:
                path, col, x, y = self.scheduleview.get_path_at_pos(1, 1)
                aiter = model.get_iter(path)

            day_iter = self.schedulestore.get_previous_day_iter(aiter)
            if day_iter == None:
                self._set_previous_day_sensitive(False)
            else:
                self._set_next_day_sensitive(True)
                day_path = model.get_path(day_iter)
                self.scheduleview.scroll_to_cell(day_path, use_align=True)
                self.scheduleview.set_cursor(day_path, None, False)

    def _on_button_next_day_clicked(self, button, user_data=None):
        if self.schedulestore != None:
            model, aiter = self.scheduleview.get_selection().get_selected()
            if aiter == None:
                path, col, x, y = self.scheduleview.get_path_at_pos(1, 1)
                aiter = model.get_iter(path)

            day_iter = self.schedulestore.get_next_day_iter(aiter)
            if day_iter == None:
                self._set_next_day_sensitive(False)
            else:
                self._set_previous_day_sensitive(True)
                day_path = model.get_path(day_iter)
                self.scheduleview.scroll_to_cell(day_path, use_align=True)
                self.scheduleview.set_cursor(day_path, None, False)

    def _on_button_prefs_clicked(self, button, user_data=None):
        prefs = Preferences(self.manager, self)
        prefs.show()

    def _on_button_recordings_clicked(self, button, user_data=None):
        dialog = RecordingsDialog(self)
        dialog.run()
        dialog.destroy()

    def _on_view_channels_clicked(self, action, user_data=None):
        if self.vbox_left:
            if action.get_active():
                self.vbox_left.show()
            else:
                self.vbox_left.hide()

    def _on_view_toolbar_clicked(self, action, user_data=None):
        if self.toolbar:
            if action.get_active():
                self.toolbar.show()
            else:
                self.toolbar.hide()

    def _on_about_clicked(self, action, user_data=None):
        about = Gtk.AboutDialog()
        about.set_transient_for(self)
        #translators: These appear in the About dialog, usual format applies.
        about.set_translator_credits(_("translator-credits"))

        for prop, val in list(gnomedvb.INFOS.items()):
            about.set_property(prop, val)

        about.set_screen(self.get_screen())
        about.run()
        about.destroy()

    def _on_edit_channellists_clicked(self, action, user_data=None):
        dialog = ChannelListEditorDialog(self.manager, parent=self)
        dialog.run()
        dialog.destroy()
    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)
Example #10
0
    def __init__(self, parent, device_group, channel=None,
            starttime=None, duration=60):
        """
        @param parent: Parent window
        @type parent: Gtk.Window
        @param device_group: DeviceGroup instance
        """
        Gtk.Dialog.__init__(self, parent=parent)

        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.set_default_size(320, -1)

        self.device_group = device_group
        self.date_valid = False
        self.allowed_delta = datetime.timedelta(hours=1)

        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
        self.ok_button = self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)

        self.set_border_width(5)

        table = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL)
        table.set_column_spacing(18)
        table.set_row_spacing(6)
        table.set_border_width(5)
        self.get_content_area().pack_start(table, True, True, 0)

        label_channel = TextFieldLabel()
        table.add(label_channel)

        if channel == None:
            self.channel_selected = False
            self.set_title(_("Add Timer"))
            self.ok_button.set_sensitive(False)

            label_channel.set_markup_with_mnemonic(_("_Channel:"))
            self.channels = ChannelsStore(device_group)

            scrolledchannels = Gtk.ScrolledWindow(expand=True)
            scrolledchannels.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
            scrolledchannels.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
            table.attach_next_to(scrolledchannels, label_channel,
                Gtk.PositionType.BOTTOM, 2, 1)

            self.channelsview = ChannelsView(self.channels)
            self.channelsview.set_headers_visible(False)
            self.channelsview.get_selection().connect("changed",
                self._on_channel_changed)
            scrolledchannels.add(self.channelsview)
            label_channel.set_mnemonic_widget(self.channelsview)
            self.channelsview.grab_focus()
        else:
            self.channel_selected = True
            self.set_title(_("Edit Timer"))
            self.ok_button.set_sensitive(True)

            label_channel.set_text(_("Channel:"))
            self.channels = None
            self.channelsview = None
            channel_label = TextFieldLabel(channel)
            table.attach_next_to(channel_label, label_channel,
                Gtk.PositionType.RIGHT, 1, 1)

        label_start = TextFieldLabel()
        label_start.set_markup_with_mnemonic(_("_Start time:"))
        table.add(label_start)

        hbox = Gtk.Box(spacing=6, hexpand=True)
        table.attach_next_to(hbox, label_start, Gtk.PositionType.RIGHT, 1, 1)

        if starttime == None:
            starttime = datetime.datetime.now()

        self.datetime_box = DateTimeBox(starttime)
        self.datetime_box.connect("changed", self._on_datetime_changed)
        hbox.pack_start(self.datetime_box, True, True, 0)
        label_start.set_mnemonic_widget(self.datetime_box)

        label_duration = TextFieldLabel()
        label_duration.set_markup_with_mnemonic(_("_Duration:"))
        table.add(label_duration)

        duration_hbox = Gtk.Box(spacing=6, hexpand=True)
        table.attach_next_to(duration_hbox, label_duration,
            Gtk.PositionType.RIGHT, 1, 1)

        self.duration = Gtk.SpinButton()
        self.duration.set_range(1, 65535)
        self.duration.set_increments(1, 10)
        self.duration.set_width_chars(3)
        self.duration.set_value(60)
        duration_hbox.pack_start(self.duration, False, True, 0)
        label_duration.set_mnemonic_widget(self.duration)

        minutes_label = TextFieldLabel(_("minutes"))
        duration_hbox.pack_start(minutes_label, True, True, 0)

        self.set_start_time(starttime)
        self.set_duration(duration)

        table.show_all()