lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] (no subject)


From: Greg Chicares
Subject: [lmi-commits] (no subject)
Date: Sun, 29 May 2016 23:16:41 +0000 (UTC)

branch: master
commit 1436cf26b6f76de73ea9f3e6b313bebdf304f639
Author: Vadim Zeitlin <address@hidden>
Date:   Mon May 2 00:17:44 2016 +0200

    Allow switching skin while lmi is running [450]
    
    This allows to dynamically change the skin used for the parameters
    dialog while running the program and is especially useful when the same
    test needs to be performed with several different skins as it allows to
    do it without restarting.
    
    To implement this, do the following:
    
    Add ce_skin_name class representing all the available skin files in the
    same way ce_product_name represents all the available product names.
    
    Expose a field of this type corresponding to the default skin file name
    stored in configurable_settings via PreferencesModel, so that it can be
    edited in the preferences dialog.
    
    Add the necessary code to reload the skin file to the code showing the
    dialog (notice that this cannot be done in the PreferencesModel itself
    as it is completely decoupled from the code using wxXmlResource).
---
 Makefile.am               |    2 +
 ce_skin_name.cpp          |  194 +++++++++++++++++++++++++++++++++++++++++++++
 ce_skin_name.hpp          |   82 +++++++++++++++++++
 configurable_settings.cpp |    5 ++
 configurable_settings.hpp |    1 +
 objects.make              |    1 +
 preferences_model.cpp     |    5 ++
 preferences_model.hpp     |    4 +
 preferences_view.xrc      |   25 ++++++
 skeleton.cpp              |   15 +++-
 10 files changed, 333 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 6dc03f9..d73025f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -290,6 +290,7 @@ liblmi_common_sources = \
     alert.cpp \
     calendar_date.cpp \
     ce_product_name.cpp \
+    ce_skin_name.cpp \
     configurable_settings.cpp \
     crc32.cpp \
     custom_io_0.cpp \
@@ -1072,6 +1073,7 @@ noinst_HEADERS = \
     callback.hpp \
     catch_exceptions.hpp \
     ce_product_name.hpp \
+    ce_skin_name.hpp \
     census_document.hpp \
     census_view.hpp \
     comma_punct.hpp \
