/* Copyright (C) 1998-1999 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, see <https://www.gnu.org/licenses/>.
 */

_DEFS(gtkmm,gtk)
_CONFIGINCLUDE(gtkmmconfig.h)
_IS_DEPRECATED // The entire file is deprecated.

#include <vector>
#include <gtkmm/enums.h>
#include <gtkmm/treemodel.h>
#include <gtkmm/treeiter.h>
#include <gtkmm/treepath.h>

_PINCLUDE(glibmm/private/object_p.h)

#m4 _PUSH(SECTION_CC_PRE_INCLUDES)
#undef GTK_DISABLE_DEPRECATED
#define GDK_DISABLE_DEPRECATION_WARNINGS 1
#m4 _POP()

namespace Gtk
{

class GTKMM_API TreeView;

/** Typedefed as Gtk::TreeView::Selection.
 * This is a helper object to manage the selection for a Gtk::TreeView widget.
 *
 * It is automatically created when a new Gtk::TreeView widget is created, and
 * cannot exist independently of this widget.  The primary reason this class
 * exists is for cleanliness of code and API. That is, there is no conceptual
 * reason all these methods could not be methods on the Gtk::TreeView widget
 * instead of a separate class.
 *
 * The Gtk::TreeSelection object can be obtained from a Gtk::TreeView by
 * calling Gtk::TreeView::get_selection().  It can be manipulated to check the
 * selection status of the tree, as well as to select and deselect individual
 * rows.  Selection is done completely view-side. As a result, multiple views
 * of the same model can have completely different selections.  Additionally,
 * you cannot change the selection of a row on the model that is not currently
 * displayed by the view without expanding its parents first.
 *
 * When monitoring the selection of a view, it's important to remember that the
 * "changed" signal is mostly a hint. That is, it may only emit one signal when
 * a range of rows is selected. Additionally, it may on occasion emit a
 * "changed" signal when nothing has happened.
 *
 * @ingroup TreeView
 * @deprecated 4.10: Use Gtk::SelectionModel instead.
 */
class GTKMM_API TreeSelection : public Glib::Object
{
  _CLASS_GOBJECT(TreeSelection, GtkTreeSelection, GTK_TREE_SELECTION, Glib::Object, GObject, , , GTKMM_API)

public:
  _WRAP_METHOD(void set_mode(SelectionMode type), gtk_tree_selection_set_mode)
  _WRAP_METHOD(SelectionMode get_mode() const, gtk_tree_selection_get_mode)

  /** For instance,
   * bool on_select_function(const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool path_currently_selected);
   *
   * The select function should return true if the state of the node may be toggled,
   * and false if the state of the node should be left unchanged.
   */
  using SlotSelect = sigc::slot<bool(const Glib::RefPtr<TreeModel>&, const TreeModel::Path&, bool)>;

  /** Sets the selection callback slot. If set, this function is called before any node is selected or unselected,
   * giving some control over which nodes are selected.
   *
   * The select function should return true if the state of the node may be toggled, and FALSE if the state of the node
   * should be left unchanged.
   *
   * @param slot The selection function.
   */
  void set_select_function(const SlotSelect& slot);
  _IGNORE(gtk_tree_selection_set_select_function, gtk_tree_selection_get_select_function)
  _IGNORE(gtk_tree_selection_get_user_data) // This would be our SignalProxy_Select* data.

  _WRAP_METHOD(TreeView* get_tree_view(), gtk_tree_selection_get_tree_view)
  _WRAP_METHOD(const TreeView* get_tree_view() const, gtk_tree_selection_get_tree_view, constversion)

  /** Shortcut for get_tree_view()->get_model().
   * @return The TreeModel associated with this TreeSelection.
   */
  Glib::RefPtr<TreeModel> get_model(); // convenience function, not in GTK+
  Glib::RefPtr<const TreeModel> get_model() const; // convenience function, not in GTK+

  /** Get the currently selected row.
   * @return The currently selected row. Or an invalid iterator, if no row is selected.
   * @note
   * This method won't work if the selection mode is <tt>Gtk::SelectionMode::MULTIPLE</tt>.
   * Use get_selected_rows() for multiple selections.
   */
  TreeModel::iterator get_selected();

  /** Get the currently selected row.
   * @return The currently selected row. Or an invalid iterator, if no row is selected.
   * @note
   * This method won't work if the selection mode is <tt>Gtk::SelectionMode::MULTIPLE</tt>.
   * Use get_selected_rows() for multiple selections.
   *
   * @newin{3,90}
   */
  TreeModel::const_iterator get_selected() const;

  /** Get the currently selected row.
   * @param[out] model The current TreeModel.
   * @return The currently selected row. Or an invalid iterator, if no row is selected.
   * @note
   * This method won't work if the selection mode is <tt>Gtk::SelectionMode::MULTIPLE</tt>.
   * Use get_selected_rows() for multiple selections.
   */
  TreeModel::iterator get_selected(Glib::RefPtr<TreeModel>& model);

