lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] [PATCH 1/2] Make InputSequenceEntry friendly to embedding in w


From: Vaclav Slavik
Subject: Re: [lmi] [PATCH 1/2] Make InputSequenceEntry friendly to embedding in wxDVC.
Date: Tue, 05 Jul 2011 15:11:23 +0200
User-agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.15) Gecko/20110303 Thunderbird/3.1.9

Hi,

On 2011-06-29 18:34, Vaclav Slavik wrote:
> this patch makes the InputSequenceEntry composite control behave more like a
> "normal" control with regard to focus changes and input events. 
> wxDataViewCtrl wants
> to intercept these events so that it knows when to close an inline editor 
> control
> and this change makes it handle InputSequenceEntry correctly.

Please replace this with an updated version:

commit 2806dea06f88c781fcf304beb6e22e6f1b752074
Author: Vaclav Slavik <address@hidden>
Date:   Fri Apr 29 10:26:53 2011 +0200

    Make InputSequenceEntry friendly to embedding in wxDVC.

diff --git a/input_sequence_entry.cpp b/input_sequence_entry.cpp
--- a/input_sequence_entry.cpp
+++ b/input_sequence_entry.cpp
@@ -190,9 +190,16 @@ class InputSequenceEditor
         default_keyword_ = default_keyword;
     }
 
+    void associate_text_ctrl(wxTextCtrl* t)
+    {
+        associated_text_ctrl_ = t;
+    }
+
     void sequence(InputSequence const& s);
     std::string sequence_string();
 
+    virtual void EndModal(int retCode);
+
   private:
     void add_row();
     void insert_row(int row);
@@ -281,6 +288,8 @@ class InputSequenceEditor
     // scalar absolute values for end durations; this is used to recompute
     // duration number for certain duration modes
     std::vector<int> duration_scalars_;
+
+    wxTextCtrl *associated_text_ctrl_;
 };
 
 InputSequenceEditor::InputSequenceEditor(wxWindow* parent, wxString const& 
title, Input const& input)
@@ -1002,9 +1011,96 @@ void InputSequenceEditor::UponAddRow(wxCommandEvent& 
event)
 
     duration_num_field(new_row).SetFocus();
 }
+
+void InputSequenceEditor::EndModal(int retCode)
+{
+    // We need to set the value as soon as possible -- when used in 
wxDataViewCtrl, the value
+    // is read from editor control as soon as focus changes, which is before 
ShowModal() returns.
+    if(associated_text_ctrl_ && retCode == wxID_OK)
+        associated_text_ctrl_->SetValue(sequence_string());
+
+    wxDialog::EndModal(retCode);
+}
+
+class InputSequenceTextCtrl
+    :public wxTextCtrl
+{
+  public:
+    InputSequenceTextCtrl(wxWindow* parent, wxWindowID id);
+
+  private:
+    void UponKillFocus(wxFocusEvent& event);
+    void UponChar(wxKeyEvent& event);
+};
+
+InputSequenceTextCtrl::InputSequenceTextCtrl(wxWindow* parent, wxWindowID id)
+    :wxTextCtrl(parent, id)
+{
+    ::Connect
+            (this
+            ,wxEVT_KILL_FOCUS
+            ,&InputSequenceTextCtrl::UponKillFocus
+            );
+    ::Connect
+            (this
+            ,wxEVT_CHAR
+            ,&InputSequenceTextCtrl::UponChar
+            );
+}
+
+void InputSequenceTextCtrl::UponKillFocus(wxFocusEvent& event)
+{
+    if(0 == event.GetWindow() || event.GetWindow()->GetParent() != GetParent())
+        GetParent()->ProcessWindowEvent(event);
+    event.Skip();
+}
+
+void InputSequenceTextCtrl::UponChar(wxKeyEvent& event)
+{
+    if(!GetParent()->ProcessWindowEvent(event))
+        event.Skip();
+}
+
+
+class InputSequenceButton
+    :public wxButton
+{
+  public:
+    InputSequenceButton(wxWindow* parent, wxWindowID id);
+
+  private:
+    void UponKillFocus(wxFocusEvent& event);
+};
+
+InputSequenceButton::InputSequenceButton(wxWindow* parent, wxWindowID id)
+    :wxButton(parent, id, "...", wxDefaultPosition, wxDefaultSize, 
wxBU_EXACTFIT)
+{
+    ::Connect
+            (this
+            ,wxEVT_KILL_FOCUS
+            ,&InputSequenceButton::UponKillFocus
+            );
+
+    SetToolTip("Open sequence editor");
+}
+
+void InputSequenceButton::UponKillFocus(wxFocusEvent& event)
+{
+    // Don't notify the parent (and thus wxDataViewCtrl) of focus change if 
its within this
+    // InputSequenceEntry composite control or a InputSequenceEditor window 
opened from it.
+    if(0 == event.GetWindow() ||
+       (event.GetWindow()->GetParent() != GetParent() &&
+        wxGetTopLevelParent(event.GetWindow())->GetParent() != this))
+        {
+        GetParent()->ProcessWindowEvent(event);
+        }
+    event.Skip();
+}
+
 } // Unnamed namespace.
 
 InputSequenceEntry::InputSequenceEntry()
