/* Copyright(C) 2002 The gtkmm Development Team
 *
 * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

// This is for including the config header before any code (such as
// the #ifndef GTKMM_DISABLE_DEPRECATED in deprecated classes) is generated:
_CONFIGINCLUDE(gtkmmconfig.h)

#include <gtkmm/treeiter.h>
#include <gtkmm/button.h>
#include <gdkmm/window.h>
#include <gtkmm/treemodel.h>
#include <gtkmm/celllayout.h>
#include <gtkmm/cellrenderer_generation.h>
_DEFS(gtkmm,gtk)
_PINCLUDE(gtkmm/private/object_p.h)

namespace Gtk
{

_CC_INCLUDE(gtk/gtk.h)
_WRAP_ENUM(TreeViewColumnSizing, GtkTreeViewColumnSizing, decl_prefix GTKMM_API)

// We use GTKMM_API here because gcc needs the extra help on win32 , even
// when using --export-all and auto-import.
// See http://bugzilla.gnome.org/show_bug.cgi?id=309030.

class GTKMM_API TreeView;

//TODO: Deal with the GtkObject->GObject change?
/** Typedefed as Gtk::TreeView::Column.
 * This is a visible column in a Gtk::TreeView widget. It determines the geometry, type.
 *
 * @ingroup TreeView
*/
class GTKMM_API TreeViewColumn
  : public Object,
    public CellLayout
{
  _CLASS_GTKOBJECT(TreeViewColumn, GtkTreeViewColumn, GTK_TREE_VIEW_COLUMN, Object, GObject, , , GTKMM_API)
  _IMPLEMENTS_INTERFACE(CellLayout)
  _IGNORE(gtk_tree_view_column_set_cell_data_func)
public:
  typedef TreeViewColumn Column;

  _CTOR_DEFAULT()

  explicit TreeViewColumn(const Glib::ustring& title);
  TreeViewColumn(const Glib::ustring& title, CellRenderer& cell);

  /** Create a default view column for the given model column type.
   */
  template<class T_ModelColumnType>
  TreeViewColumn(const Glib::ustring& title, const TreeModelColumn<T_ModelColumnType>& column);

  _WRAP_METHOD(void pack_start(CellRenderer& cell, bool expand = true), gtk_tree_view_column_pack_start)
  _WRAP_METHOD(void pack_end(CellRenderer& cell, bool expand = true), gtk_tree_view_column_pack_end)

  /** Creates an appropriate CellRenderer for the @a column, and packs that cell into the beginning of the column.
   * If @a expand  is <tt>false</tt>, then
   * the cell is allocated no more space than it needs. Any unused space is divided
   * evenly between cells for which @a expand is <tt>true</tt>.
   *
   * You can use get_first_cell() or get_cells() to access the generated CellRenderer.
   *
   * @param column The model column that will be rendered by the view cell.
   * @param expand <tt>true</tt> if the cell is to be given extra space allocated to the view column.
   */
  template<class T_ModelColumnType>
  void pack_start(const TreeModelColumn<T_ModelColumnType>& column, bool expand = true);

  /** Creates an appropriate CellRenderer for the @a column, and packs that cell at the end of the column.
   * If @a expand  is <tt>false</tt>, then
   * the cell is allocated no more space than it needs. Any unused space is divided
   * evenly between cells for which @a expand is <tt>true</tt>.
   *
   * You can use get_first_cell() or get_cells() to access the generated CellRenderer.
   *
   * @param column The model column that will be rendered by the view cell.
   * @param expand <tt>true</tt> if the cell is to be given extra space allocated to the view column.
   */
  template<class T_ModelColumnType>
  void pack_end(const TreeModelColumn<T_ModelColumnType>& column, bool expand = true);

  _WRAP_METHOD(void clear(), gtk_tree_view_column_clear)

  _WRAP_METHOD(void add_attribute(CellRenderer& cell_renderer, const Glib::ustring& attribute, int column),
               gtk_tree_view_column_add_attribute)

  void add_attribute(const Glib::PropertyProxy_Base& property, const TreeModelColumnBase& column);

  void add_attribute(Gtk::CellRenderer& cell, const Glib::ustring& property_name, const TreeModelColumnBase& column);
  _IGNORE(gtk_tree_view_column_set_attributes)

  /** Associate a view CellRenderer with a model column, so that the CellRenderer renders the data in the model column.
   *
   * @param renderer The view cell renderer which will render the model column.
   * @param column The model column to be renderered by this view.
   */
  void set_renderer(Gtk::CellRenderer& renderer, const TreeModelColumnBase& column);

 // _WRAP_METHOD(void set_attributes(CellRenderer& cell_renderer, ...), )

_DEPRECATE_IFDEF_START
  /** For instance,
   * void on_cell_data(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter);
   *
   * This function is used instead of the standard attributes mapping for setting the column value, and should set the
   * value of the column's cell renderer as appropriate.
   *
   * @deprecated Use SlotTreeCellData instead.
   */
  typedef sigc::slot<void, CellRenderer*, const Gtk::TreeModel::iterator&> SlotCellData;
_DEPRECATE_IFDEF_END

  /** For instance,
   * void on_cell_data(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter);
   *
   * This function is used instead of the standard attributes mapping for setting the column value, and should set the
   * value of the column's cell renderer as appropriate.
   */
  typedef sigc::slot<void, CellRenderer*, const Gtk::TreeModel::iterator&> SlotTreeCellData;

  /** Sets the slot callback to use for the column.
   * This callback function is used instead of the standard attributes mapping for setting the column value, and should set the
   * value of the column's cell renderer as appropriate.
   *
   * See also unset_cell_data_func().
   *
   * @param cell_renderer A Gtk::CellRenderer
   * @param slot The callback slot to use. Create this with sigc::mem_fun(), or sigc::ptr_fun().
   */
  void set_cell_data_func(CellRenderer& cell_renderer, const SlotTreeCellData& slot);

  /** Removes a previously set callback slot. See set_cell_data_func().
   */
  void unset_cell_data_func(CellRenderer& cell_renderer);

  _WRAP_METHOD(void clear_attributes(CellRenderer& cell_renderer), gtk_tree_view_column_clear_attributes)
  _WRAP_METHOD(void set_spacing(int spacing), gtk_tree_view_column_set_spacing)
  _WRAP_METHOD(int get_spacing() const, gtk_tree_view_column_get_spacing)
  _WRAP_METHOD(void set_visible(bool visible = true), gtk_tree_view_column_set_visible)
  _WRAP_METHOD(bool get_visible() const, gtk_tree_view_column_get_visible)
  _WRAP_METHOD(void set_resizable(bool resizable = true), gtk_tree_view_column_set_resizable)
  _WRAP_METHOD(bool get_resizable() const, gtk_tree_view_column_get_resizable)
  _WRAP_METHOD(void set_sizing(TreeViewColumnSizing type), gtk_tree_view_column_set_sizing)
  _WRAP_METHOD(TreeViewColumnSizing get_sizing(), gtk_tree_view_column_get_sizing)
  _WRAP_METHOD(int get_x_offset() const, gtk_tree_view_column_get_x_offset)
  _WRAP_METHOD(int get_width() const, gtk_tree_view_column_get_width)
  _WRAP_METHOD(int get_fixed_width() const, gtk_tree_view_column_get_fixed_width)
  _WRAP_METHOD(void set_fixed_width(int fixed_width), gtk_tree_view_column_set_fixed_width)
  _WRAP_METHOD(void set_min_width(int min_width), gtk_tree_view_column_set_min_width)
  _WRAP_METHOD(int get_min_width() const, gtk_tree_view_column_get_min_width)
  _WRAP_METHOD(void set_max_width(int max_width), gtk_tree_view_column_set_max_width)
  _WRAP_METHOD(int get_max_width() const, gtk_tree_view_column_get_max_width)
  _WRAP_METHOD(void clicked(), gtk_tree_view_column_clicked)

  _WRAP_METHOD(void set_title(const Glib::ustring& title), gtk_tree_view_column_set_title)
  _WRAP_METHOD(Glib::ustring get_title() const, gtk_tree_view_column_get_title)

  _WRAP_METHOD(void set_expand(bool expand = true), gtk_tree_view_column_set_expand)
  _WRAP_METHOD(bool get_expand() const, gtk_tree_view_column_get_expand)

  _WRAP_METHOD(void set_clickable(bool clickable = true), gtk_tree_view_column_set_clickable)
  _WRAP_METHOD(bool get_clickable() const, gtk_tree_view_column_get_clickable)
  _WRAP_METHOD(void set_widget(Gtk::Widget& widget), gtk_tree_view_column_set_widget)
  _WRAP_METHOD(Widget* get_widget(), gtk_tree_view_column_get_widget)
  _WRAP_METHOD(const Widget* get_widget() const, gtk_tree_view_column_get_widget)

  _WRAP_METHOD(void set_alignment(float xalign), gtk_tree_view_column_set_alignment)
  _WRAP_METHOD(void set_alignment(Align xalign), gtk_tree_view_column_set_alignment)

  _WRAP_METHOD(float get_alignment() const, gtk_tree_view_column_get_alignment)
  _WRAP_METHOD(void set_reorderable(bool reorderable = true), gtk_tree_view_column_set_reorderable)
  _WRAP_METHOD(bool get_reorderable() const, gtk_tree_view_column_get_reorderable)

  _WRAP_METHOD(void set_sort_column(const TreeModelColumnBase& sort_column_id), gtk_tree_view_column_set_sort_column_id)
  _WRAP_METHOD(void set_sort_column(int sort_column_id), gtk_tree_view_column_set_sort_column_id)

  _WRAP_METHOD(int get_sort_column_id() const, gtk_tree_view_column_get_sort_column_id)
  _WRAP_METHOD(void set_sort_indicator(bool setting), gtk_tree_view_column_set_sort_indicator)
  _WRAP_METHOD(bool get_sort_indicator() const, gtk_tree_view_column_get_sort_indicator)
  _WRAP_METHOD(void set_sort_order(SortType order), gtk_tree_view_column_set_sort_order)
  _WRAP_METHOD(SortType get_sort_order() const, gtk_tree_view_column_get_sort_order)


  _WRAP_METHOD(void cell_set_cell_data(const Glib::RefPtr<TreeModel>& tree_model, const TreeModel::iterator& iter, bool is_expander, bool is_expanded), gtk_tree_view_column_cell_set_cell_data)

  //TODO: cell_area can be NULL. Add a method overload.
  //But see http://bugzilla.gnome.org/show_bug.cgi?id=542329 about the lack of C documentation.
  _WRAP_METHOD(void cell_get_size(const Gdk::Rectangle& cell_area, int& x_offset, int& y_offset, int& width, int& height) const, gtk_tree_view_column_cell_get_size)

  _WRAP_METHOD(bool cell_is_visible() const, gtk_tree_view_column_cell_is_visible)
  _WRAP_METHOD(void focus_cell(CellRenderer& cell), gtk_tree_view_column_focus_cell)

  _WRAP_METHOD(bool get_cell_position(const CellRenderer& cell_renderer, int& start_pos, int& width) const, gtk_tree_view_column_cell_get_position)
  _WRAP_METHOD(void queue_resize(), gtk_tree_view_column_queue_resize)

  _WRAP_METHOD(TreeView* get_tree_view(), gtk_tree_view_column_get_tree_view, refreturn)
  _WRAP_METHOD(const TreeView* get_tree_view() const, gtk_tree_view_column_get_tree_view, refreturn, constversion)

  _WRAP_METHOD(Button* get_button(), gtk_tree_view_column_get_button, refreturn)
  _WRAP_METHOD(const Button* get_button() const, gtk_tree_view_column_get_button, refreturn, constversion)

  _WRAP_SIGNAL(void clicked(), "clicked")

  _WRAP_PROPERTY("visible", bool)
  _WRAP_PROPERTY("resizable", bool)
  _WRAP_PROPERTY("x-offset", int)
  _WRAP_PROPERTY("width", int)
  _WRAP_PROPERTY("spacing", int)
  _WRAP_PROPERTY("sizing", TreeViewColumnSizing)
  _WRAP_PROPERTY("fixed-width", int)
  _WRAP_PROPERTY("min-width", int)
  _WRAP_PROPERTY("max-width", int)
  _WRAP_PROPERTY("title", Glib::ustring)
  _WRAP_PROPERTY("expand", bool)
  _WRAP_PROPERTY("clickable", bool)
  _WRAP_PROPERTY("widget", Widget*)
  _WRAP_PROPERTY("alignment", float)
  _WRAP_PROPERTY("reorderable", bool)
  _WRAP_PROPERTY("sort-indicator", bool)
  _WRAP_PROPERTY("sort-order", SortType)
  _WRAP_PROPERTY("sort-column-id", int)
  _WRAP_PROPERTY("cell-area", Glib::RefPtr<CellArea>)

#ifndef DOXYGEN_SHOULD_SKIP_THIS
private:
  // Only necessary because of the templated ctor, see below.
  static const Glib::Class& class_init_();
#endif //DOXYGEN_SHOULD_SKIP_THIS
};

