From: Axel S. <si...@co...> - 2008-09-20 20:14:03
|
Sat Sep 20 15:28:10 EDT 2008 A....@ke... * Make CellLayout clever about translating iterators to child models. This patch is a hack around a bug in Gtk+ that is at least present in EntryCompletion. Often the CellLayout interface is only half-heartedly implementedin the widgets. For instance the EntryCompletion widget takes a model with the completion and wraps a TreeModelFilter around it which is used to only admit selected entries into the drop down list. Although EntryCompletion implements the CellLayout interface, all the gtk_cell_layout_set_cell_data_func does is to forward any queryies to the contained model that the user has set. What it should do is to translate from the filter model to the user model. In order to work around this bug, this patch adds the functionality to cellLayoutSetAttributeFunc that checks if the model in the call back is the same as the model that was given as an argument. If not, the model in the callback is checked to be a TreeModelFilter or a TreeModelSort and the iterator is then automatically translated. This patch therefore also makes it possible to define how the values of cell renderers should be set even if the view that contains the cell renderers accesses them using a TreeModelFilter or a TreeModelSort. hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 69 +import System.Glib.GType hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 148 --- around 'cellLayoutSetAttributeFunc' which sets the cells of the @cell@ with --- the data retrieved from the model. +-- around 'cellLayoutSetAttributeFunc' in that it sets the cells of the @cell@ +-- with the data retrieved from the model. +-- +-- * Note on using 'Graphics.UI.Gtk.ModelView.TreeModelSort.TreeModelSort' and +-- 'Graphics.UI.Gtk.ModelView.TreeModelFilter.TreeModelFilter': These two models +-- wrap another model, the so-called child model, instead of storing their own +-- data. This raises the problem that the data of cell renderers must be set +-- using the child model, while the 'TreeIter's that the view works with refer to +-- the model that encapsulates the child model. For convenience, this function +-- transparently translates an iterator to the child model before extracting the +-- data using e.g. 'Graphics.UI.Gtk.TreeModel.TreeModelSort.treeModelSortConvertIterToChildIter'. +-- Hence, it is possible to install the encapsulating model in the view and to +-- pass the child model to this function. hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 189 - iter <- peek iterPtr - let (TreeModel modelPtr) = toTreeModel model + iter <- convertIterFromParentToChildModel iterPtr modelPtr' [_$_] + (toTreeModel model) hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 192 - if unsafeForeignPtrToPtr modelPtr /= modelPtr' || - unsafeForeignPtrToPtr cellPtr /= cellPtr' then + if unsafeForeignPtrToPtr cellPtr /= cellPtr' then hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 194 - "CellRenderer from different model.") + "a different CellRenderer.") hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 206 +-- Given a 'TreeModelFilter' or a 'TreeModelSort' and a 'TreeIter', get the +-- child model of these models and convert the iter to an iter of the child +-- model. This is an ugly internal function that is needed for some widgets +-- which pass iterators to the callback function of set_cell_data_func that +-- refer to some internal TreeModelFilter models that they create around the +-- user model. This is a bug but since C programs mostly use the columns +-- rather than the cell_layout way to extract attributes, this bug does not +-- show up in many programs. Reported in the case of EntryCompletion as bug +-- #551202. +-- +convertIterFromParentToChildModel :: + Ptr TreeIter -- ^ the iterator + -> Ptr TreeModel -- ^ the model that we got from the all back + -> TreeModel -- ^ the model that we actually want + -> IO TreeIter +convertIterFromParentToChildModel iterPtr parentModelPtr childModel = + let (TreeModel modelFPtr) = childModel + modelPtr = unsafeForeignPtrToPtr modelFPtr in + if modelPtr==parentModelPtr then peek iterPtr else + if typeInstanceIsA (castPtr parentModelPtr) gTypeTreeModelFilter then + alloca $ \childIterPtr -> do + treeModelFilterConvertIterToChildIter parentModelPtr childIterPtr iterPtr + childPtr <- treeModelFilterGetModel parentModelPtr + if childPtr==modelPtr then peek childIterPtr else + convertIterFromParentToChildModel childIterPtr childPtr childModel + else if typeInstanceIsA (castPtr parentModelPtr) gTypeTreeModelSort then + alloca $ \childIterPtr -> do + treeModelSortConvertIterToChildIter parentModelPtr childIterPtr iterPtr + childPtr <- treeModelSortGetModel parentModelPtr + if childPtr==modelPtr then peek childIterPtr else + convertIterFromParentToChildModel childIterPtr childPtr childModel + else do + iter <- peek iterPtr + error ("CellLayout: don't know how to convert iter "++show iter++ + " from model "++show parentModelPtr++" to model "++ + show modelPtr++". Is it possible that you are setting the "++ + "attributes of a CellRenderer using a different model than "++ + "that which was set in the view?") + +foreign import ccall unsafe "gtk_tree_model_filter_get_model" + treeModelFilterGetModel :: Ptr TreeModel -> IO (Ptr TreeModel) + +foreign import ccall safe "gtk_tree_model_filter_convert_iter_to_child_iter" + treeModelFilterConvertIterToChildIter :: Ptr TreeModel -> Ptr TreeIter -> + Ptr TreeIter -> IO () [_$_] + +foreign import ccall unsafe "gtk_tree_model_sort_get_model" + treeModelSortGetModel :: Ptr TreeModel -> IO (Ptr TreeModel) + [_$_] +foreign import ccall safe "gtk_tree_model_sort_convert_iter_to_child_iter" + treeModelSortConvertIterToChildIter :: Ptr TreeModel -> Ptr TreeIter -> + Ptr TreeIter -> IO () [_$_] + |