X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9330d5afb6550c058ba3381a193f2ccaa66097c4..5d7792236f7e4fcbb94cdc2a5213e0c5788e8c28:/src/gtk/dataview.cpp diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 0110325a42..02423c65eb 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -33,6 +33,9 @@ #include "wx/gtk/dc.h" #include "wx/gtk/dcclient.h" +#include "wx/gtk/private/gdkconv.h" +using namespace wxGTKImpl; + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -108,6 +111,9 @@ public: wxDataViewCtrl* GetOwner() { return m_owner; } GtkWxTreeModel* GetGtkModel() { return m_gtk_model; } + // item can be deleted already in the model + int GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item ); + protected: void InitTree(); wxGtkTreeModelNode *FindNode( const wxDataViewItem &item ); @@ -539,8 +545,8 @@ wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model, gtype = G_TYPE_STRING; else { - gtype = G_TYPE_STRING; - // wxFAIL_MSG( _T("non-string columns not supported yet") ); + gtype = G_TYPE_POINTER; + // wxFAIL_MSG( wxT("non-string columns not supported for searching yet") ); } return gtype; @@ -591,7 +597,7 @@ wxgtk_tree_model_get_value (GtkTreeModel *tree_model, } else { - wxFAIL_MSG( _T("non-string columns not supported yet") ); + wxFAIL_MSG( wxT("non-string columns not supported yet") ); } } @@ -601,9 +607,8 @@ wxgtk_tree_model_iter_next (GtkTreeModel *tree_model, { GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model; - //if (wxtree_model->stamp != iter->stamp) - // wxPrintf( "crash\n" ); - // TODO: remove this code + // This happens when clearing the view by calling .._set_model( NULL ); + if (iter->stamp == 0) return FALSE; g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE); g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE); @@ -639,7 +644,7 @@ wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) { GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model; - g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE); + g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0); g_return_val_if_fail ( !iter || wxtree_model->stamp == iter->stamp, 0); return wxtree_model->internal->iter_n_children( iter ); @@ -854,7 +859,7 @@ typedef struct _GtkWxCellRendererTextClass GtkWxCellRendererTextClass; struct _GtkWxCellRendererText { GtkCellRendererText parent; - + wxDataViewRenderer *wx_renderer; }; @@ -970,7 +975,7 @@ static GtkCellEditable *gtk_wx_cell_renderer_text_start_editing( event.SetColumn( wx_renderer->GetOwner()->GetModelColumn() ); event.SetItem( item ); dv->HandleWindowEvent( event ); - + if (event.IsAllowed()) return GTK_CELL_RENDERER_CLASS(text_cell_parent_class)-> start_editing( gtk_renderer, gdk_event, widget, path, background_area, cell_area, flags ); @@ -1151,8 +1156,8 @@ static GtkCellEditable *gtk_wx_cell_renderer_start_editing( // rect.width -= renderer->xpad * 2; // rect.height -= renderer->ypad * 2; -// wxRect renderrect( rect.x, rect.y, rect.width, rect.height ); - wxRect renderrect( cell_area->x, cell_area->y, cell_area->width, cell_area->height ); +// wxRect renderrect(wxRectFromGDKRect(&rect)); + wxRect renderrect(wxRectFromGDKRect(cell_area)); GtkTreePath *treepath = gtk_tree_path_new_from_string( path ); GtkTreeIter iter; @@ -1223,54 +1228,36 @@ gtk_wx_cell_renderer_render (GtkCellRenderer *renderer, GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer; wxDataViewCustomRenderer *cell = wxrenderer->cell; - cell->window = window; - cell->widget = widget; - cell->background_area = (void*) background_area; - cell->cell_area = (void*) cell_area; - cell->expose_area = (void*) expose_area; - cell->flags = (int) flags; + cell->GTKStashRenderParams(window, widget, + background_area, expose_area, flags); - GdkRectangle rect; - gtk_wx_cell_renderer_get_size (renderer, widget, cell_area, - &rect.x, - &rect.y, - &rect.width, - &rect.height); + wxRect rect(wxRectFromGDKRect(cell_area)); + rect = rect.Deflate(renderer->xpad, renderer->ypad); - rect.x += cell_area->x; - rect.y += cell_area->y; - rect.width -= renderer->xpad * 2; - rect.height -= renderer->ypad * 2; + wxWindowDC* dc = (wxWindowDC*) cell->GetDC(); + wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl(); - GdkRectangle dummy; - if (gdk_rectangle_intersect (expose_area, &rect, &dummy)) + // Reinitialize wxWindowDC's GDK window if drawing occurs into a different + // window such as a DnD drop window. + if (window != impl->m_gdkwindow) { - wxRect renderrect( rect.x, rect.y, rect.width, rect.height ); - wxWindowDC* dc = (wxWindowDC*) cell->GetDC(); - wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl(); - - // Reinitialize wxWindowDC's GDK window if drawing occurs into a different - // window such as a DnD drop window. - if (window != impl->m_gdkwindow) - { - impl->Destroy(); - impl->m_gdkwindow = window; - impl->SetUpDC(); - } - - int state = 0; - if (flags & GTK_CELL_RENDERER_SELECTED) - state |= wxDATAVIEW_CELL_SELECTED; - if (flags & GTK_CELL_RENDERER_PRELIT) - state |= wxDATAVIEW_CELL_PRELIT; - if (flags & GTK_CELL_RENDERER_INSENSITIVE) - state |= wxDATAVIEW_CELL_INSENSITIVE; - if (flags & GTK_CELL_RENDERER_INSENSITIVE) - state |= wxDATAVIEW_CELL_INSENSITIVE; - if (flags & GTK_CELL_RENDERER_FOCUSED) - state |= wxDATAVIEW_CELL_FOCUSED; - cell->Render( renderrect, dc, state ); + impl->Destroy(); + impl->m_gdkwindow = window; + impl->SetUpDC(); } + + int state = 0; + if (flags & GTK_CELL_RENDERER_SELECTED) + state |= wxDATAVIEW_CELL_SELECTED; + if (flags & GTK_CELL_RENDERER_PRELIT) + state |= wxDATAVIEW_CELL_PRELIT; + if (flags & GTK_CELL_RENDERER_INSENSITIVE) + state |= wxDATAVIEW_CELL_INSENSITIVE; + if (flags & GTK_CELL_RENDERER_INSENSITIVE) + state |= wxDATAVIEW_CELL_INSENSITIVE; + if (flags & GTK_CELL_RENDERER_FOCUSED) + state |= wxDATAVIEW_CELL_FOCUSED; + cell->WXCallRender( rect, dc, state ); } static gboolean @@ -1298,7 +1285,7 @@ gtk_wx_cell_renderer_activate( rect.width -= renderer->xpad * 2; rect.height -= renderer->ypad * 2; - wxRect renderrect( rect.x, rect.y, rect.width, rect.height ); + wxRect renderrect(wxRectFromGDKRect(&rect)); wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel(); @@ -1410,12 +1397,26 @@ bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item ) { +#if 0 + // using _get_path for a deleted item cannot be + // a good idea GtkTreeIter iter; iter.stamp = m_wxgtk_model->stamp; iter.user_data = (gpointer) item.GetID(); - GtkTreePath *path = wxgtk_tree_model_get_path( GTK_TREE_MODEL(m_wxgtk_model), &iter ); +#else + // so get the path from the parent + GtkTreeIter iter; + iter.stamp = m_wxgtk_model->stamp; + iter.user_data = (gpointer) parent.GetID(); + GtkTreePath *path = wxgtk_tree_model_get_path( + GTK_TREE_MODEL(m_wxgtk_model), &iter ); + // and add the final index ourselves + int index = m_owner->GtkGetInternal()->GetIndexOf( parent, item ); + gtk_tree_path_append_index( path, index ); +#endif + gtk_tree_model_row_deleted( GTK_TREE_MODEL(m_wxgtk_model), path ); gtk_tree_path_free (path); @@ -1489,16 +1490,9 @@ bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsig bool wxGtkDataViewModelNotifier::Cleared() { - gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->m_treeview), NULL ); - - // this will create a new GTK model m_owner->GtkGetInternal()->Cleared(); - SetGtkModel( m_owner->GtkGetInternal()->GetGtkModel() ); - - gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->m_treeview), GTK_TREE_MODEL(m_wxgtk_model) ); - - return false; + return true; } // --------------------------------------------------------- @@ -1561,17 +1555,25 @@ wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewC { m_renderer = NULL; + // we haven't changed them yet + m_usingDefaultAttrs = true; + // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor, // after the m_renderer pointer has been initialized } +void wxDataViewRenderer::GtkPackIntoColumn(GtkTreeViewColumn *column) +{ + gtk_tree_view_column_pack_end( column, m_renderer, TRUE /* expand */); +} + void wxDataViewRenderer::GtkInitHandlers() { if (!gtk_check_version(2,6,0)) { g_signal_connect (GTK_CELL_RENDERER(m_renderer), "editing_started", - G_CALLBACK (wxgtk_renderer_editing_started), - this); + G_CALLBACK (wxgtk_renderer_editing_started), + this); } } @@ -1691,39 +1693,190 @@ int wxDataViewRenderer::GetAlignment() const return m_alignment; } +void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode) +{ +#ifdef __WXGTK26__ + if ( gtk_check_version(2, 6, 0) != NULL ) + return; + + GtkCellRendererText * const rend = GtkGetTextRenderer(); + if ( !rend ) + return; + + // we use the same values in wxEllipsizeMode as PangoEllipsizeMode so we + // can just cast between them + GValue gvalue = { 0, }; + g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE ); + g_value_set_enum( &gvalue, static_cast(mode) ); + g_object_set_property( G_OBJECT(rend), "ellipsize", &gvalue ); + g_value_unset( &gvalue ); +#else // GTK < 2.6 + wxUnusedVar(mode); +#endif // GTK 2.6/before +} + +wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const +{ +#ifdef __WXGTK26__ + if ( gtk_check_version(2, 6, 0) != NULL ) + return wxELLIPSIZE_NONE; + + GtkCellRendererText * const rend = GtkGetTextRenderer(); + if ( !rend ) + return wxELLIPSIZE_NONE; + + GValue gvalue = { 0, }; + g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE ); + g_object_get_property( G_OBJECT(rend), "ellipsize", &gvalue ); + wxEllipsizeMode + mode = static_cast(g_value_get_enum( &gvalue )); + g_value_unset( &gvalue ); + + return mode; +#else // GTK < 2.6 + return wxELLIPSIZE_NONE; +#endif // GTK 2.6/before +} + +void +wxDataViewRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str) +{ + wxVariant value(str); + if (!Validate( value )) + return; + + GtkTreePath *path = gtk_tree_path_new_from_string( itempath ); + GtkTreeIter iter; + GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, path ); + wxDataViewItem item( (void*) iter.user_data );; + gtk_tree_path_free( path ); + + GtkOnCellChanged(value, item, GetOwner()->GetModelColumn()); +} + +void +wxDataViewRenderer::GtkOnCellChanged(const wxVariant& value, + const wxDataViewItem& item, + unsigned col) +{ + wxDataViewModel *model = GetOwner()->GetOwner()->GetModel(); + model->ChangeValue( value, item, col ); +} + // --------------------------------------------------------- // wxDataViewTextRenderer // --------------------------------------------------------- -extern "C" { -static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer, - gchar *arg1, gchar *arg2, gpointer user_data ); -} +extern "C" +{ static void wxGtkTextRendererEditedCallback( GtkCellRendererText *WXUNUSED(renderer), gchar *arg1, gchar *arg2, gpointer user_data ) { wxDataViewRenderer *cell = (wxDataViewRenderer*) user_data; - wxString tmp = wxGTK_CONV_BACK_FONT(arg2, cell->GetOwner()->GetOwner()->GetFont()); - wxVariant value = tmp; - if (!cell->Validate( value )) - return; + cell->GtkOnTextEdited(arg1, wxGTK_CONV_BACK_FONT( + arg2, cell->GetOwner()->GetOwner()->GetFont())); +} - wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel(); +} - GtkTreePath *path = gtk_tree_path_new_from_string( arg1 ); - GtkTreeIter iter; - cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, path ); - wxDataViewItem item( (void*) iter.user_data );; - gtk_tree_path_free( path ); +namespace +{ - unsigned int model_col = cell->GetOwner()->GetModelColumn(); +// helper function used by wxDataViewTextRenderer and +// wxDataViewCustomRenderer::RenderText(): it applies the attributes to the +// given text renderer and returns true if anything was done +bool GtkApplyAttr(GtkCellRendererText *renderer, const wxDataViewItemAttr& attr) +{ + bool usingDefaultAttrs = true; + if (attr.HasColour()) + { + const GdkColor * const gcol = attr.GetColour().GetColor(); + + GValue gvalue = { 0, }; + g_value_init( &gvalue, GDK_TYPE_COLOR ); + g_value_set_boxed( &gvalue, gcol ); + g_object_set_property( G_OBJECT(renderer), "foreground_gdk", &gvalue ); + g_value_unset( &gvalue ); + + usingDefaultAttrs = false; + } + else + { + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_BOOLEAN ); + g_value_set_boolean( &gvalue, FALSE ); + g_object_set_property( G_OBJECT(renderer), "foreground-set", &gvalue ); + g_value_unset( &gvalue ); + } + + if (attr.GetItalic()) + { + GValue gvalue = { 0, }; + g_value_init( &gvalue, PANGO_TYPE_STYLE ); + g_value_set_enum( &gvalue, PANGO_STYLE_ITALIC ); + g_object_set_property( G_OBJECT(renderer), "style", &gvalue ); + g_value_unset( &gvalue ); + + usingDefaultAttrs = false; + } + else + { + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_BOOLEAN ); + g_value_set_boolean( &gvalue, FALSE ); + g_object_set_property( G_OBJECT(renderer), "style-set", &gvalue ); + g_value_unset( &gvalue ); + } + + + if (attr.GetBold()) + { + GValue gvalue = { 0, }; + g_value_init( &gvalue, PANGO_TYPE_WEIGHT ); + g_value_set_enum( &gvalue, PANGO_WEIGHT_BOLD ); + g_object_set_property( G_OBJECT(renderer), "weight", &gvalue ); + g_value_unset( &gvalue ); + + usingDefaultAttrs = false; + } + else + { + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_BOOLEAN ); + g_value_set_boolean( &gvalue, FALSE ); + g_object_set_property( G_OBJECT(renderer), "weight-set", &gvalue ); + g_value_unset( &gvalue ); + } + +#if 0 + if (attr.HasBackgroundColour()) + { + wxColour colour = attr.GetBackgroundColour(); + const GdkColor * const gcol = colour.GetColor(); - model->SetValue( value, item, model_col ); - model->ValueChanged( item, model_col ); + GValue gvalue = { 0, }; + g_value_init( &gvalue, GDK_TYPE_COLOR ); + g_value_set_boxed( &gvalue, gcol ); + g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue ); + g_value_unset( &gvalue ); + } + else + { + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_BOOLEAN ); + g_value_set_boolean( &gvalue, FALSE ); + g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue ); + g_value_unset( &gvalue ); + } +#endif + + return !usingDefaultAttrs; } +} // anonymous namespace + IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer) wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode, @@ -1751,29 +1904,25 @@ wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxD SetAlignment(align); } -bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) +bool wxDataViewTextRenderer::SetTextValue(const wxString& str) { - wxString tmp = value; - GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_STRING ); - g_value_set_string( &gvalue, wxGTK_CONV_FONT( tmp, GetOwner()->GetOwner()->GetFont() ) ); + g_value_set_string( &gvalue, wxGTK_CONV_FONT( str, GetOwner()->GetOwner()->GetFont() ) ); g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue ); g_value_unset( &gvalue ); return true; } -bool wxDataViewTextRenderer::GetValue( wxVariant &value ) const +bool wxDataViewTextRenderer::GetTextValue(wxString& str) const { GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_STRING ); g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue ); - wxString tmp = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast(this)->GetOwner()->GetOwner()->GetFont() ); + str = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast(this)->GetOwner()->GetOwner()->GetFont() ); g_value_unset( &gvalue ); - value = tmp; - return true; } @@ -1798,29 +1947,42 @@ void wxDataViewTextRenderer::SetAlignment( int align ) g_value_unset( &gvalue ); } -// --------------------------------------------------------- -// wxDataViewTextRendererAttr -// --------------------------------------------------------- - -IMPLEMENT_CLASS(wxDataViewTextRendererAttr,wxDataViewTextRenderer) +bool wxDataViewTextRenderer::GtkSetAttr(const wxDataViewItemAttr& attr) +{ + return GtkApplyAttr(GtkGetTextRenderer(), attr); +} -wxDataViewTextRendererAttr::wxDataViewTextRendererAttr( const wxString &varianttype, - wxDataViewCellMode mode, int align ) : - wxDataViewTextRenderer( varianttype, mode, align ) +GtkCellRendererText *wxDataViewTextRenderer::GtkGetTextRenderer() const { + return GTK_CELL_RENDERER_TEXT(m_renderer); } // --------------------------------------------------------- // wxDataViewBitmapRenderer // --------------------------------------------------------- +namespace +{ + +// set "pixbuf" property on the given renderer +void SetPixbufProp(GtkCellRenderer *renderer, GdkPixbuf *pixbuf) +{ + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_OBJECT ); + g_value_set_object( &gvalue, pixbuf ); + g_object_set_property( G_OBJECT(renderer), "pixbuf", &gvalue ); + g_value_unset( &gvalue ); +} + +} // anonymous namespace + IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer) wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode, int align ) : wxDataViewRenderer( varianttype, mode, align ) { - m_renderer = (GtkCellRenderer*) gtk_cell_renderer_pixbuf_new(); + m_renderer = gtk_cell_renderer_pixbuf_new(); SetMode(mode); SetAlignment(align); @@ -1833,38 +1995,23 @@ bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) wxBitmap bitmap; bitmap << value; - // This may create a Pixbuf representation in the - // wxBitmap object (and it will stay there) - GdkPixbuf *pixbuf = bitmap.GetPixbuf(); - - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_OBJECT ); - g_value_set_object( &gvalue, pixbuf ); - g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue ); - g_value_unset( &gvalue ); - - return true; + // GetPixbuf() may create a Pixbuf representation in the wxBitmap + // object (and it will stay there and remain owned by wxBitmap) + SetPixbufProp(m_renderer, bitmap.GetPixbuf()); } - - if (value.GetType() == wxT("wxIcon")) + else if (value.GetType() == wxT("wxIcon")) { - wxIcon bitmap; - bitmap << value; + wxIcon icon; + icon << value; - // This may create a Pixbuf representation in the - // wxBitmap object (and it will stay there) - GdkPixbuf *pixbuf = bitmap.GetPixbuf(); - - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_OBJECT ); - g_value_set_object( &gvalue, pixbuf ); - g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue ); - g_value_unset( &gvalue ); - - return true; + SetPixbufProp(m_renderer, icon.GetPixbuf()); + } + else + { + return false; } - return false; + return true; } bool wxDataViewBitmapRenderer::GetValue( wxVariant &WXUNUSED(value) ) const @@ -1909,8 +2056,7 @@ static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer, unsigned int model_col = cell->GetOwner()->GetModelColumn(); - model->SetValue( value, item, model_col ); - model->ValueChanged( item, model_col ); + model->ChangeValue( value, item, model_col ); } IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer) @@ -2008,9 +2154,10 @@ public: IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer) wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, - wxDataViewCellMode mode, int align, - bool no_init ) : - wxDataViewRenderer( varianttype, mode, align ) + wxDataViewCellMode mode, + int align, + bool no_init ) + : wxDataViewCustomRendererBase( varianttype, mode, align ) { m_dc = NULL; m_text_renderer = NULL; @@ -2021,40 +2168,47 @@ wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, Init(mode, align); } -void wxDataViewCustomRenderer::RenderText( const wxString &text, int xoffset, - wxRect WXUNUSED(cell), wxDC *WXUNUSED(dc), int WXUNUSED(state) ) +GtkCellRendererText *wxDataViewCustomRenderer::GtkGetTextRenderer() const { -#if 0 - wxDataViewCtrl *view = GetOwner()->GetOwner(); - wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ? - wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) : - view->GetForegroundColour(); - dc->SetTextForeground(col); - dc->DrawText( text, cell.x + xoffset, cell.y + ((cell.height - dc->GetCharHeight()) / 2)); -#else - if (!m_text_renderer) - m_text_renderer = gtk_cell_renderer_text_new(); + if ( !m_text_renderer ) + { + // we create it on demand so need to do it even from a const function + const_cast(this)-> + m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new()); + } + + return m_text_renderer; +} + +void wxDataViewCustomRenderer::RenderText( const wxString &text, + int xoffset, + wxRect cell, + wxDC *WXUNUSED(dc), + int WXUNUSED(state) ) +{ + + GtkCellRendererText * const textRenderer = GtkGetTextRenderer(); GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_STRING ); g_value_set_string( &gvalue, wxGTK_CONV_FONT( text, GetOwner()->GetOwner()->GetFont() ) ); - g_object_set_property( G_OBJECT(m_text_renderer), "text", &gvalue ); + g_object_set_property( G_OBJECT(textRenderer), "text", &gvalue ); g_value_unset( &gvalue ); - ((GdkRectangle*) cell_area)->x += xoffset; - ((GdkRectangle*) cell_area)->width -= xoffset; + GtkApplyAttr(textRenderer, GetAttr()); - gtk_cell_renderer_render( m_text_renderer, - window, - widget, - (GdkRectangle*) background_area, - (GdkRectangle*) cell_area, - (GdkRectangle*) expose_area, - (GtkCellRendererState) flags ); + GdkRectangle cell_area; + wxRectToGDKRect(cell, cell_area); + cell_area.x += xoffset; + cell_area.width -= xoffset; - ((GdkRectangle*) cell_area)->x -= xoffset; - ((GdkRectangle*) cell_area)->width += xoffset; -#endif + gtk_cell_renderer_render( GTK_CELL_RENDERER(textRenderer), + m_renderParams.window, + m_renderParams.widget, + m_renderParams.background_area, + &cell_area, + m_renderParams.expose_area, + (GtkCellRendererState) m_renderParams.flags ); } bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align) @@ -2347,10 +2501,7 @@ END_EVENT_TABLE() void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event ) { - wxDateTime date = event.GetDate(); - wxVariant value = date; - m_model->SetValue( value, m_item, m_col ); - m_model->ValueChanged( m_item, m_col ); + m_model->ChangeValue( event.GetDate(), m_item, m_col ); DismissAndNotify(); } @@ -2416,67 +2567,63 @@ bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *m IMPLEMENT_CLASS(wxDataViewIconTextRenderer, wxDataViewCustomRenderer) -wxDataViewIconTextRenderer::wxDataViewIconTextRenderer( - const wxString &varianttype, wxDataViewCellMode mode, int align ) : - wxDataViewCustomRenderer( varianttype, mode, align ) +wxDataViewIconTextRenderer::wxDataViewIconTextRenderer + ( + const wxString &varianttype, + wxDataViewCellMode mode, + int align + ) + : wxDataViewTextRenderer(varianttype, mode, align) { - SetMode(mode); - SetAlignment(align); + m_rendererIcon = gtk_cell_renderer_pixbuf_new(); } wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer() { } -bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value ) +void wxDataViewIconTextRenderer::GtkPackIntoColumn(GtkTreeViewColumn *column) { - m_value << value; - return true; -} + // add the icon renderer first + gtk_tree_view_column_pack_start(column, m_rendererIcon, FALSE /* !expand */); -bool wxDataViewIconTextRenderer::GetValue( wxVariant &WXUNUSED(value) ) const -{ - return false; + // add the text renderer too + wxDataViewRenderer::GtkPackIntoColumn(column); } -bool wxDataViewIconTextRenderer::Render( wxRect cell, wxDC *dc, int state ) +bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value ) { - const wxIcon &icon = m_value.GetIcon(); - int offset = 0; - if (icon.IsOk()) - { - int yoffset = wxMax( 0, (cell.height - icon.GetHeight()) / 2 ); - dc->DrawIcon( icon, cell.x, cell.y + yoffset ); - offset = icon.GetWidth() + 4; - } + m_value << value; - RenderText( m_value.GetText(), offset, cell, dc, state ); + SetTextValue(m_value.GetText()); + SetPixbufProp(m_rendererIcon, m_value.GetIcon().GetPixbuf()); return true; } -wxSize wxDataViewIconTextRenderer::GetSize() const +bool wxDataViewIconTextRenderer::GetValue(wxVariant& value) const { - wxSize size; - if (m_value.GetIcon().IsOk()) - size.x = 4 + m_value.GetIcon().GetWidth(); - wxCoord x,y,d; - GetView()->GetTextExtent( m_value.GetText(), &x, &y, &d ); - size.x += x; - size.y = y+d; - return size; -} + wxString str; + if ( !GetTextValue(str) ) + return false; -wxControl* wxDataViewIconTextRenderer::CreateEditorCtrl( - wxWindow *WXUNUSED(parent), wxRect WXUNUSED(labelRect), const wxVariant &WXUNUSED(value) ) -{ - return NULL; + // user doesn't have any way to edit the icon so leave it unchanged + value << wxDataViewIconText(str, m_value.GetIcon()); + + return true; } -bool wxDataViewIconTextRenderer::GetValueFromEditorCtrl( - wxControl* WXUNUSED(editor), wxVariant &WXUNUSED(value) ) +void +wxDataViewIconTextRenderer::GtkOnCellChanged(const wxVariant& value, + const wxDataViewItem& item, + unsigned col) { - return false; + // we receive just the text part of our value as it's the only one which + // can be edited, but we need the full wxDataViewIconText value for the + // model + wxVariant valueIconText; + valueIconText << wxDataViewIconText(value.GetString(), m_value.GetIcon()); + wxDataViewTextRenderer::GtkOnCellChanged(valueIconText, item, col); } // --------------------------------------------------------- @@ -2517,14 +2664,8 @@ gtk_dataview_header_button_press_callback( GtkWidget *WXUNUSED(widget), return FALSE; } -extern "C" { -static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data ); -} - +extern "C" +{ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column), GtkCellRenderer *renderer, @@ -2543,148 +2684,59 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column), if (!wx_model->IsVirtualListModel()) { - - if (wx_model->IsContainer( item )) - { - if (wx_model->HasContainerColumns( item ) || (cell->GetOwner()->GetModelColumn() == 0)) + gboolean visible; + if (wx_model->IsContainer( item )) { - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, TRUE ); - g_object_set_property( G_OBJECT(renderer), "visible", &gvalue ); - g_value_unset( &gvalue ); + visible = wx_model->HasContainerColumns( item ) || + (cell->GetOwner()->GetModelColumn() == 0); } else { - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, FALSE ); - g_object_set_property( G_OBJECT(renderer), "visible", &gvalue ); - g_value_unset( &gvalue ); - - return; + visible = true; } - } - else - { + GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, TRUE ); + g_value_set_boolean( &gvalue, visible ); g_object_set_property( G_OBJECT(renderer), "visible", &gvalue ); g_value_unset( &gvalue ); - } + if ( !visible ) + return; } wxVariant value; wx_model->GetValue( value, item, cell->GetOwner()->GetModelColumn() ); if (value.GetType() != cell->GetVariantType()) + { wxLogError( wxT("Wrong type, required: %s but: %s"), value.GetType().c_str(), cell->GetVariantType().c_str() ); + } cell->SetValue( value ); - if (cell->GtkHasAttributes()) - { - wxDataViewItemAttr attr; - bool colour_set = false; - bool style_set = false; - bool weight_set = false; - - if (wx_model->GetAttr( item, cell->GetOwner()->GetModelColumn(), attr )) - { - // this must be a GtkCellRendererText - wxColour colour = attr.GetColour(); - if (colour.IsOk()) - { - const GdkColor * const gcol = colour.GetColor(); - - GValue gvalue = { 0, }; - g_value_init( &gvalue, GDK_TYPE_COLOR ); - g_value_set_boxed( &gvalue, gcol ); - g_object_set_property( G_OBJECT(renderer), "foreground_gdk", &gvalue ); - g_value_unset( &gvalue ); - - colour_set = true; - } - - if (attr.GetItalic()) - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, PANGO_TYPE_STYLE ); - g_value_set_enum( &gvalue, PANGO_STYLE_ITALIC ); - g_object_set_property( G_OBJECT(renderer), "style", &gvalue ); - g_value_unset( &gvalue ); - - style_set = true; - } - - if (attr.GetBold()) - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, PANGO_TYPE_WEIGHT ); - g_value_set_enum( &gvalue, PANGO_WEIGHT_BOLD ); - g_object_set_property( G_OBJECT(renderer), "weight", &gvalue ); - g_value_unset( &gvalue ); - weight_set = true; - } - } - - if (!style_set) - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, FALSE ); - g_object_set_property( G_OBJECT(renderer), "style-set", &gvalue ); - g_value_unset( &gvalue ); - } - - if (!weight_set) - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, FALSE ); - g_object_set_property( G_OBJECT(renderer), "weight-set", &gvalue ); - g_value_unset( &gvalue ); - } - - if (!colour_set) - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, FALSE ); - g_object_set_property( G_OBJECT(renderer), "foreground-set", &gvalue ); - g_value_unset( &gvalue ); - } - } + // deal with attributes: if the renderer doesn't support them at all, we + // don't even need to query the model for them + if ( !cell->GtkSupportsAttrs() ) + return; -#if 0 - if (attr.HasBackgroundColour()) + // it can support attributes so check if this item has any + wxDataViewItemAttr attr; + if ( wx_model->GetAttr( item, cell->GetOwner()->GetModelColumn(), attr ) + || !cell->GtkIsUsingDefaultAttrs() ) { - wxColour colour = attr.GetBackgroundColour(); - const GdkColor * const gcol = colour.GetColor(); - - GValue gvalue = { 0, }; - g_value_init( &gvalue, GDK_TYPE_COLOR ); - g_value_set_boxed( &gvalue, gcol ); - g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue ); - g_value_unset( &gvalue ); - } - else - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, G_TYPE_BOOLEAN ); - g_value_set_boolean( &gvalue, FALSE ); - g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue ); - g_value_unset( &gvalue ); + bool usingDefaultAttrs = !cell->GtkSetAttr(attr); + cell->GtkSetUsingDefaultAttrs(usingDefaultAttrs); } -#endif - + // else: no custom attributes specified and we're already using the default + // ones -- nothing to do } +} // extern "C" + #include WX_DEFINE_LIST(wxDataViewColumnList) @@ -2712,7 +2764,6 @@ void wxDataViewColumn::Init(wxAlignment align, int flags, int width) { m_isConnected = false; - GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle(); GtkTreeViewColumn *column = gtk_tree_view_column_new(); m_column = (GtkWidget*) column; @@ -2731,10 +2782,13 @@ void wxDataViewColumn::Init(wxAlignment align, int flags, int width) gtk_box_pack_end( GTK_BOX(box), GTK_WIDGET(m_label), FALSE, FALSE, 1 ); gtk_tree_view_column_set_widget( column, box ); - gtk_tree_view_column_pack_end( column, renderer, TRUE ); + wxDataViewRenderer * const colRenderer = GetRenderer(); + GtkCellRenderer * const cellRenderer = colRenderer->GetGtkHandle(); + + colRenderer->GtkPackIntoColumn(column); - gtk_tree_view_column_set_cell_data_func( column, renderer, - wxGtkTreeCellDataFunc, (gpointer) GetRenderer(), NULL ); + gtk_tree_view_column_set_cell_data_func( column, cellRenderer, + wxGtkTreeCellDataFunc, (gpointer) colRenderer, NULL ); } void wxDataViewColumn::OnInternalIdle() @@ -3031,10 +3085,10 @@ void wxGtkTreeModelNode::Resort() // Sort the ptrs gs_internal = m_internal; ptrs.Sort( &wxGtkTreeModelChildPtrCmp ); - + wxGtkTreeModelChildren temp; void** base_ptr = &(m_children[0]); - // Transfer positions to new_order array and + // Transfer positions to new_order array and // IDs to temp for (i = 0; i < child_count; i++) { @@ -3074,13 +3128,13 @@ void wxGtkTreeModelNode::Resort() #if 0 // Too slow - + wxGtkTreeModelChildren temp; WX_APPEND_ARRAY( temp, m_children ); gs_internal = m_internal; m_children.Sort( &wxGtkTreeModelChildCmp ); - + unsigned int pos; for (pos = 0; pos < child_count; pos++) { @@ -3103,7 +3157,7 @@ void wxGtkTreeModelNode::Resort() gtk_tree_path_free (path); delete [] new_order; - + unsigned int pos; for (pos = 0; pos < node_count; pos++) { @@ -3320,17 +3374,16 @@ wxDataViewCtrlInternal::row_drop_possible(GtkTreeDragDest *WXUNUSED(drag_dest), bool wxDataViewCtrlInternal::Cleared() { + GtkWidget* tree_widget = GetOwner()->GtkGetTreeView(); + gtk_tree_view_set_model( GTK_TREE_VIEW(tree_widget), NULL ); + gtk_tree_view_set_model( GTK_TREE_VIEW(tree_widget), GTK_TREE_MODEL(m_gtk_model) ); + if (m_root) { delete m_root; InitTree(); } - // Create new GTK model - g_object_unref( m_gtk_model ); - m_gtk_model = wxgtk_tree_model_new(); - m_gtk_model->internal = this; - return true; } @@ -3411,9 +3464,9 @@ gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path if (m_wx_model->IsVirtualListModel()) { wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model; - + unsigned int i = (unsigned int)gtk_tree_path_get_indices (path)[0]; - + if (i >= wx_model->GetCount()) return FALSE; @@ -3466,6 +3519,9 @@ gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter ) { + // When this is called from ItemDeleted(), the item is already + // deleted in the model. + GtkTreePath *retval = gtk_tree_path_new (); if (m_wx_model->IsVirtualListModel()) @@ -3503,10 +3559,16 @@ gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter ) int n = ( (wxUIntPtr) iter->user_data ) -1; if (n == -1) + { + iter->user_data = NULL; return FALSE; + } - if (n >= (int) wx_model->GetCount()) + if (n >= (int) wx_model->GetCount()-1) + { + iter->user_data = NULL; return FALSE; + } // user_data is just the index +1 (+2 because we need the next) iter->user_data = (gpointer) (n+2); @@ -3515,14 +3577,19 @@ gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter ) { wxGtkTreeModelNode *parent = FindParentNode( iter ); if( parent == NULL ) + { + iter->user_data = NULL; return FALSE; + } int pos = parent->GetChildren().Index( iter->user_data ); if (pos == (int) parent->GetChildCount()-1) + { + iter->user_data = NULL; return FALSE; + } - iter->stamp = m_gtk_model->stamp; iter->user_data = parent->GetChildren().Item( pos+1 ); } @@ -3544,6 +3611,14 @@ gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter * } else { + if (iter == NULL) + { + if (m_root->GetChildCount() == 0) return FALSE; + iter->stamp = m_gtk_model->stamp; + iter->user_data = (gpointer) m_root->GetChildren().Item( 0 ); + return TRUE; + } + wxDataViewItem item( (void*) parent->user_data ); if (!m_wx_model->IsContainer( item )) @@ -3572,13 +3647,16 @@ gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter ) wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model; if (iter == NULL) - return (gint) wx_model->GetCount(); - + return (wx_model->GetCount() > 0); + // this is a list, nodes have no children return FALSE; } else { + if (iter == NULL) + return (m_root->GetChildCount() > 0); + wxDataViewItem item( (void*) iter->user_data ); bool is_container = m_wx_model->IsContainer( item ); @@ -3623,8 +3701,6 @@ gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter ) BuildBranch( parent_node ); - // wxPrintf( "iter_n_children %d\n", parent_node->GetChildCount() ); - return parent_node->GetChildCount(); } } @@ -3665,8 +3741,6 @@ gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter BuildBranch( parent_node ); - // wxPrintf( "iter_nth_child %d\n", n ); - iter->stamp = m_gtk_model->stamp; iter->user_data = parent_node->GetChildren().Item( n ); @@ -3693,6 +3767,21 @@ gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *ch } } +// item can be deleted already in the model +int wxDataViewCtrlInternal::GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item ) +{ + wxGtkTreeModelNode *parent_node = FindNode( parent ); + wxGtkTreeModelChildren &children = parent_node->GetChildren(); + size_t j; + for (j = 0; j < children.GetCount(); j++) + { + if (children[j] == item.GetID()) + return j; + } + return -1; +} + + static wxGtkTreeModelNode* wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item ) { @@ -3716,7 +3805,7 @@ wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *tr if( node && node->GetNodes().GetCount() != 0 ) { int len = node->GetNodes().GetCount(); - wxGtkTreeModelNodes nodes = node->GetNodes(); + wxGtkTreeModelNodes &nodes = node->GetNodes(); int j = 0; for( ; j < len; j ++) { @@ -4015,8 +4104,6 @@ gtk_dataview_motion_notify_callback( GtkWidget *WXUNUSED(widget), GtkTreeIter iter; dv->GtkGetInternal()->get_iter( &iter, path ); - // wxPrintf( "mouse %d %d\n", (int) gdk_event->x, (int) gdk_event->y ); - gtk_tree_path_free( path ); } } @@ -4095,8 +4182,6 @@ bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator ) { - Init(); - if (!PreCreation( parent, pos, size ) || !CreateBase( parent, id, pos, size, style, validator )) { @@ -4200,13 +4285,10 @@ void wxDataViewCtrl::OnInternalIdle() bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model ) { - if (GetModel()) + if ( m_internal ) { delete m_internal; m_internal = NULL; - - delete m_notifier; - m_notifier = NULL; } if (!wxDataViewCtrlBase::AssociateModel( model )) @@ -4634,6 +4716,10 @@ void wxDataViewCtrl::GtkEnableSelectionEvents() G_CALLBACK (wxdataview_selection_changed_callback), this); } +// ---------------------------------------------------------------------------- +// visual attributes stuff +// ---------------------------------------------------------------------------- + // static wxVisualAttributes wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) @@ -4641,9 +4727,12 @@ wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new); } +void wxDataViewCtrl::DoApplyWidgetStyle(GtkRcStyle *style) +{ + wxDataViewCtrlBase::DoApplyWidgetStyle(style); + gtk_widget_modify_style(m_treeview, style); +} -#endif - // !wxUSE_GENERICDATAVIEWCTRL +#endif // !wxUSE_GENERICDATAVIEWCTRL -#endif - // wxUSE_DATAVIEWCTRL +#endif // wxUSE_DATAVIEWCTRL