  /** Get the currently selected row.
   * @param[out] model The current TreeModel.
   * @return The currently selected row. Or an invalid iterator, if no row is selected.
   * @note
   * This method won't work if the selection mode is <tt>Gtk::SelectionMode::MULTIPLE</tt>.
   * Use get_selected_rows() for multiple selections.
   *
   * @newin{3,90}
   */
  TreeModel::const_iterator get_selected(Glib::RefPtr<const TreeModel>& model) const;

  /** Creates a vector of paths of all selected rows.
   * Additionally, if you are planning on modifying the model after calling this function,
   * you may want to convert the returned list into a list of GtkTreeRowReferences.
   *
   * @returns A vector containing a Gtk::TreeModel::Path for each selected row.
   */
  std::vector<TreeModel::Path> get_selected_rows() const;
  _IGNORE(gtk_tree_selection_get_selected, gtk_tree_selection_get_selected_rows)

  /** Creates a list of paths of all selected rows.
   * Additionally, if you are planning on modifying the model after calling this function,
   * you may want to convert the returned list into a list of GtkTreeRowReferences.
   *
   * @param[out] model The current TreeModel.
   * @returns A vector containing a Gtk::TreeModel::Path for each selected row.
   */
  std::vector<TreeModel::Path> get_selected_rows(Glib::RefPtr<TreeModel>& model);

  _WRAP_METHOD(int count_selected_rows() const, gtk_tree_selection_count_selected_rows)

  /** For example,
   * void on_foreach(const Gtk::TreeModel::const_iterator& iter);
   *
   * Note that you cannot modify the tree or selection from within the callback function.
   * As a result, get_selected_rows() might be more useful.
   */
  using SlotForeachIter = sigc::slot<void(const TreeModel::const_iterator&)>;

  /** Calls a callback slot for each selected node.
   * Note that you cannot modify the tree or selection from within the callback function.
   * As a result, get_selected_rows() might be more useful.
   *
   * @param slot The function to call for each selected node.
   */
  void selected_foreach_iter(const SlotForeachIter& slot) const;

  /** For example,
   * void on_foreach(const Gtk::TreeModel::Path& path);
   *
   * Note that you cannot modify the tree or selection from within the callback function.
   * As a result, get_selected_rows() might be more useful.
   */
  using SlotForeachPath = sigc::slot<void(const TreeModel::Path&)>;

  /** Calls a callback slot for each selected node.
   * Note that you cannot modify the tree or selection from within the callback function.
   * As a result, get_selected_rows() might be more useful.
   *
   * @param slot The function to call for each selected node.
   */
  void selected_foreach_path(const SlotForeachPath& slot) const;
  _IGNORE(gtk_tree_selection_selected_foreach)

  /** For example,
   * void on_foreach(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::const_iterator& iter);
   *
   * Note that you cannot modify the tree or selection from within the callback function.
   * As a result, get_selected_rows() might be more useful.
   */
  using SlotForeachPathAndIter = sigc::slot<void(const TreeModel::Path&, const TreeModel::const_iterator&)>;

  /** Calls a callback slot for each selected node.
   * Note that you cannot modify the tree or selection from within the callback function.
   * As a result, get_selected_rows() might be more useful.
   *
   * @param slot The function to call for each selected node.
   */
  void selected_foreach(const SlotForeachPathAndIter& slot) const;

  _WRAP_METHOD(void select(const TreeModel::Path& path), gtk_tree_selection_select_path)
  _WRAP_METHOD(void select(const TreeModel::Path& start_path, const TreeModel::Path& end_path), gtk_tree_selection_select_range)
  _WRAP_METHOD(void select(const TreeModel::const_iterator& iter), gtk_tree_selection_select_iter)

  _WRAP_METHOD(void unselect(const TreeModel::Path& path), gtk_tree_selection_unselect_path)
  _WRAP_METHOD(void unselect(const TreeModel::Path& start_path, const TreeModel::Path& end_path), gtk_tree_selection_unselect_range)
  _WRAP_METHOD(void unselect(const TreeModel::const_iterator& iter), gtk_tree_selection_unselect_iter)

  _WRAP_METHOD(bool is_selected(const TreeModel::Path& path) const, gtk_tree_selection_path_is_selected)
  _WRAP_METHOD(bool is_selected(const TreeModel::const_iterator& iter) const, gtk_tree_selection_iter_is_selected)

  _WRAP_METHOD(void select_all(), gtk_tree_selection_select_all)
  _WRAP_METHOD(void unselect_all(), gtk_tree_selection_unselect_all)

  _WRAP_PROPERTY("mode", SelectionMode)

  // no_default_handler because GtkTreeSelectionClass is private.
  _WRAP_SIGNAL(void changed(), "changed", no_default_handler)
};

} // namespace Gtk
