/* 
 * © 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#ifndef _LF_LISTBOX_H_
#define _LF_LISTBOX_H_


#include "mforms/listbox.h"

#include "lf_view.h"

namespace mforms
{
namespace gtk
{

class ListBoxImpl : public ViewImpl
{
  class ComboColumn : public Gtk::TreeModel::ColumnRecord
  {
    public:
      ComboColumn()
      {
        add(_item);
        add(_id);
      }
      Gtk::TreeModelColumn<Glib::ustring> _item;
      Gtk::TreeModelColumn<int>           _id;
  };

  Gtk::TreeView                 *_lbox;
  Gtk::ScrolledWindow           *_swin;

  ComboColumn                    _ccol;
  Glib::RefPtr<Gtk::ListStore>   _store;
  int                            _last_id; //This is workaround to get index from TreeView
  
  virtual Gtk::Widget *get_outer() const { return _swin; }
  virtual Gtk::Widget *get_inner() const { return _lbox; }

protected:
  ListBoxImpl(::mforms::ListBox *self, bool multi_select)
    : ViewImpl(self)
  {
    _store = Gtk::ListStore::create(_ccol);
    
    _lbox = Gtk::manage(new Gtk::TreeView(_store));

    _swin= Gtk::manage(new Gtk::ScrolledWindow());
    _swin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    _swin->set_shadow_type(Gtk::SHADOW_IN);
    _swin->add(*_lbox);
    _lbox->show();

    _lbox->append_column("Item", _ccol._item);
    _lbox->set_headers_visible(false);

    _lbox->get_selection()->signal_changed().connect(sigc::bind(sigc::ptr_fun(&ListBoxImpl::selection_changed), self));
  }
  
  static void selection_changed(::mforms::ListBox *self)
  {
    GtkAutoLock gtk_auto_lock;
    self->selection_changed();
  }

  static bool create(::mforms::ListBox *self, bool multi_select)
  {
    return new ListBoxImpl(self, multi_select) != 0;
  }

  static void clear(::mforms::ListBox *self)
  {
    GtkAutoLock gtk_auto_lock;
    ListBoxImpl* sel= self->get_data<ListBoxImpl>();

    sel->_store->clear();
    sel->_last_id = 0;
  }

  static int add_item(::mforms::ListBox *self, const std::string &item)
  {
    GtkAutoLock gtk_auto_lock;
    
    ListBoxImpl* sel= self->get_data<ListBoxImpl>();
    int ret = 0;
    
    Gtk::TreeModel::iterator it = sel->_store->append();
    if ( it )
    {
      Gtk::TreeModel::Row row = *it;
      if ( row )
      {
        row[sel->_ccol._item] = item;
        row[sel->_ccol._id]  = sel->_last_id++;
      }
    }
    return ret;
  }

  static void add_items(::mforms::ListBox *self, const std::list<std::string> &items)
  {
    GtkAutoLock gtk_auto_lock;

    ListBoxImpl* sel= self->get_data<ListBoxImpl>();

    if ( sel )
    {
      for (std::list<std::string>::const_iterator iter = items.begin(); iter != items.end(); ++iter)
        add_item(self, *iter);
    }
  }

  static std::string get_text(::mforms::ListBox *self)
  {
    ListBoxImpl* sel= self->get_data<ListBoxImpl>();
    std::string text;
    
    if ( sel )
    {
      Gtk::TreeModel::const_iterator iter = sel->_lbox->get_selection()->get_selected();
      if ( iter )
      {
        Gtk::TreeModel::Row row = *iter;
        if ( row )
          text = ((Glib::ustring)(row[sel->_ccol._item])).raw();
      }
    }
    return text;
  }

  static void set_index(::mforms::ListBox *self, int index)
  {
    GtkAutoLock gtk_auto_lock;

    ListBoxImpl* sel= self->get_data<ListBoxImpl>();

    if ( sel )
    {
      Glib::RefPtr<Gtk::TreeView::Selection> selection = sel->_lbox->get_selection();
      Gtk::TreeModel::Children children = sel->_store->children();
      if ( children.size() > (unsigned int)index && index >= 0 )
      {
        Gtk::TreeModel::Row row = children[index];
        if ( row )
          selection->select(row);
      }
    }
  }

  static int get_index(::mforms::ListBox *self)
  {
    ListBoxImpl* sel= self->get_data<ListBoxImpl>();
    int ret = -1;
    
    if ( sel )
    {
      Gtk::TreeModel::iterator selected = sel->_lbox->get_selection()->get_selected();
      if ( selected )
      {
        Gtk::TreeModel::Row row = *selected;
        ret = row[sel->_ccol._id];
      }
    }
    
    return ret;
  }

  static void set_heading(ListBox *self, const std::string &text)
  {
    g_message("mforms::ListBoxImpl::set_heading('%s') not implemented", text.c_str());
  }

 public:
  static void init()
  {
    ::mforms::ControlFactory *f = ::mforms::ControlFactory::get_instance();

    f->_listbox_impl.create      = &ListBoxImpl::create;
    f->_listbox_impl.clear       = &ListBoxImpl::clear;
    f->_listbox_impl.add_item    = &ListBoxImpl::add_item;
    f->_listbox_impl.add_items   = &ListBoxImpl::add_items;
    f->_listbox_impl.set_index   = &ListBoxImpl::set_index;
    f->_listbox_impl.get_index   = &ListBoxImpl::get_index;
    f->_listbox_impl.get_text    = &ListBoxImpl::get_text;
    f->_listbox_impl.set_heading = &ListBoxImpl::set_heading;
  }
};

}
}

#endif /* _LF_LISTBOX_H_ */
