X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/673810eeb8e16599b599f3a851692c323bc20165..9579070b94d9aaad1bdd3638163cb94e48d5508b:/src/gtk/dataview.cpp diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index a52da38744..c268ff4682 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -231,9 +231,9 @@ public: bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item ); bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item ); bool ItemChanged( const wxDataViewItem &item ); - bool ValueChanged( const wxDataViewItem &item, unsigned int col ); + bool ValueChanged( const wxDataViewItem &item, unsigned int model_column ); bool Cleared(); - bool BeforeReset(size_t old_Size,size_t new_size); + bool BeforeReset(); bool AfterReset(); void Resort(); @@ -258,8 +258,12 @@ public: // item can be deleted already in the model int GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item ); + virtual void OnInternalIdle(); + protected: void InitTree(); + void ScheduleRefresh(); + wxGtkTreeModelNode *FindNode( const wxDataViewItem &item ); wxGtkTreeModelNode *FindNode( GtkTreeIter *iter ); wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item ); @@ -282,8 +286,10 @@ private: GtkTargetEntry m_dropTargetTargetEntry; wxCharBuffer m_dropTargetTargetEntryTarget; wxDataObject *m_dropDataObject; - + wxGtkDataViewModelNotifier *m_notifier; + + bool m_dirty; }; @@ -487,11 +493,11 @@ static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *s gint sort_column_id, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy); + GDestroyNotify destroy); static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy); + GDestroyNotify destroy); static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable); /* drag'n'drop */ @@ -960,7 +966,7 @@ wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable, gint WXUNUSED(sort_column_id), GtkTreeIterCompareFunc func, gpointer WXUNUSED(data), - GtkDestroyNotify WXUNUSED(destroy)) + GDestroyNotify WXUNUSED(destroy)) { g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) ); g_return_if_fail (func != NULL); @@ -970,7 +976,7 @@ static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc func, gpointer WXUNUSED(data), - GtkDestroyNotify WXUNUSED(destroy)) + GDestroyNotify WXUNUSED(destroy)) { g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) ); g_return_if_fail (func != NULL); @@ -1327,8 +1333,10 @@ gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer, wxSize size = cell->GetSize(); - gint calc_width = (gint) renderer->xpad * 2 + size.x; - gint calc_height = (gint) renderer->ypad * 2 + size.y; + int xpad, ypad; + gtk_cell_renderer_get_padding(renderer, &xpad, &ypad); + int calc_width = xpad * 2 + size.x; + int calc_height = ypad * 2 + size.y; if (x_offset) *x_offset = 0; @@ -1337,17 +1345,17 @@ gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer, if (cell_area && size.x > 0 && size.y > 0) { + float xalign, yalign; + gtk_cell_renderer_get_alignment(renderer, &xalign, &yalign); if (x_offset) { - *x_offset = (gint)((renderer->xalign * - (cell_area->width - calc_width - 2 * renderer->xpad))); - *x_offset = MAX (*x_offset, 0) + renderer->xpad; + *x_offset = int(xalign * (cell_area->width - calc_width - 2 * xpad)); + *x_offset = MAX(*x_offset, 0) + xpad; } if (y_offset) { - *y_offset = (gint)((renderer->yalign * - (cell_area->height - calc_height - 2 * renderer->ypad))); - *y_offset = MAX (*y_offset, 0) + renderer->ypad; + *y_offset = int(yalign * (cell_area->height - calc_height - 2 * ypad)); + *y_offset = MAX(*y_offset, 0) + ypad; } } @@ -1375,7 +1383,9 @@ gtk_wx_cell_renderer_render (GtkCellRenderer *renderer, background_area, expose_area, flags); wxRect rect(wxRectFromGDKRect(cell_area)); - rect = rect.Deflate(renderer->xpad, renderer->ypad); + int xpad, ypad; + gtk_cell_renderer_get_padding(renderer, &xpad, &ypad); + rect = rect.Deflate(xpad, ypad); wxWindowDC* dc = (wxWindowDC*) cell->GetDC(); wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl(); @@ -1425,8 +1435,10 @@ gtk_wx_cell_renderer_activate( rect.x += cell_area->x; rect.y += cell_area->y; - rect.width -= renderer->xpad * 2; - rect.height -= renderer->ypad * 2; + int xpad, ypad; + gtk_cell_renderer_get_padding(renderer, &xpad, &ypad); + rect.width -= xpad * 2; + rect.height -= ypad * 2; wxRect renderrect(wxRectFromGDKRect(&rect)); @@ -1484,12 +1496,12 @@ public: virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item ); virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item ); virtual bool ItemChanged( const wxDataViewItem &item ); - virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col ); + virtual bool ValueChanged( const wxDataViewItem &item, unsigned int model_column ); virtual bool Cleared(); virtual void Resort(); - virtual bool BeforeReset(size_t old_size,size_t new_size); + virtual bool BeforeReset(); virtual bool AfterReset(); - + void UpdateLastCount(); private: @@ -1570,7 +1582,7 @@ void wxGtkDataViewModelNotifier::Resort() bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item ) { GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); - + GtkTreeIter iter; iter.stamp = wxgtk_model->stamp; iter.user_data = (gpointer) item.GetID(); @@ -1585,17 +1597,17 @@ bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item ) return true; } -bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_col ) +bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_column ) { GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); wxDataViewCtrl *ctrl = m_internal->GetOwner(); - + // This adds GTK+'s missing MVC logic for ValueChanged unsigned int index; for (index = 0; index < ctrl->GetColumnCount(); index++) { wxDataViewColumn *column = ctrl->GetColumn( index ); - if (column->GetModelColumn() == model_col) + if (column->GetModelColumn() == model_column) { GtkTreeView *widget = GTK_TREE_VIEW(ctrl->GtkGetTreeView()); GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()); @@ -1618,7 +1630,7 @@ bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsig gtk_widget_queue_draw_area( GTK_WIDGET(widget), cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height ); - m_internal->ValueChanged( item, model_col ); + m_internal->ValueChanged( item, model_column ); return true; } @@ -1627,44 +1639,44 @@ bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsig return false; } -bool wxGtkDataViewModelNotifier::BeforeReset(size_t WXUNUSED(old_size), size_t WXUNUSED(new_size)) +bool wxGtkDataViewModelNotifier::BeforeReset() { GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView(); gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL ); - + return true; } bool wxGtkDataViewModelNotifier::AfterReset() { - GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView(); - + GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); + + m_internal->Cleared(); + gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(wxgtk_model) ); - m_internal->Cleared(); - return true; } bool wxGtkDataViewModelNotifier::Cleared() { GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); - + // There is no call to tell the model that everything // has been deleted so call row_deleted() for every // child of root... int count = m_internal->iter_n_children( NULL ); // number of children of root - + GtkTreePath *path = gtk_tree_path_new_first(); // points to root int i; for (i = 0; i < count; i++) gtk_tree_model_row_deleted( GTK_TREE_MODEL(wxgtk_model), path ); - + gtk_tree_path_free( path ); - + m_internal->Cleared(); return true; @@ -1725,6 +1737,7 @@ wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewC wxDataViewRendererBase( varianttype, mode, align ) { m_renderer = NULL; + m_mode = mode; // we haven't changed them yet m_usingDefaultAttrs = true; @@ -1770,6 +1783,8 @@ void wxDataViewRenderer::SetMode( wxDataViewCellMode mode ) return; } + m_mode = mode; + // This value is most often ignored in GtkTreeView GValue gvalue = { 0, }; g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() ); @@ -2294,7 +2309,7 @@ public: m_context = window->GTKGetPangoDefaultContext(); m_layout = pango_layout_new( m_context ); - m_fontdesc = pango_font_description_copy( widget->style->font_desc ); + m_fontdesc = pango_font_description_copy(gtk_widget_get_style(widget)->font_desc); m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget ); @@ -2340,6 +2355,7 @@ GtkCellRendererText *wxDataViewCustomRenderer::GtkGetTextRenderer() const // 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()); + g_object_ref_sink(m_text_renderer); } return m_text_renderer; @@ -2397,7 +2413,7 @@ wxDataViewCustomRenderer::~wxDataViewCustomRenderer() delete m_dc; if (m_text_renderer) - gtk_object_sink( GTK_OBJECT(m_text_renderer) ); + g_object_unref(m_text_renderer); } wxDC *wxDataViewCustomRenderer::GetDC() @@ -2635,7 +2651,7 @@ wxDataViewChoiceByIndexRenderer::wxDataViewChoiceByIndexRenderer( const wxArrayS wxDataViewChoiceRenderer( choices, mode, alignment ) { } - + void wxDataViewChoiceByIndexRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str) { wxVariant value( (long) GetChoices().Index( str ) ); @@ -2654,13 +2670,13 @@ bool wxDataViewChoiceByIndexRenderer::SetValue( const wxVariant &value ) wxVariant string_value = GetChoice( value.GetLong() ); return wxDataViewChoiceRenderer::SetValue( string_value ); } - + bool wxDataViewChoiceByIndexRenderer::GetValue( wxVariant &value ) const { wxVariant string_value; if (!wxDataViewChoiceRenderer::GetValue( string_value )) return false; - + value = (long) GetChoices().Index( string_value.GetString() ); return true; } @@ -2749,7 +2765,7 @@ wxSize wxDataViewDateRenderer::GetSize() const return wxSize(x,y+d); } -bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *model, +bool wxDataViewDateRenderer::Activate( const wxRect& WXUNUSED(cell), wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) { wxVariant variant; @@ -2923,6 +2939,22 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column), cell->SetValue( value ); + // deal with disabled items + bool enabled = wx_model->IsEnabled( item, cell->GetOwner()->GetModelColumn() ); + + // a) this sets the appearance to disabled grey + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_BOOLEAN ); + g_value_set_boolean( &gvalue, enabled ); + g_object_set_property( G_OBJECT(renderer), "sensitive", &gvalue ); + g_value_unset( &gvalue ); + + // b) this actually disables the control/renderer + if (enabled) + cell->SetMode( cell->GtkGetMode() ); + else + cell->SetMode( wxDATAVIEW_CELL_INERT ); + // deal with attributes: if the renderer doesn't support them at all, we // don't even need to query the model for them @@ -2939,6 +2971,7 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column), } // else: no custom attributes specified and we're already using the default // ones -- nothing to do + } } // extern "C" @@ -3001,8 +3034,8 @@ void wxDataViewColumn::OnInternalIdle() { if (m_isConnected) return; - - if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview)) + + if (gtk_widget_get_realized(GetOwner()->m_treeview)) { GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); if (column->button) @@ -3011,8 +3044,8 @@ void wxDataViewColumn::OnInternalIdle() G_CALLBACK (gtk_dataview_header_button_press_callback), this); // otherwise the event will be blocked by GTK+ - gtk_tree_view_column_set_clickable( column, TRUE ); - + gtk_tree_view_column_set_clickable( column, TRUE ); + m_isConnected = true; } } @@ -3050,7 +3083,7 @@ void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) { wxDataViewColumnBase::SetBitmap( bitmap ); - if (bitmap.Ok()) + if (bitmap.IsOk()) { GtkImage *gtk_image = GTK_IMAGE(m_image); @@ -3081,9 +3114,9 @@ void wxDataViewColumn::SetHidden( bool hidden ) gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden ); } -void wxDataViewColumn::SetResizeable( bool resizeable ) +void wxDataViewColumn::SetResizeable( bool resizable ) { - gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable ); + gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizable ); } void wxDataViewColumn::SetAlignment( wxAlignment align ) @@ -3199,23 +3232,20 @@ int wxDataViewColumn::GetWidth() const void wxDataViewColumn::SetWidth( int width ) { - if (width < 0) + if ( width == wxCOL_WIDTH_AUTOSIZE ) { -#if 1 - gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED ); - - // TODO find a better calculation - gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), wxDVC_DEFAULT_WIDTH ); -#else - // this is unpractical for large numbers of items and disables - // user resizing, which is totally unexpected + // NB: this disables user resizing gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE ); -#endif } else { - gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED ); + if ( width == wxCOL_WIDTH_DEFAULT ) + { + // TODO find a better calculation + width = wxDVC_DEFAULT_WIDTH; + } + gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width ); } } @@ -3380,7 +3410,7 @@ wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataVie { m_owner = owner; m_wx_model = wx_model; - + m_gtk_model = NULL; m_root = NULL; m_sort_order = GTK_SORT_ASCENDING; @@ -3390,6 +3420,8 @@ wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataVie m_dragDataObject = NULL; m_dropDataObject = NULL; + m_dirty = false; + m_gtk_model = wxgtk_tree_model_new(); m_gtk_model->internal = this; @@ -3401,7 +3433,7 @@ wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataVie if (!m_wx_model->IsVirtualListModel()) InitTree(); - + gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->GtkGetTreeView()), GTK_TREE_MODEL(m_gtk_model) ); } @@ -3409,7 +3441,7 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal() { m_wx_model->RemoveNotifier( m_notifier ); - // remove the model from the GtkTreeView before it gets destroyed + // remove the model from the GtkTreeView before it gets destroyed gtk_tree_view_set_model( GTK_TREE_VIEW( m_owner->GtkGetTreeView() ), NULL ); g_object_unref( m_gtk_model ); @@ -3418,6 +3450,21 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal() delete m_dropDataObject; } +void wxDataViewCtrlInternal::ScheduleRefresh() +{ + m_dirty = true; +} + +void wxDataViewCtrlInternal::OnInternalIdle() +{ + if (m_dirty) + { + GtkWidget *widget = m_owner->GtkGetTreeView(); + gtk_widget_queue_draw( widget ); + m_dirty = false; + } +} + void wxDataViewCtrlInternal::InitTree() { wxDataViewItem item; @@ -3432,7 +3479,7 @@ void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node ) { wxDataViewItemArray children; unsigned int count = m_wx_model->GetChildren( node->GetItem(), children ); - + unsigned int pos; for (pos = 0; pos < count; pos++) { @@ -3493,6 +3540,9 @@ gboolean wxDataViewCtrlInternal::row_draggable( GtkTreeDragSource *WXUNUSED(drag event.SetEventObject( m_owner ); event.SetItem( item ); event.SetModel( m_wx_model ); + gint x, y; + gtk_widget_get_pointer(m_owner->GtkGetTreeView(), &x, &y); + event.SetPosition(x, y); if (!m_owner->HandleWindowEvent( event )) return FALSE; @@ -3522,21 +3572,22 @@ gboolean wxDataViewCtrlInternal::drag_data_get( GtkTreeDragSource *WXUNUSED(drag if ( !item ) return FALSE; - if (!m_dragDataObject->IsSupported( selection_data->target )) + GdkAtom target = gtk_selection_data_get_target(selection_data); + if (!m_dragDataObject->IsSupported(target)) return FALSE; - size_t size = m_dragDataObject->GetDataSize( selection_data->target ); + size_t size = m_dragDataObject->GetDataSize(target); if (size == 0) return FALSE; void *buf = malloc( size ); gboolean res = FALSE; - if (m_dragDataObject->GetDataHere( selection_data->target, buf )) + if (m_dragDataObject->GetDataHere(target, buf)) { res = TRUE; - gtk_selection_data_set( selection_data, selection_data->target, + gtk_selection_data_set(selection_data, target, 8, (const guchar*) buf, size ); } @@ -3558,9 +3609,9 @@ wxDataViewCtrlInternal::drag_data_received(GtkTreeDragDest *WXUNUSED(drag_dest), event.SetEventObject( m_owner ); event.SetItem( item ); event.SetModel( m_wx_model ); - event.SetDataFormat( selection_data->target ); - event.SetDataSize( selection_data->length ); - event.SetDataBuffer( selection_data->data ); + event.SetDataFormat(gtk_selection_data_get_target(selection_data)); + event.SetDataSize(gtk_selection_data_get_length(selection_data)); + event.SetDataBuffer(const_cast(gtk_selection_data_get_data(selection_data))); if (!m_owner->HandleWindowEvent( event )) return FALSE; @@ -3583,7 +3634,7 @@ wxDataViewCtrlInternal::row_drop_possible(GtkTreeDragDest *WXUNUSED(drag_dest), event.SetEventObject( m_owner ); event.SetItem( item ); event.SetModel( m_wx_model ); - event.SetDataFormat( selection_data->target ); + event.SetDataFormat(gtk_selection_data_get_target(selection_data)); if (!m_owner->HandleWindowEvent( event )) return FALSE; @@ -3602,9 +3653,11 @@ bool wxDataViewCtrlInternal::Cleared() delete m_root; m_root = NULL; } - + InitTree(); - + + ScheduleRefresh(); + return true; } @@ -3612,6 +3665,8 @@ void wxDataViewCtrlInternal::Resort() { if (!m_wx_model->IsVirtualListModel()) m_root->Resort(); + + ScheduleRefresh(); } bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item ) @@ -3628,6 +3683,8 @@ bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDa parent_node->AddLeave( item.GetID() ); } + ScheduleRefresh(); + return true; } @@ -3642,6 +3699,8 @@ bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &parent, const wx parent_node->DeleteChild( item.GetID() ); } + ScheduleRefresh(); + return true; } @@ -3656,13 +3715,13 @@ bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item ) return true; } -bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int col ) +bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int view_column ) { wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() ); event.SetEventObject( m_owner ); event.SetModel( m_owner->GetModel() ); - event.SetColumn( col ); - event.SetDataViewColumn( GetOwner()->GetColumn(col) ); + event.SetColumn( view_column ); + event.SetDataViewColumn( GetOwner()->GetColumn(view_column) ); event.SetItem( item ); m_owner->HandleWindowEvent( event ); @@ -3768,7 +3827,7 @@ GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter ) while (node) { int pos = node->GetChildren().Index( id ); - + gtk_tree_path_prepend_index( retval, pos ); id = node->GetItem().GetID(); @@ -4193,7 +4252,7 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem static void wxdataview_selection_changed_callback( GtkTreeSelection* WXUNUSED(selection), wxDataViewCtrl *dv ) { - if (!GTK_WIDGET_REALIZED(dv->m_widget)) + if (!gtk_widget_get_realized(dv->m_widget)) return; wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, dv->GetId() ); @@ -4275,7 +4334,7 @@ void wxDataViewCtrl::AddChildGTK(wxWindowGTK* child) GtkWidget* treeview = GtkGetTreeView(); // Insert widget in GtkTreeView - if (GTK_WIDGET_REALIZED(treeview)) + if (gtk_widget_get_realized(treeview)) gtk_widget_set_parent_window( child->m_widget, gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) ); gtk_widget_set_parent( child->m_widget, treeview ); @@ -4388,6 +4447,22 @@ IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase) wxDataViewCtrl::~wxDataViewCtrl() { + // Stop editing before destroying the control to remove any event handlers + // which are added when editing started: if we didn't do this, the base + // class dtor would assert as it checks for any leftover handlers. + if ( m_treeview ) + { + GtkTreeViewColumn *col; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(m_treeview), NULL, &col); + + wxDataViewColumn * const wxcol = FromGTKColumn(col); + if ( wxcol ) + { + // This won't do anything if we're not editing it + wxcol->GetRenderer()->CancelEditing(); + } + } + m_cols.Clear(); delete m_internal; @@ -4508,6 +4583,8 @@ void wxDataViewCtrl::OnInternalIdle() { wxWindow::OnInternalIdle(); + m_internal->OnInternalIdle(); + unsigned int cols = GetColumnCount(); unsigned int i; for (i = 0; i < cols; i++) @@ -4515,6 +4592,16 @@ void wxDataViewCtrl::OnInternalIdle() wxDataViewColumn *col = GetColumn( i ); col->OnInternalIdle(); } + + if (m_ensureVisibleDefered.IsOk()) + { + ExpandAncestors(m_ensureVisibleDefered); + GtkTreeIter iter; + iter.user_data = (gpointer) m_ensureVisibleDefered.GetID(); + wxGtkTreePath path(m_internal->get_path( &iter )); + gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 ); + m_ensureVisibleDefered = wxDataViewItem(0); + } } bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model ) @@ -4618,10 +4705,9 @@ unsigned int wxDataViewCtrl::GetColumnCount() const return m_cols.GetCount(); } -wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const +wxDataViewColumn* wxDataViewCtrl::FromGTKColumn(GtkTreeViewColumn *gtk_col) const { - GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos ); - if (!gtk_col) + if ( !gtk_col ) return NULL; wxDataViewColumnList::const_iterator iter; @@ -4634,9 +4720,18 @@ wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const } } + wxFAIL_MSG( "No matching column?" ); + return NULL; } +wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const +{ + GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos ); + + return FromGTKColumn(gtk_col); +} + bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column ) { gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview), @@ -4664,7 +4759,7 @@ bool wxDataViewCtrl::ClearColumns() int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const { - GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetConstGtkHandle()); + GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()); GList *list = gtk_tree_view_get_columns( GTK_TREE_VIEW(m_treeview) ); @@ -4741,6 +4836,33 @@ void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem& item) gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, NULL, FALSE); } +void wxDataViewCtrl::StartEditor(const wxDataViewItem& item, unsigned int column) +{ + wxCHECK_RET( m_treeview, + "Current item can't be set before creating the control." ); + + // We need to make sure the model knows about this item or the path would + // be invalid and gtk_tree_view_set_cursor() would silently do nothing. + ExpandAncestors(item); + + wxDataViewColumn *dvcolumn = GetColumn(column); + wxASSERT_MSG(dvcolumn, "Could not retrieve column"); + GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(dvcolumn->GetGtkHandle()); + + // We also need to preserve the existing selection from changing. + // Unfortunately the only way to do it seems to use our own selection + // function and forbid any selection changes during set cursor call. + wxGtkTreeSelectionLock + lock(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_treeview))); + + // Do move the cursor now. + GtkTreeIter iter; + iter.user_data = item.GetID(); + wxGtkTreePath path(m_internal->get_path( &iter )); + + gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, gcolumn, TRUE); +} + wxDataViewItem wxDataViewCtrl::GetSelection() const { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) ); @@ -4915,6 +5037,7 @@ void wxDataViewCtrl::UnselectAll() void wxDataViewCtrl::EnsureVisible(const wxDataViewItem& item, const wxDataViewColumn *WXUNUSED(column)) { + m_ensureVisibleDefered = item; ExpandAncestors(item); GtkTreeIter iter; @@ -4923,12 +5046,54 @@ void wxDataViewCtrl::EnsureVisible(const wxDataViewItem& item, gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 ); } -void wxDataViewCtrl::HitTest(const wxPoint& WXUNUSED(point), +void wxDataViewCtrl::HitTest(const wxPoint& point, wxDataViewItem& item, wxDataViewColumn *& column) const { - item = wxDataViewItem(0); - column = NULL; + // gtk_tree_view_get_dest_row_at_pos() is the right one. But it does not tell the column. + // gtk_tree_view_get_path_at_pos() is the wrong function. It doesn't mind the header but returns column. + // See http://mail.gnome.org/archives/gtkmm-list/2005-January/msg00080.html + // So we have to use both of them. + // Friedrich Haase 2010-9-20 + wxGtkTreePath path, pathScratch; + GtkTreeViewColumn* GtkColumn = NULL; + GtkTreeViewDropPosition pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER; + gint cell_x = 0; + gint cell_y = 0; + + // cannot directly call GtkGetTreeView(), HitTest is const and so is this pointer + wxDataViewCtrl* ctrl = (wxDataViewCtrl*)this; // ugly workaround, ctrl is NOT const + GtkTreeView* treeView = GTK_TREE_VIEW(ctrl->GtkGetTreeView()); + + // is there possibly a better suited function to get the column? + gtk_tree_view_get_path_at_pos( // and this is the wrong call but it delivers the column + treeView, + (int) point.x, (int) point.y, + pathScratch.ByRef(), + &GtkColumn, // here we get the GtkColumn + &cell_x, + &cell_y ); + + if ( GtkColumn != NULL ) + { + // we got GTK column + // the right call now which takes the header into account + gtk_tree_view_get_dest_row_at_pos( treeView, (int) point.x, (int) point.y, path.ByRef(), &pos); + + if (path) + item = wxDataViewItem(GTKPathToItem(path)); + // else we got a GTK column but the position is not over an item, e.g. below last item + for ( unsigned int i=0, cols=GetColumnCount(); iGetGtkHandle()) == GtkColumn ) + { + column = col; // here we get the wx column + break; + } + } + } + // else no column and thus no item, both null } wxRect