diff --git a/ce_skin_name.cpp b/ce_skin_name.cpp
new file mode 100644
index 0000000..db1be30
--- /dev/null
+++ b/ce_skin_name.cpp
@@ -0,0 +1,194 @@
+// A value-Constrained Enumeration for skin names.
+//
+// Copyright (C) 2016 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$
+
+#include "ce_skin_name.hpp"
+
+#include "alert.hpp"
+#include "facets.hpp"
+#include "global_settings.hpp"
+#include "path_utility.hpp" // fs::path inserter
+
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include <algorithm>
+#include <cstring>
+
+namespace
+{
+std::string const& default_skin_name()
+{
+    static std::string const default_name("default");
+    return default_name;
+}
+
+std::vector<std::string> fetch_skin_names()
+{
+    fs::path path(global_settings::instance().data_directory());
+    std::vector<std::string> names;
+    fs::directory_iterator i(path);
+    fs::directory_iterator end_i;
+    for(; i != end_i; ++i)
+        {
+        if(is_directory(*i) || ".xrc" != fs::extension(*i))
+            {
+            continue;
+            }
+        std::string const name(i->leaf());
+        // Skin files are expected to be called "skin_something.xrc" with the
+        // exception of "skin.xrc".
+        static char const* skin_prefix = "skin";
+        static std::size_t const skin_prefix_len = std::strlen(skin_prefix);
+        if(name.compare(0, skin_prefix_len, skin_prefix) != 0)
+            {
+            continue;
+            }
+        if(fs::basename(*i).length() > skin_prefix_len && 
name[skin_prefix_len] != '_')
+            {
+            continue;
+            }
+
+        names.push_back(name);
+        }
+
+    if(names.empty())
+        {
+        fatal_error()
+            << "Data directory '"
+            << path
+            << "' contains no skin files."
+            << LMI_FLUSH
+            ;
+        }
+
+    return names;
+}
+} // Unnamed namespace.
+
+ce_skin_name::ce_skin_name()
+    :mc_enum_base(skin_names().size())
+    ,value_(default_skin_name())
+{}
+
+ce_skin_name::ce_skin_name(std::string const& s)
+    :mc_enum_base(skin_names().size())
+    ,value_(skin_names()[ordinal(s)])
+{}
+
+ce_skin_name& ce_skin_name::operator=(std::string const& s)
+{
+    value_ = skin_names()[ordinal(s)];
+    return *this;
+}
+
+bool ce_skin_name::operator==(ce_skin_name const& z) const
+{
+    return z.value_ == value_;
+}
+
+bool ce_skin_name::operator==(std::string const& s) const
+{
+    return s == str();
+}
+
+std::size_t ce_skin_name::ordinal(std::string const& s)
+{
+    std::size_t v =
+            std::find
+                (skin_names().begin()
+                ,skin_names().end()
+                ,s
+                )
+        -   skin_names().begin()
+        ;
+    if(v == skin_names().size())
+        {
+        fatal_error()
+            << "Value '"
+            << s
+            << "' invalid for type '"
+            << "ce_skin_name"
+            << "'."
+            << LMI_FLUSH
+            ;
+        }
+    return v;
+}
+
+std::vector<std::string> const& ce_skin_name::all_strings() const
+{
+    return skin_names();
+}
+
+std::size_t ce_skin_name::cardinality() const
+{
+    return skin_names().size();
+}
+
+/// No skin is ever proscribed.
+
+void ce_skin_name::enforce_proscription()
+{}
+
+std::size_t ce_skin_name::ordinal() const
+{
+    return ordinal(value_);
+}
+
+std::string ce_skin_name::str(int j) const
+{
+    return skin_names()[j];
+}
+
+std::string ce_skin_name::str() const
+{
+    return value_;
+}
+
+std::string ce_skin_name::value() const
+{
+    return value_;
+}
+
+std::vector<std::string> const& ce_skin_name::skin_names()
+{
+    static std::vector<std::string> const names(fetch_skin_names());
+    return names;
+}
+
+std::istream& ce_skin_name::read(std::istream& is)
+{
+    std::locale old_locale = is.imbue(blank_is_not_whitespace_locale());
+    std::string s;
+    is >> s;
+    operator=(s);
+    is.imbue(old_locale);
+    return is;
+}
+
+std::ostream& ce_skin_name::write(std::ostream& os) const
+{
+    return os << str();
+}
+
diff --git a/ce_skin_name.hpp b/ce_skin_name.hpp
new file mode 100644
index 0000000..9650daf
--- /dev/null
+++ b/ce_skin_name.hpp
@@ -0,0 +1,82 @@
+// A value-Constrained Enumeration for skin names.
+//
+// Copyright (C) 2016 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 ce_skin_name_hpp
+#define ce_skin_name_hpp
+
+#include "config.hpp"
+
+#include "mc_enum.hpp"
+
+#include <cstddef> // std::size_t
+#include <string>
+#include <vector>
+
+/// This class encapsulates skin names. It is similar to ce_product_name in
+/// that its values are only available at run time, so there can be no compile
+/// time enum to represent them.
+///
+/// Valid values are the base names of 'skin*.xrc' product files found
+/// in the (configurable) data directory. As with ce_product_name, the valid
+/// values never change during the program lifetime and it needs to be
+/// restarted to "notice" the new skins.
+
+class ce_skin_name
+    :public mc_enum_base
+    ,private boost::equality_comparable<ce_skin_name, ce_skin_name>
+    ,private boost::equality_comparable<ce_skin_name, std::string>
+{
+  public:
+    ce_skin_name();
+    explicit ce_skin_name(std::string const&);
+
+    ce_skin_name& operator=(std::string const&);
+
+    bool operator==(ce_skin_name const&) const;
+    bool operator==(std::string const&) const;
+
+    static std::size_t ordinal(std::string const&);
+
+    // mc_enum_base required implementation.
+    virtual std::vector<std::string> const& all_strings() const;
+    virtual std::size_t cardinality() const;
+    virtual void enforce_proscription();
+    virtual std::size_t ordinal() const;
+    virtual std::string str(int) const;
+
+    std::string str() const;
+    std::string value() const;
+
+  private:
+    static std::vector<std::string> const& skin_names();
+
+    // datum_base required implementation.
+    // TODO ?? Consider moving the implementation into the base class.
+    virtual std::istream& read (std::istream&);
+    virtual std::ostream& write(std::ostream&) const;
+
+    std::string value_;
+};
+
+#endif // ce_skin_name_hpp
+
diff --git a/configurable_settings.cpp b/configurable_settings.cpp
index c4f52c5..3bc58c6 100644
--- a/configurable_settings.cpp
+++ b/configurable_settings.cpp
@@ -422,6 +422,11 @@ int 
configurable_settings::seconds_to_pause_between_printouts() const
 
 /// Name of '.xrc' interface skin.
 
+void configurable_settings::skin_filename(std::string const& skin_filename)
+{
+    skin_filename_ = skin_filename;
+}
+
 std::string const& configurable_settings::skin_filename() const
 {
     return skin_filename_;
diff --git a/configurable_settings.hpp b/configurable_settings.hpp
index 0707725..8a93497 100644
--- a/configurable_settings.hpp
+++ b/configurable_settings.hpp
@@ -56,6 +56,7 @@ class LMI_SO configurable_settings
 
     void calculation_summary_columns(std::string const&);
     void use_builtin_calculation_summary(bool);
+    void skin_filename(std::string const&);
 
     std::string const& calculation_summary_columns        () const;
     std::string const& cgi_bin_log_filename               () const;
diff --git a/objects.make b/objects.make
index b857233..24f26ea 100644
--- a/objects.make
+++ b/objects.make
@@ -181,6 +181,7 @@ common_common_objects := \
   alert.o \
   calendar_date.o \
   ce_product_name.o \
+  ce_skin_name.o \
   configurable_settings.o \
   crc32.o \
   custom_io_0.o \
diff --git a/preferences_model.cpp b/preferences_model.cpp
index ca8448a..32e247a 100644
--- a/preferences_model.cpp
+++ b/preferences_model.cpp
@@ -90,6 +90,8 @@ void PreferencesModel::AscribeMembers()
     ascribe("CalculationSummaryColumn09"  , 
&PreferencesModel::CalculationSummaryColumn09);
     ascribe("CalculationSummaryColumn10"  , 
&PreferencesModel::CalculationSummaryColumn10);
     ascribe("CalculationSummaryColumn11"  , 
&PreferencesModel::CalculationSummaryColumn11);
+
+    ascribe("SkinFileName"                , &PreferencesModel::SkinFileName);
 }
 
 void PreferencesModel::DoAdaptExternalities()
