[ontv] Improved channel reordering



commit c0b2f1a0e4d7cec20f9c8f3c25a80ea4c76d716a
Author: Olof Kindgren <olki src gnome org>
Date:   Sat Oct 23 14:57:51 2010 +0200

    Improved channel reordering
    
    The preferences dialog for reordering channels has been improved to
    use two treeview to distinguish between selected and unselected
    channels. Except for DnD, this fixes bgo#534973

 data/preferences_dialog.ui |  185 +++++++++++++++++++++++++++++++++++---------
 ontv/dialogs.py            |  160 +++++++++++++++++++++++++++++++++-----
 ontv/gui.py                |    6 +-
 3 files changed, 289 insertions(+), 62 deletions(-)
---
diff --git a/data/preferences_dialog.ui b/data/preferences_dialog.ui
index 3c8b633..3d2f919 100644
--- a/data/preferences_dialog.ui
+++ b/data/preferences_dialog.ui
@@ -1,14 +1,22 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 2.12 -->
   <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkTreeModelFilter" id="treemodelfilter1"/>
   <object class="GtkListStore" id="channels_model">
     <columns>
       <!-- column-name col_obj -->
       <column type="PyObject"/>
     </columns>
   </object>
+  <object class="GtkListStore" id="channels_selected_model">
+    <columns>
+      <!-- column-name col_channel_name -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkTreeModelFilter" id="channels_unselected_filter">
+    <property name="child_model">channels_model</property>
+  </object>
   <object class="GtkDialog" id="preferences_dialog">
     <property name="width_request">530</property>
     <property name="height_request">520</property>
@@ -16,7 +24,6 @@
     <property name="title" translatable="yes">Preferences for OnTV</property>
     <property name="window_position">center-always</property>
     <property name="type_hint">dialog</property>
-    <property name="has_separator">False</property>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
@@ -80,7 +87,7 @@
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="invisible_char">â??</property>
                                     <signal name="changed" handler="on_output_file_entry_changed"/>
                                     <signal name="activate" handler="on_output_file_entry_activate"/>
                                   </object>
@@ -109,7 +116,7 @@
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="invisible_char">â??</property>
                                     <signal name="changed" handler="on_grabber_command_entry_changed"/>
                                     <signal name="activate" handler="on_grabber_command_entry_activate"/>
                                   </object>
@@ -246,7 +253,6 @@
                                             <property name="use_underline">True</property>
                                             <property name="active">True</property>
                                             <property name="draw_indicator">True</property>
-                                            <property name="group">upcoming_programs_below_radiobutton</property>
                                           </object>
                                           <packing>
                                             <property name="position">1</property>
@@ -322,56 +328,93 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkScrolledWindow" id="scrolledwindow5">
+                      <object class="GtkHBox" id="hbox1">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="hscrollbar_policy">automatic</property>
-                        <property name="vscrollbar_policy">automatic</property>
-                        <property name="shadow_type">etched-in</property>
                         <child>
-                          <object class="GtkTreeView" id="channels_treeview">
+                          <object class="GtkScrolledWindow" id="scrolledwindow5">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
-                            <property name="model">channels_model</property>
-                            <property name="headers_visible">False</property>
-                            <property name="rules_hint">True</property>
-                            <property name="search_column">2</property>
-                            <signal name="row_activated" handler="on_channels_treeview_row_activated"/>
+                            <property name="hscrollbar_policy">automatic</property>
+                            <property name="vscrollbar_policy">automatic</property>
+                            <property name="shadow_type">etched-in</property>
                             <child>
-                              <object class="GtkTreeViewColumn" id="col_ch_selected">
-                                <property name="title">Selected</property>
+                              <object class="GtkTreeView" id="channels_treeview">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="model">channels_unselected_filter</property>
+                                <property name="headers_visible">False</property>
+                                <property name="headers_clickable">False</property>
+                                <property name="rules_hint">True</property>
+                                <property name="search_column">2</property>
+                                <signal name="row_activated" handler="on_channels_treeview_row_activated"/>
                                 <child>
