<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>I am attempting to extend the demo program at
      <a class="moz-txt-link-freetext" href="https://python-gtk-3-tutorial.readthedocs.io/en/latest/treeview.html">https://python-gtk-3-tutorial.readthedocs.io/en/latest/treeview.html</a>
      to filter on two columns and sort the resulting filtered rows. 
      The tutorial suggests the following: "Instances of
      Gtk.TreeModelFilter<code></code> can be stacked one onto another,
      to use multiple filters on the same model (in the same way you’d
      use “AND” clauses in a SQL request)."   However the tutorial does
      not give an example of this, and my google fu is failing to find
      an example online.  My attempt at filtering by two columns
      follows.  The code works when filtering by programming language,
      or when filtering by year.  I don't know how to filter by both
      programming language and year.  Suggestions anyone?<br>
    </p>
    <p>""" Sorted and Filtered TreeView Demo Program. Filters on two
      columns. """<br>
      import gi<br>
      <br>
      gi.require_version("Gtk", "3.0")<br>
      from gi.repository import Gtk<br>
      <br>
      # list of tuples for each software<br>
      SOFTWARE_LIST = [<br>
          ("Firefox", 2002, "C++"),<br>
          ("Eclipse", 2004, "Java"),<br>
          ("Pitivi", 2004, "Python"),<br>
          ("Netbeans", 1996, "Java"),<br>
          ("Chrome", 2008, "C++"),<br>
          ("Filezilla", 2001, "C++"),<br>
          ("Bazaar", 2005, "Python"),<br>
          ("Git", 2005, "C"),<br>
          ("Linux Kernel", 1991, "C"),<br>
          ("GCC", 1987, "C"),<br>
          ("Frostwire", 2004, "Java"),<br>
          ("Homebank", 1995, "C"),<br>
          ("Tellico", 2001, "C++"),<br>
          ("gLabels", 2001, "C++"),<br>
          ("Deluge", 2007, "Python"),<br>
      ]<br>
      <br>
      class TreeViewFilterWindow(Gtk.Window):<br>
          """ TreeViewFilterWindow class """<br>
          def __init__(self):<br>
              Gtk.Window.__init__(self, title="Treeview Filter Demo")<br>
              self.set_border_width(10)<br>
      <br>
              # Setting up the self.grid in which the elements are to be
      positioned<br>
              self.grid = Gtk.Grid()<br>
              self.grid.set_column_homogeneous(True)<br>
              self.grid.set_row_homogeneous(True)<br>
              self.add(self.grid)<br>
      <br>
              # Creating the ListStore model<br>
              self.software_liststore = Gtk.ListStore(str, int, str)<br>
              for software_ref in SOFTWARE_LIST:<br>
                  self.software_liststore.append(list(software_ref))<br>
      <br>
              self.current_filter_language = None<br>
              self.current_filter_year = None<br>
      <br>
              # Creating the filters, feeding it with the liststore
      model<br>
              self.language_filter =
      self.software_liststore.filter_new()<br>
              #self.year_filter = self.software_liststore.filter_new()<br>
              # Setting the filter functions<br>
             
      self.language_filter.set_visible_func(self.language_filter_func)<br>
              #self.year_filter.set_visible_func(self.year_filter_func)<br>
      <br>
              # Creating the treeview, using the sorted filter as a
      model and adding the columns<br>
              self.sortedandfilteredtree =
      Gtk.TreeModelSort(model=self.language_filter)<br>
              #self.sortedandfilteredtree =
      Gtk.TreeModelSort(model=self.year_filter)<br>
              self.sortedtreeview =
      Gtk.TreeView.new_with_model(self.sortedandfilteredtree)<br>
              for i, column_title in enumerate(["Software", "Release
      Year", "Programming Language"]):<br>
                  renderer = Gtk.CellRendererText()<br>
                  column = Gtk.TreeViewColumn(column_title, renderer,
      text=i)<br>
                  column.set_sort_order(Gtk.SortType.ASCENDING)<br>
                  column.set_sort_column_id(i)<br>
                  self.sortedtreeview.append_column(column)<br>
      <br>
              # Creating buttons to filter by programming language and
      setting up their events<br>
              self.language_buttons = list()<br>
              for prog_language in ["Java", "C", "C++", "Python",
      "None"]:<br>
                  button = Gtk.Button(label=prog_language)<br>
                  self.language_buttons.append(button)<br>
                  button.connect("clicked",
      self.on_language_selection_button_clicked)<br>
      <br>
              # Creating buttons to filter by release year and setting
      up their events<br>
              self.year_buttons = list()<br>
              for year in [1987, 1991, 1995, 1996, 2001, 2002, 2004,
      2005, 2007, 2008, "None"]:<br>
                  button = Gtk.Button(label=year)<br>
                  self.year_buttons.append(button)<br>
                  button.connect("clicked",
      self.on_year_selection_button_clicked)<br>
      <br>
              # Setting up the layout, putting the treeview in a
      scrollwindow, and the buttons in a<br>
              # set_row_homogeneous<br>
              self.scrollable_treelist = Gtk.ScrolledWindow()<br>
              self.scrollable_treelist.set_vexpand(True)<br>
              self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10)<br>
              self.grid.attach_next_to(self.language_buttons[0],
      self.scrollable_treelist,<br>
                                       Gtk.PositionType.BOTTOM, 1, 1)<br>
      <br>
              # Layout language selection buttons<br>
              for i, button in enumerate(self.language_buttons[1:]):<br>
                  self.grid.attach_next_to(button,
      self.language_buttons[i], Gtk.PositionType.RIGHT, 1, 1)<br>
      <br>
              self.grid.attach_next_to(self.year_buttons[0],
      self.language_buttons[0],<br>
                                       Gtk.PositionType.BOTTOM, 1, 1)<br>
      <br>
              # Layout year selection buttons<br>
              for i, button in enumerate(self.year_buttons[1:]):<br>
                  self.grid.attach_next_to(button, self.year_buttons[i],
      Gtk.PositionType.RIGHT, 1, 1)<br>
      <br>
              self.scrollable_treelist.add(self.sortedtreeview)<br>
      <br>
              self.show_all()<br>
      <br>
          def language_filter_func(self, model, iter, data):<br>
              """ Tests if the language in the row is the one in the
      filter """<br>
              if self.current_filter_language is None or
      self.current_filter_language == "None":<br>
                  return True<br>
              else:<br>
                  return model[iter][2] == self.current_filter_language<br>
      <br>
          def year_filter_func(self, model, iter, data):<br>
              """ Tests if the year in the row is the one in the filter.
      """<br>
              if self.current_filter_year is None or
      self.current_filter_year == "None":<br>
                  return True<br>
              else:<br>
                  return model[iter][1] == self.current_filter_year<br>
      <br>
          def on_language_selection_button_clicked(self, widget):<br>
              """ Called on any of the language button clicks """<br>
              # Set the current language filter to the button's
      scrollable_treelist<br>
              self.current_filter_language = widget.get_label()<br>
              print("%s language selected!" %
      self.current_filter_language)<br>
              # Update the filter, which updates the view in turn<br>
              self.language_filter.refilter()<br>
      <br>
          def on_year_selection_button_clicked(self, widget):<br>
              """ Called on any of the year selection button clicks. """<br>
              if (widget.get_label() == "None"):<br>
                  self.current_filter_year = None<br>
              else:<br>
                  self.current_filter_year = int(widget.get_label())<br>
              print("year %s selected!" % self.current_filter_year)<br>
              self.year_filter.refilter()<br>
      <br>
      TV_WIN = TreeViewFilterWindow()<br>
      TV_WIN.connect("destroy", Gtk.main_quit)<br>
      TV_WIN.show_all()<br>
      Gtk.main()<br>
      <br>
    </p>
  </body>
</html>