+    :input_(0)
 {
 }
 
@@ -1013,6 +1109,7 @@ InputSequenceEntry::InputSequenceEntry
     ,wxWindowID         id
     ,wxString const&    name
     )
+    :input_(0)
 {
     Create(parent, id, name);
 }
@@ -1034,16 +1131,8 @@ bool InputSequenceEntry::Create
 
     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");
+    text_ = new(wx) InputSequenceTextCtrl(this, wxID_ANY);
+    button_ = new(wx) InputSequenceButton(this, wxID_ANY);
 
     sizer->Add(text_, wxSizerFlags(1).Expand());
     sizer->Add(button_, wxSizerFlags().Expand().Border(wxLEFT, 1));
@@ -1060,21 +1149,64 @@ bool InputSequenceEntry::Create
     return true;
 }
 
+void InputSequenceEntry::input(Input const& input)
+{
+    input_ = &input;
+}
+
+Input const& InputSequenceEntry::input() const
+{
+    if(input_)
+        {
+        return *input_;
+        }
+    else
+        {
+        // MvcController's design uses editor controls that only have local
+        // knowledge of the value they directly edit. This isn't an
+        // unreasonable assumption and e.g. wxDataViewCtrl does the same.
+        // Unfortunately, it doesn't fit InputSequenceEditor, which needs
+        // additional information about the Input instance the sequence is used
+        // in. Hence this hack -- it gets the Input from the parent
+        // MvcController if used inside one.
+        MvcController const* tlw = dynamic_cast<MvcController 
const*>(wxGetTopLevelParent(const_cast<InputSequenceEntry*>(this)));
+        LMI_ASSERT(tlw);
+        Input const* input = dynamic_cast<Input const*>(&tlw->Model());
+        LMI_ASSERT(input);
+
+        return *input;
+        }
+}
+
+void InputSequenceEntry::field_name(std::string const& name)
+{
+    field_name_ = name;
+}
+
+std::string InputSequenceEntry::field_name() const
+{
+    if(!field_name_.empty())
+        {
+        return field_name_;
+        }
+    else
+        {
+        // see the explanation in input()
+        return std::string(GetName().c_str());
+        }
+}
+
 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);
+    Input const& in = 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);
+    InputSequenceEditor editor(button_, title_, in);
     editor.CentreOnParent();
 
     std::string sequence_string = std::string(text_->GetValue());
-    std::string const name(GetName().c_str());
-    datum_sequence const& ds = 
*member_cast<datum_sequence>(input->operator[](name));
+    datum_sequence const& ds = *member_cast<datum_sequence>(in[field_name()]);
 
     std::map<std::string,std::string> const kwmap = ds.allowed_keywords();
     std::vector<std::string> const keywords =
@@ -1089,11 +1221,11 @@ void InputSequenceEntry::UponOpenEditor(wxCommandEvent&)
 
     InputSequence sequence
         (sequence_string
-        ,input->years_to_maturity()
-        ,input->issue_age        ()
-        ,input->retirement_age   ()
-        ,input->inforce_year     ()
-        ,input->effective_year   ()
+        ,in.years_to_maturity()
+        ,in.issue_age        ()
+        ,in.retirement_age   ()
+        ,in.inforce_year     ()
+        ,in.effective_year   ()
         ,0
         ,keywords
         );
@@ -1111,10 +1243,8 @@ void InputSequenceEntry::UponOpenEditor(wxCommandEvent&)
 
     editor.sequence(sequence);
 
-    if(wxID_OK == editor.ShowModal())
-        {
-        text_->SetValue(editor.sequence_string());
-        }
+    editor.associate_text_ctrl(text_);
+    editor.ShowModal();
 }
 
 IMPLEMENT_DYNAMIC_CLASS(InputSequenceEntryXmlHandler, wxXmlResourceHandler)
diff --git a/input_sequence_entry.hpp b/input_sequence_entry.hpp
index c2f39cd..890619b 100644
--- a/input_sequence_entry.hpp
+++ b/input_sequence_entry.hpp
@@ -42,6 +42,12 @@ class InputSequenceEntry
     InputSequenceEntry(wxWindow* parent, wxWindowID id, wxString const& name);
     bool Create(wxWindow* parent, wxWindowID id, wxString const& name);
 
+    void input(Input const& input);
+    Input const& input() const;
+
+    void field_name(std::string const& name);
+    std::string field_name() const;
+
     wxTextCtrl& text_ctrl() {return *text_;}
 
     void set_popup_title(wxString const& title) {title_ = title;}
@@ -49,6 +55,9 @@ class InputSequenceEntry
   private:
     void UponOpenEditor(wxCommandEvent&);
 
+    Input const* input_;
+    std::string field_name_;
+
     wxTextCtrl* text_;
     wxButton*   button_;
     wxString    title_;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]