[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] [PATCH] Implement inplace editing in CensusView.
From: |
Vaclav Slavik |
Subject: |
Re: [lmi] [PATCH] Implement inplace editing in CensusView. |
Date: |
Tue, 23 Aug 2011 16:34:24 +0200 |
User-agent: |
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.18) Gecko/20110616 Thunderbird/3.1.11 |
On 2011-08-22 21:34, Greg Chicares wrote:
> If it's not too much trouble, could I ask you to post a replacement for this
> patch that can be applied to lmi HEAD?
Here it is:
---
census_view.cpp | 715 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
census_view.hpp | 3 +-
2 files changed, 679 insertions(+), 39 deletions(-)
diff --git a/census_view.cpp b/census_view.cpp
index ee44f37..702ccda 100644
--- a/census_view.cpp
+++ b/census_view.cpp
@@ -38,6 +38,7 @@
#include "illustration_view.hpp"
#include "illustrator.hpp"
#include "input.hpp"
+#include "input_sequence_entry.hpp"
#include "ledger.hpp"
#include "ledger_text_formats.hpp"
#include "miscellany.hpp" // is_ok_for_cctype()
@@ -47,9 +48,11 @@
#include "wx_utility.hpp" // class ClipboardEx
#include <wx/dataview.h>
+#include <wx/datectrl.h>
#include <wx/icon.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
+#include <wx/spinctrl.h>
#include <wx/xrc/xmlres.h>
#include <wx/wupdlock.h>
@@ -82,62 +85,700 @@ namespace
}
return r;
}
-} // Unnamed namespace.
-/// Interface to the data for wxDataViewCtrl.
+// data needed to create UI for tn_range<> types
+struct tn_range_variant_data
+ :public wxVariantData
+{
+ tn_range_variant_data(std::string const& value_, double min_, double max_)
+ :value(value_), min(min_), max(max_)
+ {
+ }
-class CensusViewDataViewModel : public wxDataViewIndexListModel
+ tn_range_variant_data(tn_range_base const& r)
+ :value(r.str()), min(r.universal_minimum()), max(r.universal_maximum())
+ {
+ }
+
+ virtual bool Eq(wxVariantData& data) const
+ {
+ tn_range_variant_data *d = dynamic_cast<tn_range_variant_data*>(&data);
+ if(!d)
+ return false;
+ return value == d->value && min == d->min && max == d->max;
+ }
+
+ virtual wxString GetType() const { return
typeid(tn_range_variant_data).name(); }
+
+ virtual wxVariantData* Clone() const
+ {
+ return new(wx) tn_range_variant_data(value, min, max);
+ }
+
+ std::string value;
+ double min, max;
+};
+
+
+class RangeTypeRenderer
+ :public wxDataViewCustomRenderer
{
+ protected:
+ RangeTypeRenderer();
+
public:
- static unsigned int const Col_CellNum = 0;
+ virtual bool HasEditorCtrl() const { return true; }
+ virtual wxWindow* CreateEditorCtrl(wxWindow* parent, wxRect labelRect,
wxVariant const& value);
+ virtual bool GetValueFromEditorCtrl(wxWindow* editor, wxVariant& value);
+ virtual bool Render(wxRect rect, wxDC* dc, int state);
+ virtual wxSize GetSize() const;
+ virtual bool SetValue(wxVariant const& value);
+ virtual bool GetValue(wxVariant& value) const;
+
+ protected:
+ virtual wxWindow* DoCreateEditor(wxWindow* parent, wxRect const& rect,
tn_range_variant_data const& data) = 0;
+ virtual std::string DoGetValueFromEditor(wxWindow* editor) = 0;
+
+ std::string m_value;
+ double m_min, m_max;
+};
- CensusViewDataViewModel(CensusView& view)
- :view_(view)
+RangeTypeRenderer::RangeTypeRenderer()
+ :wxDataViewCustomRenderer
+ (typeid(tn_range_variant_data).name()
+ ,wxDATAVIEW_CELL_EDITABLE
+ ,wxDVR_DEFAULT_ALIGNMENT)
+{
+}
+
+wxWindow* RangeTypeRenderer::CreateEditorCtrl(wxWindow* parent, wxRect
labelRect, wxVariant const& value)
+{
+ tn_range_variant_data const* data =
dynamic_cast<tn_range_variant_data*>(value.GetData());
+ LMI_ASSERT(data);
+
+ // Always use default height for editor controls
+ wxRect rect(labelRect);
+ rect.height = -1;
+
+ return DoCreateEditor(parent, rect, *data);
+}
+
+bool RangeTypeRenderer::GetValueFromEditorCtrl(wxWindow* editor, wxVariant&
value)
+{
+ std::string const val = DoGetValueFromEditor(editor);
+ value = new(wx) tn_range_variant_data(val, m_min, m_max);
+ return true;
+}
+
+bool RangeTypeRenderer::Render(wxRect rect, wxDC* dc, int state)
+{
+ RenderText(m_value, 0, rect, dc, state);
+ return true;
+}
+
+wxSize RangeTypeRenderer::GetSize() const
+{
+ wxSize sz = GetTextExtent(m_value);
+
+ // Allow some space for the spin 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 RangeTypeRenderer::SetValue(wxVariant const& value)
+{
+ tn_range_variant_data const* data =
dynamic_cast<tn_range_variant_data*>(value.GetData());
+ LMI_ASSERT(data);
+
+ m_value = data->value;
+ m_min = data->min;
+ m_max = data->max;
+ return true;
+}
+
+bool RangeTypeRenderer::GetValue(wxVariant& value) const
+{
+ value = new(wx) tn_range_variant_data(m_value, m_min, m_max);
+ return true;
+}
+
+
+class IntSpinRenderer
+ :public RangeTypeRenderer
+{
+ public:
+ IntSpinRenderer() : RangeTypeRenderer() {}
+
+ protected:
+ virtual wxWindow* DoCreateEditor(wxWindow* parent, wxRect const& rect,
tn_range_variant_data const& data);
+ virtual std::string DoGetValueFromEditor(wxWindow* editor);
+};
+
+wxWindow* IntSpinRenderer::DoCreateEditor
+ (wxWindow* parent
+ ,wxRect const& rect
+ ,tn_range_variant_data const& data)
+{
+ return new(wx) wxSpinCtrl
+ (parent
+ ,wxID_ANY
+ ,data.value
+ ,rect.GetTopLeft()
+ ,rect.GetSize()
+ ,wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER
+ ,static_cast<long>(data.min)
+ ,static_cast<long>(data.max)
+ ,value_cast<long>(data.value));
+}
+
+std::string IntSpinRenderer::DoGetValueFromEditor(wxWindow* editor)
+{
+ wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>(editor);
+ LMI_ASSERT(spin);
+
+ return value_cast<std::string>(spin->GetValue());
+}
+
+
+class DoubleSpinRenderer
+ :public RangeTypeRenderer
+{
+ public:
+ DoubleSpinRenderer() : RangeTypeRenderer() {}
+
+ protected:
+ virtual wxWindow* DoCreateEditor(wxWindow* parent, wxRect const& rect,
tn_range_variant_data const& data);
+ virtual std::string DoGetValueFromEditor(wxWindow* editor);
+};
+
+wxWindow* DoubleSpinRenderer::DoCreateEditor
+ (wxWindow* parent
+ ,wxRect const& rect
+ ,tn_range_variant_data const& data)
+{
+ return new(wx) wxSpinCtrlDouble
+ (parent
+ ,wxID_ANY
+ ,data.value
+ ,rect.GetTopLeft()
+ ,rect.GetSize()
+ ,wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER
+ ,data.min
+ ,data.max
+ ,value_cast<double>(data.value));
+}
+
+std::string DoubleSpinRenderer::DoGetValueFromEditor(wxWindow* editor)
+{
+ wxSpinCtrlDouble* spin = dynamic_cast<wxSpinCtrlDouble*>(editor);
+ LMI_ASSERT(spin);
+
+ return value_cast<std::string>(spin->GetValue());
+}
+
+
+class DateRenderer
+ :public RangeTypeRenderer
+{
+ public:
+ DateRenderer() : RangeTypeRenderer() {}
+ virtual bool Render(wxRect rect, wxDC* dc, int state);
+
+ protected:
+ virtual wxWindow* DoCreateEditor(wxWindow* parent, wxRect const& rect,
tn_range_variant_data const& data);
+ virtual std::string DoGetValueFromEditor(wxWindow* editor);
+};
+
+wxWindow* DateRenderer::DoCreateEditor
+ (wxWindow* parent
+ ,wxRect const& rect
+ ,tn_range_variant_data const& data)
+{
+
+ wxDatePickerCtrl* ctrl = new(wx) wxDatePickerCtrl
+ (parent
+ ,wxID_ANY
+ ,ConvertDateToWx(value_cast<calendar_date>(data.value))
+ ,rect.GetTopLeft()
+ ,rect.GetSize());
+
+ ctrl->SetRange
+ (ConvertDateToWx(jdn_t(data.min))
+ ,ConvertDateToWx(jdn_t(data.max))
+ );
+
+ return ctrl;
+}
+
+bool DateRenderer::Render(wxRect rect, wxDC* dc, int state)
+{
+ // Use wx for date formatting so that it is identical to the way
wxDatePickerCtrl does it.
+ wxDateTime const date =
ConvertDateToWx(value_cast<calendar_date>(m_value));
+ RenderText(date.FormatDate(), 0, rect, dc, state);
+ return true;
+}
+
+std::string DateRenderer::DoGetValueFromEditor(wxWindow* editor)
+{
+ wxDatePickerCtrl* ctrl = dynamic_cast<wxDatePickerCtrl*>(editor);
+ LMI_ASSERT(ctrl);
+
+ return value_cast<std::string>(ConvertDateFromWx(ctrl->GetValue()));
+}
+
+
+// data needed to create UI for input sequences
+struct input_sequence_variant_data
+ :public wxVariantData
+{
+ input_sequence_variant_data(std::string const& value_, Input const*
input_, std::string const& field_)
+ :value(value_), input(input_), field(field_)
{
}
- virtual void GetValueByRow
- (wxVariant& variant
- ,unsigned int row
- ,unsigned int col
- ) const
+ virtual bool Eq(wxVariantData& data) const
{
- if(col == Col_CellNum)
- {
- variant = wxString::Format("%d", 1 + row);
- }
+ input_sequence_variant_data *d =
dynamic_cast<input_sequence_variant_data*>(&data);
+ if(!d)
+ return false;
+ return value == d->value;
+ }
+
+ virtual wxString GetType() const { return
typeid(input_sequence_variant_data).name(); }
+
+ virtual wxVariantData* Clone() const
+ {
+ return new(wx) input_sequence_variant_data(value, input, field);
+ }
+
+ std::string value;
+ Input const* input;
+ std::string field;
+};
+
+class DatumSequenceRenderer
+ :public wxDataViewCustomRenderer
+{
+ public:
+ DatumSequenceRenderer();
+ virtual bool HasEditorCtrl() const { return true; }
+ virtual wxWindow* CreateEditorCtrl(wxWindow* parent, wxRect labelRect,
wxVariant const& value);
+ virtual bool GetValueFromEditorCtrl(wxWindow* editor, wxVariant& value);
+ virtual bool Render(wxRect rect, wxDC* dc, int state);
+ virtual wxSize GetSize() const;
+ virtual bool SetValue(wxVariant const& value);
+ virtual bool GetValue(wxVariant& value) const;
+
+ std::string m_value;
+ Input const *m_input;
+ std::string m_field;
+};
+
+DatumSequenceRenderer::DatumSequenceRenderer()
+ :wxDataViewCustomRenderer(typeid(input_sequence_variant_data).name(),
wxDATAVIEW_CELL_EDITABLE, wxDVR_DEFAULT_ALIGNMENT)
+ ,m_input(0)
+{
+}
+
+wxWindow* DatumSequenceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect
labelRect, wxVariant const& value)
+{
+ input_sequence_variant_data const* data =
dynamic_cast<input_sequence_variant_data*>(value.GetData());
+ LMI_ASSERT(data);
+ LMI_ASSERT(data->input);
+
+ InputSequenceEntry *ctrl = new(wx) InputSequenceEntry(parent, wxID_ANY,
"sequence_editor");
+
+ ctrl->text_ctrl().SetValue(data->value.c_str());
+ ctrl->input(*data->input);
+ ctrl->field_name(data->field);
+
+ // Always use default height for editor controls
+ wxRect rect(labelRect);
+ rect.height = -1;
+
+ ctrl->SetSize(rect);
+
+ return ctrl;
+}
+
+bool DatumSequenceRenderer::GetValueFromEditorCtrl(wxWindow* editor,
wxVariant& value)
+{
+ InputSequenceEntry *ctrl = dynamic_cast<InputSequenceEntry*>(editor);
+ LMI_ASSERT(ctrl);
+
+ value = new(wx) input_sequence_variant_data
+ (ctrl->text_ctrl().GetValue().ToStdString()
+ ,&ctrl->input()
+ ,ctrl->field_name());
+ return true;
+}
+
+bool DatumSequenceRenderer::Render(wxRect rect, wxDC* dc, int state)
+{
+ RenderText(m_value, 0, rect, dc, state);
+ return true;
+}
+
+wxSize DatumSequenceRenderer::GetSize() const
+{
+ wxSize sz = GetTextExtent(m_value);
+
+ // Add size of the "..." button. We assume it will use the same font that
this renderer
+ // uses and add some extra whitespace in addition to InputSequenceButton's
8px padding.
+ sz.x += 16 + GetTextExtent("...").x;
+
+ return sz;
+}
+
+bool DatumSequenceRenderer::SetValue(wxVariant const& value)
+{
+ input_sequence_variant_data const* data =
dynamic_cast<input_sequence_variant_data*>(value.GetData());
+ LMI_ASSERT(data);
+
+ m_value = data->value;
+ m_input = data->input;
+ m_field = data->field;
+ return true;
+}
+
+bool DatumSequenceRenderer::GetValue(wxVariant& value) const
+{
+ value = new(wx) input_sequence_variant_data(m_value, m_input, m_field);
+ return true;
+}
+
+
+// This class is used to implement conversion to and from wxVariant for use by
+// wxDVC renderers in a single place.
+class renderer_type_convertor
+{
+ public:
+ virtual wxVariant to_variant(any_member<Input> const& x, Input const& row,
std::string const& col) const = 0;
+ virtual std::string from_variant(wxVariant const& x) const = 0;
+ virtual char const* variant_type() const = 0;
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&
representative_value) const = 0;
+
+ static renderer_type_convertor const& get(any_member<Input> const& value);
+
+ private:
+ template<typename T>
+ static renderer_type_convertor const& get_impl();
+};
+
+
+class renderer_bool_convertor : public renderer_type_convertor
+{
+ virtual wxVariant to_variant(any_member<Input> const& x, Input const&,
std::string const&) const
+ {
+ mce_yes_or_no const* val = member_cast<mce_yes_or_no>(x);
+ if(val->value() == mce_yes)
+ return true;
else
- {
- std::string s = view_.cell_parms()[row][all_headers()[col -
1]].str();
- variant = s;
- }
+ return false;
}
- virtual bool SetValueByRow(wxVariant const&, unsigned int, unsigned int)
+ virtual std::string from_variant(wxVariant const& x) const
{
- // in-place editing not yet implemented
- return false;
+ mce_yes_or_no val(x.GetBool() ? mce_yes : mce_no);
+ return val.str();
}
- virtual unsigned int GetColumnCount() const
+ virtual char const* variant_type() const
{
- return all_headers().size() + 1;
+ return "bool";
}
- virtual wxString GetColumnType(unsigned int) const
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&) const
+ {
+ return new(wx) wxDataViewToggleRenderer("bool",
wxDATAVIEW_CELL_ACTIVATABLE, wxALIGN_CENTER);
+ }
+};
+
+
+class renderer_enum_convertor : public renderer_type_convertor
+{
+ virtual wxVariant to_variant(any_member<Input> const& x, Input const&,
std::string const&) const
+ {
+ return wxString(x.str());
+ }
+
+ virtual std::string from_variant(wxVariant const& x) const
+ {
+ return x.GetString().ToStdString();
+ }
+
+ virtual char const* variant_type() const
{
return "string";
}
- private:
- std::vector<std::string> const& all_headers() const
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&
representative_value) const
+ {
+ mc_enum_base const* as_enum =
member_cast<mc_enum_base>(representative_value);
+
+ std::vector<std::string> const& all_strings =
as_enum->get_all_strings();
+ wxArrayString choices;
+ choices.assign(all_strings.begin(), all_strings.end());
+ return new(wx) wxDataViewChoiceRenderer(choices,
wxDATAVIEW_CELL_EDITABLE);
+ }
+};
+
+
+class renderer_sequence_convertor : public renderer_type_convertor
+{
+ public:
+ virtual wxVariant to_variant(any_member<Input> const& x, Input const& row,
std::string const& col) const
+ {
+ return new(wx) input_sequence_variant_data(x.str(), &row, col);
+ }
+
+ virtual std::string from_variant(wxVariant const& x) const
+ {
+ input_sequence_variant_data const* data =
dynamic_cast<input_sequence_variant_data*>(x.GetData());
+ LMI_ASSERT(data);
+ return data->value;
+ }
+
+ virtual char const* variant_type() const
{
- return view_.case_parms()[0].member_names();
+ return typeid(input_sequence_variant_data).name();
}
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&) const
+ {
+ return new(wx) DatumSequenceRenderer();
+ }
+};
+
+
+class renderer_range_convertor : public renderer_type_convertor
+{
+ public:
+ virtual wxVariant to_variant(any_member<Input> const& x, Input const&,
std::string const&) const
+ {
+ tn_range_base const* as_range = member_cast<tn_range_base>(x);
+ LMI_ASSERT(as_range);
+ return new(wx) tn_range_variant_data(*as_range);
+ }
+
+ virtual std::string from_variant(wxVariant const& x) const
+ {
+ tn_range_variant_data const* data =
dynamic_cast<tn_range_variant_data*>(x.GetData());
+ LMI_ASSERT(data);
+ return data->value;
+ }
+
+ virtual char const* variant_type() const
+ {
+ return typeid(tn_range_variant_data).name();
+ }
+};
+
+class renderer_int_range_convertor : public renderer_range_convertor
+{
+ public:
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&) const
+ {
+ return new(wx) IntSpinRenderer();
+ }
+};
+
+class renderer_double_range_convertor : public renderer_range_convertor
+{
+ public:
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&) const
+ {
+ return new(wx) DoubleSpinRenderer();
+ }
+};
+
+class renderer_date_convertor : public renderer_range_convertor
+{
+ public:
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&) const
+ {
+ return new(wx) DateRenderer();
+ }
+};
+
+
+class renderer_fallback_convertor : public renderer_type_convertor
+{
+ public:
+ virtual wxVariant to_variant(any_member<Input> const& x, Input const&,
std::string const&) const
+ {
+ return wxString(x.str());
+ }
+
+ virtual std::string from_variant(wxVariant const& x) const
+ {
+ return x.GetString().ToStdString();
+ }
+
+ virtual char const* variant_type() const
+ {
+ return "string";
+ }
+
+ virtual wxDataViewRenderer* create_renderer(any_member<Input> const&) const
+ {
+ return new(wx) wxDataViewTextRenderer("string",
wxDATAVIEW_CELL_EDITABLE);
+ }
+};
+
+
+renderer_type_convertor const& renderer_type_convertor::get(any_member<Input>
const& value)
+{
+ mc_enum_base const* as_enum = NULL;
+ datum_sequence const* as_sequence = NULL;
+ tn_range_base const* as_range = NULL;
+
+ if(typeid(mce_yes_or_no Input::*) == value.type())
+ {
+ return get_impl<renderer_bool_convertor>();
+ }
+ else if(0 != (as_enum = try_member_cast<mc_enum_base>(value)))
+ {
+ return get_impl<renderer_enum_convertor>();
+ }
+ else if(0 != (as_sequence = try_member_cast<datum_sequence>(value)))
+ {
+ return get_impl<renderer_sequence_convertor>();
+ }
+ else if(0 != (as_range = try_member_cast<tn_range_base>(value)))
+ {
+ if(typeid(int) == as_range->value_type())
+ return get_impl<renderer_int_range_convertor>();
+ else if(typeid(double) == as_range->value_type())
+ return get_impl<renderer_double_range_convertor>();
+ else if(typeid(calendar_date) == as_range->value_type())
+ return get_impl<renderer_date_convertor>();
+ // else: fall through
+ }
+
+ return get_impl<renderer_fallback_convertor>();
+}
+
+template<typename T>
+renderer_type_convertor const& renderer_type_convertor::get_impl()
+{
+ static const T singleton;
+ return singleton;
+}
+
+} // Unnamed namespace.
+
+/// Interface to the data for wxDataViewCtrl.
+
+class CensusViewDataViewModel : public wxDataViewIndexListModel
+{
+ public:
+ static unsigned int const Col_CellNum = 0;
+
+ CensusViewDataViewModel(CensusView& view)
+ :view_(view)
+ {
+ }
+
+ virtual void GetValueByRow(wxVariant& variant, unsigned int row, unsigned
int col) const;
+ virtual bool SetValueByRow(wxVariant const&, unsigned int, unsigned int);
+
+ virtual unsigned int GetColumnCount() const;
+
+ virtual wxString GetColumnType(unsigned int col) const;
+
+ std::string const& col_name(unsigned col) const;
+ any_member<Input>& cell_at(unsigned row, unsigned col);
+ any_member<Input> const& cell_at(unsigned row, unsigned col) const;
+
+ private:
+ std::vector<std::string> const& all_headers() const;
+
CensusView& view_;
};
+void CensusViewDataViewModel::GetValueByRow(wxVariant& variant, unsigned row,
unsigned col) const
+{
+ if(col == Col_CellNum)
+ {
+ variant = static_cast<long>(1 + row);
+ }
+ else
+ {
+ any_member<Input> const& cell = cell_at(row, col);
+ renderer_type_convertor const& conv =
renderer_type_convertor::get(cell);
+ Input const& row_data = view_.cell_parms()[row];
+
+ variant = conv.to_variant(cell, row_data, col_name(col));
+ }
+}
+
+bool CensusViewDataViewModel::SetValueByRow(wxVariant const& variant, unsigned
row, unsigned col)
+{
+ LMI_ASSERT(col != Col_CellNum);
+
+ any_member<Input>& cell = cell_at(row, col);
+ renderer_type_convertor const& conv = renderer_type_convertor::get(cell);
+
+ std::string const prev_val = cell.str();
+ std::string new_val = conv.from_variant(variant);
+
+ if(prev_val == new_val)
+ return false;
+
+ cell = new_val;
+
+ view_.document().Modify(true);
+
+ return true;
+}
+
+unsigned int CensusViewDataViewModel::GetColumnCount() const
+{
+ return all_headers().size() + 1;
+}
+
+wxString CensusViewDataViewModel::GetColumnType(unsigned int col) const
+{
+ if(col == Col_CellNum)
+ {
+ return "long";
+ }
+ else
+ {
+ any_member<Input> const& representative_value = cell_at(0, col);
+ renderer_type_convertor const& conv =
renderer_type_convertor::get(representative_value);
+
+ return conv.variant_type();
+ }
+}
+
+std::string const& CensusViewDataViewModel::col_name(unsigned col) const
+{
+ LMI_ASSERT(col > 0);
+ return all_headers()[col - 1];
+}
+
+inline any_member<Input>& CensusViewDataViewModel::cell_at(unsigned row,
unsigned col)
+{
+ return view_.cell_parms()[row][col_name(col)];
+}
+
+inline any_member<Input> const& CensusViewDataViewModel::cell_at(unsigned row,
unsigned col) const
+{
+ return view_.cell_parms()[row][col_name(col)];
+}
+
+inline std::vector<std::string> const& CensusViewDataViewModel::all_headers()
const
+{
+ return view_.case_parms()[0].member_names();
+}
+
+
IMPLEMENT_DYNAMIC_CLASS(CensusView, ViewEx)
BEGIN_EVENT_TABLE(CensusView, ViewEx)
@@ -184,11 +825,6 @@ CensusView::CensusView()
{
}
-CensusView::~CensusView()
-{
- list_model_->DecRef();
-}
-
inline std::vector<Input>& CensusView::case_parms()
{
return document().doc_.case_parms_;
@@ -302,7 +938,7 @@ wxWindow* CensusView::CreateChildWindow()
// on the screen over slightly improved readability.
list_window_->SetRowHeight(list_window_->GetCharHeight() + 1);
- list_window_->AssociateModel(list_model_);
+ list_window_->AssociateModel(list_model_.get());
// Show headers.
document().Modify(false);
@@ -564,7 +1200,7 @@ void CensusView::update_visible_columns()
,new(wx) wxDataViewTextRenderer("string", wxDATAVIEW_CELL_INERT)
,CensusViewDataViewModel::Col_CellNum
,width
- ,wxALIGN_NOT
+ ,wxALIGN_LEFT
,wxDATAVIEW_COL_RESIZABLE
)
);
@@ -585,13 +1221,18 @@ void CensusView::update_visible_columns()
|| column_value_varies_across_cells(*i, cell_parms ())
)
{
+ any_member<Input> const& representative_value =
list_model_->cell_at(0, 1 + column);
+
+ wxDataViewRenderer* renderer =
renderer_type_convertor::get(representative_value).create_renderer(representative_value);
+ LMI_ASSERT(renderer);
+
list_window_->AppendColumn
(new(wx) wxDataViewColumn
(insert_spaces_between_words(*i)
- ,new(wx) wxDataViewTextRenderer("string",
wxDATAVIEW_CELL_INERT)
+ ,renderer
,1 + column
,width
- ,wxALIGN_NOT
+ ,wxALIGN_LEFT
,wxDATAVIEW_COL_RESIZABLE
)
);
diff --git a/census_view.hpp b/census_view.hpp
index ae34e91..35d9c8a 100644
--- a/census_view.hpp
+++ b/census_view.hpp
@@ -58,7 +58,6 @@ class CensusView
public:
CensusView();
- virtual ~CensusView();
private:
void update_visible_columns();
@@ -140,7 +139,7 @@ class CensusView
bool was_cancelled_;
wxDataViewCtrl* list_window_;
- CensusViewDataViewModel* list_model_;
+ wxObjectDataPtr<CensusViewDataViewModel> list_model_;
DECLARE_DYNAMIC_CLASS(CensusView)
DECLARE_EVENT_TABLE()
--
Regards,
Vaclav