class WXDLLIMPEXP_FWD_ADV wxDataViewCtrl;
class WXDLLIMPEXP_FWD_ADV wxDataViewCtrlInternal;
+typedef struct _GtkTreeViewColumn GtkTreeViewColumn;
// ---------------------------------------------------------
// wxDataViewRenderer
virtual void SetAlignment( int align );
virtual int GetAlignment() const;
- // implementation
+
+ // GTK-specific implementation
+ // ---------------------------
+
+ // pack the GTK cell renderers used by this renderer to the given column
+ //
+ // by default only a single m_renderer is used but some renderers use more
+ // than one GTK cell renderer
+ virtual void GtkPackIntoColumn(GtkTreeViewColumn *column);
+
+ // called when the cell value was edited by user with the new value
+ //
+ // it validates the new value and notifies the model about the change by
+ // calling GtkOnCellChanged() if it was accepted
+ void GtkOnTextEdited(const gchar *itempath, const wxString& value);
+
GtkCellRenderer* GetGtkHandle() { return m_renderer; }
void GtkInitHandlers();
void GtkUpdateAlignment();
void GtkSetUsingDefaultAttrs(bool def) { m_usingDefaultAttrs = def; }
protected:
+ virtual void GtkOnCellChanged(const wxVariant& value,
+ const wxDataViewItem& item,
+ unsigned col);
+
+
GtkCellRenderer *m_renderer;
int m_alignment;
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int align = wxDVR_DEFAULT_ALIGNMENT );
- bool SetValue( const wxVariant &value );
- bool GetValue( wxVariant &value ) const;
+ virtual bool SetValue( const wxVariant &value )
+ {
+ return SetTextValue(value);
+ }
- void SetAlignment( int align );
+ virtual bool GetValue( wxVariant &value ) const
+ {
+ wxString str;
+ if ( !GetTextValue(str) )
+ return false;
+
+ value = str;
+
+ return true;
+ }
+
+ virtual void SetAlignment( int align );
protected:
+ // implementation of Set/GetValue()
+ bool SetTextValue(const wxString& str);
+ bool GetTextValue(wxString& str) const;
+
+
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer)
};
wxDC *m_dc;
public:
- // Internal, temporay for RenderText.
+ // Internal, temporary for RenderText.
GtkCellRenderer *m_text_renderer;
GdkWindow *window;
GtkWidget *widget;
// wxDataViewIconTextRenderer
// ---------------------------------------------------------
-class WXDLLIMPEXP_ADV wxDataViewIconTextRenderer: public wxDataViewCustomRenderer
+class WXDLLIMPEXP_ADV wxDataViewIconTextRenderer: public wxDataViewTextRenderer
{
public:
wxDataViewIconTextRenderer( const wxString &varianttype = wxT("wxDataViewIconText"),
bool SetValue( const wxVariant &value );
bool GetValue( wxVariant &value ) const;
- virtual bool Render( wxRect cell, wxDC *dc, int state );
- virtual wxSize GetSize() const;
+ virtual void GtkPackIntoColumn(GtkTreeViewColumn *column);
- virtual bool HasEditorCtrl() const { return true; }
- virtual wxControl* CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value );
- virtual bool GetValueFromEditorCtrl( wxControl* editor, wxVariant &value );
+protected:
+ virtual void GtkOnCellChanged(const wxVariant& value,
+ const wxDataViewItem& item,
+ unsigned col);
private:
wxDataViewIconText m_value;
-protected:
+ // we use the base class m_renderer for the text and this one for the icon
+ GtkCellRenderer *m_rendererIcon;
+
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewIconTextRenderer)
};
m_virtualItems = INITIAL_NUMBER_OF_ITEMS;
// the first 100 items are really stored in this model;
- // all the others are synthetized on request
- for (unsigned int i = 0; i < 100; i++)
+ // all the others are synthesized on request
+ static const unsigned NUMBER_REAL_ITEMS = 100;
+
+ m_textColValues.reserve(NUMBER_REAL_ITEMS);
+ for (unsigned int i = 0; i < NUMBER_REAL_ITEMS; i++)
{
- wxString str;
- str.Printf( "real row %d", i );
- m_array.Add( str );
+ m_textColValues.push_back(wxString::Format("real row %d", i));
}
+ m_iconColValues.assign(NUMBER_REAL_ITEMS, "test");
+
m_icon[0] = wxIcon( null_xpm );
m_icon[1] = wxIcon( wx_small_xpm );
}
void MyListModel::Prepend( const wxString &text )
{
- m_array.Insert( text, 0 );
+ m_textColValues.Insert( text, 0 );
RowPrepended();
}
void MyListModel::DeleteItem( const wxDataViewItem &item )
{
unsigned int row = GetRow( item );
- if (row >= m_array.GetCount())
+ if (row >= m_textColValues.GetCount())
return;
- m_array.RemoveAt( row );
+ m_textColValues.RemoveAt( row );
RowDeleted( row );
}
for (i = 0; i < items.GetCount(); i++)
{
unsigned int row = GetRow( items[i] );
- if (row < m_array.GetCount())
+ if (row < m_textColValues.GetCount())
rows.Add( row );
}
{
// none of the selected items were in the range of the items
// which we store... for simplicity, don't allow removing them
- wxLogError( "Cannot remove rows with an index greater than %d", m_array.GetCount() );
+ wxLogError( "Cannot remove rows with an index greater than %d", m_textColValues.GetCount() );
return;
}
// remaining indeces would all be wrong.
rows.Sort( my_sort_reverse );
for (i = 0; i < rows.GetCount(); i++)
- m_array.RemoveAt( rows[i] );
+ m_textColValues.RemoveAt( rows[i] );
// This is just to test if wxDataViewCtrl can
// cope with removing rows not sorted in
void MyListModel::AddMany()
{
m_virtualItems += 1000;
- Reset( m_array.GetCount() + m_virtualItems );
+ Reset( m_textColValues.GetCount() + m_virtualItems );
}
void MyListModel::GetValueByRow( wxVariant &variant,
{
if (col==0)
{
- if (row >= m_array.GetCount())
+ if (row >= m_textColValues.GetCount())
variant = wxString::Format( "virtual row %d", row );
else
- variant = m_array[ row ];
+ variant = m_textColValues[ row ];
}
else if (col==1)
{
- wxDataViewIconText data( "test", m_icon[ row%2 ] );
- variant << data;
+ wxString text;
+ if ( row >= m_iconColValues.GetCount() )
+ text = "virtual icon";
+ else
+ text = m_iconColValues[row];
+
+ variant << wxDataViewIconText(text, m_icon[row % 2]);
}
else if (col==2)
{
bool MyListModel::SetValueByRow( const wxVariant &variant,
unsigned int row, unsigned int col )
{
- if (col == 0)
+ switch ( col )
{
- if (row >= m_array.GetCount())
- {
- // the item is not in the range of the items
- // which we store... for simplicity, don't allow editing it
- wxLogError( "Cannot edit rows with an index greater than %d", m_array.GetCount() );
- return false;
- }
+ case 0:
+ case 1:
+ if (row >= m_textColValues.GetCount())
+ {
+ // the item is not in the range of the items
+ // which we store... for simplicity, don't allow editing it
+ wxLogError( "Cannot edit rows with an index greater than %d",
+ m_textColValues.GetCount() );
+ return false;
+ }
- m_array[row] = variant.GetString();
- return true;
+ if ( col == 0 )
+ {
+ m_textColValues[row] = variant.GetString();
+ }
+ else // col == 1
+ {
+ wxDataViewIconText iconText;
+ iconText << variant;
+ m_iconColValues[row] = iconText.GetText();
+ }
+ break;
+
+ default:
+ wxLogError("Cannot edit the column %d", col);
+ return false;
}
- return false;
+ return true;
}
// 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))
return m_alignment;
}
+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->SetValue( value, item, col );
+ model->ValueChanged( 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;
-
- 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 );
-
- unsigned int model_col = cell->GetOwner()->GetModelColumn();
+ cell->GtkOnTextEdited(arg1, wxGTK_CONV_BACK_FONT(
+ arg2, cell->GetOwner()->GetOwner()->GetFont()));
+}
- model->SetValue( value, item, model_col );
- model->ValueChanged( item, model_col );
}
IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
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<wxDataViewTextRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
+ str = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast<wxDataViewTextRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
g_value_unset( &gvalue );
- value = tmp;
-
return true;
}
// 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);
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
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);
}
// ---------------------------------------------------------
{
m_isConnected = false;
- GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle();
GtkTreeViewColumn *column = gtk_tree_view_column_new();
m_column = (GtkWidget*) column;
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()