#ifndef DOXYGEN_SHOULD_SKIP_THIS

template<class T_ModelColumnType> inline
void TreeViewColumn::pack_start(const TreeModelColumn<T_ModelColumnType>& column, bool expand)
{
  //Generate appropriate Renderer for the column:
  CellRenderer* pCellRenderer = manage( CellRenderer_Generation::generate_cellrenderer<T_ModelColumnType>() );

  //Use the renderer:
  pack_start(*pCellRenderer, expand);
  set_renderer(*pCellRenderer, column);
}

template<class T_ModelColumnType> inline
void TreeViewColumn::pack_end(const TreeModelColumn<T_ModelColumnType>& column, bool expand)
{
  //Generate appropriate Renderer for the column:
  CellRenderer* pCellRenderer= manage( CellRenderer_Generation::generate_cellrenderer<T_ModelColumnType>() );

  //Use the renderer:
  pack_end(*pCellRenderer, expand);
  set_renderer(*pCellRenderer, column);
}

template <class T_ModelColumnType> inline
TreeViewColumn::TreeViewColumn(const Glib::ustring& title,
                               const TreeModelColumn<T_ModelColumnType>& column)
:
  Glib::ObjectBase(nullptr), // not (yet) a custom class
  Gtk::Object(Glib::ConstructParams(class_init_(), "title", title.c_str(), nullptr))
{
  pack_start(column, true /* expand */);
}

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} // namespace Gtk