-                                  <object class="GtkCellRendererToggle" id="cr_toggle">
-                                    <property name="xpad">6</property>
-                                    <property name="ypad">3</property>
-                                    <signal name="toggled" handler="on_channels_treeview_toggled" object="channels_model"/>
+                                  <object class="GtkTreeViewColumn" id="col_ch_logo">
+                                    <property name="title">Logo</property>
+                                    <child>
+                                      <object class="GtkCellRendererPixbuf" id="cr_logo">
+                                        <property name="xpad">3</property>
+                                        <property name="ypad">3</property>
+                                      </object>
+                                    </child>
                                   </object>
                                 </child>
-                              </object>
-                            </child>
-                            <child>
-                              <object class="GtkTreeViewColumn" id="col_ch_logo">
-                                <property name="title">Logo</property>
                                 <child>
-                                  <object class="GtkCellRendererPixbuf" id="cr_logo">
-                                    <property name="xpad">3</property>
-                                    <property name="ypad">3</property>
+                                  <object class="GtkTreeViewColumn" id="col_ch_name">
+                                    <property name="title">Channel</property>
+                                    <child>
+                                      <object class="GtkCellRendererText" id="cr_name">
+                                        <property name="xpad">3</property>
+                                        <property name="ypad">3</property>
+                                      </object>
+                                    </child>
                                   </object>
                                 </child>
                               </object>
                             </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkScrolledWindow" id="scrolledwindow1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hscrollbar_policy">automatic</property>
+                            <property name="vscrollbar_policy">automatic</property>
                             <child>
-                              <object class="GtkTreeViewColumn" id="col_ch_name">
-                                <property name="title">Channel</property>
+                              <object class="GtkTreeView" id="selected_channels_treeview">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="model">channels_selected_model</property>
+                                <property name="headers_visible">False</property>
+                                <property name="headers_clickable">False</property>
+                                <property name="rules_hint">True</property>
                                 <child>
-                                  <object class="GtkCellRendererText" id="cr_name">
-                                    <property name="xpad">3</property>
-                                    <property name="ypad">3</property>
+                                  <object class="GtkTreeViewColumn" id="col_ch_sel_logo">
+                                    <property name="title">Logo</property>
+                                    <child>
+                                      <object class="GtkCellRendererPixbuf" id="cr_ch_sel_logo">
+                                        <property name="xpad">3</property>
+                                        <property name="ypad">3</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkTreeViewColumn" id="col_ch_sel_name">
+                                    <property name="title">Channel</property>
+                                    <child>
+                                      <object class="GtkCellRendererText" id="cr_ch_sel_name"/>
+                                    </child>
                                   </object>
                                 </child>
                               </object>
                             </child>
                           </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
                         </child>
                       </object>
                       <packing>
@@ -385,6 +428,7 @@
                           <object class="GtkButton" id="channel_properties_button">
                             <property name="label">gtk-properties</property>
                             <property name="visible">True</property>
+                            <property name="sensitive">False</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">True</property>
                             <property name="use_stock">True</property>
@@ -396,7 +440,74 @@
                           </packing>
                         </child>
                         <child>
-                          <placeholder/>
+                          <object class="GtkHButtonBox" id="hbuttonbox1">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkButton" id="button_remove_channel">
+                                <property name="label">gtk-remove</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_stock">True</property>
+                                <signal name="clicked" handler="on_button_remove_channel_clicked"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_add_channel">
+                                <property name="label">gtk-add</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_stock">True</property>
+                                <signal name="clicked" handler="on_button_add_channel_clicked"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_move_channel_down">
+                                <property name="label">gtk-go-down</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_stock">True</property>
+                                <signal name="clicked" handler="on_button_move_channel_down_clicked"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_move_channel_up">
+                                <property name="label">gtk-go-up</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_stock">True</property>
+                                <signal name="clicked" handler="on_button_move_channel_up_clicked"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">3</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="fill">False</property>
+                            <property name="pack_type">end</property>
+                            <property name="position">1</property>
+                          </packing>
                         </child>
                       </object>
                       <packing>
