[gtkmm] Gtk::TreeView: Use std::strtol() and friends



commit b90f88423b72c99da8e971e2bd23ff64c39b21aa
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Fri Oct 20 13:40:41 2017 +0200

    Gtk::TreeView: Use std::strtol() and friends
    
    Use std::strtol(), strtoul(), strtoll(), strtoull(), strtof(), strtod(),
    strtold() for converting a string to a numerical value in
    _auto_store_on_cellrenderer_text_edited_numerical<>().
    This patch was inspired by a patch by Justinas <vygis d gmail com>.
    Bug 765044

 gtk/src/treeview.ccg |   76 +++++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/src/treeview.hg  |   70 +++++++++++++++++++++++++++++++--------------
 2 files changed, 123 insertions(+), 23 deletions(-)
---
diff --git a/gtk/src/treeview.ccg b/gtk/src/treeview.ccg
index 83e3679..5c98f11 100644
--- a/gtk/src/treeview.ccg
+++ b/gtk/src/treeview.ccg
@@ -15,8 +15,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <climits> // INT_MIN, etc.
 #include <glibmm/vectorutils.h>
-
 #include <gtkmm/treeviewcolumn.h>
 #include <gtkmm/treeview_private.h>
 #include <gtkmm/treemodel.h>
@@ -472,4 +472,78 @@ void TreeView::unset_row_separator_func()
   gtk_tree_view_set_row_separator_func(gobj(), nullptr, nullptr, nullptr);
 }
 
+namespace TreeView_Private
+{
+// Complete specializations of _convert_from_ustring_to_numeric_type()
+
+// Floating point specializations
+template<>
+float _convert_from_ustring_to_numeric_type<float>(const Glib::ustring& text)
+{
+  return std::strtof(text.c_str(), nullptr);
+}
+
+template<>
+long double _convert_from_ustring_to_numeric_type<long double>(const Glib::ustring& text)
+{
+  return std::strtold(text.c_str(), nullptr);
+}
+
+// Integral specializations
+template<>
+short _convert_from_ustring_to_numeric_type<short>(const Glib::ustring& text)
+{
+  const auto result = std::strtol(text.c_str(), nullptr, 0);
+  return (result < SHRT_MIN) ? SHRT_MIN :
+        ((result > SHRT_MAX) ? SHRT_MAX : static_cast<short>(result));
+}
+
+template<>
+unsigned short _convert_from_ustring_to_numeric_type<unsigned short>(const Glib::ustring& text)
+{
+  const auto result = std::strtoul(text.c_str(), nullptr, 0);
+  return (result > USHRT_MAX) ? USHRT_MAX : static_cast<unsigned short>(result);
+}
+
+template<>
+int _convert_from_ustring_to_numeric_type<int>(const Glib::ustring& text)
+{
+  const auto result = std::strtol(text.c_str(), nullptr, 0);
+  return (result < INT_MIN) ? INT_MIN :
+        ((result > INT_MAX) ? INT_MAX : static_cast<int>(result));
+}
+
+template<>
+unsigned int _convert_from_ustring_to_numeric_type<unsigned int>(const Glib::ustring& text)
+{
+  const auto result = std::strtoul(text.c_str(), nullptr, 0);
+  return (result > UINT_MAX) ? UINT_MAX : static_cast<unsigned int>(result);
+}
+
+template<>
+long _convert_from_ustring_to_numeric_type<long>(const Glib::ustring& text)
+{
+  return std::strtol(text.c_str(), nullptr, 0);
+}
+
+template<>
+unsigned long _convert_from_ustring_to_numeric_type<unsigned long>(const Glib::ustring& text)
+{
+  return std::strtoul(text.c_str(), nullptr, 0);
+}
+
+template<>
+long long _convert_from_ustring_to_numeric_type<long long>(const Glib::ustring& text)
+{
+  return std::strtoll(text.c_str(), nullptr, 0);
+}
+
+template<>
+unsigned long long _convert_from_ustring_to_numeric_type<unsigned long long>(const Glib::ustring& text)
+{
+  return std::strtoull(text.c_str(), nullptr, 0);
+}
+
+} // namespace TreeView_Private
+
 } // namespace Gtk
diff --git a/gtk/src/treeview.hg b/gtk/src/treeview.hg
index a47247d..bbcb99e 100644
--- a/gtk/src/treeview.hg
+++ b/gtk/src/treeview.hg
@@ -20,7 +20,7 @@
 _CONFIGINCLUDE(gtkmmconfig.h)
 
 #include <vector>
-
+#include <cstdlib> // std::strto*()
 #include <gtkmm/container.h>
 #include <gtkmm/treeviewcolumn.h>
 #include <gtkmm/treeselection.h>
