wxWidgets/samples/dataview/mymodels.cpp
Vadim Zeitlin 205bdf2069 Implement icon text column using native GTK renderers in wxDVC.
This has a possible advantage of a more native look and feel (although it's
hard to tell the difference between drawing the icon ourselves and how the
default GTK+ renderer does it to be honest) and a very real advantage of
allowing to edit in place cells with icons. It also reduces code duplication
in GTK implementation.

Modify the sample to make the icon-text column in the list model editable to
show that it works. This required storing the values of the second column as
well, so do it in its own array and to avoid calling it "m_array2", rename the
existing m_array to m_textColValues (which accounts for most of the diff in
the sample) and call the new one m_iconColValues.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62423 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2009-10-16 01:29:06 +00:00

517 lines
14 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: mymodels.cpp
// Purpose: wxDataViewCtrl wxWidgets sample
// Author: Robert Roebling
// Modified by: Francesco Montorsi, Bo Yang
// Created: 06/01/06
// RCS-ID: $Id$
// Copyright: (c) Robert Roebling
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/dataview.h"
#include "mymodels.h"
// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------
#include "null.xpm"
#include "wx_small.xpm"
// ----------------------------------------------------------------------------
// MyMusicTreeModel
// ----------------------------------------------------------------------------
MyMusicTreeModel::MyMusicTreeModel()
{
m_root = new MyMusicTreeModelNode( NULL, "My Music" );
// setup pop music
m_pop = new MyMusicTreeModelNode( m_root, "Pop music" );
m_pop->Append(
new MyMusicTreeModelNode( m_pop, "You are not alone", "Michael Jackson", 1995 ) );
m_pop->Append(
new MyMusicTreeModelNode( m_pop, "Take a bow", "Madonna", 1994 ) );
m_root->Append( m_pop );
// setup classical music
m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
m_ninth = new MyMusicTreeModelNode( m_classical, "Ninth symphony",
"Ludwig van Beethoven", 1824 );
m_classical->Append( m_ninth );
m_classical->Append( new MyMusicTreeModelNode( m_classical, "German Requiem",
"Johannes Brahms", 1868 ) );
m_root->Append( m_classical );
m_classicalMusicIsKnownToControl = false;
}
wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const
{
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
if (!node) // happens if item.IsOk()==false
return wxEmptyString;
return node->m_title;
}
wxString MyMusicTreeModel::GetArtist( const wxDataViewItem &item ) const
{
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
if (!node) // happens if item.IsOk()==false
return wxEmptyString;
return node->m_artist;
}
int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const
{
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
if (!node) // happens if item.IsOk()==false
return 2000;
return node->m_year;
}
void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist,
unsigned int year )
{
if (!m_classical)
{
wxASSERT(m_root);
// it was removed: restore it
m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
m_root->Append( m_classical );
// notify control
wxDataViewItem child( (void*) m_classical );
wxDataViewItem parent( (void*) m_root );
ItemAdded( parent, child );
}
// add to the classical music node a new node:
MyMusicTreeModelNode *child_node =
new MyMusicTreeModelNode( m_classical, title, artist, year );
m_classical->Append( child_node );
// FIXME: what's m_classicalMusicIsKnownToControl for?
if (m_classicalMusicIsKnownToControl)
{
// notify control
wxDataViewItem child( (void*) child_node );
wxDataViewItem parent( (void*) m_classical );
ItemAdded( parent, child );
}
}
void MyMusicTreeModel::Delete( const wxDataViewItem &item )
{
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
if (!node) // happens if item.IsOk()==false
return;
wxDataViewItem parent( node->GetParent() );
if (!parent.IsOk())
{
wxASSERT(node == m_root);
// don't make the control completely empty:
wxLogError( "Cannot remove the root item!" );
return;
}
// is the node one of those we keep stored in special pointers?
if (node == m_pop)
m_pop = NULL;
else if (node == m_classical)
m_classical = NULL;
else if (node == m_ninth)
m_ninth = NULL;
// first remove the node from the parent's array of children;
// NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
node->GetParent()->GetChildren().Remove( node );
// free the node
delete node;
// notify control
ItemDeleted( parent, item );
}
int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
unsigned int column, bool ascending ) const
{
wxASSERT(item1.IsOk() && item2.IsOk());
// should never happen
if (IsContainer(item1) && IsContainer(item2))
{
wxVariant value1, value2;
GetValue( value1, item1, 0 );
GetValue( value2, item2, 0 );
wxString str1 = value1.GetString();
wxString str2 = value2.GetString();
int res = str1.Cmp( str2 );
if (res) return res;
// items must be different
wxUIntPtr litem1 = (wxUIntPtr) item1.GetID();
wxUIntPtr litem2 = (wxUIntPtr) item2.GetID();
return litem1-litem2;
}
return wxDataViewModel::Compare( item1, item2, column, ascending );
}
void MyMusicTreeModel::GetValue( wxVariant &variant,
const wxDataViewItem &item, unsigned int col ) const
{
wxASSERT(item.IsOk());
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
switch (col)
{
case 0:
variant = node->m_title;
break;
case 1:
variant = node->m_artist;
break;
case 2:
variant = (long) node->m_year;
break;
case 3:
variant = node->m_quality;
break;
case 4:
// wxMac doesn't conceal the popularity progress renderer, return 0 for containers
if (IsContainer(item))
variant = (long) 0;
else
variant = (long) 80; // all music is very 80% popular
break;
case 5:
// Make size of red square depend on year
if (GetYear(item) < 1900)
variant = (long) 35;
else
variant = (long) 25;
break;
default:
wxLogError( "MyMusicTreeModel::GetValue: wrong column %d", col );
}
}
bool MyMusicTreeModel::SetValue( const wxVariant &variant,
const wxDataViewItem &item, unsigned int col )
{
wxASSERT(item.IsOk());
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
switch (col)
{
case 0:
node->m_title = variant.GetString();
return true;
case 1:
node->m_artist = variant.GetString();
return true;
case 2:
node->m_year = variant.GetLong();
return true;
case 3:
node->m_quality = variant.GetString();
return true;
default:
wxLogError( "MyMusicTreeModel::SetValue: wrong column" );
}
return false;
}
wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const
{
// the invisible root node has no parent
if (!item.IsOk())
return wxDataViewItem(0);
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
// "MyMusic" also has no parent
if (node == m_root)
return wxDataViewItem(0);
return wxDataViewItem( (void*) node->GetParent() );
}
bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const
{
// the invisble root node can have children
// (in our model always "MyMusic")
if (!item.IsOk())
return true;
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
return node->IsContainer();
}
unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent,
wxDataViewItemArray &array ) const
{
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) parent.GetID();
if (!node)
{
array.Add( wxDataViewItem( (void*) m_root ) );
return 1;
}
if (node == m_classical)
{
MyMusicTreeModel *model = (MyMusicTreeModel*)(const MyMusicTreeModel*) this;
model->m_classicalMusicIsKnownToControl = true;
}
if (node->GetChildCount() == 0)
{
return 0;
}
unsigned int count = node->GetChildren().GetCount();
for (unsigned int pos = 0; pos < count; pos++)
{
MyMusicTreeModelNode *child = node->GetChildren().Item( pos );
array.Add( wxDataViewItem( (void*) child ) );
}
return count;
}
// ----------------------------------------------------------------------------
// MyListModel
// ----------------------------------------------------------------------------
static int my_sort_reverse( int *v1, int *v2 )
{
return *v2-*v1;
}
static int my_sort( int *v1, int *v2 )
{
return *v1-*v2;
}
#ifdef __WXMAC__
#define INITIAL_NUMBER_OF_ITEMS 100
#else
#define INITIAL_NUMBER_OF_ITEMS 100000
#endif
MyListModel::MyListModel() :
wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS )
{
m_virtualItems = INITIAL_NUMBER_OF_ITEMS;
// the first 100 items are really stored in this model;
// 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++)
{
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_textColValues.Insert( text, 0 );
RowPrepended();
}
void MyListModel::DeleteItem( const wxDataViewItem &item )
{
unsigned int row = GetRow( item );
if (row >= m_textColValues.GetCount())
return;
m_textColValues.RemoveAt( row );
RowDeleted( row );
}
void MyListModel::DeleteItems( const wxDataViewItemArray &items )
{
unsigned i;
wxArrayInt rows;
for (i = 0; i < items.GetCount(); i++)
{
unsigned int row = GetRow( items[i] );
if (row < m_textColValues.GetCount())
rows.Add( row );
}
if (rows.GetCount() == 0)
{
// 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_textColValues.GetCount() );
return;
}
// Sort in descending order so that the last
// row will be deleted first. Otherwise the
// remaining indeces would all be wrong.
rows.Sort( my_sort_reverse );
for (i = 0; i < rows.GetCount(); i++)
m_textColValues.RemoveAt( rows[i] );
// This is just to test if wxDataViewCtrl can
// cope with removing rows not sorted in
// descending order
rows.Sort( my_sort );
RowsDeleted( rows );
}
void MyListModel::AddMany()
{
m_virtualItems += 1000;
Reset( m_textColValues.GetCount() + m_virtualItems );
}
void MyListModel::GetValueByRow( wxVariant &variant,
unsigned int row, unsigned int col ) const
{
if (col==0)
{
if (row >= m_textColValues.GetCount())
variant = wxString::Format( "virtual row %d", row );
else
variant = m_textColValues[ row ];
}
else if (col==1)
{
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)
{
static const char *labels[5] =
{
"blue", "green", "red", "bold cyan", "default",
};
variant = labels[row % 5];
}
}
bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col,
wxDataViewItemAttr &attr )
{
switch ( col )
{
case 0:
return false;
case 1:
if ( !(row % 2) )
return false;
attr.SetColour(*wxLIGHT_GREY);
break;
case 2:
// do what the labels defined above hint at
switch ( row % 5 )
{
case 0:
attr.SetColour(*wxBLUE);
break;
case 1:
attr.SetColour(*wxGREEN);
break;
case 2:
attr.SetColour(*wxRED);
break;
case 3:
attr.SetColour(*wxCYAN);
attr.SetBold(true);
break;
case 4:
return false;
}
break;
}
return true;
}
bool MyListModel::SetValueByRow( const wxVariant &variant,
unsigned int row, unsigned int col )
{
switch ( col )
{
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;
}
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 true;
}