[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] sequence input editor -- how to get accepted keywords
From: |
Vaclav Slavik |
Subject: |
Re: [lmi] sequence input editor -- how to get accepted keywords |
Date: |
Fri, 11 Jun 2010 11:47:21 +0200 |
On Thu, 2010-05-13 at 17:38 +0000, Greg Chicares wrote:
> This seems to be the central question. It's really hard for me to
> answer without seeing your (unfinished) code. But if that's not ready
> to share yet
I think it mostly is now. You can see the patch, including some (Linux)
screenshots of the control, here:
http://review.bakefile.org/r/210/diff/
Downloadable patch is here:
http://review.bakefile.org/r/210/diff/raw/
I'm including it below, too.
There are two problems with the patch that I didn't address yet:
(1) The code depends on wx-2.9, because it uses wxTextEntry, which is a
new base class for wxTextCtrl (used for keywords-less entry) and
wxComboBox (used when keywords are available). Unless you plan to
migrate to 2.9 soon anyway (do you?), I'll fix this.
(2) Keywords-only fields aren't supported. If the model has such fields,
then they should use read-only wxComboBox.
Then there's the gross hack with accesssing the model in
InputSequenceEntry::UponOpenEditor(), but I don't know how else to do it
now.
Also, I only converted the Payment field for now; I can do more of them
if you agree with the general approach, but I would need some
hand-holding, as I am unfamiliar with the model.
Regards,
Vaclav
Index: Makefile.am
===================================================================
--- Makefile.am (revision 4971)
+++ Makefile.am (working copy)
@@ -164,6 +164,7 @@ lmi_wx_SOURCES = \
icon_monger.cpp \
illustration_document.cpp \
illustration_view.cpp \
+ input_sequence_entry.cpp \
main_common.cpp \
main_wx.cpp \
mec_document.cpp \
@@ -249,6 +250,7 @@ liblmi_common_sources = \
database.cpp \
datum_base.cpp \
datum_boolean.cpp \
+ datum_sequence.cpp \
datum_string.cpp \
dbdict.cpp \
dbnames.cpp \
@@ -900,6 +902,7 @@ noinst_HEADERS = \
database_view_editor.hpp \
datum_base.hpp \
datum_boolean.hpp \
+ datum_sequence.hpp \
datum_string.hpp \
dbdict.hpp \
dbindex.hpp \
@@ -936,6 +939,7 @@ noinst_HEADERS = \
input.hpp \
input_seq_helpers.hpp \
input_sequence.hpp \
+ input_sequence_entry.hpp \
interest_rates.hpp \
istream_to_string.hpp \
ledger.hpp \
Index: datum_sequence.hpp
===================================================================
--- datum_sequence.hpp (revision 0)
+++ datum_sequence.hpp (revision 0)
@@ -0,0 +1,90 @@
+// Sequence string input class for wx data-transfer framework.
+//
+// Copyright (C) 2010 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifndef datum_sequence_hpp
+#define datum_sequence_hpp
+
+#include "config.hpp"
+
+#include "datum_string.hpp"
+#include "value_cast.hpp"
+
+#include <map>
+
+class datum_sequence : public datum_string
+{
+ public:
+ datum_sequence();
+ explicit datum_sequence(std::string const& s);
+
+ datum_sequence& operator=(std::string const& s);
+
+ void allow_keywords(bool allow) { allow_keywords_ = allow; }
+
+ virtual std::map<std::string,std::string> const keywords() const;
+
+ protected:
+ bool allow_keywords_;
+};
+
+template<>
+inline datum_sequence value_cast<datum_sequence,std::string>
+ (std::string const& from)
+{
+ return datum_sequence(from);
+}
+
+template<>
+inline std::string value_cast<std::string,datum_sequence>
+ (datum_sequence const& from)
+{
+ return from.value();
+}
+
+
+class payment_sequence : public datum_sequence
+{
+ public:
+ payment_sequence() {}
+ explicit payment_sequence(std::string const& s) : datum_sequence(s) {}
+
+ payment_sequence& operator=(std::string const& s);
+
+ virtual std::map<std::string,std::string> const keywords() const;
+};
+
+template<>
+inline payment_sequence value_cast<payment_sequence,std::string>
+ (std::string const& from)
+{
+ return payment_sequence(from);
+}
+
+template<>
+inline std::string value_cast<std::string,payment_sequence>
+ (payment_sequence const& from)
+{
+ return from.value();
+}
+
+#endif // datum_sequence_hpp
Index: datum_sequence.cpp
===================================================================
--- datum_sequence.cpp (revision 0)
+++ datum_sequence.cpp (revision 0)
@@ -0,0 +1,96 @@
+// Sequence string input class for wx data-transfer framework.
+//
+// Copyright (C) 2010 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifdef __BORLANDC__
+# include "pchfile.hpp"
+# pragma hdrstop
+#endif // __BORLANDC__
+
+#include "datum_sequence.hpp"
+
+datum_sequence::datum_sequence()
+ :allow_keywords_(true)
+{
+}
+
+datum_sequence::datum_sequence(std::string const& s)
+ :datum_string(s), allow_keywords_(true)
+{
+}
+
+datum_sequence& datum_sequence::operator=(std::string const& s)
+{
+ datum_string::operator=(s);
+ return *this;
+}
+
+std::map<std::string,std::string> const datum_sequence::keywords() const
+{
+ // TODO !! Make this function pure virtual so that datum_sequence is
+ // abstract class. This can only be done after all derived types are
+ // implemented
+ return std::map<std::string,std::string>();
+}
+
+
+payment_sequence& payment_sequence::operator=(std::string const& s)
+{
+ datum_sequence::operator=(s);
+ return *this;
+}
+
+std::map<std::string,std::string> const payment_sequence::keywords() const
+{
+ if(!allow_keywords_)
+ return std::map<std::string,std::string>();
+
+ static std::map<std::string,std::string> all_keywords;
+ if(all_keywords.empty())
+ {
+ all_keywords["minimum" ] = "PmtMinimum" ;
+ all_keywords["target" ] = "PmtTarget" ;
+ all_keywords["sevenpay"] = "PmtMEP" ;
+ all_keywords["glp" ] = "PmtGLP" ;
+ all_keywords["gsp" ] = "PmtGSP" ;
+ all_keywords["corridor"] = "PmtCorridor" ;
+ all_keywords["table" ] = "PmtTable" ;
+ all_keywords["none" ] = "PmtInputScalar" ;
+ }
+ std::map<std::string,std::string> permissible_keywords = all_keywords;
+ permissible_keywords.erase("none");
+
+ bool payment_indeterminate =
+ (
+ false
+ // TODO ?? Further conditions to disallow improper input:
+ // need to compare corresponding years.
+ // || specamt strategy is neither 'none' nor 'salary-based'
+ );
+
+ if(payment_indeterminate)
+ {
+ permissible_keywords.clear();
+ }
+
+ return permissible_keywords;
+}
Index: input.hpp
===================================================================
--- input.hpp (revision 4971)
+++ input.hpp (working copy)
@@ -31,6 +31,7 @@
#include "any_member.hpp"
#include "ce_product_name.hpp"
#include "datum_boolean.hpp"
+#include "datum_sequence.hpp"
#include "datum_string.hpp"
#include "mc_enum.hpp"
#include "mc_enum_types.hpp"
@@ -50,10 +51,6 @@ class product_database;
#include <string>
#include <vector>
-/// Eventually it may become important to distinguish strings that
-/// represent input sequences, for interactive validation.
-
-typedef datum_string datum_sequence;
/// Design notes for class input.
///
@@ -203,7 +200,6 @@ class LMI_SO Input
std::map<std::string,std::string> const
permissible_specified_amount_strategy_keywords();
std::map<std::string,std::string> const
permissible_death_benefit_option_keywords();
- std::map<std::string,std::string> const
permissible_payment_strategy_keywords();
std::map<std::string,std::string> const
permissible_payment_mode_keywords();
std::string RealizeExtraMonthlyCustodialFee ();
@@ -396,9 +392,9 @@ class LMI_SO Input
datum_sequence ProjectedSalary ;
datum_sequence SpecifiedAmount ;
datum_sequence DeathBenefitOption ;
- datum_sequence Payment ;
+ payment_sequence Payment ;
datum_sequence PaymentMode ;
- datum_sequence CorporationPayment ;
+ payment_sequence CorporationPayment ;
datum_sequence CorporationPaymentMode ;
datum_sequence GeneralAccountRate ;
datum_sequence SeparateAccountRate ;
@@ -504,6 +500,7 @@ template<> struct reconstitutor<datum_base, Input>
{
DesiredType* z = 0;
z = exact_cast<ce_product_name >(m); if(z) return z;
+ z = exact_cast<datum_sequence >(m); if(z) return z;
z = exact_cast<datum_string >(m); if(z) return z;
z = exact_cast<mce_gen_basis >(m); if(z) return z;
z = exact_cast<mce_class >(m); if(z) return z;
@@ -536,6 +533,7 @@ template<> struct reconstitutor<datum_base, Input>
z = exact_cast<mce_to_point >(m); if(z) return z;
z = exact_cast<mce_uw_basis >(m); if(z) return z;
z = exact_cast<mce_yes_or_no >(m); if(z) return z;
+ z = exact_cast<payment_sequence >(m); if(z) return z;
z = exact_cast<tnr_attained_age >(m); if(z) return z;
z = exact_cast<tnr_corridor_factor >(m); if(z) return z;
z = exact_cast<tnr_date >(m); if(z) return z;
@@ -550,5 +548,20 @@ template<> struct reconstitutor<datum_base, Input>
}
};
+/// Specialization of struct template reconstitutor for this Model
+/// and the datum_sequence base class.
+
+template<> struct reconstitutor<datum_sequence, Input>
+{
+ typedef datum_sequence DesiredType;
+ static DesiredType* reconstitute(any_member<Input>& m)
+ {
+ DesiredType* z = 0;
+ z = exact_cast<datum_sequence >(m); if(z) return z;
+ z = exact_cast<payment_sequence >(m); if(z) return z;
+ return z;
+ }
+};
+
#endif // input_hpp
Index: input_harmonization.cpp
===================================================================
--- input_harmonization.cpp (revision 4971)
+++ input_harmonization.cpp (working copy)
@@ -596,6 +596,8 @@ false // Silly workaround for now.
Payment .enable(mce_solve_ee_prem != SolveType);
CorporationPayment.enable(mce_solve_er_prem != SolveType);
+ Payment .allow_keywords(mce_solve_ee_prem != SolveType);
+ CorporationPayment.allow_keywords(mce_solve_er_prem != SolveType);
IndividualPaymentMode.allow_all(true);
// TODO ?? Should the following be permitted? If so, then either
Index: input_realization.cpp
===================================================================
--- input_realization.cpp (revision 4971)
+++ input_realization.cpp (working copy)
@@ -194,41 +194,6 @@ Input::permissible_death_benefit_option_keywords()
//============================================================================
std::map<std::string,std::string> const
-Input::permissible_payment_strategy_keywords()
-{
- static std::map<std::string,std::string> all_keywords;
- if(all_keywords.empty())
- {
- all_keywords["minimum" ] = "PmtMinimum" ;
- all_keywords["target" ] = "PmtTarget" ;
- all_keywords["sevenpay"] = "PmtMEP" ;
- all_keywords["glp" ] = "PmtGLP" ;
- all_keywords["gsp" ] = "PmtGSP" ;
- all_keywords["corridor"] = "PmtCorridor" ;
- all_keywords["table" ] = "PmtTable" ;
- all_keywords["none" ] = "PmtInputScalar" ;
- }
- std::map<std::string,std::string> permissible_keywords = all_keywords;
- permissible_keywords.erase("none");
-
- bool payment_indeterminate =
- (
- false
- // TODO ?? Further conditions to disallow improper input:
- // need to compare corresponding years.
- // || specamt strategy is neither 'none' nor 'salary-based'
- );
-
- if(payment_indeterminate)
- {
- permissible_keywords.clear();
- }
-
- return permissible_keywords;
-}
-
-//============================================================================
-std::map<std::string,std::string> const
Input::permissible_payment_mode_keywords()
{
static std::map<std::string,std::string> all_keywords;
@@ -636,17 +601,12 @@ std::string Input::RealizeDeathBenefitOption()
//============================================================================
std::string Input::RealizePayment()
{
- std::map<std::string,std::string> z =
permissible_payment_strategy_keywords();
- if(mce_solve_ee_prem == SolveType)
- {
- z.clear();
- }
return realize_sequence_string
(*this
,PaymentRealized_
,PaymentStrategyRealized_
,Payment
- ,z
+ ,Payment.keywords()
,std::string("none")
);
}
@@ -670,18 +630,12 @@ std::string Input::RealizePaymentMode()
//============================================================================
std::string Input::RealizeCorporationPayment()
{
- std::map<std::string,std::string> z =
permissible_payment_strategy_keywords();
- if(mce_solve_er_prem == SolveType)
- {
- z.clear();
- }
-
return realize_sequence_string
(*this
,CorporationPaymentRealized_
,CorporationPaymentStrategyRealized_
,CorporationPayment
- ,z
+ ,CorporationPayment.keywords()
,std::string("none")
);
}
Index: input_sequence_entry.hpp
===================================================================
--- input_sequence_entry.hpp (revision 0)
+++ input_sequence_entry.hpp (revision 0)
@@ -0,0 +1,72 @@
+// Input sequences user-friendly editor.
+//
+// Copyright (C) 2010 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifndef input_sequence_entry_hpp
+#define input_sequence_entry_hpp
+
+#include "config.hpp"
+
+#include "input_sequence.hpp"
+
+#include <wx/panel.h>
+#include <wx/xrc/xmlres.h>
+
+class WXDLLIMPEXP_FWD_CORE wxButton;
+class WXDLLIMPEXP_FWD_CORE wxTextCtrl;
+
+class InputSequenceEntry
+ :public wxPanel
+{
+ public:
+ InputSequenceEntry();
+ InputSequenceEntry(wxWindow* parent, wxWindowID id, wxString const& name);
+ bool Create(wxWindow* parent, wxWindowID id, wxString const& name);
+
+ wxTextCtrl& text_ctrl() { return *text_; }
+
+ void set_popup_title(const wxString& title) { title_ = title; }
+
+ private:
+ void UponOpenEditor(wxCommandEvent&);
+
+ private:
+ wxTextCtrl* text_;
+ wxButton* button_;
+ wxString title_;
+};
+
+class InputSequenceEntryXmlHandler
+ :public wxXmlResourceHandler
+{
+ public:
+ InputSequenceEntryXmlHandler();
+
+ private:
+ virtual wxObject* DoCreateResource();
+ virtual bool CanHandle(wxXmlNode* node);
+
+ DECLARE_DYNAMIC_CLASS(InputSequenceEntryXmlHandler)
+};
+
+#endif // input_sequence_entry_hpp
+
Index: input_sequence_entry.cpp
===================================================================
--- input_sequence_entry.cpp (revision 0)
+++ input_sequence_entry.cpp (revision 0)
@@ -0,0 +1,995 @@
+// Input sequences user-friendly editor.
+//
+// Copyright (C) 2010 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifdef __BORLANDC__
+# include "pchfile.hpp"
+# pragma hdrstop
+#endif // __BORLANDC__
+
+#include "input_sequence_entry.hpp"
+
+#include "alert.hpp"
+#include "assert_lmi.hpp"
+#include "input.hpp"
+#include "input_sequence.hpp"
+#include "input_seq_helpers.hpp"
+#include "mvc_controller.hpp"
+#include "value_cast.hpp"
+#include "wx_new.hpp"
+#include "wx_utility.hpp"
+
+#include <wx/button.h>
+#include <wx/bmpbuttn.h>
+#include <wx/choice.h>
+#include <wx/combobox.h>
+#include <wx/dialog.h>
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+#include <wx/valtext.h>
+#include <wx/wupdlock.h>
+
+#include <algorithm> // std::copy(), std::find()
+#include <iterator> // std::back_inserter
+#include <map>
+#include <vector>
+
+namespace
+{
+
+class DurationModeChoice
+ :public wxChoice
+{
+ public:
+ DurationModeChoice(wxWindow* parent);
+
+ void value(duration_mode x);
+ duration_mode value() const;
+
+ void allow_maturity(bool allow);
+ bool needs_number() const;
+};
+
+struct choice_value
+{
+ duration_mode mode;
+ const char* label;
+};
+
+choice_value duration_mode_choice_values[] =
+ {
+ {e_retirement, "until retirement"},
+ {e_attained_age, "until age"},
+ {e_duration, "until duration"},
+ {e_number_of_years, "for a period of"},
+ {e_maturity, "until maturity"} // e_maturity must be last
+ };
+
+unsigned const duration_mode_choices = sizeof(duration_mode_choice_values) /
sizeof(choice_value);
+
+DurationModeChoice::DurationModeChoice(wxWindow* parent)
+{
+ Create(parent, wxID_ANY);
+
+ for(unsigned i = 0; i < duration_mode_choices; ++i)
+ {
+ Append(duration_mode_choice_values[i].label);
+ }
+
+ // "maturity" is the default
+ value(e_maturity);
+}
+
+void DurationModeChoice::allow_maturity(bool allow)
+{
+ LMI_ASSERT(e_maturity ==
duration_mode_choice_values[duration_mode_choices-1].mode);
+
+ if(allow == (duration_mode_choices == GetCount()))
+ return;
+
+ // "until maturity" is the last entry
+ if(allow)
+ Append(duration_mode_choice_values[duration_mode_choices-1].label);
+ else
+ Delete(duration_mode_choices-1);
+
+}
+
+void DurationModeChoice::value(duration_mode x)
+{
+ for(unsigned i = 0; i < duration_mode_choices; ++i)
+ {
+ if(x == duration_mode_choice_values[i].mode)
+ {
+ SetSelection(i);
+ return;
+ }
+ }
+
+ fatal_error() << "unexpected duration_mode value" << LMI_FLUSH;
+}
+
+duration_mode DurationModeChoice::value() const
+{
+ const int sel = GetSelection();
+
+ LMI_ASSERT(sel >= 0);
+ LMI_ASSERT(sel < static_cast<int>(duration_mode_choices));
+
+ return duration_mode_choice_values[sel].mode;
+}
+
+bool DurationModeChoice::needs_number() const
+{
+ switch(value())
+ {
+ case e_attained_age:
+ case e_duration:
+ case e_number_of_years:
+ return true;
+
+ case e_invalid_mode:
+ case e_inception:
+ case e_inforce:
+ case e_retirement:
+ case e_maturity:
+ return false;
+ }
+}
+
+
+class InputSequenceEditor
+ :public wxDialog
+{
+ public:
+ InputSequenceEditor(wxWindow* parent, wxString const& title, Input const&
input);
+
+ void set_keywords(std::vector<std::string> const& keywords)
+ {
+ keywords_ = keywords;
+ }
+
+ void sequence(InputSequence const& s);
+ std::string sequence_string();
+
+ private:
+ void add_row();
+ void insert_row(int row);
+ void remove_row(int row);
+ void update_row(int row);
+ void redo_layout();
+ wxString format_from_text(int row);
+
+ enum Col
+ {
+ Col_Value,
+ Col_From,
+ Col_DurationMode,
+ Col_DurationNum,
+ Col_Then,
+ Col_Remove,
+ Col_Add,
+ Col_Max
+ };
+ static int const COLUMNS_COUNT = Col_Max;
+
+ wxTextEntry& value_field(int row)
+ {
+ return get_field<wxTextEntry>(Col_Value, row);
+ }
+
+ wxControl& value_field_ctrl(int row)
+ {
+ return get_field<wxControl>(Col_Value, row);
+ }
+
+ wxStaticText& from_field(int row)
+ {
+ return get_field<wxStaticText>(Col_From, row);
+ }
+
+ DurationModeChoice& duration_mode_field(int row)
+ {
+ return get_field<DurationModeChoice>(Col_DurationMode, row);
+ }
+
+ wxTextCtrl& duration_num_field(int row)
+ {
+ return get_field<wxTextCtrl>(Col_DurationNum, row);
+ }
+
+ wxStaticText& then_field(int row)
+ {
+ return get_field<wxStaticText>(Col_Then, row);
+ }
+
+ wxButton& remove_button(int row)
+ {
+ return get_field<wxButton>(Col_Remove, row);
+ }
+
+ wxButton& add_button(int row)
+ {
+ return get_field<wxButton>(Col_Add, row);
+ }
+
+ template<typename T>
+ T& get_field(int col, int row);
+
+ int compute_duration_scalar(int row);
+ void adjust_duration_num(int row);
+
+ void UponDurationModeChange(wxCommandEvent& event);
+ void UponDurationNumChange(wxCommandEvent& event);
+ void UponRemoveRow(wxCommandEvent& event);
+ void UponAddRow(wxCommandEvent& event);
+
+ Input const& input_;
+ std::vector<std::string> keywords_;
+
+ int rows_count_;
+ wxFlexGridSizer* sizer_;
+ wxButton* last_button_;
+ typedef std::map<wxWindowID, int> id_to_row_map;
+ id_to_row_map id_to_row_;
+
+ // scalar absolute values for end durations; this is used to recompute
+ // duration number for certain duration modes
+ std::vector<int> duration_scalars_;
+};
+
+
+InputSequenceEditor::InputSequenceEditor(wxWindow* parent, wxString const&
title, Input const& input)
+ :wxDialog
+ (parent
+ ,wxID_ANY
+ ,title
+ ,wxDefaultPosition
+ ,wxDefaultSize
+ ,wxDEFAULT_DIALOG_STYLE
+ )
+ ,input_(input)
+ ,rows_count_(0)
+{
+ wxSizer *top = new(wx) wxBoxSizer(wxVERTICAL);
+
+ sizer_ = new(wx) wxFlexGridSizer(/*cols=*/Col_Max, /*vgap=*/5, /*hgap=*/5);
+ top->Add(sizer_, wxSizerFlags(1).Expand().DoubleBorder());
+
+ wxStdDialogButtonSizer *buttons = new(wx) wxStdDialogButtonSizer();
+ buttons->AddButton(new(wx) wxButton(this, wxID_OK));
+ buttons->AddButton(last_button_ = new(wx) wxButton(this, wxID_CANCEL));
+ buttons->Realize();
+
+ top->Add(buttons, wxSizerFlags().Expand().Border());
+
+ SetSizerAndFit(top);
+
+ add_row();
+
+ value_field_ctrl(0).SetFocus();
+
+ ::Connect
+ (this
+ ,wxEVT_COMMAND_CHOICE_SELECTED
+ ,&InputSequenceEditor::UponDurationModeChange
+ );
+ ::Connect
+ (this
+ ,wxEVT_COMMAND_TEXT_UPDATED
+ ,&InputSequenceEditor::UponDurationNumChange
+ );
+}
+
+void InputSequenceEditor::sequence(InputSequence const& s)
+{
+ while(rows_count_ > 0)
+ remove_row(0);
+
+ std::vector<ValueInterval> const& intervals = s.interval_representation();
+ const int num_intervals = intervals.size();
+
+ if(intervals.empty())
+ {
+ // have single row (initial state)
+ add_row();
+ return;
+ }
+
+ LMI_ASSERT(0 == intervals.front().begin_duration);
+ LMI_ASSERT(e_maturity == intervals.back().end_mode);
+ for(int i = 1; i < num_intervals; ++i)
+ {
+ LMI_ASSERT(intervals[i].begin_duration == intervals[i-1].end_duration);
+ }
+
+ for(int i = 0; i < num_intervals; ++i)
+ {
+ ValueInterval const& data = intervals[i];
+ LMI_ASSERT(!data.insane);
+
+ add_row();
+
+ duration_mode_field(i).value(data.end_mode);
+
+ int dur_num;
+ switch(data.end_mode)
+ {
+ case e_number_of_years:
+ {
+ dur_num = data.end_duration - data.begin_duration;
+ }
+ break;
+ case e_attained_age:
+ {
+ dur_num = input_.issue_age() + data.end_duration;
+ }
+ break;
+
+ case e_invalid_mode:
+ case e_duration:
+ case e_inception:
+ case e_inforce:
+ case e_retirement:
+ case e_maturity:
+ {
+ dur_num = data.end_duration;
+ }
+ }
+
+
duration_num_field(i).SetValue(value_cast<std::string>(dur_num).c_str());
+
+ if(data.value_is_keyword)
+ {
+ value_field(i).SetValue(data.value_keyword.c_str());
+ }
+ else
+ {
+
value_field(i).SetValue(value_cast<std::string>(data.value_number).c_str());
+ }
+ }
+
+ // move focus to a reasonable place
+ value_field_ctrl(0).SetFocus();
+}
+
+
+std::string InputSequenceEditor::sequence_string()
+{
+ std::string s;
+
+ for(int i = 0; i < rows_count_; ++i)
+ {
+ if(!s.empty())
+ s.append("; ");
+
+ s.append(value_field(i).GetValue().c_str());
+
+ switch(duration_mode_field(i).value())
+ {
+ case e_retirement:
+ {
+ s.append(" retirement");
+ break;
+ }
+ case e_attained_age:
+ {
+ s.append(" @");
+ s.append(duration_num_field(i).GetValue().c_str());
+ break;
+ }
+ case e_duration:
+ {
+ s.append(" ");
+ s.append(duration_num_field(i).GetValue().c_str());
+ break;
+ }
+ case e_number_of_years:
+ {
+ s.append(" #");
+ s.append(duration_num_field(i).GetValue().c_str());
+ break;
+ }
+ case e_maturity:
+ {
+ LMI_ASSERT(i == rows_count_ - 1);
+ // " maturity" is implicit, don't add it
+ break;
+ }
+
+ case e_invalid_mode:
+ case e_inception:
+ case e_inforce:
+ {
+ fatal_error() << "unexpected duration_mode value" << LMI_FLUSH;
+ return "";
+ }
+ }
+ }
+
+ return s;
+}
+
+
+void SizeWinForText(wxWindow *win, const wxString& text, int extra = 0)
+{
+ int x, y;
+ win->GetTextExtent(text, &x, &y);
+ win->SetMinSize(wxSize(x+extra, -1));
+}
+
+void InputSequenceEditor::add_row()
+{
+ insert_row(rows_count_);
+}
+
+void InputSequenceEditor::insert_row(int row)
+{
+ int insert_pos = Col_Max * row;
+
+#ifdef __WXMSW__
+ wxWindowUpdateLocker no_updates(this);
+#endif
+
+ int const prev_row = rows_count_ - 1;
+ int const new_row = rows_count_;
+
+ // Employee payment:
+ // [ 0] from issue date until [year] [ 5], then
+ // [1000] from year 5 until [year] [10], then
+ // [ 0] from year 10 until [ age] [70], then
+ // [ 0] from age 70 until [maturity].
+
+ #define LARGEST_FROM_TEXT "from duration 999 + 999 years"
+ #define LARGEST_THEN_TEXT "years, then"
+
+ wxSizerFlags const flags = wxSizerFlags().Align(wxALIGN_LEFT |
wxALIGN_CENTRE_VERTICAL);
+
+ wxControl *value_ctrl;
+ if(!keywords_.empty())
+ {
+ wxComboBox *combo = new(wx) wxComboBox(this, wxID_ANY, "0");
+ value_ctrl = combo;
+
+ wxArrayString kw;
+ std::copy(keywords_.begin(), keywords_.end(), std::back_inserter(kw));
+ combo->Append(kw);
+#if wxCHECK_VERSION(2,9,0)
+ combo->AutoComplete(kw);
+#endif
+ }
+ else
+ {
+ // No keywords, only numeric values
+ value_ctrl = new(wx) wxTextCtrl(this, wxID_ANY, "0");
+ value_ctrl->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
+ }
+
+ sizer_->Insert(insert_pos++, value_ctrl,
wxSizerFlags(flags).TripleBorder(wxRIGHT));
+ wxStaticText *from_label = new(wx) wxStaticText(this, wxID_ANY,
LARGEST_FROM_TEXT);
+ SizeWinForText(from_label, LARGEST_FROM_TEXT);
+ sizer_->Insert(insert_pos++, from_label, flags);
+ sizer_->Insert(insert_pos++, new(wx) DurationModeChoice(this), flags);
+ wxTextCtrl *duration_num = new(wx) wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, wxTE_RIGHT);
+ duration_num->SetValidator(wxTextValidator(wxFILTER_DIGITS));
+ sizer_->Insert(insert_pos++, duration_num, flags);
+ SizeWinForText(duration_num, "999", 20);
+ wxStaticText *then_label = new(wx) wxStaticText(this, wxID_ANY,
LARGEST_THEN_TEXT);
+ sizer_->Insert(insert_pos++, then_label, flags);
+ SizeWinForText(then_label, LARGEST_THEN_TEXT);
+
+ wxButton *remove = new(wx) wxButton
+ (this
+ ,wxID_REMOVE
+ ,"Remove"
+ ,wxDefaultPosition
+ ,wxDefaultSize
+ ,wxBU_AUTODRAW | wxBU_EXACTFIT | wxBORDER_NONE
+ );
+
+ remove->SetToolTip("Remove this row");
+ remove->MoveBeforeInTabOrder(last_button_);
+ remove->Connect
+ (wxEVT_COMMAND_BUTTON_CLICKED
+ ,wxCommandEventHandler(InputSequenceEditor::UponRemoveRow)
+ ,NULL
+ ,this
+ );
+ sizer_->Insert(insert_pos++, remove,
wxSizerFlags(flags).TripleBorder(wxLEFT));
+
+ wxButton *add = new(wx) wxButton
+ (this
+ ,wxID_ADD
+ ,"Add"
+ ,wxDefaultPosition
+ ,wxDefaultSize
+ ,wxBU_AUTODRAW | wxBU_EXACTFIT | wxBORDER_NONE
+ );
+
+ add->SetToolTip("Insert a new row after this one");
+ add->MoveBeforeInTabOrder(last_button_);
+ add->Connect
+ (wxEVT_COMMAND_BUTTON_CLICKED
+ ,wxCommandEventHandler(InputSequenceEditor::UponAddRow)
+ ,NULL
+ ,this
+ );
+ sizer_->Insert(insert_pos++, add, wxSizerFlags(flags).Border(wxLEFT,
0).Right());
+
+
+ // keep track of which windows belong to which rows
+ for(int i = 0; i < Col_Max; ++i)
+ id_to_row_[get_field<wxWindow>(i, new_row).GetId()] = new_row;
+
+ if(rows_count_ == 0)
+ {
+ sizer_->SetMinSize(sizer_->CalcMin());
+ }
+
+ rows_count_++;
+ duration_scalars_.insert(duration_scalars_.begin() + new_row, -1);
+
+ // update state of controls on the two rows affected by addition of
+ // a new row
+ if(prev_row!=-1)
+ update_row(prev_row);
+ update_row(new_row);
+
+ redo_layout();
+}
+
+void InputSequenceEditor::remove_row(int row)
+{
+#ifdef __WXMSW__
+ wxWindowUpdateLocker no_updates(this);
+#endif
+
+ duration_scalars_.erase(duration_scalars_.begin() + row);
+ rows_count_--;
+
+ // remove all controls from the row
+ for(int i = 0; i < Col_Max; ++i)
+ {
+ int index = row * Col_Max;
+ wxWindow* win = sizer_->GetItem(index)->GetWindow();
+ sizer_->Detach(index);
+ win->Destroy();
+ }
+
+ redo_layout();
+
+ // update id_to_row_ mapping:
+ for(id_to_row_map::iterator i = id_to_row_.begin()
+ ;i != id_to_row_.end()
+ ;++i)
+ {
+ if(i->second>row)
+ i->second = i->second - 1;
+ }
+
+ // update the row following the one we just removed and the one before it,
+ // as well as all subsequent rows (because many "from ..." lines may be
+ // affected):
+ for(int i = wxMax(0, row - 1); i < rows_count_; i++)
+ update_row(i); // for "from ..." text
+}
+
+void InputSequenceEditor::update_row(int row)
+{
+#ifdef __WXMSW__
+ wxWindowUpdateLocker no_updates(this);
+#endif
+
+ bool const is_last_row = (row == rows_count_ - 1);
+
+ // update duration_scalars_ to reflect current UI state
+ duration_scalars_[row] = compute_duration_scalar(row);
+
+ // "from" column:
+ from_field(row).SetLabel(format_from_text(row));
+
+ // "maturity" should be an option only on the last row:
+ duration_mode_field(row).allow_maturity(is_last_row);
+
+ // duration number visibility:
+ duration_num_field(row).Show(duration_mode_field(row).needs_number());
+
+ if ( duration_mode_field(row).value() == e_number_of_years )
+ {
+ // ", then" is not shown on the last row:
+ if(is_last_row)
+ then_field(row).SetLabel("years");
+ else
+ then_field(row).SetLabel("years, then");
+ }
+ else
+ {
+ // ", then" is not shown on the last row:
+ if(is_last_row)
+ then_field(row).SetLabel("");
+ else
+ then_field(row).SetLabel(", then");
+ }
+
+ // remove/add buttons aren't shown on the last row:
+ remove_button(row).Show(!is_last_row);
+ add_button(row).Show(!is_last_row);
+
+ redo_layout();
+}
+
+void InputSequenceEditor::redo_layout()
+{
+ wxSizer *sizer = GetSizer();
+ sizer->Layout();
+ sizer->Fit(this);
+ sizer->SetSizeHints(this);
+}
+
+wxString InputSequenceEditor::format_from_text(int row)
+{
+ if(row==0)
+ return "from issue date";
+
+ duration_mode mode = duration_mode_field(row-1).value();
+ long num = 0;
+ if(duration_mode_field(row-1).needs_number())
+ {
+ if(!duration_num_field(row-1).GetValue().ToLong(&num))
+ return "";
+ }
+
+ switch(mode)
+ {
+ case e_retirement:
+ {
+ return "from retirement";
+ }
+ case e_attained_age:
+ {
+ return wxString::Format("from age %ld", num);
+ }
+ case e_duration:
+ {
+ return wxString::Format("from duration %ld", num);
+ }
+ case e_number_of_years:
+ {
+ long yrs = 0;
+ int i = row-1;
+ while(i >= 0 && duration_mode_field(i).value() ==
e_number_of_years)
+ {
+ long num_i = 0;
+ duration_num_field(i).GetValue().ToLong(&num_i);
+ yrs += num_i;
+ i--;
+ }
+ return wxString::Format("%s + %ld years",
+ format_from_text(i+1).c_str(),
+ yrs);
+ }
+ case e_maturity:
+ case e_invalid_mode:
+ case e_inception:
+ case e_inforce:
+ {
+ fatal_error() << "unexpected duration_mode value" << LMI_FLUSH;
+ return "";
+ }
+ }
+}
+
+template<typename T>
+T& InputSequenceEditor::get_field(int col, int row)
+{
+ wxSizerItem* i = sizer_->GetItem(col + Col_Max * row);
+ LMI_ASSERT(i);
+
+ wxWindow* w = i->GetWindow();
+ LMI_ASSERT(w);
+
+ T* t = dynamic_cast<T*>(w);
+ LMI_ASSERT(t);
+
+ return *t;
+}
+
+int InputSequenceEditor::compute_duration_scalar(int row)
+{
+ long duration_num = -1;
+ wxString const duration_num_str = duration_num_field(row).GetValue();
+ if(duration_num_str.empty())
+ duration_num = 0;
+ else
+ duration_num_str.ToLong(&duration_num);
+ LMI_ASSERT(-1 != duration_num);
+
+ switch(duration_mode_field(row).value())
+ {
+ case e_retirement:
+ {
+ return input_.retirement_age() - input_.issue_age();
+ }
+ case e_attained_age:
+ {
+ return duration_num - input_.issue_age();
+ }
+ case e_duration:
+ {
+ return duration_num;
+ }
+ case e_number_of_years:
+ {
+ if(row == 0)
+ return duration_num;
+ else
+ return compute_duration_scalar(row - 1) + duration_num;
+ }
+ case e_maturity:
+ {
+ return input_.years_to_maturity();
+ }
+
+ case e_invalid_mode:
+ case e_inception:
+ case e_inforce:
+ {
+ fatal_error() << "unexpected duration_mode value" << LMI_FLUSH;
+ return 0;
+ }
+ }
+}
+
+void InputSequenceEditor::adjust_duration_num(int row)
+{
+ int const scalar = duration_scalars_[row];
+ int num = -1;
+
+ switch(duration_mode_field(row).value())
+ {
+ case e_attained_age:
+ {
+ num = scalar + input_.issue_age();
+ break;
+ }
+ case e_duration:
+ {
+ num = scalar;
+ break;
+ }
+ case e_number_of_years:
+ {
+ if(row == 0)
+ num = scalar;
+ else
+ num = scalar - duration_scalars_[row - 1];
+ break;
+ }
+
+ case e_invalid_mode:
+ case e_inception:
+ case e_inforce:
+ case e_retirement:
+ case e_maturity:
+ {
+ return; // no visible number field to update
+ }
+ }
+
+ duration_num_field(row).SetValue(wxString::Format("%d", num));
+}
+
+void InputSequenceEditor::UponDurationModeChange(wxCommandEvent& event)
+{
+ int row = id_to_row_[event.GetId()];
+
+ adjust_duration_num(row);
+
+ update_row(row);
+
+ if(row == rows_count_-1)
+ {
+ if(duration_mode_field(row).value() != e_maturity)
+ add_row();
+ }
+ else
+ {
+ for(int i = row + 1; i < rows_count_; i++)
+ update_row(i); // for "from ..." text
+ }
+}
+
+void InputSequenceEditor::UponDurationNumChange(wxCommandEvent& event)
+{
+ int row = id_to_row_[event.GetId()];
+
+ for(int i = row; i < rows_count_; i++)
+ update_row(i); // for "from ..." text and duration_scalars_
+}
+
+void InputSequenceEditor::UponRemoveRow(wxCommandEvent& event)
+{
+ int row = id_to_row_[event.GetId()];
+ remove_row(row);
+}
+
+void InputSequenceEditor::UponAddRow(wxCommandEvent& event)
+{
+ int prev_row = id_to_row_[event.GetId()];
+ int new_row = prev_row + 1;
+
+ insert_row(new_row);
+
+ // as a reasonable default for the value, use previous row's
+ value_field(new_row).SetValue(value_field(prev_row).GetValue());
+
+ // the best choice for the new row is e_number_of_years, so choose it;
+ // set focus to the number to adjust it immediately
+ duration_mode_field(new_row).value(e_number_of_years);
+ for(int i = new_row; i < rows_count_; i++)
+ update_row(i);
+
+ duration_num_field(new_row).SetFocus();
+}
+
+} // anonymous namespace
+
+
+InputSequenceEntry::InputSequenceEntry()
+{
+}
+
+InputSequenceEntry::InputSequenceEntry
+ (wxWindow* parent
+ ,wxWindowID id
+ ,wxString const& name
+ )
+{
+ Create(parent, id, name);
+}
+
+bool InputSequenceEntry::Create
+ (wxWindow* parent
+ ,wxWindowID id
+ ,wxString const& name
+ )
+{
+ title_ = "Edit Sequence";
+
+ if ( !wxPanel::Create(parent, id) )
+ return false;
+
+ SetName(name);
+
+ wxSizer *sizer = new(wx) wxBoxSizer(wxHORIZONTAL);
+
+ text_ = new(wx) wxTextCtrl(this, wxID_ANY);
+ button_ = new(wx) wxButton
+ (this
+ ,wxID_ANY
+ ,"..."
+ ,wxDefaultPosition
+ ,wxDefaultSize
+ ,wxBU_EXACTFIT
+ );
+ button_->SetToolTip("Open sequence editor");
+
+ sizer->Add(text_, wxSizerFlags(1).Expand());
+ sizer->Add(button_, wxSizerFlags().Expand().Border(wxLEFT, 1));
+
+ SetSizer(sizer);
+
+ button_->Connect
+ (wxEVT_COMMAND_BUTTON_CLICKED
+ ,wxCommandEventHandler(InputSequenceEntry::UponOpenEditor)
+ ,NULL
+ ,this
+ );
+
+ return true;
+}
+
+void InputSequenceEntry::UponOpenEditor(wxCommandEvent&)
+{
+ MvcController const* tlw = dynamic_cast<MvcController
const*>(wxGetTopLevelParent(this));
+ LMI_ASSERT(tlw);
+ Input const* input = dynamic_cast<Input const*>(&tlw->Model());
+ LMI_ASSERT(input);
+
+ // Center the window on the [...] button for best locality -- it will be
+ // close to user's point of attention and the mouse cursor.
+ InputSequenceEditor editor(button_, title_, *input);
+ editor.CentreOnParent();
+
+ std::string sequence_string = std::string(text_->GetValue());
+ if(!sequence_string.empty())
+ {
+ std::string const name(GetName().c_str());
+ const datum_sequence* ds =
member_cast<datum_sequence>(input->operator[](name));
+ LMI_ASSERT(ds);
+
+ std::map<std::string,std::string> const kwmap = ds->keywords();
+ std::vector<std::string> const keywords =
+ detail::extract_keys_from_string_map(kwmap);
+
+ editor.set_keywords(keywords);
+
+ InputSequence sequence
+ (sequence_string
+ ,input->years_to_maturity()
+ ,input->issue_age ()
+ ,input->retirement_age ()
+ ,input->inforce_year ()
+ ,input->effective_year ()
+ ,0
+ ,keywords
+ );
+
+ std::string const diagnostics = sequence.formatted_diagnostics();
+ if(!diagnostics.empty())
+ {
+ warning() << "The sequence is invalid and cannot be edited
visually.\n"
+ << "Please clear or fix it, then try again.\n\n"
+ << diagnostics << LMI_FLUSH;
+ return;
+ }
+
+ editor.sequence(sequence);
+ }
+
+ if(wxID_OK == editor.ShowModal())
+ {
+ text_->SetValue(editor.sequence_string());
+ }
+}
+
+IMPLEMENT_DYNAMIC_CLASS(InputSequenceEntryXmlHandler, wxXmlResourceHandler)
+
+InputSequenceEntryXmlHandler::InputSequenceEntryXmlHandler()
+ :wxXmlResourceHandler()
+{
+ AddWindowStyles();
+}
+
+wxObject* InputSequenceEntryXmlHandler::DoCreateResource()
+{
+ XRC_MAKE_INSTANCE(control, InputSequenceEntry)
+
+ control->Create
+ (m_parentAsWindow
+ ,GetID()
+ ,GetName()
+ );
+
+ SetupWindow(control);
+
+ if(HasParam("title"))
+ control->set_popup_title(GetText("title"));
+
+ return control;
+}
+
+bool InputSequenceEntryXmlHandler::CanHandle(wxXmlNode* node)
+{
+ return IsOfClass(node, "InputSequenceEntry");
+}
Index: main_wx.cpp
===================================================================
--- main_wx.cpp (revision 4971)
+++ main_wx.cpp (working copy)
@@ -61,6 +61,7 @@
#include "icon_monger.hpp"
#include "illustration_document.hpp"
#include "illustration_view.hpp"
+#include "input_sequence_entry.hpp" // InputSequenceEntryXmlHandler
#include "license.hpp"
#include "main_common.hpp"
#include "mec_document.hpp"
@@ -646,6 +647,7 @@ bool Skeleton::OnInit()
// TODO ?? Should not it be moved directly into rounding_view.hpp
// or rounding_view_editor.hpp?
xml_resources.AddHandler(new(wx) RoundingButtonsXmlHandler);
+ xml_resources.AddHandler(new(wx) InputSequenceEntryXmlHandler);
DefaultView const v0;
#if wxCHECK_VERSION(2,9,0)
Index: mec.xrc
===================================================================
--- mec.xrc (revision 4971)
+++ mec.xrc (working copy)
@@ -654,7 +654,8 @@ here, but it looks weird if we don't make this look like
its siblings.
<object class="sizeritem">
<flag>wxGROW|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxLEFT</flag>
<border>4</border>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Payment</help>
<size>80,-1</size>
</object>
Index: mec_input.hpp
===================================================================
--- mec_input.hpp (revision 4971)
+++ mec_input.hpp (working copy)
@@ -31,6 +31,7 @@
#include "any_member.hpp"
#include "ce_product_name.hpp"
#include "datum_boolean.hpp"
+#include "datum_sequence.hpp"
#include "datum_string.hpp"
#include "mc_enum.hpp"
#include "mc_enum_types.hpp"
@@ -49,11 +50,6 @@ class product_database;
#include <string>
#include <vector>
-/// Eventually it may become important to distinguish strings that
-/// represent input sequences, for interactive validation.
-
-typedef datum_string datum_sequence;
-
/// This class is the Model of the MVC framework for MEC testing.
///
/// See general notes on class Input.
@@ -193,6 +189,7 @@ template<> struct reconstitutor<datum_base, mec_input>
{
DesiredType* z = 0;
z = exact_cast<ce_product_name >(m); if(z) return z;
+ z = exact_cast<datum_sequence >(m); if(z) return z;
z = exact_cast<datum_string >(m); if(z) return z;
z = exact_cast<mce_class >(m); if(z) return z;
z = exact_cast<mce_defn_life_ins >(m); if(z) return z;
@@ -203,6 +200,7 @@ template<> struct reconstitutor<datum_base, mec_input>
z = exact_cast<mce_table_rating >(m); if(z) return z;
z = exact_cast<mce_uw_basis >(m); if(z) return z;
z = exact_cast<mce_yes_or_no >(m); if(z) return z;
+ z = exact_cast<payment_sequence >(m); if(z) return z;
z = exact_cast<tnr_date >(m); if(z) return z;
z = exact_cast<tnr_duration >(m); if(z) return z;
z = exact_cast<tnr_issue_age >(m); if(z) return z;
Index: mvc_controller.hpp
===================================================================
--- mvc_controller.hpp (revision 4971)
+++ mvc_controller.hpp (working copy)
@@ -421,6 +421,8 @@ class MvcController
void TestModelViewConsistency() const;
+ const MvcModel& Model() const { return model_; }
+
private:
void Assimilate(std::string const& name_to_ignore);
void Bind(std::string const& name, std::string& data) const;
Index: objects.make
===================================================================
--- objects.make (revision 4971)
+++ objects.make (working copy)
@@ -188,6 +188,7 @@ common_common_objects := \
database.o \
datum_base.o \
datum_boolean.o \
+ datum_sequence.o \
datum_string.o \
dbdict.o \
dbnames.o \
@@ -306,6 +307,7 @@ lmi_wx_objects := \
icon_monger.o \
illustration_document.o \
illustration_view.o \
+ input_sequence_entry.o \
main_common.o \
main_wx.o \
mec_document.o \
Index: skin.xrc
===================================================================
--- skin.xrc (revision 4971)
+++ skin.xrc (working copy)
@@ -2368,7 +2368,8 @@ the other is perforce ignored.
</object>
<object class="sizeritem">
<flag>wxGROW</flag>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor, glp,
gsp, minimum, sevenpay, table, target</help>
<size>180,-1</size>
</object>
Index: skin_coli_boli.xrc
===================================================================
--- skin_coli_boli.xrc (revision 4971)
+++ skin_coli_boli.xrc (working copy)
@@ -2350,7 +2350,8 @@ useful in the future.
<object class="sizeritem">
<flag>wxGROW|wxBOTTOM</flag>
<border>2</border>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor, glp,
gsp, minimum, sevenpay, table, target</help>
</object>
</object>
Index: skin_group_carveout.xrc
===================================================================
--- skin_group_carveout.xrc (revision 4971)
+++ skin_group_carveout.xrc (working copy)
@@ -1513,7 +1513,8 @@
<object class="sizeritem">
<flag>wxGROW|wxBOTTOM</flag>
<border>2</border>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor, glp,
gsp, minimum, sevenpay, table, target</help>
</object>
</object>
Index: skin_group_carveout2.xrc
===================================================================
--- skin_group_carveout2.xrc (revision 4971)
+++ skin_group_carveout2.xrc (working copy)
@@ -1065,7 +1065,8 @@
<object class="sizeritem">
<flag>wxGROW|wxBOTTOM</flag>
<border>2</border>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor, glp,
gsp, minimum, sevenpay, table, target</help>
</object>
</object>
Index: skin_reg_d.xrc
===================================================================
--- skin_reg_d.xrc (revision 4971)
+++ skin_reg_d.xrc (working copy)
@@ -777,7 +777,8 @@ the real 'StateOfJurisdiction' is implemented.
<object class="sizeritem">
<flag>wxGROW|wxALL</flag>
<border>4</border>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor,
glp, gsp, minimum, sevenpay, table, target</help>
</object>
</object>
Index: skin_single_premium.xrc
===================================================================
--- skin_single_premium.xrc (revision 4971)
+++ skin_single_premium.xrc (working copy)
@@ -985,7 +985,8 @@
</object>
<object class="sizeritem">
<flag>wxGROW</flag>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor, glp,
gsp, minimum, sevenpay, table, target</help>
<size>180,-1</size>
</object>
Index: skin_variable_annuity.xrc
===================================================================
--- skin_variable_annuity.xrc (revision 4971)
+++ skin_variable_annuity.xrc (working copy)
@@ -349,7 +349,8 @@ useful in the future.
<object class="sizeritem">
<flag>wxGROW|wxLEFT|wxRIGHT</flag>
<border>2</border>
- <object class="wxTextCtrl" name="Payment">
+ <object class="InputSequenceEntry" name="Payment">
+ <title>Edit Payment</title>
<help>Individual payment amount, or corridor,
glp, gsp, minimum, sevenpay, table, target</help>
</object>
</object>
Index: transferor.cpp
===================================================================
--- transferor.cpp (revision 4971)
+++ transferor.cpp (working copy)
@@ -38,6 +38,7 @@
#include "alert.hpp"
#include "calendar_date.hpp"
+#include "input_sequence_entry.hpp"
#include "numeric_io_cast.hpp"
#include "wx_utility.hpp"
@@ -65,22 +66,23 @@ IMPLEMENT_CLASS(Transferor, wxValidator)
namespace
{
- bool Transfer(transfer_direction, std::string&, wxButton& );
- bool Transfer(transfer_direction, std::string&, wxCheckBox& );
- bool Transfer(transfer_direction, std::string&, wxCheckListBox& );
- bool Transfer(transfer_direction, std::string&, wxChoice& );
- bool Transfer(transfer_direction, std::string&, wxComboBox& );
- bool Transfer(transfer_direction, std::string&, wxDatePickerCtrl& );
- bool Transfer(transfer_direction, std::string&, wxGauge& );
- bool Transfer(transfer_direction, std::string&, wxListBox& );
- bool Transfer(transfer_direction, std::string&, wxRadioBox& );
- bool Transfer(transfer_direction, std::string&, wxRadioButton& );
- bool Transfer(transfer_direction, std::string&, wxScrollBar& );
- bool Transfer(transfer_direction, std::string&, wxSlider& );
- bool Transfer(transfer_direction, std::string&, wxSpinButton& );
- bool Transfer(transfer_direction, std::string&, wxSpinCtrl& );
- bool Transfer(transfer_direction, std::string&, wxStaticText& );
- bool Transfer(transfer_direction, std::string&, wxTextCtrl& );
+ bool Transfer(transfer_direction, std::string&, wxButton& );
+ bool Transfer(transfer_direction, std::string&, wxCheckBox& );
+ bool Transfer(transfer_direction, std::string&, wxCheckListBox& );
+ bool Transfer(transfer_direction, std::string&, wxChoice& );
+ bool Transfer(transfer_direction, std::string&, wxComboBox& );
+ bool Transfer(transfer_direction, std::string&, wxDatePickerCtrl& );
+ bool Transfer(transfer_direction, std::string&, wxGauge& );
+ bool Transfer(transfer_direction, std::string&, wxListBox& );
+ bool Transfer(transfer_direction, std::string&, wxRadioBox& );
+ bool Transfer(transfer_direction, std::string&, wxRadioButton& );
+ bool Transfer(transfer_direction, std::string&, wxScrollBar& );
+ bool Transfer(transfer_direction, std::string&, wxSlider& );
+ bool Transfer(transfer_direction, std::string&, wxSpinButton& );
+ bool Transfer(transfer_direction, std::string&, wxSpinCtrl& );
+ bool Transfer(transfer_direction, std::string&, wxStaticText& );
+ bool Transfer(transfer_direction, std::string&, wxTextCtrl& );
+ bool Transfer(transfer_direction, std::string&, InputSequenceEntry& );
} // Unnamed namespace.
Transferor::Transferor(std::string& data, std::string const& name)
@@ -141,22 +143,23 @@ bool Transferor::PerformTransfer(transfer_direction td)
}
wxWindowBase* control = m_validatorWindow;
- wxButton * button ;
- wxCheckBox * checkbox ;
- wxCheckListBox * checklistbox ;
- wxComboBox * combobox ;
- wxChoice * choice ;
- wxDatePickerCtrl * datepicker ;
- wxGauge * gauge ;
- wxListBox * listbox ;
- wxRadioBox * radiobox ;
- wxRadioButton * radiobutton ;
- wxScrollBar * scrollbar ;
- wxSlider * slider ;
- wxSpinButton * spinbutton ;
- wxSpinCtrl * spinctrl ;
- wxStaticText * statictext ;
- wxTextCtrl * textctrl ;
+ wxButton * button ;
+ wxCheckBox * checkbox ;
+ wxCheckListBox * checklistbox ;
+ wxComboBox * combobox ;
+ wxChoice * choice ;
+ wxDatePickerCtrl * datepicker ;
+ wxGauge * gauge ;
+ wxListBox * listbox ;
+ wxRadioBox * radiobox ;
+ wxRadioButton * radiobutton ;
+ wxScrollBar * scrollbar ;
+ wxSlider * slider ;
+ wxSpinButton * spinbutton ;
+ wxSpinCtrl * spinctrl ;
+ wxStaticText * statictext ;
+ wxTextCtrl * textctrl ;
+ InputSequenceEntry * sequence ;
if (0 != (button = dynamic_cast<wxButton *>(control)))
return Transfer(td, data_, *button );
@@ -190,6 +193,8 @@ bool Transferor::PerformTransfer(transfer_direction td)
return Transfer(td, data_, *statictext );
else if(0 != (textctrl = dynamic_cast<wxTextCtrl *>(control)))
return Transfer(td, data_, *textctrl );
+ else if(0 != (sequence = dynamic_cast<InputSequenceEntry *>(control)))
+ return Transfer(td, data_, *sequence );
else
{
fatal_error()
@@ -449,5 +454,10 @@ namespace
}
return true;
}
+
+ bool Transfer(transfer_direction td, std::string& data,
InputSequenceEntry& control)
+ {
+ return Transfer(td, data, control.text_ctrl());
+ }
} // Unnamed namespace.
- Re: [lmi] sequence input editor -- how to get accepted keywords, Vaclav Slavik, 2010/06/01
- Re: [lmi] sequence input editor -- how to get accepted keywords,
Vaclav Slavik <=
- Re: [lmi] sequence input editor -- how to get accepted keywords, Greg Chicares, 2010/06/16
- Re: [lmi] sequence input editor -- how to get accepted keywords, Vaclav Slavik, 2010/06/17
- Re: [lmi] sequence input editor -- how to get accepted keywords, Greg Chicares, 2010/06/17
- Re: [lmi] sequence input editor -- how to get accepted keywords, Vaclav Slavik, 2010/06/18
- Re: [lmi] sequence input editor -- how to get accepted keywords, Greg Chicares, 2010/06/25
- Re: [lmi] sequence input editor -- how to get accepted keywords, Greg Chicares, 2010/06/25
- Re[2]: [lmi] sequence input editor -- how to get accepted keywords, Vadim Zeitlin, 2010/06/26
- Re: Re[2]: [lmi] sequence input editor -- how to get accepted keywords, Vaclav Slavik, 2010/06/26
- Re: [lmi] sequence input editor -- how to get accepted keywords, Greg Chicares, 2010/06/26
- Re: [lmi] sequence input editor -- how to get accepted keywords, Vaclav Slavik, 2010/06/27