@@ -69,6 +69,9 @@ namespace TreeView_Private
 
   template <class ColumnType> inline
   void _auto_cell_data_func(Gtk::CellRenderer* cell, const Gtk::TreeModel::const_iterator& iter, int 
model_column, const Glib::ustring& format);
+
+  template <typename T>
+  T _convert_from_ustring_to_numeric_type(const Glib::ustring& text);
 }
 
 #endif //DOXYGEN_SHOULD_SKIP_THIS
@@ -203,7 +206,7 @@ public:
    * This convenience template uses TreeView::Column::set_cell_data_func(), so the numeric formatting will
    * be deactivated if you specify your own cell_data callback by calling set_cell_data_func() again.
    *
-   * Note that the user's input will be interpreted as decimal (base 10), regardless of the @a format.
+   * Note that the @a format does not influence the interpretation of the user's input.
    *
    * @param title The text to be used in the title header of this column.
    * @param model_column The column in the TreeModel that will be rendered by this View column.
@@ -889,7 +892,6 @@ int TreeView::append_column_numeric_editable(const Glib::ustring& title, const T
   int cols_count = append_column_numeric(title, model_column, format);
 
   //connect signal handlers for auto-storing of edited cell data
-  //Note: This will only work for base-10 (decimal) formatted numbers:
   CellRenderer *const cell = get_column_cell_renderer(cols_count - 1);
   if(cell)
   {
@@ -1000,7 +1002,7 @@ void _connect_auto_store_editable_signal_handler(Gtk::TreeView* this_p, Gtk::Cel
       )
     );
 
-    //We use bind<1> instead of bind because some compilers need the extra hint.
+    //We use bind<-1> instead of bind because some compilers need the extra hint.
   }
 }
 
@@ -1054,6 +1056,46 @@ void _connect_auto_store_editable_signal_handler(Gtk::TreeView* this_p, Gtk::Cel
 namespace TreeView_Private
 {
 
+// Primary template falls back to std::strtod()
+template <typename T>
+T _convert_from_ustring_to_numeric_type(const Glib::ustring& text)
+{
+  return std::strtod(text.c_str(), nullptr);
+}
+
+// Floating point specializations
+template<>
+float _convert_from_ustring_to_numeric_type<float>(const Glib::ustring& text);
+
+template<>
+long double _convert_from_ustring_to_numeric_type<long double>(const Glib::ustring& text);
+
+// Integral specializations
+template<>
+short _convert_from_ustring_to_numeric_type<short>(const Glib::ustring& text);
+
+template<>
+unsigned short _convert_from_ustring_to_numeric_type<unsigned short>(const Glib::ustring& text);
+
+template<>
+int _convert_from_ustring_to_numeric_type<int>(const Glib::ustring& text);
+
+template<>
+unsigned int _convert_from_ustring_to_numeric_type<unsigned int>(const Glib::ustring& text);
+
+template<>
+long _convert_from_ustring_to_numeric_type<long>(const Glib::ustring& text);
+
+template<>
+unsigned long _convert_from_ustring_to_numeric_type<unsigned long>(const Glib::ustring& text);
+
+template<>
+long long _convert_from_ustring_to_numeric_type<long long>(const Glib::ustring& text);
+
+template<>
+unsigned long long _convert_from_ustring_to_numeric_type<unsigned long long>(const Glib::ustring& text);
+
+
 template <class ColumnType> inline
 void _connect_auto_store_editable_signal_handler(Gtk::TreeView* this_p, Gtk::CellRenderer* pCellRenderer, 
const Gtk::TreeModelColumn<ColumnType>& model_column)
 {
@@ -1147,25 +1189,9 @@ void _auto_store_on_cellrenderer_text_edited_numerical(const Glib::ustring& path
     auto iter = model->get_iter(path);
     if(iter)
     {
-      //std::istringstream astream(new_text); //Put it in a stream.
-      //ColumnType new_value = ColumnType();
-      //new_value << astream; //Get it out of the stream as the numerical type.
-
-      //Convert the text to a number, using the same logic used by GtkCellRendererText when it stores 
numbers.
-      ColumnType new_value = ColumnType();
-      try
-      {
-        new_value =  static_cast<ColumnType>( std::stod(new_text) );
-      }
-      catch(const std::invalid_argument&)
-      {
-         //Intentionally ignored.
-         //Applications can use their own logic if they want to handle invalid input differently.
-      }
-
-      //Store the user's new text in the model:
+      // Convert the user's new text to a number, and store the number in the model:
       Gtk::TreeRow row = *iter;
-      row.set_value(model_column, (ColumnType)new_value);
+      row.set_value(model_column, _convert_from_ustring_to_numeric_type<ColumnType>(new_text));
     }
   }
 }


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