diff --git a/ontv/dialogs.py b/ontv/dialogs.py
index 8b4fd61..0227c82 100644
--- a/ontv/dialogs.py
+++ b/ontv/dialogs.py
@@ -147,7 +147,6 @@ class PreferencesDialog:
 
         self.__get_widgets()
 
-        self.__make_channels_treeview()
         self.__make_reminders_treeview()
         #self.sd.create_search_treeview_menu(self.reminders_treeview.get_model())
         self.pw.set_reminders_model(self.reminders_treeview.get_model())
@@ -194,16 +193,26 @@ class PreferencesDialog:
 
         # Channels tab
         self.channels_treeview = builder.get_object("channels_treeview")
+        self.selected_channels_treeview = builder.get_object("selected_channels_treeview")
         self.channels_model = builder.get_object("channels_model")
-
-        builder.get_object("col_ch_selected").set_cell_data_func(builder.get_object("cr_toggle"),
-                                                self.__crtoggle_cell_data_func)
+        self.unselected_channels_filter = builder.get_object("channels_unselected_filter")
+        self.selected_channels_filter = builder.get_object("channels_selected_filter")
         builder.get_object("col_ch_logo").set_cell_data_func(builder.get_object("cr_logo"),
                                                 self.__crpixbuf_cell_data_func)
         builder.get_object("col_ch_name").set_cell_data_func(builder.get_object("cr_name"),
                                                 self.__crtext_cell_data_func)
-
+        builder.get_object("col_ch_sel_logo").set_cell_data_func(builder.get_object("cr_ch_sel_logo"),
+                                                self.__crpixbuf_cell_sel_data_func)
+        builder.get_object("col_ch_sel_name").set_cell_data_func(builder.get_object("cr_ch_sel_name"),
+                                                self.__crtext_cell_sel_data_func)
+        self.unselected_channels_filter.set_visible_func(self.filter)
+        self.selected_channels_model = builder.get_object("channels_selected_model")
         self.channel_properties_button = builder.get_object("channel_properties_button")
+        self.button_add_channel = builder.get_object("button_add_channel")
+        self.button_remove_channel = builder.get_object("button_remove_channel")
+        self.button_move_channel_up = builder.get_object("button_move_channel_up")
+        self.button_move_channel_down = builder.get_object("button_move_channel_down")
+
         # Reminders tab
         self.reminders_treeview = builder.get_object("reminders_treeview")
         self.program_entry = builder.get_object("program_entry")
@@ -213,12 +222,6 @@ class PreferencesDialog:
         self.update_reminder_button = builder.get_object("update_reminder_button")
         self.remove_reminder_button = builder.get_object("remove_reminder_button")
 
-
-    def __make_channels_treeview(self):
-        self.channels_model.set_sort_func(0, self.__channels_model_sort_func)
-        self.channels_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
-        self.channels_treeview.set_search_equal_func(self.__channels_treeview_search_equal)
-
     def __channels_model_sort_func(self, model, iter1, iter2, object=True):
         channel = model.get_value(iter1, 0)
         other_channel = model.get_value(iter2, 0)
@@ -226,6 +229,12 @@ class PreferencesDialog:
             return utils.natcmp(channel.name.lower(), other_channel.name.lower())
         return utils.natcmp(channel.lower(), other_channel.lower())
 
+    def filter(self, model, iter):
+        if iter:
+            channel = model.get_value(iter, 0)
+            if channel:
+                return not channel.selected
+
     def on_channels_treeview_toggled(self, model, path):
         channel = model[path][0]
         channel.selected = not channel.selected
@@ -243,10 +252,6 @@ class PreferencesDialog:
         channel = model.get_value(iter, 0)
         return key.lower() not in channel.name.lower()
 
