#endif
#include "wx/stockitem.h"
-#include "wx/calctrl.h"
#include "wx/popupwin.h"
#include "wx/listimpl.cpp"
#include "wx/gtk/dcclient.h"
#include "wx/gtk/private/gdkconv.h"
+#include "wx/gtk/private/list.h"
+#include "wx/gtk/private/event.h"
using namespace wxGTKImpl;
class wxGtkDataViewModelNotifier;
wxDECLARE_NO_COPY_CLASS(wxGtkTreePath);
};
+// ----------------------------------------------------------------------------
+// wxGtkTreePathList: self-destroying list of GtkTreePath objects.
+// ----------------------------------------------------------------------------
+
+class wxGtkTreePathList : public wxGtkList
+{
+public:
+ // Ctor takes ownership of the list.
+ explicit wxGtkTreePathList(GList* list)
+ : wxGtkList(list)
+ {
+ }
+
+ ~wxGtkTreePathList()
+ {
+ // Delete the list contents, wxGtkList will delete the list itself.
+ g_list_foreach(m_list, (GFunc)gtk_tree_path_free, NULL);
+ }
+};
+
// ----------------------------------------------------------------------------
// wxGtkTreeSelectionLock: prevent selection from changing during the
// lifetime of this object
static
int LINKAGEMODE wxGtkTreeModelChildCmp( void** id1, void** id2 )
{
- int ret = gs_internal->GetDataViewModel()->Compare( *id1, *id2,
+ int ret = gs_internal->GetDataViewModel()->Compare( wxDataViewItem(*id1), wxDataViewItem(*id2),
gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
return ret;
}
}
- unsigned int AddNode( wxGtkTreeModelNode* child )
+ void AddNode( wxGtkTreeModelNode* child )
{
m_nodes.Add( child );
{
gs_internal = m_internal;
m_children.Sort( &wxGtkTreeModelChildCmp );
- return m_children.Index( id );
}
+ }
+
+ void InsertNode( wxGtkTreeModelNode* child, unsigned pos )
+ {
+ if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
+ {
+ AddNode(child);
+ return;
+ }
+
+ void *id = child->GetItem().GetID();
+
+ // Insert into m_nodes so that the order of nodes in m_nodes is the
+ // same as the order of their corresponding IDs in m_children:
+ const unsigned int count = m_nodes.GetCount();
+ bool inserted = false;
+ for (unsigned i = 0; i < count; i++)
+ {
+ wxGtkTreeModelNode *node = m_nodes[i];
+ int posInChildren = m_children.Index(node->GetItem().GetID());
+ if ( (unsigned)posInChildren >= pos )
+ {
+ m_nodes.Insert(child, i);
+ inserted = true;
+ break;
+ }
+ }
+ if ( !inserted )
+ m_nodes.Add(child);
- return m_children.GetCount()-1;
+ m_children.Insert( id, pos );
}
- unsigned int AddLeave( void* id )
+ void AddLeaf( void* id )
{
- m_children.Add( id );
+ InsertLeaf(id, m_children.size());
+ }
+
+ void InsertLeaf( void* id, unsigned pos )
+ {
+ m_children.Insert( id, pos );
if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
{
gs_internal = m_internal;
m_children.Sort( &wxGtkTreeModelChildCmp );
- return m_children.Index( id );
}
-
- return m_children.GetCount()-1;
}
void DeleteChild( void* id )
}
}
+ // returns position of child node for given item in children list or wxNOT_FOUND
+ int FindChildByItem(const wxDataViewItem& item) const
+ {
+ const void* itemId = item.GetID();
+ const wxGtkTreeModelChildren& nodes = m_children;
+ const int len = nodes.size();
+ for ( int i = 0; i < len; i++ )
+ {
+ if ( nodes[i] == itemId )
+ return i;
+ }
+ return wxNOT_FOUND;
+ }
+
wxGtkTreeModelNode* GetParent()
{ return m_parent; }
wxGtkTreeModelNodes &GetNodes()
/*< private >*/
wxDataViewCustomRenderer *cell;
- guint32 last_click;
};
struct _GtkWxCellRendererClass
gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
{
cell->cell = NULL;
- cell->last_click = 0;
}
static void
wxSize size = cell->GetSize();
+ wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
+
+ // Uniform row height, if specified, overrides the value returned by the
+ // renderer.
+ if ( !ctrl->HasFlag(wxDV_VARIABLE_LINE_HEIGHT) )
+ {
+ const int uniformHeight = ctrl->GTKGetUniformRowHeight();
+ if ( uniformHeight > 0 )
+ size.y = uniformHeight;
+ }
+
int xpad, ypad;
gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
int calc_width = xpad * 2 + size.x;
unsigned int model_col = cell->GetOwner()->GetModelColumn();
- if (!event)
+ if ( !event )
{
- bool ret = false;
-
// activated by <ENTER>
- if (cell->Activate( renderrect, model, item, model_col ))
- ret = true;
-
- return ret;
+ return cell->ActivateCell(renderrect, model, item, model_col, NULL);
}
- else if (event->type == GDK_BUTTON_PRESS)
+ else if ( event->type == GDK_BUTTON_PRESS )
{
- GdkEventButton *button_event = (GdkEventButton*) event;
- wxPoint pt( ((int) button_event->x) - renderrect.x,
- ((int) button_event->y) - renderrect.y );
-
- bool ret = false;
- if (button_event->button == 1)
+ GdkEventButton *button_event = (GdkEventButton*)event;
+ if ( button_event->button == 1 )
{
- if (cell->LeftClick( pt, renderrect, model, item, model_col ))
- ret = true;
- // TODO: query system double-click time
- if (button_event->time - wxrenderer->last_click < 400)
- if (cell->Activate( renderrect, model, item, model_col ))
- ret = true;
- }
- wxrenderer->last_click = button_event->time;
+ wxMouseEvent mouse_event(wxEVT_LEFT_DOWN);
+ InitMouseEvent(ctrl, mouse_event, button_event);
+
+ mouse_event.m_x -= renderrect.x;
+ mouse_event.m_y -= renderrect.y;
- return ret;
+ return cell->ActivateCell(renderrect, model, item, model_col, &mouse_event);
+ }
}
+ wxLogDebug("unexpected event type in gtk_wx_cell_renderer_activate()");
return false;
}
GTK_TREE_MODEL(wxgtk_model), &iter ));
#else
// so get the path from the parent
- GtkTreeIter iter;
- iter.stamp = wxgtk_model->stamp;
- iter.user_data = (gpointer) parent.GetID();
- wxGtkTreePath path(wxgtk_tree_model_get_path(
- GTK_TREE_MODEL(wxgtk_model), &iter ));
+ GtkTreeIter parentIter;
+ parentIter.stamp = wxgtk_model->stamp;
+ parentIter.user_data = (gpointer) parent.GetID();
+ wxGtkTreePath parentPath(wxgtk_tree_model_get_path(
+ GTK_TREE_MODEL(wxgtk_model), &parentIter ));
+
// and add the final index ourselves
+ wxGtkTreePath path(gtk_tree_path_copy(parentPath));
int index = m_internal->GetIndexOf( parent, item );
gtk_tree_path_append_index( path, index );
#endif
m_internal->ItemDeleted( parent, item );
+ // Did we remove the last child, causing 'parent' to become a leaf?
+ if ( !m_wx_model->IsContainer(parent) )
+ {
+ gtk_tree_model_row_has_child_toggled
+ (
+ GTK_TREE_MODEL(wxgtk_model),
+ parentPath,
+ &parentIter
+ );
+ }
+
return true;
}
GtkTreeView *widget = GTK_TREE_VIEW(ctrl->GtkGetTreeView());
GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
- // Get cell area
- GtkTreeIter iter;
- iter.stamp = wxgtk_model->stamp;
- iter.user_data = (gpointer) item.GetID();
- wxGtkTreePath path(wxgtk_tree_model_get_path(
- GTK_TREE_MODEL(wxgtk_model), &iter ));
- GdkRectangle cell_area;
- gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
-
- GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
- double d = gtk_adjustment_get_value( hadjust );
- int xdiff = (int) d;
-
- int ydiff = gcolumn->button->allocation.height;
- // Redraw
- gtk_widget_queue_draw_area( GTK_WIDGET(widget),
- cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
+ // Don't attempt to refresh not yet realized tree, it is useless
+ // and results in GTK errors.
+ if ( gtk_widget_get_realized(ctrl->GtkGetTreeView()) )
+ {
+ // Get cell area
+ GtkTreeIter iter;
+ iter.stamp = wxgtk_model->stamp;
+ iter.user_data = (gpointer) item.GetID();
+ wxGtkTreePath path(wxgtk_tree_model_get_path(
+ GTK_TREE_MODEL(wxgtk_model), &iter ));
+ GdkRectangle cell_area;
+ gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
+
+ GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
+ double d = gtk_adjustment_get_value( hadjust );
+ int xdiff = (int) d;
+
+ int ydiff = gcolumn->button->allocation.height;
+ // Redraw
+ 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_column );
return ret;
}
-void wxDataViewRenderer::GtkUpdateAlignment()
+void wxDataViewRenderer::GtkApplyAlignment(GtkCellRenderer *renderer)
{
int align = m_alignment;
GValue gvalue = { 0, };
g_value_init( &gvalue, G_TYPE_FLOAT );
g_value_set_float( &gvalue, xalign );
- g_object_set_property( G_OBJECT(m_renderer), "xalign", &gvalue );
+ g_object_set_property( G_OBJECT(renderer), "xalign", &gvalue );
g_value_unset( &gvalue );
// vertical alignment:
GValue gvalue2 = { 0, };
g_value_init( &gvalue2, G_TYPE_FLOAT );
g_value_set_float( &gvalue2, yalign );
- g_object_set_property( G_OBJECT(m_renderer), "yalign", &gvalue2 );
+ g_object_set_property( G_OBJECT(renderer), "yalign", &gvalue2 );
g_value_unset( &gvalue2 );
}
}
void
-wxDataViewRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
+wxDataViewRenderer::GtkOnTextEdited(const char *itempath, const wxString& str)
{
wxVariant value(str);
if (!Validate( value ))
Init(mode, align);
}
+void wxDataViewCustomRenderer::GtkInitTextRenderer()
+{
+ m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
+ g_object_ref_sink(m_text_renderer);
+
+ GtkApplyAlignment(GTK_CELL_RENDERER(m_text_renderer));
+}
+
GtkCellRendererText *wxDataViewCustomRenderer::GtkGetTextRenderer() const
{
if ( !m_text_renderer )
{
// we create it on demand so need to do it even from a const function
- const_cast<wxDataViewCustomRenderer *>(this)->
- m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
- g_object_ref_sink(m_text_renderer);
+ const_cast<wxDataViewCustomRenderer *>(this)->GtkInitTextRenderer();
}
return m_text_renderer;
{
m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
- GValue gvalue = { 0, };
- g_value_init( &gvalue, G_TYPE_STRING );
-
- g_value_set_string( &gvalue, wxGTK_CONV_FONT( m_label, GetOwner()->GetOwner()->GetFont() ) );
- g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
- g_value_unset( &gvalue );
-
SetMode(mode);
SetAlignment(align);
+
+#if !wxUSE_UNICODE
+ // We can't initialize the renderer just yet because we don't have the
+ // pointer to the column that uses this renderer yet and so attempt to
+ // dereference GetOwner() to get the font that is used as a source of
+ // encoding in multibyte-to-Unicode conversion in GTKSetLabel() in
+ // non-Unicode builds would crash. So simply remember to do it later.
+ if ( !m_label.empty() )
+ m_needsToSetLabel = true;
+ else
+#endif // !wxUSE_UNICODE
+ GTKSetLabel();
}
else
#endif
{
}
+void wxDataViewProgressRenderer::GTKSetLabel()
+{
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_STRING );
+
+ // Take care to not use GetOwner() here if the label is empty, we can be
+ // called from ctor when GetOwner() is still NULL in this case.
+ wxScopedCharBuffer buf;
+ if ( m_label.empty() )
+ buf = wxScopedCharBuffer::CreateNonOwned("");
+ else
+ buf = wxGTK_CONV_FONT(m_label, GetOwner()->GetOwner()->GetFont());
+
+ g_value_set_string( &gvalue, buf);
+ g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
+ g_value_unset( &gvalue );
+
+#if !wxUSE_UNICODE
+ m_needsToSetLabel = false;
+#endif // !wxUSE_UNICODE
+}
+
bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
{
#ifdef __WXGTK26__
if (!gtk_check_version(2,6,0))
{
+#if !wxUSE_UNICODE
+ if ( m_needsToSetLabel )
+ GTKSetLabel();
+#endif // !wxUSE_UNICODE
+
gint tmp = (long) value;
GValue gvalue = { 0, };
g_value_init( &gvalue, G_TYPE_INT );
{
}
-void wxDataViewChoiceByIndexRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
+void wxDataViewChoiceByIndexRenderer::GtkOnTextEdited(const char *itempath, const wxString& str)
{
wxVariant value( (long) GetChoices().Index( str ) );
return true;
}
-// ---------------------------------------------------------
-// wxDataViewDateRenderer
-// ---------------------------------------------------------
-
-class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
-{
-public:
- wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
- wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
- wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
- {
- m_model = model;
- m_item = item;
- m_col = col;
- m_cal = new wxCalendarCtrl( this, -1, *value );
- wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
- sizer->Add( m_cal, 1, wxGROW );
- SetSizer( sizer );
- sizer->Fit( this );
- }
-
- virtual void OnDismiss()
- {
- }
-
- void OnCalendar( wxCalendarEvent &event );
-
- wxCalendarCtrl *m_cal;
- wxDataViewModel *m_model;
- wxDataViewItem m_item;
- unsigned int m_col;
-
-private:
- DECLARE_EVENT_TABLE()
-};
-
-BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
- EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
-END_EVENT_TABLE()
-
-void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
-{
- m_model->ChangeValue( event.GetDate(), m_item, m_col );
- DismissAndNotify();
-}
-
-IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
-
-wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
- wxDataViewCellMode mode, int align ) :
- wxDataViewCustomRenderer( varianttype, mode, align )
-{
- SetMode(mode);
- SetAlignment(align);
-}
-
-bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
-{
- m_date = value.GetDateTime();
-
- return true;
-}
-
-bool wxDataViewDateRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
-{
- return false;
-}
-
-bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
-{
- dc->SetFont( GetOwner()->GetOwner()->GetFont() );
- wxString tmp = m_date.FormatDate();
- RenderText( tmp, 0, cell, dc, state );
- return true;
-}
-
-wxSize wxDataViewDateRenderer::GetSize() const
-{
- wxString tmp = m_date.FormatDate();
- wxCoord x,y,d;
- GetView()->GetTextExtent( tmp, &x, &y, &d );
- return wxSize(x,y+d);
-}
-
-bool wxDataViewDateRenderer::Activate( const wxRect& WXUNUSED(cell), wxDataViewModel *model,
- const wxDataViewItem &item, unsigned int col )
-{
- wxVariant variant;
- model->GetValue( variant, item, col );
- wxDateTime value = variant.GetDateTime();
-
- wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
- GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
- wxPoint pos = wxGetMousePosition();
- popup->Move( pos );
- popup->Layout();
- popup->Popup( popup->m_cal );
-
- return true;
-}
-
-
// ---------------------------------------------------------
// wxDataViewIconTextRenderer
// ---------------------------------------------------------
{
wxDataViewColumnBase::SetBitmap( bitmap );
- if (bitmap.Ok())
+ if (bitmap.IsOk())
{
GtkImage *gtk_image = GTK_IMAGE(m_image);
return gtk_tree_view_column_get_clickable( column );
}
-void wxDataViewColumn::SetAsSortKey( bool WXUNUSED(sort) )
-{
- // it might not make sense to have this function in wxHeaderColumn at
- // all in fact, changing of the sort order should only be done using the
- // associated control API
- wxFAIL_MSG( "not implemented" );
-}
-
bool wxDataViewColumn::IsSortKey() const
{
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
static
int LINKAGEMODE wxGtkTreeModelChildPtrCmp( void*** data1, void*** data2 )
{
- return gs_internal->GetDataViewModel()->Compare( **data1, **data2,
+ return gs_internal->GetDataViewModel()->Compare( wxDataViewItem(**data1), wxDataViewItem(**data2),
gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
}
if (m_wx_model->IsContainer( child ))
node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
else
- node->AddLeave( child.GetID() );
+ node->AddLeaf( child.GetID() );
// Don't send any events here
}
GtkTreePath *path )
{
delete m_dragDataObject;
+ m_dragDataObject = NULL;
wxDataViewItem item(GetOwner()->GTKPathToItem(path));
if ( !item )
if (!m_wx_model->IsVirtualListModel())
{
wxGtkTreeModelNode *parent_node = FindNode( parent );
- wxASSERT_MSG(parent_node,
+ wxCHECK_MSG(parent_node, false,
"Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
+ wxDataViewItemArray modelSiblings;
+ m_wx_model->GetChildren(parent, modelSiblings);
+ const int modelSiblingsSize = modelSiblings.size();
+
+ int posInModel = modelSiblings.Index(item, /*fromEnd=*/true);
+ wxCHECK_MSG( posInModel != wxNOT_FOUND, false, "adding non-existent item?" );
+
+ const wxGtkTreeModelChildren& nodeSiblings = parent_node->GetChildren();
+ const int nodeSiblingsSize = nodeSiblings.size();
+
+ int nodePos = 0;
+
+ if ( posInModel == modelSiblingsSize - 1 )
+ {
+ nodePos = nodeSiblingsSize;
+ }
+ else if ( modelSiblingsSize == nodeSiblingsSize + 1 )
+ {
+ // This is the simple case when our node tree already matches the
+ // model and only this one item is missing.
+ nodePos = posInModel;
+ }
+ else
+ {
+ // It's possible that a larger discrepancy between the model and
+ // our realization exists. This can happen e.g. when adding a bunch
+ // of items to the model and then calling ItemsAdded() just once
+ // afterwards. In this case, we must find the right position by
+ // looking at sibling items.
+
+ // append to the end if we won't find a better position:
+ nodePos = nodeSiblingsSize;
+
+ for ( int nextItemPos = posInModel + 1;
+ nextItemPos < modelSiblingsSize;
+ nextItemPos++ )
+ {
+ int nextNodePos = parent_node->FindChildByItem(modelSiblings[nextItemPos]);
+ if ( nextNodePos != wxNOT_FOUND )
+ {
+ nodePos = nextNodePos;
+ break;
+ }
+ }
+ }
+
if (m_wx_model->IsContainer( item ))
- parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
+ parent_node->InsertNode( new wxGtkTreeModelNode( parent_node, item, this ), nodePos );
else
- parent_node->AddLeave( item.GetID() );
+ parent_node->InsertLeaf( item.GetID(), nodePos );
}
ScheduleRefresh();
GtkTreeViewColumn *column = NULL;
gint cell_x = 0;
gint cell_y = 0;
- if (gtk_tree_view_get_path_at_pos(
+ gtk_tree_view_get_path_at_pos
+ (
GTK_TREE_VIEW(dv->GtkGetTreeView()),
(int) gdk_event->x, (int) gdk_event->y,
path.ByRef(),
&column,
&cell_x,
- &cell_y))
- {
- if (path)
- {
- wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, dv->GetId() );
- event.SetItem(dv->GTKPathToItem(path));
- event.SetModel( dv->GetModel() );
- return dv->HandleWindowEvent( event );
- }
- }
+ &cell_y
+ );
+
+ wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, dv->GetId() );
+ if (path)
+ event.SetItem(dv->GTKPathToItem(path));
+ event.SetModel( dv->GetModel() );
+ return dv->HandleWindowEvent( event );
}
return FALSE;
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;
m_internal = NULL;
m_cols.DeleteContents( true );
+
+ m_uniformRowHeight = -1;
}
bool wxDataViewCtrl::Create(wxWindow *parent,
m_treeview = gtk_tree_view_new();
gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
+ m_focusWidget = GTK_WIDGET(m_treeview);
+
g_signal_connect (m_treeview, "size_allocate",
G_CALLBACK (gtk_dataviewctrl_size_callback), this);
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;
}
}
+ 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),
{
GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
- GList *list = gtk_tree_view_get_columns( GTK_TREE_VIEW(m_treeview) );
-
- gint pos = g_list_index( list, (gconstpointer) gtk_column );
+ wxGtkList list(gtk_tree_view_get_columns(GTK_TREE_VIEW(m_treeview)));
- g_list_free( list );
-
- return pos;
+ return g_list_index( list, (gconstpointer) gtk_column );
}
wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, NULL, FALSE);
}
-wxDataViewItem wxDataViewCtrl::GetSelection() const
+void wxDataViewCtrl::StartEditor(const wxDataViewItem& item, unsigned int column)
{
- GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+ wxCHECK_RET( m_treeview,
+ "Current item can't be set before creating the control." );
- if (m_windowStyle & wxDV_MULTIPLE)
- {
- // Report the first one
- GtkTreeModel *model;
- GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
+ // 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());
- if (list)
- {
- GtkTreePath *path = (GtkTreePath*) list->data;
- wxDataViewItem item(GTKPathToItem(path));
+ // 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)));
- // delete list
- g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
- g_list_free( list );
+ // Do move the cursor now.
+ GtkTreeIter iter;
+ iter.user_data = item.GetID();
+ wxGtkTreePath path(m_internal->get_path( &iter ));
- return item;
- }
- }
- else
- {
- GtkTreeIter iter;
- if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
- {
- wxDataViewItem item( iter.user_data );
- return item;
- }
- }
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, gcolumn, TRUE);
+}
- return wxDataViewItem(0);
+int wxDataViewCtrl::GetSelectedItemsCount() const
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+
+ return gtk_tree_selection_count_selected_rows(selection);
}
int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
if (HasFlag(wxDV_MULTIPLE))
{
GtkTreeModel *model;
- GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
+ wxGtkTreePathList list(gtk_tree_selection_get_selected_rows(selection, &model));
- int count = 0;
- while (list)
+ for ( GList* current = list; current; current = g_list_next(current) )
{
- GtkTreePath *path = (GtkTreePath*) list->data;
+ GtkTreePath *path = (GtkTreePath*) current->data;
sel.Add(GTKPathToItem(path));
-
- list = g_list_next( list );
- count++;
}
-
- // delete list
- g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
- g_list_free( list );
-
- return count;
}
else
{
- GtkTreeModel *model;
GtkTreeIter iter;
- gboolean has_selection = gtk_tree_selection_get_selected( selection, &model, &iter );
- if (has_selection)
+ if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
{
- sel.Add( wxDataViewItem( (void*) iter.user_data) );
- return 1;
+ sel.Add( wxDataViewItem(iter.user_data) );
}
}
- return 0;
+ return sel.size();
}
void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
return wxRect();
}
+bool wxDataViewCtrl::SetRowHeight(int rowHeight)
+{
+ m_uniformRowHeight = rowHeight;
+ return true;
+}
+
void wxDataViewCtrl::DoSetExpanderColumn()
{
gtk_tree_view_set_expander_column( GTK_TREE_VIEW(m_treeview),