treeview selection single



I'm using gtk+ via gtkmm.

I'm porting an application from to the new API but I have a problem with
code that was working in the previous version. I use several selectors
that are connected to "folders" following the model/view pattern (well,
with gtkmm 2.0 it's model/model-of-the-model/view!). I use the same code
in folder editors pannel and in one-click pop-up menus. In this second
situation I use Gtk::SELECTION_SINGLE otherwise Gtk::SELECTION_BROWSE.
The problems seems to be that, even with Gtk::SELECTION_SINGLE,
somewhere Gtk automatically selects the first item and the pop-up
closes. Obviously this was not the case using gtkmm-1.2.

I also tried connecting my selection callback after the population of
the model and unselecting all in several places but there is no way.

Strange but the examples/book/tree/list demo behaves in a similar way.
The first item is selected even if it shouldn't. The gtk demo on the
list store seems to work fine instead.

Any suggestion?

I hope this is not a stupid error on my side. I attached the code.

Maurizio Umberto Puxeddu.

// MetaControl
// Copyright (C) 2003 Maurizio Umberto Puxeddu

#ifndef _itemList_H_
#define _itemList_H_

#include <iostream>
#include <list>
#include <string>
#include <algorithm>

#include <gtkmm.h>

#include "utility.H"
#include "box.H"
#include "folder.H"
#include "window.H"
#include "regex.H"

template <class Item, class ItemFolder>
class ItemList : public Gtk::TreeView {
public:
  ItemList(ItemFolder &folder, bool autoselect = true, bool showtitle = true, 
	   const std::list<std::string> &excluded = std::list<std::string>());
 
  SigC::Signal1<void, const std::string &> item_selected;
  SigC::Signal1<void, int> resized;

  int size(void);

  std::string get_focused_item(void) const;
  void set_focused_item(const std::string &name, bool noemit = false);
  void clear_selection(void);

  void set_pattern(const std::string &pattern);
  std::string get_pattern(void) const;

  void copy_selection(void);
  void remove_selection(void);
  void add_item(void);

protected:
  class ModelColumns : public Gtk::TreeModel::ColumnRecord {
  public:

    ModelColumns() {
      add(m_col_id);
      add(m_col_name);
    }

    Gtk::TreeModelColumn<unsigned int> m_col_id;
    Gtk::TreeModelColumn<Glib::ustring> m_col_name;
  };

  ModelColumns m_Columns;
  Glib::RefPtr<Gtk::ListStore> m_refTreeModel;

  ItemFolder &m_folder;
  std::string m_focused_item;
  bool m_autoselect;
  std::list<std::string> m_excluded;
  Regex m_rx;

  void item_selected_cb(void);

  void update_list(void);

  // Folder callbacks
  void item_added_cb(const std::string &name, const Item &);
  void item_removed_cb(const std::string &name);
  void item_renamed_cb(const std::string &old_name, const std::string &new_name);
  void folder_cleared_cb(void);

  void copy_row(const Gtk::TreeModel::iterator& i);
  void remove_row(const Gtk::TreeModel::iterator& i);
};

template <class Item, class ItemFolder>
ItemList<Item, ItemFolder>::ItemList(ItemFolder &folder, bool autoselect, bool showtitle,
				     const std::list<std::string> &excluded) :
  m_folder(folder),
  m_autoselect(autoselect),
  m_excluded(excluded)
{
  if (m_autoselect) {
    get_selection()->set_mode(Gtk::SELECTION_BROWSE);
    std::cout << "browse" << std::endl;
  } else {
    get_selection()->set_mode(Gtk::SELECTION_SINGLE);
    std::cout << "single" << std::endl;
  }

  m_refTreeModel = Gtk::ListStore::create(m_Columns);
  set_model(m_refTreeModel);

  append_column("Name", m_Columns.m_col_name);
  set_headers_visible(showtitle);
  set_headers_clickable(false);

  update_list();

  get_selection()->signal_changed().connect(SigC::slot(*this, &ItemList::item_selected_cb));

  m_folder.item_renamed.connect(SigC::slot(*this, &ItemList<Item, ItemFolder>::item_renamed_cb));
  m_folder.item_added.connect(SigC::slot(*this, &ItemList<Item, ItemFolder>::item_added_cb));
  m_folder.item_removed.connect(SigC::slot(*this, &ItemList<Item, ItemFolder>::item_removed_cb));
  m_folder.cleared.connect(SigC::slot(*this, &ItemList<Item, ItemFolder>::folder_cleared_cb));

  get_selection()->unselect_all();
  std::cout << "created" << std::endl;
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::set_pattern(const std::string &pattern) {
  m_rx.compile(pattern);
  update_list();
}

template <class Item, class ItemFolder>
std::string ItemList<Item, ItemFolder>::get_pattern(void) const {
  return m_rx.get_pattern();
}

template <class Item, class ItemFolder>
int ItemList<Item, ItemFolder>::size(void) {
  return m_folder.size();
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::update_list(void) {
  typename ItemFolder::Items::iterator i;
  
  m_refTreeModel->clear();
  for (i = m_folder.begin(); i != m_folder.end(); ++i) {
    if (!m_rx.match(i->first)) continue;
    if (std::find(m_excluded.begin(), m_excluded.end(), i->first) == m_excluded.end())
      item_added_cb(i->first, i->second);
  }
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::item_selected_cb(void) {
  Gtk::TreeModel::iterator iter = get_selection()->get_selected();
  if(iter) {
    Gtk::TreeModel::Row row = *iter;
    std::cout << row.get_value(m_Columns.m_col_name) << std::endl;
    set_focused_item(row.get_value(m_Columns.m_col_name));
  }
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::clear_selection(void) {
  if (m_focused_item != "") {
    m_focused_item = "";
    get_selection()->unselect_all();
  }
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::set_focused_item(const std::string &name, bool noemit) {
  if (name == "" && m_focused_item == name) return;
  m_focused_item = name;
  if (!noemit) item_selected(name);
}

template <class Item, class ItemFolder>
std::string ItemList<Item, ItemFolder>::get_focused_item(void) const {
  return m_focused_item;
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::item_added_cb(const std::string &name, const Item &) {
  if (std::find(m_excluded.begin(), m_excluded.end(), name) != m_excluded.end()) return;

  Gtk::TreeModel::iterator iter = m_refTreeModel->append();
  Gtk::TreeModel::Row row = *iter;

  row[m_Columns.m_col_name] = name;

  if (m_autoselect) {
    std::cout << "autoselecting: " << name << std::endl;
    get_selection()->select(row);
  }

  resized(m_folder.size());
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::item_removed_cb(const std::string &name) {
  int i;
  
  if (std::find(m_excluded.begin(), m_excluded.end(), name) != m_excluded.end())
    m_excluded.remove(name);

  typedef Gtk::TreeModel::Children type_children;
  type_children children = m_refTreeModel->children();
  for(type_children::iterator i = children.begin(); i != children.end(); ++i) {
    Gtk::TreeModel::Row row = *i;
    if (row[m_Columns.m_col_name] == name) {
      if (name == m_focused_item)
	set_focused_item("");

      m_refTreeModel->erase(i);

      if (m_autoselect) {
      }

      resized(m_folder.size());
      break;
    }
  }
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::item_renamed_cb(const std::string &old_name, const std::string &new_name) {
  std::string s;
  int i;

  if (std::find(m_excluded.begin(), m_excluded.end(), old_name) != m_excluded.end()) {
    m_excluded.remove(old_name);
    m_excluded.push_back(new_name);
  }

  typedef Gtk::TreeModel::Children type_children;
  type_children children = m_refTreeModel->children();
  for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
    Gtk::TreeModel::Row row = *iter;

#if 0
    std::cout << "renaming " << old_name << " to " << new_name << " - " << row[m_Columns.m_col_name] << std::endl;
#endif

    if (row[m_Columns.m_col_name] == old_name) {
      row[m_Columns.m_col_name] = new_name;
      break;
    }
  }
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::folder_cleared_cb(void) {
  m_excluded.clear();
  m_refTreeModel->clear();
  set_focused_item("");
  resized(0);
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::copy_row(const Gtk::TreeModel::iterator& i) {
  std::string name;
  if (i) {
    name = i->get_value(m_Columns.m_col_name);
    
    std::string new_name;
    int i;

    for (i = 1; i < 10000; ++i) {
      new_name = name + " copy n." + int_to_string(i);
      if (m_folder.copy_item_if_possible(name, new_name))
	break;
    }
  }
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::copy_selection(void) {
  get_selection()->selected_foreach(SigC::slot(*this, &ItemList<Item, ItemFolder>::copy_row));
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::remove_row(const Gtk::TreeModel::iterator& i) {
  m_folder.remove_item(i->get_value(m_Columns.m_col_name));
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::remove_selection(void) {
  get_selection()->selected_foreach(SigC::slot(*this, &ItemList<Item, ItemFolder>::remove_row));
}

template <class Item, class ItemFolder>
void ItemList<Item, ItemFolder>::add_item(void) {
  std::string name;
  int i;

  name = m_folder.create_item();

  typedef Gtk::TreeModel::Children type_children;
  type_children children = m_refTreeModel->children();
  for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
    Gtk::TreeModel::Row row = *iter;
    if (row[m_Columns.m_col_name] == name) {
      get_selection()->select(row);
      break;
    }
  }
}

#endif // _itemList_H_


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