-    def __crtoggle_cell_data_func(self, column, cell, model, iter):
-        channel = model.get_value(iter, 0)
-        cell.props.active = channel.selected
-
     def __crpixbuf_cell_data_func(self, column, cell, model, iter):
         channel = model.get_value(iter, 0)
         cell.props.pixbuf = channel.logo
@@ -256,6 +261,17 @@ class PreferencesDialog:
         markup = "<b>%s</b>"
         cell.props.markup = markup % channel.markup_escaped_name
 
+    def __crpixbuf_cell_sel_data_func(self, column, cell, model, iter):
+        channel_name = model.get_value(iter, 0)
+        channel = self.listings.channels[channel_name]
+        cell.props.pixbuf = channel.logo
+
+    def __crtext_cell_sel_data_func(self, column, cell, model, iter):
+        channel_name = model.get_value(iter, 0)
+        channel = self.listings.channels[channel_name]
+        markup = "<b>%s</b>"
+        cell.props.markup = markup % channel.markup_escaped_name
+
     def __make_reminders_treeview(self):
         reminders_model = gtk.ListStore(object)
         self.reminders_treeview.set_model(reminders_model)
@@ -307,6 +323,9 @@ class PreferencesDialog:
         selection = self.channels_treeview.get_selection()
         selection.connect("changed", self.__channels_treeview_selection_changed)
 
+        selection = self.selected_channels_treeview.get_selection()
+        selection.connect("changed", self.__selected_channels_treeview_selection_changed)
+
         # Reminders tab
         self.reminders_treeview.connect("key-press-event", self.__reminders_treeview_key_press_event)
         selection = self.reminders_treeview.get_selection()
@@ -332,12 +351,56 @@ class PreferencesDialog:
     def __dialog_delete(self, dialog, event):
         return True
 
+    def __selected_channels_treeview_selection_changed(self, selection):
+        (model, iter) = selection.get_selected()
+        if iter:
+            self.channels_treeview.get_selection().unselect_all()
+            self.update_buttons(selection, True)
+        else:
+            self.update_buttons(None, True)
+
     def __channels_treeview_selection_changed(self, selection):
-        (search_model, search_iter) = selection.get_selected()
-        if search_iter:
+        (model, iter) = selection.get_selected()
+        if iter:
+            self.selected_channels_treeview.get_selection().unselect_all()
+            self.update_buttons(selection, False)
+        else:
+            self.update_buttons(None, False)
+
+    def update_buttons(self, selection, selected):
+        if selection:
             self.channel_properties_button.set_sensitive(True)
+            (model, iter) = selection.get_selected()
+
+            self.button_remove_channel.set_sensitive(selected)
+            self.button_add_channel.set_sensitive(not selected)
+
+            if selected:
+                channel_name = model.get_value(iter, 0)
+                self.selected_channel = self.listings.channels[channel_name]
+
+                row, = model.get_path(iter)
+                if row == 0:
+                    self.button_move_channel_up.set_sensitive(False)
+                else:
+                    self.button_move_channel_up.set_sensitive(True)
+                if row == len(self.selected_channels_model)-:
+                    self.button_move_channel_down.set_sensitive(False)
+                else:
+                    self.button_move_channel_down.set_sensitive(True)
+
+            else:
+                filter = model
+                model = filter.get_model()
+                self.selected_channel = model.get_value(filter.convert_iter_to_child_iter(iter), 0)
+                self.button_move_channel_up.set_sensitive(False)
+                self.button_move_channel_down.set_sensitive(False)
         else:
             self.channel_properties_button.set_sensitive(False)
+            self.button_remove_channel.set_sensitive(False)
+            self.button_add_channel.set_sensitive(False)
+            self.button_move_channel_up.set_sensitive(False)
+            self.button_move_channel_down.set_sensitive(False)
 
     def on_grabber_command_entry_changed(self, entry):
         self.config.grabber_command = entry.get_text()
@@ -385,12 +448,64 @@ class PreferencesDialog:
             menu.popup(None, None, None, event.button, event.time)
 
     def on_channel_properties_button_clicked(self, button):
