Files
wxWidgets/src/common/datavcmn.cpp
Vadim Zeitlin e417913f46 Reset the wxDataViewItem being edited once it's not edited any more
No real changes, just some cleanup to ensure that the item being edited stored
in wxDataViewRendererBase never refers to an item which is not, actually,
being edited any longer.
2016-02-20 17:07:04 +01:00

2698 lines
77 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/datavcmn.cpp
// Purpose: wxDataViewCtrl base classes and common parts
// Author: Robert Roebling
// Created: 2006/02/20
// Copyright: (c) 2006, Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_DATAVIEWCTRL
#include "wx/dataview.h"
#ifndef WX_PRECOMP
#include "wx/dc.h"
#include "wx/settings.h"
#include "wx/log.h"
#include "wx/crt.h"
#endif
#include "wx/datectrl.h"
#include "wx/spinctrl.h"
#include "wx/choice.h"
#include "wx/imaglist.h"
#include "wx/renderer.h"
const char wxDataViewCtrlNameStr[] = "dataviewCtrl";
namespace
{
// Custom handler pushed on top of the edit control used by wxDataViewCtrl to
// forward some events to the main control itself.
class wxDataViewEditorCtrlEvtHandler: public wxEvtHandler
{
public:
wxDataViewEditorCtrlEvtHandler(wxWindow *editor, wxDataViewRenderer *owner)
{
m_editorCtrl = editor;
m_owner = owner;
m_finished = false;
}
void SetFocusOnIdle( bool focus = true ) { m_focusOnIdle = focus; }
protected:
void OnChar( wxKeyEvent &event );
void OnTextEnter( wxCommandEvent &event );
void OnKillFocus( wxFocusEvent &event );
void OnIdle( wxIdleEvent &event );
private:
wxDataViewRenderer *m_owner;
wxWindow *m_editorCtrl;
bool m_finished;
bool m_focusOnIdle;
private:
wxDECLARE_EVENT_TABLE();
};
} // anonymous namespace
// ---------------------------------------------------------
// wxDataViewItemAttr
// ---------------------------------------------------------
wxFont wxDataViewItemAttr::GetEffectiveFont(const wxFont& font) const
{
if ( !HasFont() )
return font;
wxFont f(font);
if ( GetBold() )
f.MakeBold();
if ( GetItalic() )
f.MakeItalic();
return f;
}
// ---------------------------------------------------------
// wxDataViewModelNotifier
// ---------------------------------------------------------
#include "wx/listimpl.cpp"
WX_DEFINE_LIST(wxDataViewModelNotifiers)
bool wxDataViewModelNotifier::ItemsAdded( const wxDataViewItem &parent, const wxDataViewItemArray &items )
{
size_t count = items.GetCount();
size_t i;
for (i = 0; i < count; i++)
if (!ItemAdded( parent, items[i] )) return false;
return true;
}
bool wxDataViewModelNotifier::ItemsDeleted( const wxDataViewItem &parent, const wxDataViewItemArray &items )
{
size_t count = items.GetCount();
size_t i;
for (i = 0; i < count; i++)
if (!ItemDeleted( parent, items[i] )) return false;
return true;
}
bool wxDataViewModelNotifier::ItemsChanged( const wxDataViewItemArray &items )
{
size_t count = items.GetCount();
size_t i;
for (i = 0; i < count; i++)
if (!ItemChanged( items[i] )) return false;
return true;
}
// ---------------------------------------------------------
// wxDataViewModel
// ---------------------------------------------------------
wxDataViewModel::wxDataViewModel()
{
m_notifiers.DeleteContents( true );
}
bool wxDataViewModel::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ItemAdded( parent, item ))
ret = false;
}
return ret;
}
bool wxDataViewModel::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ItemDeleted( parent, item ))
ret = false;
}
return ret;
}
bool wxDataViewModel::ItemChanged( const wxDataViewItem &item )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ItemChanged( item ))
ret = false;
}
return ret;
}
bool wxDataViewModel::ItemsAdded( const wxDataViewItem &parent, const wxDataViewItemArray &items )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ItemsAdded( parent, items ))
ret = false;
}
return ret;
}
bool wxDataViewModel::ItemsDeleted( const wxDataViewItem &parent, const wxDataViewItemArray &items )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ItemsDeleted( parent, items ))
ret = false;
}
return ret;
}
bool wxDataViewModel::ItemsChanged( const wxDataViewItemArray &items )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ItemsChanged( items ))
ret = false;
}
return ret;
}
bool wxDataViewModel::ValueChanged( const wxDataViewItem &item, unsigned int col )
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->ValueChanged( item, col ))
ret = false;
}
return ret;
}
bool wxDataViewModel::Cleared()
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->Cleared())
ret = false;
}
return ret;
}
bool wxDataViewModel::BeforeReset()
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->BeforeReset())
ret = false;
}
return ret;
}
bool wxDataViewModel::AfterReset()
{
bool ret = true;
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
if (!notifier->AfterReset())
ret = false;
}
return ret;
}
void wxDataViewModel::Resort()
{
wxDataViewModelNotifiers::iterator iter;
for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
{
wxDataViewModelNotifier* notifier = *iter;
notifier->Resort();
}
}
void wxDataViewModel::AddNotifier( wxDataViewModelNotifier *notifier )
{
m_notifiers.push_back( notifier );
notifier->SetOwner( this );
}
void wxDataViewModel::RemoveNotifier( wxDataViewModelNotifier *notifier )
{
m_notifiers.DeleteObject( notifier );
}
int wxDataViewModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
unsigned int column, bool ascending ) const
{
wxVariant value1,value2;
GetValue( value1, item1, column );
GetValue( value2, item2, column );
if (!ascending)
{
wxVariant temp = value1;
value1 = value2;
value2 = temp;
}
if (value1.GetType() == wxT("string"))
{
wxString str1 = value1.GetString();
wxString str2 = value2.GetString();
int res = str1.Cmp( str2 );
if (res)
return res;
}
else if (value1.GetType() == wxT("long"))
{
long l1 = value1.GetLong();
long l2 = value2.GetLong();
if (l1 < l2)
return -1;
else if (l1 > l2)
return 1;
}
else if (value1.GetType() == wxT("double"))
{
double d1 = value1.GetDouble();
double d2 = value2.GetDouble();
if (d1 < d2)
return -1;
else if (d1 > d2)
return 1;
}
#if wxUSE_DATETIME
else if (value1.GetType() == wxT("datetime"))
{
wxDateTime dt1 = value1.GetDateTime();
wxDateTime dt2 = value2.GetDateTime();
if (dt1.IsEarlierThan(dt2))
return -1;
if (dt2.IsEarlierThan(dt1))
return 1;
}
#endif // wxUSE_DATETIME
else if (value1.GetType() == wxT("bool"))
{
bool b1 = value1.GetBool();
bool b2 = value2.GetBool();
if (b1 != b2)
return b1 ? 1 : -1;
}
else if (value1.GetType() == wxT("wxDataViewIconText"))
{
wxDataViewIconText iconText1, iconText2;
iconText1 << value1;
iconText2 << value2;
int res = iconText1.GetText().Cmp(iconText2.GetText());
if (res != 0)
return res;
}
// items must be different
wxUIntPtr id1 = wxPtrToUInt(item1.GetID()),
id2 = wxPtrToUInt(item2.GetID());
return ascending ? id1 - id2 : id2 - id1;
}
// ---------------------------------------------------------
// wxDataViewIndexListModel
// ---------------------------------------------------------
static int my_sort( int *v1, int *v2 )
{
return *v2-*v1;
}
wxDataViewIndexListModel::wxDataViewIndexListModel( unsigned int initial_size )
{
// IDs are ordered until an item gets deleted or inserted
m_ordered = true;
// build initial index
unsigned int i;
for (i = 1; i < initial_size+1; i++)
m_hash.Add( wxDataViewItem(wxUIntToPtr(i)) );
m_nextFreeID = initial_size + 1;
}
void wxDataViewIndexListModel::Reset( unsigned int new_size )
{
/* wxDataViewModel:: */ BeforeReset();
m_hash.Clear();
// IDs are ordered until an item gets deleted or inserted
m_ordered = true;
// build initial index
unsigned int i;
for (i = 1; i < new_size+1; i++)
m_hash.Add( wxDataViewItem(wxUIntToPtr(i)) );
m_nextFreeID = new_size + 1;
/* wxDataViewModel:: */ AfterReset();
}
void wxDataViewIndexListModel::RowPrepended()
{
m_ordered = false;
unsigned int id = m_nextFreeID;
m_nextFreeID++;
wxDataViewItem item( wxUIntToPtr(id) );
m_hash.Insert( item, 0 );
ItemAdded( wxDataViewItem(0), item );
}
void wxDataViewIndexListModel::RowInserted( unsigned int before )
{
m_ordered = false;
unsigned int id = m_nextFreeID;
m_nextFreeID++;
wxDataViewItem item( wxUIntToPtr(id) );
m_hash.Insert( item, before );
ItemAdded( wxDataViewItem(0), item );
}
void wxDataViewIndexListModel::RowAppended()
{
unsigned int id = m_nextFreeID;
m_nextFreeID++;
wxDataViewItem item( wxUIntToPtr(id) );
m_hash.Add( item );
ItemAdded( wxDataViewItem(0), item );
}
void wxDataViewIndexListModel::RowDeleted( unsigned int row )
{
m_ordered = false;
wxDataViewItem item( m_hash[row] );
m_hash.RemoveAt( row );
/* wxDataViewModel:: */ ItemDeleted( wxDataViewItem(0), item );
}
void wxDataViewIndexListModel::RowsDeleted( const wxArrayInt &rows )
{
m_ordered = false;
wxDataViewItemArray array;
unsigned int i;
for (i = 0; i < rows.GetCount(); i++)
{
wxDataViewItem item( m_hash[rows[i]] );
array.Add( item );
}
wxArrayInt sorted = rows;
sorted.Sort( my_sort );
for (i = 0; i < sorted.GetCount(); i++)
m_hash.RemoveAt( sorted[i] );
/* wxDataViewModel:: */ ItemsDeleted( wxDataViewItem(0), array );
}
void wxDataViewIndexListModel::RowChanged( unsigned int row )
{
/* wxDataViewModel:: */ ItemChanged( GetItem(row) );
}
void wxDataViewIndexListModel::RowValueChanged( unsigned int row, unsigned int col )
{
/* wxDataViewModel:: */ ValueChanged( GetItem(row), col );
}
unsigned int wxDataViewIndexListModel::GetRow( const wxDataViewItem &item ) const
{
if (m_ordered)
return wxPtrToUInt(item.GetID())-1;
// assert for not found
return (unsigned int) m_hash.Index( item );
}
wxDataViewItem wxDataViewIndexListModel::GetItem( unsigned int row ) const
{
wxASSERT( row < m_hash.GetCount() );
return wxDataViewItem( m_hash[row] );
}
unsigned int wxDataViewIndexListModel::GetChildren( const wxDataViewItem &item, wxDataViewItemArray &children ) const
{
if (item.IsOk())
return 0;
children = m_hash;
return m_hash.GetCount();
}
// ---------------------------------------------------------
// wxDataViewVirtualListModel
// ---------------------------------------------------------
#ifndef __WXMAC__
wxDataViewVirtualListModel::wxDataViewVirtualListModel( unsigned int initial_size )
{
m_size = initial_size;
}
void wxDataViewVirtualListModel::Reset( unsigned int new_size )
{
/* wxDataViewModel:: */ BeforeReset();
m_size = new_size;
/* wxDataViewModel:: */ AfterReset();
}
void wxDataViewVirtualListModel::RowPrepended()
{
m_size++;
wxDataViewItem item( wxUIntToPtr(1) );
ItemAdded( wxDataViewItem(0), item );
}
void wxDataViewVirtualListModel::RowInserted( unsigned int before )
{
m_size++;
wxDataViewItem item( wxUIntToPtr(before+1) );
ItemAdded( wxDataViewItem(0), item );
}
void wxDataViewVirtualListModel::RowAppended()
{
m_size++;
wxDataViewItem item( wxUIntToPtr(m_size) );
ItemAdded( wxDataViewItem(0), item );
}
void wxDataViewVirtualListModel::RowDeleted( unsigned int row )
{
m_size--;
wxDataViewItem item( wxUIntToPtr(row+1) );
/* wxDataViewModel:: */ ItemDeleted( wxDataViewItem(0), item );
}
void wxDataViewVirtualListModel::RowsDeleted( const wxArrayInt &rows )
{
m_size -= rows.GetCount();
wxArrayInt sorted = rows;
sorted.Sort( my_sort );
wxDataViewItemArray array;
unsigned int i;
for (i = 0; i < sorted.GetCount(); i++)
{
wxDataViewItem item( wxUIntToPtr(sorted[i]+1) );
array.Add( item );
}
/* wxDataViewModel:: */ ItemsDeleted( wxDataViewItem(0), array );
}
void wxDataViewVirtualListModel::RowChanged( unsigned int row )
{
/* wxDataViewModel:: */ ItemChanged( GetItem(row) );
}
void wxDataViewVirtualListModel::RowValueChanged( unsigned int row, unsigned int col )
{
/* wxDataViewModel:: */ ValueChanged( GetItem(row), col );
}
unsigned int wxDataViewVirtualListModel::GetRow( const wxDataViewItem &item ) const
{
return wxPtrToUInt( item.GetID() ) -1;
}
wxDataViewItem wxDataViewVirtualListModel::GetItem( unsigned int row ) const
{
return wxDataViewItem( wxUIntToPtr(row+1) );
}
bool wxDataViewVirtualListModel::HasDefaultCompare() const
{
return true;
}
int wxDataViewVirtualListModel::Compare(const wxDataViewItem& item1,
const wxDataViewItem& item2,
unsigned int WXUNUSED(column),
bool ascending) const
{
unsigned int pos1 = wxPtrToUInt(item1.GetID()); // -1 not needed here
unsigned int pos2 = wxPtrToUInt(item2.GetID()); // -1 not needed here
if (ascending)
return pos1 - pos2;
else
return pos2 - pos1;
}
unsigned int wxDataViewVirtualListModel::GetChildren( const wxDataViewItem &WXUNUSED(item), wxDataViewItemArray &WXUNUSED(children) ) const
{
return 0; // should we report an error ?
}
#endif // __WXMAC__
//-----------------------------------------------------------------------------
// wxDataViewIconText
//-----------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxDataViewIconText,wxObject);
IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxDataViewIconText, WXDLLIMPEXP_ADV)
// ---------------------------------------------------------
// wxDataViewRendererBase
// ---------------------------------------------------------
wxIMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase, wxObject);
wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype,
wxDataViewCellMode WXUNUSED(mode),
int WXUNUSED(align) )
{
m_variantType = varianttype;
m_owner = NULL;
}
wxDataViewRendererBase::~wxDataViewRendererBase()
{
if ( m_editorCtrl )
DestroyEditControl();
}
wxDataViewCtrl* wxDataViewRendererBase::GetView() const
{
return const_cast<wxDataViewRendererBase*>(this)->GetOwner()->GetOwner();
}
bool wxDataViewRendererBase::StartEditing( const wxDataViewItem &item, wxRect labelRect )
{
wxDataViewCtrl* dv_ctrl = GetOwner()->GetOwner();
// Before doing anything we send an event asking if editing of this item is really wanted.
wxDataViewEvent start_event( wxEVT_DATAVIEW_ITEM_START_EDITING, dv_ctrl->GetId() );
start_event.SetDataViewColumn( GetOwner() );
start_event.SetModel( dv_ctrl->GetModel() );
start_event.SetItem( item );
start_event.SetEventObject( dv_ctrl );
dv_ctrl->GetEventHandler()->ProcessEvent( start_event );
if( !start_event.IsAllowed() )
return false;
unsigned int col = GetOwner()->GetModelColumn();
const wxVariant& value = CheckedGetValue(dv_ctrl->GetModel(), item, col);
m_editorCtrl = CreateEditorCtrl( dv_ctrl->GetMainWindow(), labelRect, value );
// there might be no editor control for the given item
if(!m_editorCtrl)
return false;
wxDataViewEditorCtrlEvtHandler *handler =
new wxDataViewEditorCtrlEvtHandler( m_editorCtrl, (wxDataViewRenderer*) this );
m_editorCtrl->PushEventHandler( handler );
#if defined(__WXGTK20__) && !defined(wxUSE_GENERICDATAVIEWCTRL)
handler->SetFocusOnIdle();
#else
m_editorCtrl->SetFocus();
#endif
return true;
}
void wxDataViewRendererBase::NotifyEditingStarted(const wxDataViewItem& item)
{
// Remember the item being edited for use in FinishEditing() later.
m_item = item;
wxDataViewColumn* const column = GetOwner();
wxDataViewCtrl* const dv_ctrl = column->GetOwner();
wxDataViewEvent event( wxEVT_DATAVIEW_ITEM_EDITING_STARTED, dv_ctrl->GetId() );
event.SetDataViewColumn( column );
event.SetModel( dv_ctrl->GetModel() );
event.SetItem( item );
event.SetEventObject( dv_ctrl );
dv_ctrl->GetEventHandler()->ProcessEvent( event );
}
void wxDataViewRendererBase::DestroyEditControl()
{
// Remove our event handler first to prevent it from (recursively) calling
// us again as it would do via a call to FinishEditing() when the editor
// loses focus when we hide it below.
wxEvtHandler * const handler = m_editorCtrl->PopEventHandler();
// Hide the control immediately but don't delete it yet as there could be
// some pending messages for it.
m_editorCtrl->Hide();
wxPendingDelete.Append(handler);
wxPendingDelete.Append(m_editorCtrl);
// Ensure that DestroyEditControl() is not called again for this control.
m_editorCtrl.Release();
}
void wxDataViewRendererBase::CancelEditing()
{
if (!m_editorCtrl)
return;
DestroyEditControl();
}
bool wxDataViewRendererBase::FinishEditing()
{
if (!m_editorCtrl)
return true;
// Try to get the value, normally we should succeed but if we fail, don't
// return immediately, we still need to destroy the edit control.
wxVariant value;
const bool gotValue = GetValueFromEditorCtrl(m_editorCtrl, value);
wxDataViewCtrl* dv_ctrl = GetOwner()->GetOwner();
DestroyEditControl();
dv_ctrl->GetMainWindow()->SetFocus();
if ( !gotValue )
return false;
bool isValid = Validate(value);
unsigned int col = GetOwner()->GetModelColumn();
// Now we should send Editing Done event
wxDataViewEvent event( wxEVT_DATAVIEW_ITEM_EDITING_DONE, dv_ctrl->GetId() );
event.SetDataViewColumn( GetOwner() );
event.SetModel( dv_ctrl->GetModel() );
event.SetItem( m_item );
event.SetValue( value );
event.SetColumn( col );
event.SetEditCanceled( !isValid );
event.SetEventObject( dv_ctrl );
dv_ctrl->GetEventHandler()->ProcessEvent( event );
bool accepted = false;
if ( isValid && event.IsAllowed() )
{
dv_ctrl->GetModel()->ChangeValue(value, m_item, col);
accepted = true;
}
m_item = wxDataViewItem();
return accepted;
}
wxVariant
wxDataViewRendererBase::CheckedGetValue(const wxDataViewModel* model,
const wxDataViewItem& item,
unsigned column) const
{
wxVariant value;
model->GetValue(value, item, column);
// We always allow the cell to be null, regardless of the renderer type.
if ( !value.IsNull() )
{
if ( value.GetType() != GetVariantType() )
{
// If you're seeing this message, this indicates that either your
// renderer is using the wrong type, or your model returns values
// of the wrong type.
wxLogDebug("Wrong type returned from the model for column %u: "
"%s required but actual type is %s",
column,
GetVariantType(),
value.GetType());
// Don't return data of mismatching type, this could be unexpected.
value.MakeNull();
}
}
return value;
}
bool
wxDataViewRendererBase::PrepareForItem(const wxDataViewModel *model,
const wxDataViewItem& item,
unsigned column)
{
// Now check if we have a value and remember it for rendering it later.
// Notice that we do it even if it's null, as the cell should be empty then
// and not show the last used value.
const wxVariant& value = CheckedGetValue(model, item, column);
SetValue(value);
if ( !value.IsNull() )
{
// Also set up the attributes for this item if it's not empty.
wxDataViewItemAttr attr;
model->GetAttr(item, column, attr);
SetAttr(attr);
}
// Finally determine the enabled/disabled state and apply it, even to the
// empty cells.
bool enabled = true;
switch ( GetMode() )
{
case wxDATAVIEW_CELL_INERT:
enabled = false;
break;
case wxDATAVIEW_CELL_ACTIVATABLE:
case wxDATAVIEW_CELL_EDITABLE:
enabled = model->IsEnabled(item, column);
break;
}
SetEnabled(enabled);
return true;
}
int wxDataViewRendererBase::GetEffectiveAlignment() const
{
int alignment = GetAlignment();
if ( alignment == wxDVR_DEFAULT_ALIGNMENT )
{
// if we don't have an explicit alignment ourselves, use that of the
// column in horizontal direction and default vertical alignment
alignment = GetOwner()->GetAlignment() | wxALIGN_CENTRE_VERTICAL;
}
return alignment;
}
// ----------------------------------------------------------------------------
// wxDataViewCustomRendererBase
// ----------------------------------------------------------------------------
bool wxDataViewCustomRendererBase::ActivateCell(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem & item,
unsigned int col,
const wxMouseEvent* mouseEvent)
{
// Compatibility code
if ( mouseEvent )
return LeftClick(mouseEvent->GetPosition(), cell, model, item, col);
else
return Activate(cell, model, item, col);
}
void wxDataViewCustomRendererBase::RenderBackground(wxDC* dc, const wxRect& rect)
{
if ( !m_attr.HasBackgroundColour() )
return;
const wxColour& colour = m_attr.GetBackgroundColour();
wxDCPenChanger changePen(*dc, colour);
wxDCBrushChanger changeBrush(*dc, colour);
dc->DrawRectangle(rect);
}
void
wxDataViewCustomRendererBase::WXCallRender(wxRect rectCell, wxDC *dc, int state)
{
wxCHECK_RET( dc, "no DC to draw on in custom renderer?" );
// adjust the rectangle ourselves to account for the alignment
wxRect rectItem = rectCell;
const int align = GetEffectiveAlignment();
const wxSize size = GetSize();
// take alignment into account only if there is enough space, otherwise
// show as much contents as possible
//
// notice that many existing renderers (e.g. wxDataViewSpinRenderer)
// return hard-coded size which can be more than they need and if we
// trusted their GetSize() we'd draw the text out of cell bounds
// entirely
if ( size.x >= 0 && size.x < rectCell.width )
{
if ( align & wxALIGN_CENTER_HORIZONTAL )
rectItem.x += (rectCell.width - size.x)/2;
else if ( align & wxALIGN_RIGHT )
rectItem.x += rectCell.width - size.x;
// else: wxALIGN_LEFT is the default
rectItem.width = size.x;
}
if ( size.y >= 0 && size.y < rectCell.height )
{
if ( align & wxALIGN_CENTER_VERTICAL )
rectItem.y += (rectCell.height - size.y)/2;
else if ( align & wxALIGN_BOTTOM )
rectItem.y += rectCell.height - size.y;
// else: wxALIGN_TOP is the default
rectItem.height = size.y;
}
// set up the DC attributes
// override custom foreground with the standard one for the selected items
// because we currently don't allow changing the selection background and
// custom colours may be unreadable on it
wxColour col;
if ( state & wxDATAVIEW_CELL_SELECTED )
col = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
else if ( m_attr.HasColour() )
col = m_attr.GetColour();
else // use default foreground
col = GetOwner()->GetOwner()->GetForegroundColour();
wxDCTextColourChanger changeFg(*dc, col);
wxDCFontChanger changeFont(*dc);
if ( m_attr.HasFont() )
changeFont.Set(m_attr.GetEffectiveFont(dc->GetFont()));
Render(rectItem, dc, state);
}
wxSize wxDataViewCustomRendererBase::GetTextExtent(const wxString& str) const
{
const wxDataViewCtrl *view = GetView();
if ( m_attr.HasFont() )
{
wxFont font(m_attr.GetEffectiveFont(view->GetFont()));
wxSize size;
view->GetTextExtent(str, &size.x, &size.y, NULL, NULL, &font);
return size;
}
else
{
return view->GetTextExtent(str);
}
}
void
wxDataViewCustomRendererBase::RenderText(const wxString& text,
int xoffset,
wxRect rect,
wxDC *dc,
int state)
{
wxRect rectText = rect;
rectText.x += xoffset;
rectText.width -= xoffset;
int flags = 0;
if ( state & wxDATAVIEW_CELL_SELECTED )
flags |= wxCONTROL_SELECTED | wxCONTROL_FOCUSED;
if ( !GetOwner()->GetOwner()->IsEnabled() )
flags |= wxCONTROL_DISABLED;
wxRendererNative::Get().DrawItemText(
GetOwner()->GetOwner(),
*dc,
text,
rectText,
GetEffectiveAlignment(),
flags,
GetEllipsizeMode());
}
void wxDataViewCustomRendererBase::SetEnabled(bool enabled)
{
// The native base renderer needs to know about the enabled state as well
// but in the generic case the base class method is pure, so we can't just
// call it unconditionally.
#ifndef wxHAS_GENERIC_DATAVIEWCTRL
wxDataViewRenderer::SetEnabled(enabled);
#endif // !wxHAS_GENERIC_DATAVIEWCTRL
m_enabled = enabled;
}
//-----------------------------------------------------------------------------
// wxDataViewEditorCtrlEvtHandler
//-----------------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler, wxEvtHandler)
EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar)
EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus)
EVT_IDLE (wxDataViewEditorCtrlEvtHandler::OnIdle)
EVT_TEXT_ENTER (-1, wxDataViewEditorCtrlEvtHandler::OnTextEnter)
wxEND_EVENT_TABLE()
void wxDataViewEditorCtrlEvtHandler::OnIdle( wxIdleEvent &event )
{
if (m_focusOnIdle)
{
m_focusOnIdle = false;
if (wxWindow::FindFocus() != m_editorCtrl)
m_editorCtrl->SetFocus();
}
event.Skip();
}
void wxDataViewEditorCtrlEvtHandler::OnTextEnter( wxCommandEvent &WXUNUSED(event) )
{
m_finished = true;
m_owner->FinishEditing();
}
void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent &event )
{
switch ( event.m_keyCode )
{
case WXK_ESCAPE:
m_finished = true;
m_owner->CancelEditing();
break;
case WXK_RETURN:
if ( !event.HasAnyModifiers() )
{
m_finished = true;
m_owner->FinishEditing();
break;
}
wxFALLTHROUGH; // Ctrl/Alt/Shift-Enter is not handled specially
default:
event.Skip();
}
}
void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent &event )
{
if (!m_finished)
{
m_finished = true;
m_owner->FinishEditing();
}
event.Skip();
}
// ---------------------------------------------------------
// wxDataViewColumnBase
// ---------------------------------------------------------
void wxDataViewColumnBase::Init(wxDataViewRenderer *renderer,
unsigned int model_column)
{
m_renderer = renderer;
m_model_column = model_column;
m_owner = NULL;
m_renderer->SetOwner( (wxDataViewColumn*) this );
}
wxDataViewColumnBase::~wxDataViewColumnBase()
{
delete m_renderer;
}
// ---------------------------------------------------------
// wxDataViewCtrlBase
// ---------------------------------------------------------
wxIMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl);
wxDataViewCtrlBase::wxDataViewCtrlBase()
{
m_model = NULL;
m_expander_column = 0;
m_indent = 8;
}
wxDataViewCtrlBase::~wxDataViewCtrlBase()
{
if (m_model)
{
m_model->DecRef();
m_model = NULL;
}
}
bool wxDataViewCtrlBase::AssociateModel( wxDataViewModel *model )
{
if (m_model)
{
m_model->DecRef(); // discard old model, if any
}
// add our own reference to the new model:
m_model = model;
if (m_model)
{
m_model->IncRef();
}
return true;
}
wxDataViewModel* wxDataViewCtrlBase::GetModel()
{
return m_model;
}
const wxDataViewModel* wxDataViewCtrlBase::GetModel() const
{
return m_model;
}
void wxDataViewCtrlBase::ExpandAncestors( const wxDataViewItem & item )
{
if (!m_model) return;
if (!item.IsOk()) return;
wxVector<wxDataViewItem> parentChain;
// at first we get all the parents of the selected item
wxDataViewItem parent = m_model->GetParent(item);
while (parent.IsOk())
{
parentChain.push_back(parent);
parent = m_model->GetParent(parent);
}
// then we expand the parents, starting at the root
while (!parentChain.empty())
{
Expand(parentChain.back());
parentChain.pop_back();
}
}
wxDataViewItem wxDataViewCtrlBase::GetCurrentItem() const
{
return HasFlag(wxDV_MULTIPLE) ? DoGetCurrentItem()
: GetSelection();
}
void wxDataViewCtrlBase::SetCurrentItem(const wxDataViewItem& item)
{
wxCHECK_RET( item.IsOk(), "Can't make current an invalid item." );
if ( HasFlag(wxDV_MULTIPLE) )
DoSetCurrentItem(item);
else
Select(item);
}
wxDataViewItem wxDataViewCtrlBase::GetSelection() const
{
if ( GetSelectedItemsCount() != 1 )
return wxDataViewItem();
wxDataViewItemArray selections;
GetSelections(selections);
return selections[0];
}
namespace
{
// Helper to account for inconsistent signature of wxDataViewProgressRenderer
// ctor: it takes an extra "label" argument as first parameter, unlike all the
// other renderers.
template <typename Renderer>
struct RendererFactory
{
static Renderer*
New(wxDataViewCellMode mode, int align)
{
return new Renderer(Renderer::GetDefaultType(), mode, align);
}
};
template <>
struct RendererFactory<wxDataViewProgressRenderer>
{
static wxDataViewProgressRenderer*
New(wxDataViewCellMode mode, int align)
{
return new wxDataViewProgressRenderer(
wxString(),
wxDataViewProgressRenderer::GetDefaultType(),
mode,
align
);
}
};
template <typename Renderer, typename LabelType>
wxDataViewColumn*
CreateColumnWithRenderer(const LabelType& label,
unsigned model_column,
wxDataViewCellMode mode,
int width,
wxAlignment align,
int flags)
{
// For compatibility reason, handle wxALIGN_NOT as wxDVR_DEFAULT_ALIGNMENT
// when creating the renderer here because a lot of existing code,
// including our own dataview sample, uses wxALIGN_NOT just because it's
// the default value of the alignment argument in AppendXXXColumn()
// methods, but this doesn't mean that it actually wants to top-align the
// column text.
//
// This does make it impossible to create top-aligned text using these
// functions, but it can always be done by creating the renderer with the
// desired alignment explicitly and should be so rarely needed in practice
// (without speaking that vertical alignment is completely unsupported in
// native OS X version), that it's preferable to do the right thing by
// default here rather than account for it.
return new wxDataViewColumn(
label,
RendererFactory<Renderer>::New(
mode,
align & wxALIGN_BOTTOM
? align
: align | wxALIGN_CENTRE_VERTICAL
),
model_column,
width,
align,
flags
);
}
// Common implementation of all {Append,Prepend}XXXColumn() below.
template <typename Renderer, typename LabelType>
wxDataViewColumn*
AppendColumnWithRenderer(wxDataViewCtrlBase* dvc,
const LabelType& label,
unsigned model_column,
wxDataViewCellMode mode,
int width,
wxAlignment align,
int flags)
{
wxDataViewColumn* const
col = CreateColumnWithRenderer<Renderer>(
label, model_column, mode, width, align, flags
);
dvc->AppendColumn(col);
return col;
}
template <typename Renderer, typename LabelType>
wxDataViewColumn*
PrependColumnWithRenderer(wxDataViewCtrlBase* dvc,
const LabelType& label,
unsigned model_column,
wxDataViewCellMode mode,
int width,
wxAlignment align,
int flags)
{
wxDataViewColumn* const
col = CreateColumnWithRenderer<Renderer>(
label, model_column, mode, width, align, flags
);
dvc->PrependColumn(col);
return col;
}
} // anonymous namespace
wxDataViewColumn *
wxDataViewCtrlBase::AppendTextColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendIconTextColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewIconTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewToggleRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewProgressRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendDateColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewDateRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendBitmapColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewBitmapRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendTextColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendIconTextColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewIconTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewToggleRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewProgressRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendDateColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewDateRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return AppendColumnWithRenderer<wxDataViewBitmapRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependTextColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependIconTextColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewIconTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependToggleColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewToggleRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependProgressColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewProgressRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependDateColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewDateRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependBitmapColumn( const wxString &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewBitmapRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependTextColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependIconTextColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewIconTextRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependToggleColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewToggleRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependProgressColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewProgressRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependDateColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewDateRenderer>(
this, label, model_column, mode, width, align, flags
);
}
wxDataViewColumn *
wxDataViewCtrlBase::PrependBitmapColumn( const wxBitmap &label, unsigned int model_column,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
return PrependColumnWithRenderer<wxDataViewBitmapRenderer>(
this, label, model_column, mode, width, align, flags
);
}
bool
wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col )
{
col->SetOwner( (wxDataViewCtrl*) this );
return true;
}
bool
wxDataViewCtrlBase::PrependColumn( wxDataViewColumn *col )
{
col->SetOwner( (wxDataViewCtrl*) this );
return true;
}
bool
wxDataViewCtrlBase::InsertColumn( unsigned int WXUNUSED(pos), wxDataViewColumn *col )
{
col->SetOwner( (wxDataViewCtrl*) this );
return true;
}
void wxDataViewCtrlBase::StartEditor(const wxDataViewItem& item, unsigned int column)
{
EditItem(item, GetColumn(column));
}
// ---------------------------------------------------------
// wxDataViewEvent
// ---------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent,wxNotifyEvent);
wxDEFINE_EVENT( wxEVT_DATAVIEW_SELECTION_CHANGED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_ACTIVATED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_COLLAPSING, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_COLLAPSED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_EXPANDING, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_EXPANDED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_EDITING_STARTED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_START_EDITING, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_EDITING_DONE, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_COLUMN_SORTED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_COLUMN_REORDERED, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_CACHE_HINT, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, wxDataViewEvent );
wxDEFINE_EVENT( wxEVT_DATAVIEW_ITEM_DROP, wxDataViewEvent );
#if wxUSE_SPINCTRL
// -------------------------------------
// wxDataViewSpinRenderer
// -------------------------------------
wxDataViewSpinRenderer::wxDataViewSpinRenderer( int min, int max, wxDataViewCellMode mode, int alignment ) :
wxDataViewCustomRenderer(wxT("long"), mode, alignment )
{
m_min = min;
m_max = max;
}
wxWindow* wxDataViewSpinRenderer::CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value )
{
long l = value;
wxString str;
str.Printf( wxT("%d"), (int) l );
wxSpinCtrl *sc = new wxSpinCtrl( parent, wxID_ANY, str,
labelRect.GetTopLeft(), labelRect.GetSize(), wxSP_ARROW_KEYS|wxTE_PROCESS_ENTER, m_min, m_max, l );
#ifdef __WXMAC__
const wxSize size = sc->GetSize();
wxPoint pt = sc->GetPosition();
sc->SetSize( pt.x - 4, pt.y - 4, size.x, size.y );
#endif
return sc;
}
bool wxDataViewSpinRenderer::GetValueFromEditorCtrl( wxWindow* editor, wxVariant &value )
{
wxSpinCtrl *sc = (wxSpinCtrl*) editor;
long l = sc->GetValue();
value = l;
return true;
}
bool wxDataViewSpinRenderer::Render( wxRect rect, wxDC *dc, int state )
{
wxString str;
str.Printf(wxT("%d"), (int) m_data );
RenderText( str, 0, rect, dc, state );
return true;
}
wxSize wxDataViewSpinRenderer::GetSize() const
{
wxSize sz = GetTextExtent(wxString::Format("%d", (int)m_data));
// Allow some space for the spin buttons, which is approximately the size
// of a scrollbar (and getting pixel-exact value would be complicated).
// Also add some whitespace between the text and the button:
sz.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
sz.x += GetTextExtent("M").x;
return sz;
}
bool wxDataViewSpinRenderer::SetValue( const wxVariant &value )
{
m_data = value.GetLong();
return true;
}
bool wxDataViewSpinRenderer::GetValue( wxVariant &value ) const
{
value = m_data;
return true;
}
#endif // wxUSE_SPINCTRL
// -------------------------------------
// wxDataViewChoiceRenderer
// -------------------------------------
#if defined(wxHAS_GENERIC_DATAVIEWCTRL)
wxDataViewChoiceRenderer::wxDataViewChoiceRenderer( const wxArrayString& choices, wxDataViewCellMode mode, int alignment ) :
wxDataViewCustomRenderer(wxT("string"), mode, alignment )
{
m_choices = choices;
}
wxWindow* wxDataViewChoiceRenderer::CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value )
{
wxChoice* c = new wxChoice
(
parent,
wxID_ANY,
labelRect.GetTopLeft(),
wxSize(labelRect.GetWidth(), -1),
m_choices
);
c->Move(labelRect.GetRight() - c->GetRect().width, wxDefaultCoord);
c->SetStringSelection( value.GetString() );
return c;
}
bool wxDataViewChoiceRenderer::GetValueFromEditorCtrl( wxWindow* editor, wxVariant &value )
{
wxChoice *c = (wxChoice*) editor;
wxString s = c->GetStringSelection();
value = s;
return true;
}
bool wxDataViewChoiceRenderer::Render( wxRect rect, wxDC *dc, int state )
{
RenderText( m_data, 0, rect, dc, state );
return true;
}
wxSize wxDataViewChoiceRenderer::GetSize() const
{
wxSize sz;
for ( wxArrayString::const_iterator i = m_choices.begin(); i != m_choices.end(); ++i )
sz.IncTo(GetTextExtent(*i));
// Allow some space for the right-side button, which is approximately the
// size of a scrollbar (and getting pixel-exact value would be complicated).
// Also add some whitespace between the text and the button:
sz.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
sz.x += GetTextExtent("M").x;
return sz;
}
bool wxDataViewChoiceRenderer::SetValue( const wxVariant &value )
{
m_data = value.GetString();
return true;
}
bool wxDataViewChoiceRenderer::GetValue( wxVariant &value ) const
{
value = m_data;
return true;
}
// ----------------------------------------------------------------------------
// wxDataViewChoiceByIndexRenderer
// ----------------------------------------------------------------------------
wxDataViewChoiceByIndexRenderer::wxDataViewChoiceByIndexRenderer( const wxArrayString &choices,
wxDataViewCellMode mode, int alignment ) :
wxDataViewChoiceRenderer( choices, mode, alignment )
{
}
wxWindow* wxDataViewChoiceByIndexRenderer::CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value )
{
wxVariant string_value = GetChoice( value.GetLong() );
return wxDataViewChoiceRenderer::CreateEditorCtrl( parent, labelRect, string_value );
}
bool wxDataViewChoiceByIndexRenderer::GetValueFromEditorCtrl( wxWindow* editor, wxVariant &value )
{
wxVariant string_value;
if (!wxDataViewChoiceRenderer::GetValueFromEditorCtrl( editor, string_value ))
return false;
value = (long) GetChoices().Index( string_value.GetString() );
return true;
}
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;
}
#endif
// ---------------------------------------------------------
// wxDataViewDateRenderer
// ---------------------------------------------------------
#if (defined(wxHAS_GENERIC_DATAVIEWCTRL) || defined(__WXGTK__)) && wxUSE_DATEPICKCTRL
wxDataViewDateRenderer::wxDataViewDateRenderer(const wxString& varianttype,
wxDataViewCellMode mode, int align)
: wxDataViewCustomRenderer(varianttype, mode, align)
{
}
wxWindow *
wxDataViewDateRenderer::CreateEditorCtrl(wxWindow *parent, wxRect labelRect, const wxVariant& value)
{
return new wxDatePickerCtrl
(
parent,
wxID_ANY,
value.GetDateTime(),
labelRect.GetTopLeft(),
labelRect.GetSize()
);
}
bool wxDataViewDateRenderer::GetValueFromEditorCtrl(wxWindow *editor, wxVariant& value)
{
wxDatePickerCtrl *ctrl = static_cast<wxDatePickerCtrl*>(editor);
value = ctrl->GetValue();
return true;
}
bool wxDataViewDateRenderer::SetValue(const wxVariant& value)
{
m_date = value.GetDateTime();
return true;
}
bool wxDataViewDateRenderer::GetValue(wxVariant& value) const
{
value = m_date;
return true;
}
bool wxDataViewDateRenderer::Render(wxRect cell, wxDC* dc, int state)
{
wxString tmp = m_date.FormatDate();
RenderText( tmp, 0, cell, dc, state );
return true;
}
wxSize wxDataViewDateRenderer::GetSize() const
{
return GetTextExtent(m_date.FormatDate());
}
#endif // (defined(wxHAS_GENERIC_DATAVIEWCTRL) || defined(__WXGTK__)) && wxUSE_DATEPICKCTRL
//-----------------------------------------------------------------------------
// wxDataViewListStore
//-----------------------------------------------------------------------------
wxDataViewListStore::wxDataViewListStore()
{
}
wxDataViewListStore::~wxDataViewListStore()
{
wxVector<wxDataViewListStoreLine*>::iterator it;
for (it = m_data.begin(); it != m_data.end(); ++it)
{
wxDataViewListStoreLine* line = *it;
delete line;
}
}
void wxDataViewListStore::PrependColumn( const wxString &varianttype )
{
m_cols.Insert( varianttype, 0 );
}
void wxDataViewListStore::InsertColumn( unsigned int pos, const wxString &varianttype )
{
m_cols.Insert( varianttype, pos );
}
void wxDataViewListStore::AppendColumn( const wxString &varianttype )
{
m_cols.Add( varianttype );
}
unsigned int wxDataViewListStore::GetColumnCount() const
{
return m_cols.GetCount();
}
unsigned int wxDataViewListStore::GetItemCount() const
{
return m_data.size();
}
wxString wxDataViewListStore::GetColumnType( unsigned int pos ) const
{
return m_cols[pos];
}
void wxDataViewListStore::AppendItem( const wxVector<wxVariant> &values, wxUIntPtr data )
{
wxDataViewListStoreLine *line = new wxDataViewListStoreLine( data );
line->m_values = values;
m_data.push_back( line );
RowAppended();
}
void wxDataViewListStore::PrependItem( const wxVector<wxVariant> &values, wxUIntPtr data )
{
wxDataViewListStoreLine *line = new wxDataViewListStoreLine( data );
line->m_values = values;
m_data.insert( m_data.begin(), line );
RowPrepended();
}
void wxDataViewListStore::InsertItem( unsigned int row, const wxVector<wxVariant> &values,
wxUIntPtr data )
{
wxDataViewListStoreLine *line = new wxDataViewListStoreLine( data );
line->m_values = values;
m_data.insert( m_data.begin()+row, line );
RowInserted( row );
}
void wxDataViewListStore::DeleteItem( unsigned int row )
{
wxVector<wxDataViewListStoreLine*>::iterator it = m_data.begin() + row;
delete *it;
m_data.erase( it );
RowDeleted( row );
}
void wxDataViewListStore::DeleteAllItems()
{
wxVector<wxDataViewListStoreLine*>::iterator it;
for (it = m_data.begin(); it != m_data.end(); ++it)
{
wxDataViewListStoreLine* line = *it;
delete line;
}
m_data.clear();
Reset( 0 );
}
void wxDataViewListStore::ClearColumns()
{
m_cols.clear();
}
void wxDataViewListStore::SetItemData( const wxDataViewItem& item, wxUIntPtr data )
{
wxDataViewListStoreLine* line = m_data[GetRow(item)];
if (!line) return;
line->SetData( data );
}
wxUIntPtr wxDataViewListStore::GetItemData( const wxDataViewItem& item ) const
{
wxDataViewListStoreLine* line = m_data[GetRow(item)];
if (!line) return 0;
return line->GetData();
}
void wxDataViewListStore::GetValueByRow( wxVariant &value, unsigned int row, unsigned int col ) const
{
wxDataViewListStoreLine *line = m_data[row];
value = line->m_values[col];
}
bool wxDataViewListStore::SetValueByRow( const wxVariant &value, unsigned int row, unsigned int col )
{
wxDataViewListStoreLine *line = m_data[row];
line->m_values[col] = value;
return true;
}
//-----------------------------------------------------------------------------
// wxDataViewListCtrl
//-----------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxDataViewListCtrl,wxDataViewCtrl);
wxBEGIN_EVENT_TABLE(wxDataViewListCtrl,wxDataViewCtrl)
EVT_SIZE( wxDataViewListCtrl::OnSize )
wxEND_EVENT_TABLE()
wxDataViewListCtrl::wxDataViewListCtrl()
{
}
wxDataViewListCtrl::wxDataViewListCtrl( wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style,
const wxValidator& validator )
{
Create( parent, id, pos, size, style, validator );
}
wxDataViewListCtrl::~wxDataViewListCtrl()
{
}
bool wxDataViewListCtrl::Create( wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style,
const wxValidator& validator )
{
if ( !wxDataViewCtrl::Create( parent, id, pos, size, style, validator ) )
return false;
wxDataViewListStore *store = new wxDataViewListStore;
AssociateModel( store );
store->DecRef();
return true;
}
bool wxDataViewListCtrl::AppendColumn( wxDataViewColumn *column, const wxString &varianttype )
{
GetStore()->AppendColumn( varianttype );
return wxDataViewCtrl::AppendColumn( column );
}
bool wxDataViewListCtrl::PrependColumn( wxDataViewColumn *column, const wxString &varianttype )
{
GetStore()->PrependColumn( varianttype );
return wxDataViewCtrl::PrependColumn( column );
}
bool wxDataViewListCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *column, const wxString &varianttype )
{
GetStore()->InsertColumn( pos, varianttype );
return wxDataViewCtrl::InsertColumn( pos, column );
}
bool wxDataViewListCtrl::PrependColumn( wxDataViewColumn *col )
{
return PrependColumn( col, col->GetRenderer()->GetVariantType() );
}
bool wxDataViewListCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
{
return InsertColumn( pos, col, col->GetRenderer()->GetVariantType() );
}
bool wxDataViewListCtrl::AppendColumn( wxDataViewColumn *col )
{
return AppendColumn( col, col->GetRenderer()->GetVariantType() );
}
bool wxDataViewListCtrl::ClearColumns()
{
GetStore()->ClearColumns();
return wxDataViewCtrl::ClearColumns();
}
wxDataViewColumn *wxDataViewListCtrl::AppendTextColumn( const wxString &label,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
GetStore()->AppendColumn( wxT("string") );
wxDataViewColumn *ret = new wxDataViewColumn( label,
new wxDataViewTextRenderer( wxT("string"), mode ),
GetStore()->GetColumnCount()-1, width, align, flags );
wxDataViewCtrl::AppendColumn( ret );
return ret;
}
wxDataViewColumn *wxDataViewListCtrl::AppendToggleColumn( const wxString &label,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
GetStore()->AppendColumn( wxT("bool") );
wxDataViewColumn *ret = new wxDataViewColumn( label,
new wxDataViewToggleRenderer( wxT("bool"), mode ),
GetStore()->GetColumnCount()-1, width, align, flags );
return wxDataViewCtrl::AppendColumn( ret ) ? ret : NULL;
}
wxDataViewColumn *wxDataViewListCtrl::AppendProgressColumn( const wxString &label,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
GetStore()->AppendColumn( wxT("long") );
wxDataViewColumn *ret = new wxDataViewColumn( label,
new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ),
GetStore()->GetColumnCount()-1, width, align, flags );
return wxDataViewCtrl::AppendColumn( ret ) ? ret : NULL;
}
wxDataViewColumn *wxDataViewListCtrl::AppendIconTextColumn( const wxString &label,
wxDataViewCellMode mode, int width, wxAlignment align, int flags )
{
GetStore()->AppendColumn( wxT("wxDataViewIconText") );
wxDataViewColumn *ret = new wxDataViewColumn( label,
new wxDataViewIconTextRenderer( wxT("wxDataViewIconText"), mode ),
GetStore()->GetColumnCount()-1, width, align, flags );
return wxDataViewCtrl::AppendColumn( ret ) ? ret : NULL;
}
void wxDataViewListCtrl::OnSize( wxSizeEvent &event )
{
event.Skip( true );
}
//-----------------------------------------------------------------------------
// wxDataViewTreeStore
//-----------------------------------------------------------------------------
wxDataViewTreeStoreNode::wxDataViewTreeStoreNode(
wxDataViewTreeStoreNode *parent,
const wxString &text, const wxIcon &icon, wxClientData *data )
{
m_parent = parent;
m_text = text;
m_icon = icon;
m_data = data;
}
wxDataViewTreeStoreNode::~wxDataViewTreeStoreNode()
{
if (m_data)
delete m_data;
}
#include "wx/listimpl.cpp"
WX_DEFINE_LIST(wxDataViewTreeStoreNodeList)
wxDataViewTreeStoreContainerNode::wxDataViewTreeStoreContainerNode(
wxDataViewTreeStoreNode *parent, const wxString &text,
const wxIcon &icon, const wxIcon &expanded, wxClientData *data ) :
wxDataViewTreeStoreNode( parent, text, icon, data )
{
m_iconExpanded = expanded;
m_isExpanded = false;
m_children.DeleteContents(true);
}
wxDataViewTreeStoreContainerNode::~wxDataViewTreeStoreContainerNode()
{
}
//-----------------------------------------------------------------------------
wxDataViewTreeStore::wxDataViewTreeStore()
{
m_root = new wxDataViewTreeStoreContainerNode( NULL, wxEmptyString );
}
wxDataViewTreeStore::~wxDataViewTreeStore()
{
delete m_root;
}
wxDataViewItem wxDataViewTreeStore::AppendItem( const wxDataViewItem& parent,
const wxString &text, const wxIcon &icon, wxClientData *data )
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreNode *node =
new wxDataViewTreeStoreNode( parent_node, text, icon, data );
parent_node->GetChildren().Append( node );
return node->GetItem();
}
wxDataViewItem wxDataViewTreeStore::PrependItem( const wxDataViewItem& parent,
const wxString &text, const wxIcon &icon, wxClientData *data )
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreNode *node =
new wxDataViewTreeStoreNode( parent_node, text, icon, data );
parent_node->GetChildren().Insert( node );
return node->GetItem();
}
wxDataViewItem
wxDataViewTreeStore::InsertItem(const wxDataViewItem& parent,
const wxDataViewItem& previous,
const wxString& text,
const wxIcon& icon,
wxClientData *data)
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreNode *previous_node = FindNode( previous );
int pos = parent_node->GetChildren().IndexOf( previous_node );
if (pos == wxNOT_FOUND) return wxDataViewItem(0);
wxDataViewTreeStoreNode *node =
new wxDataViewTreeStoreNode( parent_node, text, icon, data );
parent_node->GetChildren().Insert( (size_t) pos, node );
return node->GetItem();
}
wxDataViewItem wxDataViewTreeStore::PrependContainer( const wxDataViewItem& parent,
const wxString &text, const wxIcon &icon, const wxIcon &expanded,
wxClientData *data )
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreContainerNode *node =
new wxDataViewTreeStoreContainerNode( parent_node, text, icon, expanded, data );
parent_node->GetChildren().Insert( node );
return node->GetItem();
}
wxDataViewItem
wxDataViewTreeStore::AppendContainer(const wxDataViewItem& parent,
const wxString &text,
const wxIcon& icon,
const wxIcon& expanded,
wxClientData * data)
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreContainerNode *node =
new wxDataViewTreeStoreContainerNode( parent_node, text, icon, expanded, data );
parent_node->GetChildren().Append( node );
return node->GetItem();
}
wxDataViewItem
wxDataViewTreeStore::InsertContainer(const wxDataViewItem& parent,
const wxDataViewItem& previous,
const wxString& text,
const wxIcon& icon,
const wxIcon& expanded,
wxClientData * data)
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreNode *previous_node = FindNode( previous );
int pos = parent_node->GetChildren().IndexOf( previous_node );
if (pos == wxNOT_FOUND) return wxDataViewItem(0);
wxDataViewTreeStoreContainerNode *node =
new wxDataViewTreeStoreContainerNode( parent_node, text, icon, expanded, data );
parent_node->GetChildren().Insert( (size_t) pos, node );
return node->GetItem();
}
bool wxDataViewTreeStore::IsContainer( const wxDataViewItem& item ) const
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return false;
return node->IsContainer();
}
wxDataViewItem wxDataViewTreeStore::GetNthChild( const wxDataViewItem& parent, unsigned int pos ) const
{
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
if (!parent_node) return wxDataViewItem(0);
wxDataViewTreeStoreNodeList::compatibility_iterator node = parent_node->GetChildren().Item( pos );
if (node)
return wxDataViewItem(node->GetData());
return wxDataViewItem(0);
}
int wxDataViewTreeStore::GetChildCount( const wxDataViewItem& parent ) const
{
wxDataViewTreeStoreNode *node = FindNode( parent );
if (!node) return -1;
if (!node->IsContainer())
return 0;
wxDataViewTreeStoreContainerNode *container_node = (wxDataViewTreeStoreContainerNode*) node;
return (int) container_node->GetChildren().GetCount();
}
void wxDataViewTreeStore::SetItemText( const wxDataViewItem& item, const wxString &text )
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return;
node->SetText( text );
}
wxString wxDataViewTreeStore::GetItemText( const wxDataViewItem& item ) const
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return wxEmptyString;
return node->GetText();
}
void wxDataViewTreeStore::SetItemIcon( const wxDataViewItem& item, const wxIcon &icon )
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return;
node->SetIcon( icon );
}
const wxIcon &wxDataViewTreeStore::GetItemIcon( const wxDataViewItem& item ) const
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return wxNullIcon;
return node->GetIcon();
}
void wxDataViewTreeStore::SetItemExpandedIcon( const wxDataViewItem& item, const wxIcon &icon )
{
wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
if (!node) return;
node->SetExpandedIcon( icon );
}
const wxIcon &wxDataViewTreeStore::GetItemExpandedIcon( const wxDataViewItem& item ) const
{
wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
if (!node) return wxNullIcon;
return node->GetExpandedIcon();
}
void wxDataViewTreeStore::SetItemData( const wxDataViewItem& item, wxClientData *data )
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return;
node->SetData( data );
}
wxClientData *wxDataViewTreeStore::GetItemData( const wxDataViewItem& item ) const
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return NULL;
return node->GetData();
}
void wxDataViewTreeStore::DeleteItem( const wxDataViewItem& item )
{
if (!item.IsOk()) return;
wxDataViewItem parent_item = GetParent( item );
wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent_item );
if (!parent_node) return;
parent_node->GetChildren().DeleteObject( FindNode(item) );
}
void wxDataViewTreeStore::DeleteChildren( const wxDataViewItem& item )
{
wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
if (!node) return;
node->GetChildren().clear();
}
void wxDataViewTreeStore::DeleteAllItems()
{
DeleteChildren(wxDataViewItem(m_root));
}
void
wxDataViewTreeStore::GetValue(wxVariant &variant,
const wxDataViewItem &item,
unsigned int WXUNUSED(col)) const
{
// if (col != 0) return;
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return;
wxIcon icon( node->GetIcon());
if (node->IsContainer())
{
wxDataViewTreeStoreContainerNode *container = (wxDataViewTreeStoreContainerNode*) node;
if (container->IsExpanded() && container->GetExpandedIcon().IsOk())
icon = container->GetExpandedIcon();
}
wxDataViewIconText data( node->GetText(), icon );
variant << data;
}
bool
wxDataViewTreeStore::SetValue(const wxVariant& variant,
const wxDataViewItem& item,
unsigned int WXUNUSED(col))
{
// if (col != 0) return false;
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return false;
wxDataViewIconText data;
data << variant;
node->SetText( data.GetText() );
node->SetIcon( data.GetIcon() );
return true;
}
wxDataViewItem wxDataViewTreeStore::GetParent( const wxDataViewItem &item ) const
{
wxDataViewTreeStoreNode *node = FindNode( item );
if (!node) return wxDataViewItem(0);
wxDataViewTreeStoreNode *parent = node->GetParent();
if (!parent) return wxDataViewItem(0);
if (parent == m_root)
return wxDataViewItem(0);
return parent->GetItem();
}
unsigned int wxDataViewTreeStore::GetChildren( const wxDataViewItem &item, wxDataViewItemArray &children ) const
{
wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
if (!node) return 0;
wxDataViewTreeStoreNodeList::iterator iter;
for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++)
{
wxDataViewTreeStoreNode* child = *iter;
children.Add( child->GetItem() );
}
return node->GetChildren().GetCount();
}
int wxDataViewTreeStore::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
unsigned int WXUNUSED(column), bool WXUNUSED(ascending) ) const
{
wxDataViewTreeStoreNode *node1 = FindNode( item1 );
wxDataViewTreeStoreNode *node2 = FindNode( item2 );
if (!node1 || !node2)
return 0;
wxDataViewTreeStoreContainerNode* parent1 =
(wxDataViewTreeStoreContainerNode*) node1->GetParent();
wxDataViewTreeStoreContainerNode* parent2 =
(wxDataViewTreeStoreContainerNode*) node2->GetParent();
if (parent1 != parent2)
{
wxLogError( wxT("Comparing items with different parent.") );
return 0;
}
if (node1->IsContainer() && !node2->IsContainer())
return -1;
if (node2->IsContainer() && !node1->IsContainer())
return 1;
return parent1->GetChildren().IndexOf( node1 ) - parent2->GetChildren().IndexOf( node2 );
}
wxDataViewTreeStoreNode *wxDataViewTreeStore::FindNode( const wxDataViewItem &item ) const
{
if (!item.IsOk())
return m_root;
return (wxDataViewTreeStoreNode*) item.GetID();
}
wxDataViewTreeStoreContainerNode *wxDataViewTreeStore::FindContainerNode( const wxDataViewItem &item ) const
{
if (!item.IsOk())
return (wxDataViewTreeStoreContainerNode*) m_root;
wxDataViewTreeStoreNode* node = (wxDataViewTreeStoreNode*) item.GetID();
if (!node->IsContainer())
return NULL;
return (wxDataViewTreeStoreContainerNode*) node;
}
//-----------------------------------------------------------------------------
// wxDataViewTreeCtrl
//-----------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxDataViewTreeCtrl,wxDataViewCtrl);
wxBEGIN_EVENT_TABLE(wxDataViewTreeCtrl,wxDataViewCtrl)
EVT_DATAVIEW_ITEM_EXPANDED(-1, wxDataViewTreeCtrl::OnExpanded)
EVT_DATAVIEW_ITEM_COLLAPSED(-1, wxDataViewTreeCtrl::OnCollapsed)
EVT_SIZE( wxDataViewTreeCtrl::OnSize )
wxEND_EVENT_TABLE()
bool wxDataViewTreeCtrl::Create( wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator )
{
if ( !wxDataViewCtrl::Create( parent, id, pos, size, style, validator ) )
return false;
// create the standard model and a column in the tree
wxDataViewTreeStore *store = new wxDataViewTreeStore;
AssociateModel( store );
store->DecRef();
AppendIconTextColumn
(
wxString(), // no label (header is not shown anyhow)
0, // the only model column
wxDATAVIEW_CELL_EDITABLE,
-1, // default width
wxALIGN_NOT, // and alignment
0 // not resizable
);
return true;
}
wxDataViewItem wxDataViewTreeCtrl::AppendItem( const wxDataViewItem& parent,
const wxString &text, int iconIndex, wxClientData *data )
{
wxDataViewItem res = GetStore()->
AppendItem( parent, text, GetImage(iconIndex), data );
GetStore()->ItemAdded( parent, res );
return res;
}
wxDataViewItem wxDataViewTreeCtrl::PrependItem( const wxDataViewItem& parent,
const wxString &text, int iconIndex, wxClientData *data )
{
wxDataViewItem res = GetStore()->
PrependItem( parent, text, GetImage(iconIndex), data );
GetStore()->ItemAdded( parent, res );
return res;
}
wxDataViewItem wxDataViewTreeCtrl::InsertItem( const wxDataViewItem& parent, const wxDataViewItem& previous,
const wxString &text, int iconIndex, wxClientData *data )
{
wxDataViewItem res = GetStore()->
InsertItem( parent, previous, text, GetImage(iconIndex), data );
GetStore()->ItemAdded( parent, res );
return res;
}
wxDataViewItem wxDataViewTreeCtrl::PrependContainer( const wxDataViewItem& parent,
const wxString &text, int iconIndex, int expandedIndex, wxClientData *data )
{
wxDataViewItem res = GetStore()->
PrependContainer( parent, text,
GetImage(iconIndex), GetImage(expandedIndex), data );
GetStore()->ItemAdded( parent, res );
return res;
}
wxDataViewItem wxDataViewTreeCtrl::AppendContainer( const wxDataViewItem& parent,
const wxString &text, int iconIndex, int expandedIndex, wxClientData *data )
{
wxDataViewItem res = GetStore()->
AppendContainer( parent, text,
GetImage(iconIndex), GetImage(expandedIndex), data );
GetStore()->ItemAdded( parent, res );
return res;
}
wxDataViewItem wxDataViewTreeCtrl::InsertContainer( const wxDataViewItem& parent, const wxDataViewItem& previous,
const wxString &text, int iconIndex, int expandedIndex, wxClientData *data )
{
wxDataViewItem res = GetStore()->
InsertContainer( parent, previous, text,
GetImage(iconIndex), GetImage(expandedIndex), data );
GetStore()->ItemAdded( parent, res );
return res;
}
void wxDataViewTreeCtrl::SetItemText( const wxDataViewItem& item, const wxString &text )
{
GetStore()->SetItemText(item,text);
// notify control
GetStore()->ValueChanged( item, 0 );
}
void wxDataViewTreeCtrl::SetItemIcon( const wxDataViewItem& item, const wxIcon &icon )
{
GetStore()->SetItemIcon(item,icon);
// notify control
GetStore()->ValueChanged( item, 0 );
}
void wxDataViewTreeCtrl::SetItemExpandedIcon( const wxDataViewItem& item, const wxIcon &icon )
{
GetStore()->SetItemExpandedIcon(item,icon);
// notify control
GetStore()->ValueChanged( item, 0 );
}
void wxDataViewTreeCtrl::DeleteItem( const wxDataViewItem& item )
{
wxDataViewItem parent_item = GetStore()->GetParent( item );
GetStore()->DeleteItem(item);
// notify control
GetStore()->ItemDeleted( parent_item, item );
}
void wxDataViewTreeCtrl::DeleteChildren( const wxDataViewItem& item )
{
wxDataViewTreeStoreContainerNode *node = GetStore()->FindContainerNode( item );
if (!node) return;
wxDataViewItemArray array;
wxDataViewTreeStoreNodeList::iterator iter;
for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++)
{
wxDataViewTreeStoreNode* child = *iter;
array.Add( child->GetItem() );
}
GetStore()->DeleteChildren( item );
// notify control
GetStore()->ItemsDeleted( item, array );
}
void wxDataViewTreeCtrl::DeleteAllItems()
{
GetStore()->DeleteAllItems();
GetStore()->Cleared();
}
void wxDataViewTreeCtrl::OnExpanded( wxDataViewEvent &event )
{
if (HasImageList()) return;
wxDataViewTreeStoreContainerNode* container = GetStore()->FindContainerNode( event.GetItem() );
if (!container) return;
container->SetExpanded( true );
GetStore()->ItemChanged( event.GetItem() );
}
void wxDataViewTreeCtrl::OnCollapsed( wxDataViewEvent &event )
{
if (HasImageList()) return;
wxDataViewTreeStoreContainerNode* container = GetStore()->FindContainerNode( event.GetItem() );
if (!container) return;
container->SetExpanded( false );
GetStore()->ItemChanged( event.GetItem() );
}
void wxDataViewTreeCtrl::OnSize( wxSizeEvent &event )
{
#if defined(wxUSE_GENERICDATAVIEWCTRL)
// automatically resize our only column to take the entire control width
if ( GetColumnCount() )
{
wxSize size = GetClientSize();
GetColumn(0)->SetWidth(size.x);
}
#endif
event.Skip( true );
}
#endif // wxUSE_DATAVIEWCTRL