@@ -241,6 +243,8 @@ void PreferencesModel::Load()
             operator[](name) = columns[i];
             }
         }
+
+    SkinFileName = z.skin_filename();
 }
 
 std::string PreferencesModel::string_of_column_names() const
@@ -275,5 +279,6 @@ void PreferencesModel::Save() const
     configurable_settings& z = configurable_settings::instance();
     z.calculation_summary_columns(s);
     z.use_builtin_calculation_summary("Yes" == UseBuiltinCalculationSummary);
+    z.skin_filename(SkinFileName.value());
 }
 
diff --git a/preferences_model.hpp b/preferences_model.hpp
index 133c44e..07be169 100644
--- a/preferences_model.hpp
+++ b/preferences_model.hpp
@@ -27,6 +27,7 @@
 #include "mvc_model.hpp"
 
 #include "any_member.hpp"
+#include "ce_skin_name.hpp"
 #include "mc_enum.hpp"
 #include "mc_enum_types.hpp"
 #include "obstruct_slicing.hpp"
@@ -78,6 +79,8 @@ class LMI_SO PreferencesModel
     mce_report_column CalculationSummaryColumn09;
     mce_report_column CalculationSummaryColumn10;
     mce_report_column CalculationSummaryColumn11;
+
+    ce_skin_name      SkinFileName;
 };
 
 /// Specialization of struct template reconstitutor for this Model
@@ -89,6 +92,7 @@ template<> struct reconstitutor<datum_base, PreferencesModel>
     static DesiredType* reconstitute(any_member<PreferencesModel>& m)
         {
         DesiredType* z = 0;
+        z = exact_cast<ce_skin_name     >(m); if(z) return z;
         z = exact_cast<mce_report_column>(m); if(z) return z;
         z = exact_cast<mce_yes_or_no    >(m); if(z) return z;
         return z;
diff --git a/preferences_view.xrc b/preferences_view.xrc
index af0c5b4..fb5e356 100644
--- a/preferences_view.xrc
+++ b/preferences_view.xrc
@@ -214,6 +214,27 @@
     </object>
 </object>
 
+<object class="wxPanel" name="parameters_editor_panel">
+    <object class="wxBoxSizer">
+        <orient>wxVERTICAL</orient>
+        <object class="sizeritem">
+            <flag>wxALL</flag>
+            <border>5</border>
+            <object class="wxStaticText">
+                <label>Choose the skin to use for the parameters 
editor:</label>
+            </object>
+        </object>
+        <object class="sizeritem">
+            <option>1</option>
+            <flag>wxGROW|wxALL</flag>
+            <border>5</border>
+            <object class="wxListBox" name="SkinFileName">
+                <style>wxLB_SINGLE</style>
+            </object>
+        </object>
+    </object>
+</object>
+
 <object class="wxDialog" name="dialog_containing_preferences_notebook">
     <title>Preferences</title>
     <style>wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU</style>
@@ -234,6 +255,10 @@
                     <label>Calculation summary columns</label>
                     <object_ref ref="calculation_summary_panel"/>
                 </object>
+                <object class="notebookpage">
+                    <label>Parameters editor appearance</label>
+                    <object_ref ref="parameters_editor_panel"/>
+                </object>
             </object>
         </object>
         <object class="sizeritem">
diff --git a/skeleton.cpp b/skeleton.cpp
index 697015d..70e26e8 100644
--- a/skeleton.cpp
+++ b/skeleton.cpp
@@ -910,8 +910,21 @@ void Skeleton::UponPreferences(wxCommandEvent&)
     int const rc = controller.ShowModal();
     if(wxID_OK == rc && preferences.IsModified())
         {
+        configurable_settings& z = configurable_settings::instance();
+        std::string const orig_skin_filename = z.skin_filename();
         preferences.Save();
-        configurable_settings::instance().save();
+        z.save();
+        if(z.skin_filename() != orig_skin_filename)
+            {
+            // If the default skin file name has changed, we need to explicitly
+            // re-load the corresponding file, otherwise the old definitions of
+            // the objects defined in it would be still used when they're
+            // needed the next time.
+            wxXmlResource& res = *wxXmlResource::Get();
+            res.Unload(AddDataDir(orig_skin_filename));
+            load_xrc_file_from_data_directory(res, 
DefaultView().ResourceFileName());
+            }
+
         UpdateViews();
         }
 }



reply via email to

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