[gtkmm] ListStore sorting and Gtk::TreeIter validity problems



Hello,

I am trying to write a program showing a list of books. There are three
columns, the first column having two renderers (Icon + Text).

I have appended a file with the list implementation, also a test package
(can be compiled using "g++ *.cc -o test `pkg-config gtkmm-2.4 --cflags
--libs`") wich demonstrates the following problems:

(1) When using Gtk::TreeModelSort, the initial sorting is done on the
second column, while through using

sortstore->set_sort_column_id(columns.author_and_title, Gtk::SORT_ASCENDING);

i expected it to be done on the first column. How can I change that?

(2) When clicking the first column to change the sort order, the program
is trying to sort the column by the icon rather then the text. How can I
change that?

(3) Most importantly: I am trying to somehow remove the currently
selected row. But when using

store->erase(get_selection()->get_selected());

(the offending code is in GtkBookList::remove_selected())

There is an error message

(test:22738): Gtk-CRITICAL **: file gtkliststore.c: line 1013
(gtk_list_store_remove): assertion `VALID_ITER (iter, list_store)'
failed

(This can be tested by clicking "delete" in the appended test.)

I have been hunting especially the last bug for hours and hours and now
I'm completely lost.

Any hints appreciated.

Thanks,
-Samuel
-- 
 ------------------------------------------------------
|      Samuel Abels       |   http://www.debain.org    |
| spam ad debain dod org  | knipknap ad jabber dod org |
 ------------------------------------------------------
/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "GtkBookList.h"


GtkBookList::GtkBookList()
{
  // Attach the liststore to the treeview.
  store     = Gtk::ListStore::create(columns);
  sortstore = Gtk::TreeModelSort::create(store);
  sortstore->set_sort_column_id(columns.author_and_title, Gtk::SORT_ASCENDING);
  set_model(sortstore);
  set_rules_hint();
  set_headers_visible(TRUE);
  set_headers_clickable();
  
  // Load the icon.
  pixbuf_book = Gdk::Pixbuf::create_from_file("book.png");
  
  // Create a cell renderer and pack it into the "Author and Title" column.
  Gtk::TreeView::Column* col = Gtk::manage(
                                  new Gtk::TreeView::Column("Autor und Titel"));
  col->pack_start(columns.icon,             FALSE);
  col->pack_start(columns.author_and_title, TRUE);
  
  // Enable pango markup language for the text renderer and change the layout
  // for the icon renderer.
  std::vector<Gtk::CellRenderer*> rends = col->get_cell_renderers();
  rends[0]->set_fixed_size(60, 48);
  col->clear_attributes(*rends[1]);
  col->add_attribute(*rends[1], "markup", 1);
  rends[1]->property_yalign() = 0.3;
  
  // Append all columns.
  append_column(*col);
  get_column(0)->set_resizable(TRUE);
  get_column(0)->set_sort_column_id(0);
  append_column("Kategorie", columns.category);
  get_column(1)->set_resizable(TRUE);
  get_column(1)->set_sort_column_id(1);
  append_column("ISBN",      columns.isbn);
  get_column(2)->set_resizable(TRUE);
  get_column(2)->set_sort_column_id(2);
  
  signal_row_activated().connect(
                    sigc::mem_fun(*this, &GtkBookList::on_selection_activated));
  get_selection()->signal_changed().connect(
                    sigc::mem_fun(*this, &GtkBookList::on_selection_changed));
}


GtkBookList::~GtkBookList()
{
}


void GtkBookList::insert_book(Book* book)
{
  Gtk::TreeIter iter = store->append();
  Gtk::TreeRow  row  = *iter;
  row_fill(row, book);
  booklist[book] = iter;
}


void GtkBookList::remove_book(Book* book)
{
  //FIXME: This does not work.
  printf("GtkBookList::remove_book(): %s\n", book->get_title().c_str());
  g_assert(booklist.find(book) != booklist.end());
  Gtk::TreeIter iter = booklist.find(book)->second;
  store->erase(iter);
  booklist.erase(book);
}


void GtkBookList::remove_selected(void)
{
  //FIXME: Neither does this.
  printf("GtkBookList::remove_selected(): Called.\n");
  if (!get_selection()->get_selected())
    return;
  Book* book = get_selection()->get_selected()->get_value(columns.book);
  store->erase(get_selection()->get_selected());
  booklist.erase(book);
}


void GtkBookList::update_soft(void)
{
  std::map<Book*, Gtk::TreeIter>::iterator iter = booklist.begin();
  while (iter != booklist.end()) {
    Book*        book = iter->first;
    Gtk::TreeRow row  = *iter->second;
    row_fill(row, book);
    iter++;
  }
}


Book* GtkBookList::get_first_selected(void)
{
  if (!get_selection()->get_selected())
    return NULL;
  return get_selection()->get_selected()->get_value(columns.book);
}


void GtkBookList::row_fill(Gtk::TreeModel::Row &row, Book* book)
{
  std::vector<Gtk::CellRenderer*> rends = get_column(0)->get_cell_renderers();
  row[columns.icon]             = pixbuf_book;
  row[columns.author_and_title] = "<b>" + book->get_author() + "</b>\n"
                                + book->get_title();
  row[columns.category]         = book->get_category();
  row[columns.isbn]             = book->get_isbn();
  row[columns.book]             = book;
}


void GtkBookList::on_selection_activated(Gtk::TreePath path,
                                         Gtk::TreeViewColumn* column)
{
  Book* book = sortstore->get_iter(path)->get_value(columns.book);
  signal_book_activated.emit(book);
}


void GtkBookList::on_selection_changed(void)
{
  Book* book = get_selection()->get_selected()->get_value(columns.book);
  signal_book_selected.emit(book);
}
/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#ifndef _GTKBOOKLIST_H
#define _GTKBOOKLIST_H

#include <gtkmm.h>
#include <iostream>
#include <map>
#include "Book.h"

class GtkBookList : public Gtk::TreeView {
public:
  GtkBookList();
  ~GtkBookList();
  
  /* Triggered whenever a book has been selected. */
  SigC::Signal1<void, Book*> signal_book_selected;
  /* Triggered whenever a book has been activated. */
  SigC::Signal1<void, Book*> signal_book_activated;
  
  /* Inserts the given book. */
  void insert_book(Book* book);
  
  /* Removes the given book from the list. */
  void remove_book(Book* book);
  
  /* Removes the selected book. */
  void remove_selected(void);
  
  /* Walks through all books that are currently in the list, updating the
   * row text in case anything changed. */
  void update_soft(void);
  
  /* Returns the first selected book. */
  Book* get_first_selected(void);
  
private:
  /* Fills the given tree row with the data from the given book. */
  void row_fill(Gtk::TreeModel::Row &row, Book* book);
  
  void on_selection_activated(Gtk::TreePath path,
                              Gtk::TreeViewColumn* column);
  void on_selection_changed(void);
  
  // List model columns.
  class ModelColumns : public Gtk::TreeModel::ColumnRecord {
  public:
    Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon;
    Gtk::TreeModelColumn<Glib::ustring>              author_and_title;
    Gtk::TreeModelColumn<Glib::ustring>              category;
    Gtk::TreeModelColumn<Glib::ustring>              isbn;
    Gtk::TreeModelColumn<Book*>                      book;
    ModelColumns() {
      add(icon);
      add(author_and_title);
      add(category);
      add(isbn);
      add(book);
    }
  };
  Glib::RefPtr<Gtk::ListStore>     store;
  Glib::RefPtr<Gtk::TreeModelSort> sortstore;
  Gtk::CellRendererText            renderer_text;
  Glib::RefPtr<Gdk::Pixbuf>        pixbuf_book;
  ModelColumns                     columns;
  std::map<Book*, Gtk::TreeIter>   booklist;
};

#endif /* _GTKBOOKLIST_H */

Attachment: booklist.tar.bz2
Description: application/bzip-compressed-tar



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