+        cd = ChannelDialog(self.selected_channel, self)
+        cd.dialog.show()
+
+    def on_button_remove_channel_clicked(self, button):
+        selection = self.selected_channels_treeview.get_selection()
+        (model, iter) = selection.get_selected()
+        if iter:
+            channel_name = model.get_value(iter, 0)
+
+            channel = self.listings.channels[channel_name]
+            channel.selected = False
+            self.unselected_channels_filter.refilter()
+            self.listings.selected_channels.remove(channel_name)
+            self.selected_channels_model.remove(iter)
+            self.pw.update()
+            self.listings.save()
+
+    def on_button_add_channel_clicked(self, button):
         selection = self.channels_treeview.get_selection()
+        (filter, iter) = selection.get_selected()
+        if iter:
+            model = filter.get_model()
+            channel = model.get_value(filter.convert_iter_to_child_iter(iter), 0)
+
+            channel.selected = True
+            self.listings.selected_channels.append(channel.name)
+            self.selected_channels_model.append([channel.name])
+            self.unselected_channels_filter.refilter()
+            self.pw.update()
+            self.listings.save()
+
+    def on_button_move_channel_down_clicked(self, button):
+        selection = self.selected_channels_treeview.get_selection()
+        (model, iter) = selection.get_selected()
+        if iter:
+            row,  = model.get_path(iter)
+            self.listings.selected_channels[row], self.listings.selected_channels[row+1] = \
+                self.listings.selected_channels[row+1], self.listings.selected_channels[row]
+            iter_next = model.get_iter(row+1)
+
+            model.swap(iter,iter_next)
+            self.selected_channels_treeview.get_selection().emit("changed")
+            self.pw.update()
+            self.listings.save()
+
+    def on_button_move_channel_up_clicked(self, button):
+        selection = self.selected_channels_treeview.get_selection()
         (model, iter) = selection.get_selected()
-        channel = model.get_value(iter,0)
-        if channel:
-            cd = ChannelDialog(channel, self)
-            cd.dialog.show()
+        if iter:
+            row,  = model.get_path(iter)
+            self.listings.selected_channels[row], self.listings.selected_channels[row-1] = \
+                self.listings.selected_channels[row-1], self.listings.selected_channels[row]
+            iter_prev = model.get_iter(row-1)
+
+            model.swap(iter,iter_prev)
+            self.selected_channels_treeview.get_selection().emit("changed")
+            self.pw.update()
+            self.listings.save()
 
     def __reminders_treeview_selection_changed(self, selection):
         (reminders_model, reminders_iter) = selection.get_selected()
@@ -553,6 +668,9 @@ class PreferencesDialog:
             self.listings = listings
             self.channels_combobox_model.append([_("All")])
             self.sd.set_all_as_combo_active(self.sd.channels_combobox)
+        self.selected_channels_model.clear()
+        for channel_name in self.listings.selected_channels:
+            self.selected_channels_model.append([channel_name])
 
     def __xmltvfile_loaded_channel(self, xmltvfile, channel):
         self.channels_model.append([channel])
diff --git a/ontv/gui.py b/ontv/gui.py
index 30885f2..7170571 100644
--- a/ontv/gui.py
+++ b/ontv/gui.py
@@ -35,7 +35,6 @@ search_dialog_ui_file = os.path.join(DATA_DIR, "search_dialog.ui")
 preferences_dialog_ui_file = os.path.join(DATA_DIR, "preferences_dialog.ui")
 icon_theme = gtk.icon_theme_get_default()
 
-COL_PROG = 2
 def get_icon_list(sizes):
     icon_list = []
     for size in sizes:
@@ -73,12 +72,11 @@ def has_selection(treeview):
         return True
     return False
 
-def get_selected_value(treeview):
+def get_selected_value(treeview, col=0):
     selection = treeview.get_selection()
     (model, iter) = selection.get_selected()
     if iter:
-        value = model.get_value(iter, COL_PROG)
-        return value
+        return model.get_value(iter, col)
     return None
 
 def queue_resize(treeview):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]