lmi
[Top][All Lists]
Advanced

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

[lmi] [PATCH 2/5] Split lmi_wx_shared into a DLL and small executable.


From: Václav Slavík
Subject: [lmi] [PATCH 2/5] Split lmi_wx_shared into a DLL and small executable.
Date: Tue, 18 Feb 2014 18:14:41 +0100
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.3.0

Hi,

this series of patches introduces the GUI testing app. This part
splits the app into two pieces. Some file renaming is involved, so
it would be nice to have patches 2/5 (this one) and 3/5 integrated
in order to minimize the risk of conflicts between our changes.

Thanks,
Vaclav


Split lmi_wx_shared into a DLL and small executable.

This allows reusing most of the code for the test application.
---
 Makefile.am    |   25 +-
 main_wx.cpp    | 1252 +-----------------------------------------------------
 main_wx.hpp    |  134 ------
 objects.make   |    7 +-
 skeleton.cpp   | 1294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 skeleton.hpp   |  134 ++++++
 view_ex.cpp    |    2 +-
 workhorse.make |    9 +-
 8 files changed, 1464 insertions(+), 1393 deletions(-)
 delete mode 100644 main_wx.hpp
 create mode 100644 skeleton.cpp
 create mode 100644 skeleton.hpp

diff --git a/Makefile.am b/Makefile.am
index 3d40b6a..599588b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -62,7 +62,8 @@ EXTRA_PROGRAMS = \
 
 # libtool libraries installed in lib
 lib_LTLIBRARIES = \
-    liblmi.la
+    liblmi.la \
+    liblmi_wx_lib.la
 
 # libtool convenience libraries which are not installed at all
 noinst_LTLIBRARIES = \
@@ -153,8 +154,8 @@ check_PROGRAMS = $(TESTS)
 # Targets definitions
 ##############################################################################
 
-# main program executables
-lmi_wx_SOURCES = \
+# wx GUI's files are in a library to be shared with the tests
+liblmi_wx_lib_la_SOURCES = \
     about_dialog.cpp \
     alert_wx.cpp \
     census_document.cpp \
@@ -171,7 +172,6 @@ lmi_wx_SOURCES = \
     illustration_view.cpp \
     input_sequence_entry.cpp \
     main_common.cpp \
-    main_wx.cpp \
     mec_document.cpp \
     mec_view.cpp \
     msw_workarounds.cpp \
@@ -189,6 +189,7 @@ lmi_wx_SOURCES = \
     rounding_view.cpp \
     rounding_view_editor.cpp \
     single_choice_popup_menu.cpp \
+    skeleton.cpp \
     system_command_wx.cpp \
     text_doc.cpp \
     text_view.cpp \
@@ -200,6 +201,21 @@ lmi_wx_SOURCES = \
     wx_checks.cpp \
     wx_utility.cpp
 
+# main program executables
+lmi_wx_SOURCES = \
+    main_wx.cpp
+
+liblmi_wx_lib_la_CXXFLAGS =
+     $(AM_CXXFLAGS) $(WX_CXXFLAGS) $(XMLWRAPP_CFLAGS) $(GTK_CFLAGS)
+
+liblmi_wx_lib_la_LIBADD = \
+    liblmi.la \
+    libwx_new.la \
+    $(XMLWRAPP_LIBS) \
+    $(GTK_LIBS) \
+    $(BOOST_LIBS) \
+    $(WX_LIBS)
+
 lmi_wx_CXXFLAGS = $(AM_CXXFLAGS) $(WX_CXXFLAGS) $(XMLWRAPP_CFLAGS) 
$(GTK_CFLAGS)
 # $(CGICC_INCLUDE_FLAGS)
 
@@ -210,6 +226,7 @@ if LMI_MSW
        $(WINDRES) -I $(top_srcdir) $(WX_CPPFLAGS) $< $@
 endif
 lmi_wx_LDADD = \
+    liblmi_wx_lib.la \
     liblmi.la \
     libwx_new.la \
     $(XMLWRAPP_LIBS) \
diff --git a/main_wx.cpp b/main_wx.cpp
index 19c7691..453bf2b 100644
--- a/main_wx.cpp
+++ b/main_wx.cpp
@@ -36,141 +36,16 @@
 #   pragma hdrstop
 #endif
 
-#include "main_wx.hpp"
+#include "skeleton.hpp"
 
-#include "about_dialog.hpp"
-#include "alert.hpp"
-#include "assert_lmi.hpp"
-#include "authenticity.hpp"
-#include "census_document.hpp"
-#include "census_view.hpp"
-#include "configurable_settings.hpp"
-#include "contains.hpp"
-#include "data_directory.hpp"
-#include "database_document.hpp"
-#include "database_view.hpp"
-#include "dbdict.hpp"                   // print_databases()
-#include "default_view.hpp"
-#include "docmanager_ex.hpp"
-#include "docmdichildframe_ex.hpp"
 #include "fenv_guard.hpp"
 #include "fenv_lmi.hpp"
-#include "getopt.hpp"
-#include "global_settings.hpp"
 #include "handle_exceptions.hpp"
-#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"
-#include "mec_view.hpp"
-#include "miscellany.hpp"
 #include "msw_workarounds.hpp"
-#include "mvc_controller.hpp"
 #include "path_utility.hpp"
-#include "policy_document.hpp"
-#include "policy_view.hpp"
-#include "preferences_model.hpp"
-#include "preferences_view.hpp"
-#include "progress_meter.hpp"
-#include "rounding_document.hpp"
-#include "rounding_view.hpp"
-#include "rounding_view_editor.hpp"     // RoundingButtonsXmlHandler
-#include "system_command.hpp"
-#include "text_doc.hpp"
-#include "text_view.hpp"
-#include "tier_document.hpp"
-#include "tier_view.hpp"
-#include "wx_new.hpp"
-#include "wx_utility.hpp"               // class ClipboardEx
 
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
-
-#include <wx/artprov.h>
-#include <wx/config.h>
-#include <wx/cshelp.h>
-#include <wx/docmdi.h>
-#include <wx/image.h>
-#include <wx/log.h>                     // wxSafeShowMessage()
-#include <wx/menu.h>
-#include <wx/textctrl.h>
-#include <wx/textdlg.h>                 // wxGetTextFromUser()
-#include <wx/toolbar.h>
-#include <wx/utils.h>                   // wxMilliSleep(), wxSafeYield()
-#include <wx/xrc/xmlres.h>
-
-#include <iterator>
-#include <stdexcept>
-#include <string>
-
-#if defined __WXGTK__
-#   include <gtk/gtk.h>
-#endif
-
-IMPLEMENT_APP_NO_MAIN(Skeleton)
-IMPLEMENT_WX_THEME_SUPPORT
-
-// Where a builtin wxID_X identifier exists, use it as such, even if
-// it's used as the 'name=' attribute of an entity in an '.xrc' file.
-// For example, write 'wxID_SAVE' here, not 'XRCID("wxID_SAVE")'.
-// The builtin doc-view framework uses the builtin identifiers only;
-// using the XRCID here prevents the menu command from working, but
-// either one makes toolbar enablement work correctly.
-//
-BEGIN_EVENT_TABLE(Skeleton, wxApp)
-    EVT_DROP_FILES(                                    Skeleton::UponDropFiles 
                   )
-    EVT_BUTTON(wxID_HELP                              ,Skeleton::UponHelp      
                   )
-    EVT_MENU(  wxID_HELP                              ,Skeleton::UponHelp      
                   )
-    EVT_MENU(wxID_ABOUT                               ,Skeleton::UponAbout     
                   )
-    EVT_MENU(wxID_PREFERENCES                         
,Skeleton::UponPreferences                  )
-    EVT_MENU(XRCID("edit_default_cell"               
),Skeleton::UponEditDefaultCell              )
-    EVT_MENU(XRCID("test_app_status_alert"           
),Skeleton::UponTestAppStatus                )
-    EVT_MENU(XRCID("test_app_warning_alert"          
),Skeleton::UponTestAppWarning               )
-    EVT_MENU(XRCID("test_app_hobsons_choice_alert"   
),Skeleton::UponTestAppHobsons               )
-    EVT_MENU(XRCID("test_app_fatal_error_alert"      
),Skeleton::UponTestAppFatal                 )
-    EVT_MENU(XRCID("test_app_standard_exception"     
),Skeleton::UponTestAppStandardException     )
-    EVT_MENU(XRCID("test_app_arbitrary_exception"    
),Skeleton::UponTestAppArbitraryException    )
-    EVT_MENU(XRCID("test_lib_status_alert"           
),Skeleton::UponTestLibStatus                )
-    EVT_MENU(XRCID("test_lib_warning_alert"          
),Skeleton::UponTestLibWarning               )
-    EVT_MENU(XRCID("test_lib_hobsons_choice_alert"   
),Skeleton::UponTestLibHobsons               )
-    EVT_MENU(XRCID("test_lib_fatal_error_alert"      
),Skeleton::UponTestLibFatal                 )
-    EVT_MENU(XRCID("test_lib_standard_exception"     
),Skeleton::UponTestLibStandardException     )
-    EVT_MENU(XRCID("test_lib_arbitrary_exception"    
),Skeleton::UponTestLibArbitraryException    )
-    EVT_MENU(XRCID("test_lib_catastrophe_report"     
),Skeleton::UponTestLibCatastropheReport     )
-    EVT_MENU(XRCID("test_date_conversions"           
),Skeleton::UponTestDateConversions          )
-    EVT_MENU(XRCID("test_floating_point_environment" 
),Skeleton::UponTestFloatingPointEnvironment )
-    EVT_MENU(XRCID("test_pasting"                    
),Skeleton::UponTestPasting                  )
-    EVT_MENU(XRCID("test_system_command"             
),Skeleton::UponTestSystemCommand            )
-    EVT_MENU(XRCID("window_cascade"                  
),Skeleton::UponWindowCascade                )
-    EVT_MENU(XRCID("window_next"                     
),Skeleton::UponWindowNext                   )
-    EVT_MENU(XRCID("window_previous"                 
),Skeleton::UponWindowPrevious               )
-    EVT_MENU(XRCID("window_tile_horizontally"        
),Skeleton::UponWindowTileHorizontally       )
-    EVT_MENU(XRCID("window_tile_vertically"          
),Skeleton::UponWindowTileVertically         )
-    EVT_MENU_OPEN(                                     Skeleton::UponMenuOpen  
                   )
-// TODO ?? There has to be a better way.
-/*
-    EVT_UPDATE_UI(XRCID("edit_cell"            
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("edit_class"           
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("edit_case"            
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("run_cell"             
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("run_class"            
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("run_case"             
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("print_cell"           
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("print_class"          
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("print_case"           
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("print_group_roster"   
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("paste_census"         
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("add_cell"             
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("delete_cells"         
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("column_width_varying" 
),Skeleton::UponUpdateInapplicable)
-    EVT_UPDATE_UI(XRCID("column_width_fixed"   
),Skeleton::UponUpdateInapplicable)
-*/
-END_EVENT_TABLE()
+#include <wx/defs.h> // for wx_dependent_objects in workhorse.make
 
 #ifndef LMI_MSW
 int main(int argc, char* argv[])
@@ -225,1126 +100,3 @@ int WINAPI WinMain
     return result;
 }
 
-/// 'config_' can't be initialized in the initializer list with
-/// wxConfigBase::Get(), which must be called after SetAppName() and
-/// SetVendorName(): otherwise, the configuration object wouldn't
-/// reflect the vendor and application name; on the msw platform,
-/// for instance, that would prevent writing to a registry key based
-/// on the application's name.
-///
-/// The application name contains 'wx' because it may someday become
-/// desirable to maintain different configuration information in a
-/// similar manner for other lmi user interfaces.
-///
-/// The application display name, however, omits 'wx', because:
-///  - it'll always be specific to wx; and
-///  - 'lmi' is all lowercase, but wx capitalizes the first letter of
-///     the "AppName" (but not the "AppDisplayName").
-
-Skeleton::Skeleton()
-    :config_          (0)
-    ,doc_manager_     (0)
-    ,frame_           (0)
-    ,timer_           (this)
-{
-    SetAppName("lmi_wx");
-
-#if wxCHECK_VERSION(2,9,0)
-    SetAppDisplayName("lmi...");
-#endif // wxCHECK_VERSION(2,9,0)
-
-    SetVendorName("lmi");
-    config_ = wxConfigBase::Get();
-    timer_.Start(100);
-}
-
-Skeleton::~Skeleton()
-{
-}
-
-wxMDIChildFrame* Skeleton::CreateChildFrame
-    (wxDocument* doc
-    ,ViewEx*     view
-    )
-{
-// WX !! An exception thrown here does not get caught gracefully, e.g.
-//    throw std::runtime_error("This does not get caught gracefully.");
-    bool maximize_child =
-            frame_->GetActiveChild()
-        &&  frame_->GetActiveChild()->IsMaximized()
-        ;
-    DocMDIChildFrameEx* child_frame = new DocMDIChildFrameEx
-        (doc
-        ,view
-        ,frame_
-        );
-    child_frame->SetIcon(view->Icon());
-    child_frame->SetMenuBar(AdjustMenus(view->MenuBar()));
-
-    // Style flag wxMAXIMIZE could have been used instead, but that
-    // seems to work only with the msw platform.
-    if(maximize_child)
-        {
-        child_frame->Maximize();
-        }
-
-    return child_frame;
-}
-
-/// Adjust menus read from wxxrc resources.
-///
-/// Whatever can be done in wxxrc generally should be done there. Use
-/// this function to add finishing touches. Prefer to call it before
-/// wxFrame::SetMenuBar(), to avoid flicker.
-///
-/// The "Test" menu should not be exposed to end users. All of lmi's
-/// wxxrc resources include it; this function removes it whenever it's
-/// not wanted. Alternatively, it could be coded as a separate wxxrc
-/// resource and conditionally inserted here, but that would be less
-/// flexible: e.g., menu order couldn't be controlled completely in
-/// the wxxrc file.
-
-wxMenuBar* Skeleton::AdjustMenus(wxMenuBar* argument)
-{
-    LMI_ASSERT(argument);
-    wxMenuBar& menu_bar = *argument;
-
-    if(!global_settings::instance().ash_nazg())
-        {
-        int test_menu_index = menu_bar.FindMenu("Test");
-        if(wxNOT_FOUND == test_menu_index)
-            {
-            warning() << "No 'Test' menu found.";
-            }
-        else
-            {
-            delete menu_bar.Remove(test_menu_index);
-            }
-        }
-
-    LMI_ASSERT(argument);
-    return argument;
-}
-
-void Skeleton::InitDocManager()
-{
-    // WX !! At least in wx-2.5.1, this can't be created in the
-    // constructor, because that would try to create an instance of
-    // class wxPageSetupDialogData, which apparently mustn't be done
-    // before the application object is constructed.
-    doc_manager_ = new DocManagerEx;
-    doc_manager_->FileHistoryLoad(*config_);
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Census"
-        ,"*.cns"
-        ,""
-        ,"cns"
-        ,"Census document"
-        ,"Census view"
-        ,CLASSINFO(CensusDocument)
-        ,CLASSINFO(CensusView)
-        );
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Illustration"
-        ,"*.ill"
-        ,""
-        ,"ill"
-        ,"Illustration document"
-        ,"Illustration view"
-        ,CLASSINFO(IllustrationDocument)
-        ,CLASSINFO(IllustrationView)
-        );
-
-    if(!global_settings::instance().mellon())
-        {
-        return;
-        }
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Database"
-        ,"*.database"
-        ,""
-        ,"database"
-        ,"Database document"
-        ,"Database view"
-        ,CLASSINFO(DatabaseDocument)
-        ,CLASSINFO(DatabaseView)
-        );
-
-    // Apparently there's no way to edit a '.funds' file.
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Policy"
-        ,"*.policy"
-        ,""
-        ,"policy"
-        ,"Policy document"
-        ,"Policy view"
-        ,CLASSINFO(PolicyDocument)
-        ,CLASSINFO(PolicyView)
-        );
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Rounding"
-        ,"*.rounding"
-        ,""
-        ,"rounding"
-        ,"Rounding document"
-        ,"Rounding view"
-        ,CLASSINFO(RoundingDocument)
-        ,CLASSINFO(RoundingView)
-        );
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Strata"
-        ,"*.strata"
-        ,""
-        ,"strata"
-        ,"Tier document"
-        ,"Tier view"
-        ,CLASSINFO(TierDocument)
-        ,CLASSINFO(TierView)
-        );
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"MEC testing"
-        ,"*.mec"
-        ,""
-        ,"mec"
-        ,"MEC-testing document"
-        ,"MEC-testing view"
-        ,CLASSINFO(mec_document)
-        ,CLASSINFO(mec_view)
-        );
-
-    if(!global_settings::instance().ash_nazg())
-        {
-        return;
-        }
-
-    new(wx) wxDocTemplate
-        (doc_manager_
-        ,"Te&xt"
-        ,"*.txt"
-        ,""
-        ,"txt"
-        ,"Text document"
-        ,"Text view"
-        ,CLASSINFO(TextEditDocument)
-        ,CLASSINFO(TextEditView)
-        );
-}
-
-/// Initialize help subsystem.
-///
-/// Contextual <help> elements in wxxrc files are made available by
-/// wxSimpleHelpProvider. No fancier version of that class is needed.
-///
-/// An html user manual is displayed by wxLaunchDefaultBrowser(),
-/// which requires no initialization here.
-
-void Skeleton::InitHelp()
-{
-    wxHelpProvider::Set(new(wx) wxSimpleHelpProvider);
-    LMI_ASSERT(wxHelpProvider::Get());
-}
-
-void Skeleton::InitIcon()
-{
-    frame_->SetIcons(wxIconBundle(AddDataDir("lmi.ico"), wxBITMAP_TYPE_ICO));
-}
-
-void Skeleton::InitMenuBar()
-{
-    wxMenuBar* menu_bar = wxXmlResource::Get()->LoadMenuBar("main_menu");
-    if(!menu_bar)
-        {
-        fatal_error() << "Unable to create menubar." << LMI_FLUSH;
-        }
-    else
-        {
-        doc_manager_->AssociateFileHistoryWithFileMenu(menu_bar);
-        }
-    frame_->SetMenuBar(AdjustMenus(menu_bar));
-}
-
-// WX !! It seems odd that LoadMenuBar has two signatures, the simpler
-// of which requires no 'parent' argument, while LoadToolBar does not.
-//
-void Skeleton::InitToolBar()
-{
-    wxToolBar* tool_bar = wxXmlResource::Get()->LoadToolBar(frame_, "toolbar");
-    if(!tool_bar)
-        {
-        fatal_error() << "Unable to create toolbar." << LMI_FLUSH;
-        }
-    frame_->SetToolBar(tool_bar);
-}
-
-void Skeleton::UponAbout(wxCommandEvent&)
-{
-    AboutDialog(frame_).ShowModal();
-}
-
-void Skeleton::UponDropFiles(wxDropFilesEvent& event)
-{
-    wxString const* filenames = event.GetFiles();
-    for(int j = 0; j < event.GetNumberOfFiles(); ++j)
-        {
-        doc_manager_->CreateDocument(filenames[j], wxDOC_SILENT);
-        }
-}
-
-void Skeleton::UponEditDefaultCell(wxCommandEvent&)
-{
-    doc_manager_->CreateDocument
-        (configurable_settings::instance().default_input_filename()
-        ,wxDOC_SILENT
-        );
-}
-
-/// Display user manual in default browser.
-///
-/// If this changes the x86 floating-point control word, suppress the
-/// resulting diagnostic unless it changed to a really bizarre value.
-///
-/// If wxLaunchDefaultBrowser() fails, then it normally displays an
-/// error message of its own, which is suppressed here. See:
-///   http://lists.nongnu.org/archive/html/lmi/2009-03/msg00039.html
-
-void Skeleton::UponHelp(wxCommandEvent&)
-{
-    fenv_guard fg;
-
-    std::string const canonical_url("http://lmi.nongnu.org/user_manual.html";);
-
-    std::string s(AddDataDir("user_manual.html"));
-    fs::path p(fs::system_complete(fs::path(s)));
-    if(fs::exists(p))
-        {
-        s = "file://" + p.native_file_string();
-        }
-    else
-        {
-        warning()
-            << "A local copy of the user manual should have been placed here:"
-            << "\n    " << p.native_file_string()
-            << "\nbut was not. Try reinstalling."
-            << '\n'
-            << "\nMeanwhile, the online user manual will be used if possible."
-            << std::flush
-            ;
-        s = canonical_url;
-        }
-
-    bool r = false;
-    {
-    wxLogNull x;
-    r = wxLaunchDefaultBrowser(s);
-    }
-    if(!r)
-        {
-        fatal_error()
-            << "Unable to open"
-            << "\n    " << s
-            << "\nin default browser."
-            ;
-        if(canonical_url != s)
-            {
-            fatal_error()
-                << '\n'
-                << "\nThe user manual can be read online here:"
-                << "\n    " << canonical_url
-                ;
-            }
-        fatal_error() << std::flush;
-        }
-
-    fenv_validate(e_fenv_indulge_0x027f);
-}
-
-/// Rethrow an exception caught by wx into a local catch clause.
-///
-/// Report the exception, then return 'true' to continue processing.
-///
-/// This virtual function exists only to be overridden. Calling the
-/// base-class implementation would normally be pointless. However,
-/// for MinGW gcc-3.4.4 and earlier
-///   http://article.gmane.org/gmane.comp.gnu.mingw.user/18594
-///     [2006-01-10T22:00:24Z from Danny Smith]
-/// it is crucial that the exception be rethrown from the same shared
-/// library that caught it. That need is met by calling a base class's
-/// OnExceptionInMainLoop() explicitly; since wx-2.7 at least, that
-/// function is provided by class wxAppBase, but some earlier versions
-/// provide it only in class wxAppConsole, and the latter requires a
-/// 'monolithic' wx shared library.
-
-bool Skeleton::OnExceptionInMainLoop()
-{
-    try
-        {
-#if !(defined __GNUC__ && LMI_GCC_VERSION < 30405)
-        throw;
-#else  // defined __GNUC__ && LMI_GCC_VERSION < 30405
-#   if wxCHECK_VERSION(2,7,0)
-        return wxAppBase::OnExceptionInMainLoop();
-#   else  // !wxCHECK_VERSION(2,7,0)
-        return wxAppConsole::OnExceptionInMainLoop();
-#   endif // !wxCHECK_VERSION(2,7,0)
-#endif // defined __GNUC__ && LMI_GCC_VERSION < 30405
-        }
-    catch(...)
-        {
-        report_exception();
-        }
-    return true;
-}
-
-/// wxApp::OnExit() override.
-///
-/// Call the base class's implementation--see:
-///   http://lists.nongnu.org/archive/html/lmi/2013-11/msg00020.html
-
-int Skeleton::OnExit()
-{
-    try
-        {
-        doc_manager_->FileHistorySave(*config_);
-        delete doc_manager_;
-        }
-    catch(...)
-        {
-        report_exception();
-        }
-    return wxApp::OnExit(); // Deletes config_.
-}
-
-// WX !! An exception thrown anywhere in this function, even right
-// before the 'return' statement at the end, either causes a crash
-// (wx-2.5.1) or gets caught by OnUnhandledException() (which loses
-// exception information) instead of by OnExceptionInMainLoop().
-// Therefore, exceptions must be trapped explicitly.
-//
-bool Skeleton::OnInit()
-{
-    try
-        {
-        if(false == ProcessCommandLine(argc, argv))
-            {
-            return false;
-            }
-
-        authenticate_system();
-
-        wxInitAllImageHandlers();
-
-        // For GTK+, native theme takes precedence over local icons.
-        // For other platforms, local icons take precedence.
-#if defined __WXGTK__
-        wxArtProvider::PushBack(new(wx) icon_monger);
-#else  // !defined __WXGTK__
-        wxArtProvider::Push    (new(wx) icon_monger);
-#endif // !defined __WXGTK__
-
-        wxXmlResource& xml_resources = *wxXmlResource::Get();
-
-        xml_resources.InitAllHandlers();
-        xml_resources.AddHandler(new(wx) RoundingButtonsXmlHandler);
-        xml_resources.AddHandler(new(wx) InputSequenceEntryXmlHandler);
-
-        DefaultView const v0;
-#if wxCHECK_VERSION(2,9,0)
-        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(v0.ResourceFileName()))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir(v0.ResourceFileName())))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load xml resources." << LMI_FLUSH;
-            }
-
-        PreferencesView const v1;
-#if wxCHECK_VERSION(2,9,0)
-        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(v1.ResourceFileName()))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir(v1.ResourceFileName())))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load xml resources." << LMI_FLUSH;
-            }
-
-        mec_mvc_view const v2;
-#if wxCHECK_VERSION(2,9,0)
-        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(v2.ResourceFileName()))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir(v2.ResourceFileName())))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load xml resources." << LMI_FLUSH;
-            }
-
-#if wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.LoadFile(wxFileName(AddDataDir("menus.xrc"))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir("menus.xrc")))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load menubar." << LMI_FLUSH;
-            }
-
-#if wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.LoadFile(wxFileName(AddDataDir("toolbar.xrc"))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir("toolbar.xrc")))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load toolbar." << LMI_FLUSH;
-            }
-
-#if wxCHECK_VERSION(2,9,0)
-        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(PolicyView::resource_file_name()))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir(PolicyView::resource_file_name())))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load Policy resources." << LMI_FLUSH;
-            }
-
-#if wxCHECK_VERSION(2,9,0)
-        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(RoundingView::resource_file_name()))))
-#else  // !wxCHECK_VERSION(2,9,0)
-        if(!xml_resources.Load(AddDataDir(RoundingView::resource_file_name())))
-#endif // !wxCHECK_VERSION(2,9,0)
-            {
-            fatal_error() << "Unable to load Rounding resources." << LMI_FLUSH;
-            }
-
-        InitDocManager();
-
-        frame_ = new(wx) wxDocMDIParentFrame
-            (doc_manager_
-            ,NULL
-            ,wxID_ANY
-            ,"lmi"
-            ,wxDefaultPosition
-            ,wxDefaultSize
-            ,   wxDEFAULT_FRAME_STYLE
-            |   wxFRAME_NO_WINDOW_MENU
-            |   wxHSCROLL
-            |   wxVSCROLL
-            );
-
-        InitHelp();
-        InitIcon();
-        InitMenuBar();
-        InitToolBar();
-        frame_->CreateStatusBar();
-#if defined LMI_MSW || wxCHECK_VERSION(2,8,10)
-        frame_->DragAcceptFiles(true);
-#endif // defined LMI_MSW || wxCHECK_VERSION(2,8,10)
-        frame_->Centre(wxBOTH);
-        frame_->Maximize(true);
-
-        if(custom_io_0_run_if_file_exists(doc_manager_))
-            {
-            return false;
-            }
-
-        frame_->Show(true);
-        SetTopWindow(frame_);
-
-        // This handler may write to the statusbar, so connect it only
-        // after the frame has been created.
-        Connect
-            (wxEVT_TIMER
-            ,wxTimerEventHandler(Skeleton::UponTimer)
-            );
-
-        // Intercept 'Text Paste' events for all windows.
-        Connect
-            (wxEVT_COMMAND_TEXT_PASTE
-            ,wxClipboardTextEventHandler(Skeleton::UponPaste)
-            );
-
-        if
-            (!
-                (   global_settings::instance().ash_nazg()
-                ||  global_settings::instance().custom_io_0()
-                )
-            )
-            {
-            wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxID_ABOUT);
-            wxPostEvent(frame_, event);
-            }
-        }
-    catch(...)
-        {
-        report_exception();
-        // Orderly termination: see
-        //   http://lists.gnu.org/archive/html/lmi/2005-12/msg00020.html
-        // Returning 'true' here without creating a frame would leave
-        // the application running as an apparent zombie.
-        if(GetTopWindow())
-            {
-            GetTopWindow()->Close();
-            }
-        return false;
-        }
-    return true;
-}
-
-void Skeleton::UponMenuOpen(wxMenuEvent& event)
-{
-    event.Skip();
-
-    int child_frame_count = 0;
-    wxWindowList wl = frame_->GetChildren();
-    for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i)
-        {
-        child_frame_count += !!dynamic_cast<wxMDIChildFrame*>(*i);
-        }
-
-    wxMDIChildFrame* child_frame = frame_->GetActiveChild();
-    if(child_frame)
-        {
-        wxMenuItem* window_next = child_frame->GetMenuBar()->FindItem
-            (XRCID("window_next")
-            );
-        if(window_next)
-            {
-            window_next->Enable(1 < child_frame_count);
-            }
-
-        wxMenuItem* window_previous = child_frame->GetMenuBar()->FindItem
-            (XRCID("window_previous")
-            );
-        if(window_previous)
-            {
-            window_previous->Enable(1 < child_frame_count);
-            }
-        }
-    // (else) Parent menu enablement could be handled here, but, for
-    // now at least, none is required.
-}
-
-namespace
-{
-    std::string redelimit_with_semicolons(std::string const& original_text)
-        {
-        std::string new_text;
-        new_text.reserve(original_text.size());
-
-        std::insert_iterator<std::string> j(new_text, new_text.begin());
-        typedef std::string::const_iterator sci;
-        std::string::const_iterator i = original_text.begin();
-        for(sci i = original_text.begin(); i != original_text.end(); ++i)
-            {
-            switch(*i)
-                {
-                case '\n': {*j++ = ';';} break;
-                case '\r': {           } break;
-                case '\t': {*j++ = ';';} break;
-                default  : {*j++ =  *i;}
-                }
-            }
-
-        new_text.resize(1 + new_text.find_last_not_of(';'));
-
-        return new_text;
-        }
-
-} // Unnamed namespace.
-
-/// Paste "\n"- or "\r\n"-delimited clipboard contents into a control,
-/// replacing nonterminal delimiters with semicolons to form an input
-/// sequence. The motivation is to permit pasting spreadsheet columns.
-///
-/// At least for now, this transformation is performed iff the paste
-/// target is a wxTextCtrl.
-
-void Skeleton::UponPaste(wxClipboardTextEvent& event)
-{
-    event.Skip();
-
-    wxTextCtrl* t = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
-    if(!t)
-        {
-        return;
-        }
-
-    std::string const s(ClipboardEx::GetText());
-    if(s.empty())
-        {
-        return;
-        }
-
-    t->WriteText(redelimit_with_semicolons(s));
-    event.Skip(false);
-}
-
-void Skeleton::UponPreferences(wxCommandEvent&)
-{
-    PreferencesModel preferences;
-    PreferencesView const preferences_view;
-    MvcController controller(frame_, preferences, preferences_view);
-    int const rc = controller.ShowModal();
-    if(wxID_OK == rc && preferences.IsModified())
-        {
-        preferences.Save();
-        configurable_settings::instance().save();
-        UpdateViews();
-        }
-}
-
-void Skeleton::UponTestAppStatus(wxCommandEvent&)
-{
-    status()         << "Test status() ."         << LMI_FLUSH;
-}
-
-void Skeleton::UponTestAppWarning(wxCommandEvent&)
-{
-    warning()        << "Test warning() ."        << LMI_FLUSH;
-}
-
-void Skeleton::UponTestAppHobsons(wxCommandEvent&)
-{
-    hobsons_choice() << "Test hobsons_choice() ." << LMI_FLUSH;
-}
-
-void Skeleton::UponTestAppFatal(wxCommandEvent&)
-{
-    fatal_error()    << "Test fatal_error() ."    << LMI_FLUSH;
-}
-
-void Skeleton::UponTestAppStandardException(wxCommandEvent&)
-{
-    throw std::runtime_error("Test a standard exception.");
-}
-
-void Skeleton::UponTestAppArbitraryException(wxCommandEvent&)
-{
-    throw "Test an arbitrary exception.";
-}
-
-void Skeleton::UponTestLibStatus(wxCommandEvent&)
-{
-    test_status();
-}
-
-void Skeleton::UponTestLibWarning(wxCommandEvent&)
-{
-    test_warning();
-}
-
-void Skeleton::UponTestLibHobsons(wxCommandEvent&)
-{
-    test_hobsons_choice();
-}
-
-void Skeleton::UponTestLibFatal(wxCommandEvent&)
-{
-    test_fatal_error();
-}
-
-void Skeleton::UponTestLibStandardException(wxCommandEvent&)
-{
-    test_standard_exception();
-}
-
-void Skeleton::UponTestLibArbitraryException(wxCommandEvent&)
-{
-    test_arbitrary_exception();
-}
-
-/// Test catastrophic-error report.
-///
-/// This error occurs only when normal error reporting is impossible;
-/// it is internal to 'alert.cpp', so no corresponding application-
-/// level UponTestAppCatastropheReport() can be written.
-
-void Skeleton::UponTestLibCatastropheReport(wxCommandEvent&)
-{
-    test_catastrophe_report();
-}
-
-void Skeleton::UponTestDateConversions(wxCommandEvent&)
-{
-    TestDateConversions();
-}
-
-void Skeleton::UponTestFloatingPointEnvironment(wxCommandEvent&)
-{
-    status() << "Begin test of floating-point environment." << std::flush;
-
-    warning()
-        << "Expect 'Resetting floating-point control word.' on statusbar."
-        << std::flush
-        ;
-    x87_control_word(0x027f);
-    wxMilliSleep(500); wxSafeYield();
-    LMI_ASSERT(fenv_is_valid());
-
-    warning() << "Expect statusbar to be cleared." << std::flush;
-    status() << "" << std::flush;
-    wxMilliSleep(500); wxSafeYield();
-
-    warning()
-        << "Expect a messagebox complaining about '0x007f',"
-        << " and 'Resetting floating-point control word.' on statusbar."
-        << std::flush
-        ;
-    x87_control_word(0x007f);
-    wxMilliSleep(500); wxSafeYield();
-
-    warning() << "Expect statusbar to be cleared." << std::flush;
-    status() << "" << std::flush;
-    wxMilliSleep(500); wxSafeYield();
-
-    {
-    fenv_guard fg;
-    warning()
-        << "Test '0x027f' as if in guarded calculations."
-        << " Expect a messagebox complaining about that."
-        << std::flush
-        ;
-    x87_control_word(0x027f);
-    wxMilliSleep(500); wxSafeYield();
-    LMI_ASSERT(!fenv_is_valid());
-    }
-    LMI_ASSERT(fenv_is_valid());
-
-    {
-    fenv_guard fg;
-    warning()
-        << "Test '0x007f' as if in guarded calculations."
-        << " Expect a messagebox complaining about that."
-        << std::flush
-        ;
-    x87_control_word(0x007f);
-    wxMilliSleep(500); wxSafeYield();
-    LMI_ASSERT(!fenv_is_valid());
-    }
-    LMI_ASSERT(fenv_is_valid());
-
-    status() << "End test of floating-point environment." << std::flush;
-}
-
-namespace
-{
-/// Send a paste message to a window.
-///
-/// Design rationale--see:
-///   http://lists.nongnu.org/archive/html/lmi/2008-02/msg00005.html
-
-void send_paste_message_to(wxWindow const& w)
-{
-#if defined __WXGTK__
-    g_signal_emit_by_name(w.m_focusWidget, "paste_clipboard");
-#elif defined __WXMSW__
-    ::SendMessage(reinterpret_cast<HWND>(w.GetHandle()), WM_PASTE, 0, 0);
-#else  // Unsupported platform.
-#   error Platform not yet supported. Consider contributing support.
-#endif // Unsupported platform.
-}
-} // Unnamed namespace.
-
-/// Test custom handler UponPaste().
-///
-/// See:
-///   http://savannah.nongnu.org/task/?5224
-
-void Skeleton::UponTestPasting(wxCommandEvent&)
-{
-    wxTextCtrl* t = new wxTextCtrl(frame_, wxID_ANY, "Testing...");
-    LMI_ASSERT(t);
-
-    ClipboardEx::SetText("1\r\n2\r\n3\r\n");
-    t->SetSelection(-1L, -1L);
-    send_paste_message_to(*t);
-    if("1;2;3" != t->GetValue())
-        {
-        warning() << "'1;2;3' != '" << t->GetValue() << "'" << LMI_FLUSH;
-        }
-
-    ClipboardEx::SetText("X\tY\tZ\t");
-    t->SetSelection(-1L, -1L);
-    send_paste_message_to(*t);
-    if("X;Y;Z" != t->GetValue())
-        {
-        warning() << "'X;Y;Z' != '" << t->GetValue() << "'" << LMI_FLUSH;
-        }
-
-    t->Destroy();
-    status() << "Pasting test finished." << std::flush;
-}
-
-/// SOMEDAY !! Cancelling the wxGetTextFromUser() dialog causes it to
-/// return an empty string. It might be nicer to use a more elaborate
-/// facility that exits immediately in that case, because wxExecute()
-/// asserts that its first argument is nonempty in wx's debug mode.
-/// However, in the present implementation, it would be wrong to exit
-/// immediately: that would mask any such side effects and make it
-/// impossible to use this function to test the consequences of
-/// attempting to execute an empty command.
-
-void Skeleton::UponTestSystemCommand(wxCommandEvent&)
-{
-    wxString const w = wxGetTextFromUser
-        ("Type a command."
-        ,"Test system_command()"
-        ,""
-        ,&TopWindow()
-        );
-    std::string const z(w.c_str());
-    system_command(z);
-}
-
-/// Periodically test the floating-point control word when no critical
-/// calculation is being performed. If some rogue dll has changed it
-/// to the undesirable but nonegregious value 0x027f, then reset it,
-/// displaying a message on the statusbar; if it has been changed to
-/// any other value, which could interfere with the orderly operation
-/// of the program or even cause a crash, then reset it and pop up a
-/// message box.
-///
-/// If an fenv_guard object exists, do nothing: in that case, some
-/// critical calculation is being performed, so resetting the control
-/// word would prevent the fenv_guard object from detecting a change
-/// when any value but 0x037f is unacceptable.
-
-void Skeleton::UponTimer(wxTimerEvent&)
-{
-    if(0 == fenv_guard::instance_count())
-        {
-        if(!fenv_is_valid())
-            {
-            status() << "Resetting floating-point control word. " << 
std::flush;
-            }
-        fenv_validate(e_fenv_indulge_0x027f);
-        }
-}
-
-// WX !! The wx exception-handling code doesn't seem to permit
-// graceful handling here.
-//
-void Skeleton::OnUnhandledException()
-{
-    wxSafeShowMessage("Terminating due to unhandled exception.", "Fatal 
error");
-}
-
-// TODO ?? An unsuccessful experiment.
-void Skeleton::UponUpdateInapplicable(wxUpdateUIEvent& event)
-{
-// This handler seems to override mdi childrens'.
-//    e.Enable(0 != frame_->GetChildren().GetCount());
-
-/*
-This doesn't undo that override.
-    e.Enable(false);
-    if(0 != frame_->GetChildren().GetCount())
-        {
-        e.Skip();
-        }
-*/
-
-// Presumably we need to use ProcessEvent(), somehow.
-}
-
-void Skeleton::UponWindowCascade(wxCommandEvent&)
-{
-    frame_->Cascade();
-}
-
-void Skeleton::UponWindowNext(wxCommandEvent&)
-{
-    frame_->ActivateNext();
-}
-
-void Skeleton::UponWindowPrevious(wxCommandEvent&)
-{
-    frame_->ActivatePrevious();
-}
-
-void Skeleton::UponWindowTileHorizontally(wxCommandEvent&)
-{
-    frame_->Tile(wxHORIZONTAL);
-}
-
-void Skeleton::UponWindowTileVertically(wxCommandEvent&)
-{
-#if wxCHECK_VERSION(2,6,0)
-    frame_->Tile(wxVERTICAL);
-#else  // !wxCHECK_VERSION(2,6,0)
-    warning()
-        << "Vertical tiling not supported in this old wx version."
-        << LMI_FLUSH
-        ;
-#endif // !wxCHECK_VERSION(2,6,0)
-}
-
-bool Skeleton::ProcessCommandLine(int argc, char* argv[])
-{
-    // TRICKY !! Some long options are aliased to unlikely octal values.
-    static Option long_options[] =
-      {
-        {"ash_nazg"  ,NO_ARG   ,0 ,001 ,0 ,"ash nazg durbatulûk"},
-        {"ash_naz"   ,NO_ARG   ,0 ,003 ,0 ,"fraud"},
-        {"help"      ,NO_ARG   ,0 ,'h' ,0 ,"display this help and exit"},
-        {"mellon"    ,NO_ARG   ,0 ,002 ,0 ,"pedo mellon a minno"},
-        {"mello"     ,NO_ARG   ,0 ,003 ,0 ,"fraud"},
-        {"pyx"       ,REQD_ARG ,0 ,'x' ,0 ,"for docimasy"},
-        {"data_path" ,REQD_ARG ,0 ,'d' ,0 ,"path to data files"},
-        {"print_db"  ,NO_ARG   ,0 ,'p' ,0 ,"print product databases"},
-        {0           ,NO_ARG   ,0 ,0   ,0 ,""}
-      };
-
-    bool show_help        = false;
-
-    int option_index = 0;
-    GetOpt getopt_long
-        (argc
-        ,argv
-        ,""
-        ,long_options
-        ,&option_index
-        ,true
-        );
-
-    int c;
-    while(EOF != (c = getopt_long()))
-        {
-        switch(c)
-            {
-            case 001:
-                {
-                global_settings::instance().set_ash_nazg(true);
-                }
-                break;
-
-            case 002:
-                {
-                global_settings::instance().set_mellon(true);
-                }
-                break;
-
-            case 'd':
-                {
-                global_settings::instance().set_data_directory
-                    (getopt_long.optarg
-                    );
-                }
-                break;
-
-            case 'h':
-                {
-                show_help = true;
-                }
-                break;
-
-            case 'p':
-                {
-                print_databases();
-                }
-                break;
-
-            case 'x':
-                {
-                global_settings::instance().set_pyx(getopt_long.optarg);
-                if(contains(global_settings::instance().pyx(), 
"system_testing"))
-                    {
-                    global_settings::instance().set_regression_testing(true);
-                    }
-                }
-                break;
-
-            case '?':
-                {
-                warning() << "Unrecognized option '";
-                int offset = getopt_long.optind - 1;
-                if(0 < offset)
-                    {
-                    warning() << getopt_long.nargv[offset];
-                    }
-                warning() << "'." << std::flush;
-                }
-                break;
-
-            default:
-                {
-                warning()
-                    << "Unrecognized option character '"
-                    << c
-                    << "'."
-                    << std::flush
-                    ;
-                }
-            }
-        }
-
-    if((c = getopt_long.optind) < argc)
-        {
-        warning() << "Unrecognized parameters:\n";
-        while(c < argc)
-            {
-            warning() << "  '" << argv[c++] << "'\n";
-            }
-        warning() << std::flush;
-        }
-
-    if(show_help)
-        {
-        getopt_long.usage(warning());
-        warning() << std::flush;
-        return false;
-        }
-
-    return true;
-}
-
-// TODO ?? CALCULATION_SUMMARY It would probably be in much better
-// taste to use wxView::OnUpdate() for this purpose.
-
-// TODO ?? CALCULATION_SUMMARY The progress meter's count is wrong.
-// Consider writing a function to get a container of pointers to
-// children of a given type.
-//
-// TODO ?? CALCULATION_SUMMARY Instead, why not just update the
-// topmost window first, then update other windows, putting some
-// progress indication on the statusbar?
-
-void Skeleton::UpdateViews()
-{
-    wxWindowList wl = frame_->GetChildren();
-    boost::shared_ptr<progress_meter> meter
-        (create_progress_meter
-            (wl.size()
-            ,"Updating calculation summaries"
-            )
-        );
-    for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i)
-        {
-        wxDocMDIChildFrame const* c = dynamic_cast<wxDocMDIChildFrame*>(*i);
-        if(c)
-            {
-            IllustrationView* v = 
dynamic_cast<IllustrationView*>(c->GetView());
-            if(v)
-                {
-                v->DisplaySelectedValuesAsHtml();
-                }
-            }
-        if(!meter->reflect_progress())
-            {
-            break;
-            }
-        }
-    meter->culminate();
-}
-
diff --git a/main_wx.hpp b/main_wx.hpp
deleted file mode 100644
index 9f84d23..0000000
--- a/main_wx.hpp
+++ /dev/null
@@ -1,134 +0,0 @@
-// Main file for life insurance illustrations with wx interface.
-//
-// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 
2012, 2013, 2014 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$
-
-// Portions of this file are derived from wxWindows files
-//   samples/docvwmdi/docview.h (C) 1998 Julian Smart and Markus Holzem
-// which is covered by the wxWindows license, and
-//   samples/html/printing/printing.cpp
-// which bears no copyright or license notice.
-//
-// GWC used that code as an application skeleton and printing
-// implementation, modifying it in 2002 and the later years given in
-// the copyright notice above.
-
-#ifndef main_wx_hpp
-#define main_wx_hpp
-
-#include "config.hpp"
-
-#include "obstruct_slicing.hpp"
-#include "uncopyable_lmi.hpp"
-
-#include <wx/app.h>
-#include <wx/timer.h>
-
-class DocManagerEx;
-class ViewEx;
-
-class WXDLLIMPEXP_FWD_CORE wxConfigBase;
-class WXDLLIMPEXP_FWD_CORE wxDocMDIParentFrame;
-class WXDLLIMPEXP_FWD_CORE wxDocument;
-class WXDLLIMPEXP_FWD_CORE wxMDIChildFrame;
-class WXDLLIMPEXP_FWD_CORE wxMenuBar;
-
-class Skeleton
-    :        public  wxApp
-    ,        private lmi::uncopyable <Skeleton>
-    ,virtual private obstruct_slicing<Skeleton>
-{
-  public:
-    Skeleton();
-    ~Skeleton();
-
-    // Called by view classes when they are instantiated.
-    wxMDIChildFrame* CreateChildFrame(wxDocument*, ViewEx*);
-
-  private:
-    wxMenuBar* AdjustMenus(wxMenuBar*);
-
-    void InitDocManager ();
-    void InitHelp       ();
-    void InitIcon       ();
-    void InitMenuBar    ();
-    void InitToolBar    ();
-
-    void UponAbout                        (wxCommandEvent&);
-    void UponDropFiles                    (wxDropFilesEvent&);
-    void UponEditDefaultCell              (wxCommandEvent&);
-    void UponHelp                         (wxCommandEvent&);
-    void UponMenuOpen                     (wxMenuEvent&);
-    void UponPaste                        (wxClipboardTextEvent&);
-    void UponPreferences                  (wxCommandEvent&);
-
-    // Test alerts from application.
-    void UponTestAppStatus                (wxCommandEvent&);
-    void UponTestAppWarning               (wxCommandEvent&);
-    void UponTestAppHobsons               (wxCommandEvent&);
-    void UponTestAppFatal                 (wxCommandEvent&);
-    void UponTestAppStandardException     (wxCommandEvent&);
-    void UponTestAppArbitraryException    (wxCommandEvent&);
-
-    // Test alerts from shared library.
-    void UponTestLibStatus                (wxCommandEvent&);
-    void UponTestLibWarning               (wxCommandEvent&);
-    void UponTestLibHobsons               (wxCommandEvent&);
-    void UponTestLibFatal                 (wxCommandEvent&);
-    void UponTestLibStandardException     (wxCommandEvent&);
-    void UponTestLibArbitraryException    (wxCommandEvent&);
-    void UponTestLibCatastropheReport     (wxCommandEvent&);
-
-    // Miscellaneous tests.
-    void UponTestDateConversions          (wxCommandEvent&);
-    void UponTestFloatingPointEnvironment (wxCommandEvent&);
-    void UponTestPasting                  (wxCommandEvent&);
-    void UponTestSystemCommand            (wxCommandEvent&);
-
-    void UponTimer                        (wxTimerEvent&);
-    void UponUpdateInapplicable           (wxUpdateUIEvent&);
-    void UponWindowCascade                (wxCommandEvent&);
-    void UponWindowNext                   (wxCommandEvent&);
-    void UponWindowPrevious               (wxCommandEvent&);
-    void UponWindowTileHorizontally       (wxCommandEvent&);
-    void UponWindowTileVertically         (wxCommandEvent&);
-
-    // wxApp overrides.
-    virtual bool OnExceptionInMainLoop ();
-    virtual int  OnExit                ();
-    virtual bool OnInit                ();
-    virtual void OnUnhandledException  ();
-
-    bool ProcessCommandLine(int argc, char* argv[]);
-    void UpdateViews();
-
-    wxConfigBase*         config_;
-    DocManagerEx*         doc_manager_;
-    wxDocMDIParentFrame*  frame_;
-    wxTimer               timer_;
-
-    DECLARE_EVENT_TABLE()
-};
-
-DECLARE_APP(Skeleton)
-
-#endif // main_wx_hpp
-
diff --git a/objects.make b/objects.make
index 8b408cd..b53a4bd 100644
--- a/objects.make
+++ b/objects.make
@@ -296,7 +296,7 @@ lmi_common_objects := \
   stratified_algorithms.o \
   stratified_charges.o \
 
-lmi_wx_objects := \
+lmi_wx_lib_objects := \
   $(duplicated_objects) \
   about_dialog.o \
   alert_wx.o \
@@ -314,7 +314,6 @@ lmi_wx_objects := \
   illustration_view.o \
   input_sequence_entry.o \
   main_common.o \
-  main_wx.o \
   mec_document.o \
   mec_view.o \
   msw_workarounds.o \
@@ -332,6 +331,7 @@ lmi_wx_objects := \
   rounding_view.o \
   rounding_view_editor.o \
   single_choice_popup_menu.o \
+  skeleton.o \
   system_command_wx.o \
   text_doc.o \
   text_view.o \
@@ -343,6 +343,9 @@ lmi_wx_objects := \
   wx_checks.o \
   wx_utility.o \
 
+lmi_wx_objects := \
+  main_wx.o \
+
 ifneq (,$(RC))
   lmi_wx_objects += lmi_msw_res.o
 endif
diff --git a/skeleton.cpp b/skeleton.cpp
new file mode 100644
index 0000000..dd46ed5
--- /dev/null
+++ b/skeleton.cpp
@@ -0,0 +1,1294 @@
+// Main file for life insurance illustrations with wx interface.
+//
+// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 
2012, 2013, 2014 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$
+
+// Portions of this file are derived from wxWindows files
+//   samples/docvwmdi/docview.cpp (C) 1998 Julian Smart and Markus Holzem
+// which is covered by the wxWindows license, and
+//   samples/html/printing/printing.cpp
+// which bears no copyright or license notice.
+//
+// GWC used that code as an application skeleton and printing
+// implementation, modifying it in 2002 and the later years given in
+// the copyright notice above.
+
+#ifdef __BORLANDC__
+#   include "pchfile.hpp"
+#   pragma hdrstop
+#endif
+
+#include "skeleton.hpp"
+
+#include "about_dialog.hpp"
+#include "alert.hpp"
+#include "assert_lmi.hpp"
+#include "authenticity.hpp"
+#include "census_document.hpp"
+#include "census_view.hpp"
+#include "configurable_settings.hpp"
+#include "contains.hpp"
+#include "data_directory.hpp"
+#include "database_document.hpp"
+#include "database_view.hpp"
+#include "dbdict.hpp"                   // print_databases()
+#include "default_view.hpp"
+#include "docmanager_ex.hpp"
+#include "docmdichildframe_ex.hpp"
+#include "fenv_guard.hpp"
+#include "fenv_lmi.hpp"
+#include "getopt.hpp"
+#include "global_settings.hpp"
+#include "handle_exceptions.hpp"
+#include "icon_monger.hpp"
+#include "illustration_document.hpp"
+#include "illustration_view.hpp"
+#include "input_sequence_entry.hpp"     // InputSequenceEntryXmlHandler
+#include "license.hpp"
+#include "mec_document.hpp"
+#include "mec_view.hpp"
+#include "miscellany.hpp"
+#include "mvc_controller.hpp"
+#include "policy_document.hpp"
+#include "policy_view.hpp"
+#include "preferences_model.hpp"
+#include "preferences_view.hpp"
+#include "progress_meter.hpp"
+#include "rounding_document.hpp"
+#include "rounding_view.hpp"
+#include "rounding_view_editor.hpp"     // RoundingButtonsXmlHandler
+#include "system_command.hpp"
+#include "text_doc.hpp"
+#include "text_view.hpp"
+#include "tier_document.hpp"
+#include "tier_view.hpp"
+#include "wx_new.hpp"
+#include "wx_utility.hpp"               // class ClipboardEx
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include <wx/artprov.h>
+#include <wx/config.h>
+#include <wx/cshelp.h>
+#include <wx/docmdi.h>
+#include <wx/image.h>
+#include <wx/log.h>                     // wxSafeShowMessage()
+#include <wx/menu.h>
+#include <wx/textctrl.h>
+#include <wx/textdlg.h>                 // wxGetTextFromUser()
+#include <wx/toolbar.h>
+#include <wx/utils.h>                   // wxMilliSleep(), wxSafeYield()
+#include <wx/xrc/xmlres.h>
+
+#include <iterator>
+#include <stdexcept>
+#include <string>
+
+#if defined __WXGTK__
+#   include <gtk/gtk.h>
+#endif
+
+IMPLEMENT_APP_NO_MAIN(Skeleton)
+IMPLEMENT_WX_THEME_SUPPORT
+
+// Where a builtin wxID_X identifier exists, use it as such, even if
+// it's used as the 'name=' attribute of an entity in an '.xrc' file.
+// For example, write 'wxID_SAVE' here, not 'XRCID("wxID_SAVE")'.
+// The builtin doc-view framework uses the builtin identifiers only;
+// using the XRCID here prevents the menu command from working, but
+// either one makes toolbar enablement work correctly.
+//
+BEGIN_EVENT_TABLE(Skeleton, wxApp)
+    EVT_DROP_FILES(                                    Skeleton::UponDropFiles 
                   )
+    EVT_BUTTON(wxID_HELP                              ,Skeleton::UponHelp      
                   )
+    EVT_MENU(  wxID_HELP                              ,Skeleton::UponHelp      
                   )
+    EVT_MENU(wxID_ABOUT                               ,Skeleton::UponAbout     
                   )
+    EVT_MENU(wxID_PREFERENCES                         
,Skeleton::UponPreferences                  )
+    EVT_MENU(XRCID("edit_default_cell"               
),Skeleton::UponEditDefaultCell              )
+    EVT_MENU(XRCID("test_app_status_alert"           
),Skeleton::UponTestAppStatus                )
+    EVT_MENU(XRCID("test_app_warning_alert"          
),Skeleton::UponTestAppWarning               )
+    EVT_MENU(XRCID("test_app_hobsons_choice_alert"   
),Skeleton::UponTestAppHobsons               )
+    EVT_MENU(XRCID("test_app_fatal_error_alert"      
),Skeleton::UponTestAppFatal                 )
+    EVT_MENU(XRCID("test_app_standard_exception"     
),Skeleton::UponTestAppStandardException     )
+    EVT_MENU(XRCID("test_app_arbitrary_exception"    
),Skeleton::UponTestAppArbitraryException    )
+    EVT_MENU(XRCID("test_lib_status_alert"           
),Skeleton::UponTestLibStatus                )
+    EVT_MENU(XRCID("test_lib_warning_alert"          
),Skeleton::UponTestLibWarning               )
+    EVT_MENU(XRCID("test_lib_hobsons_choice_alert"   
),Skeleton::UponTestLibHobsons               )
+    EVT_MENU(XRCID("test_lib_fatal_error_alert"      
),Skeleton::UponTestLibFatal                 )
+    EVT_MENU(XRCID("test_lib_standard_exception"     
),Skeleton::UponTestLibStandardException     )
+    EVT_MENU(XRCID("test_lib_arbitrary_exception"    
),Skeleton::UponTestLibArbitraryException    )
+    EVT_MENU(XRCID("test_lib_catastrophe_report"     
),Skeleton::UponTestLibCatastropheReport     )
+    EVT_MENU(XRCID("test_date_conversions"           
),Skeleton::UponTestDateConversions          )
+    EVT_MENU(XRCID("test_floating_point_environment" 
),Skeleton::UponTestFloatingPointEnvironment )
+    EVT_MENU(XRCID("test_pasting"                    
),Skeleton::UponTestPasting                  )
+    EVT_MENU(XRCID("test_system_command"             
),Skeleton::UponTestSystemCommand            )
+    EVT_MENU(XRCID("window_cascade"                  
),Skeleton::UponWindowCascade                )
+    EVT_MENU(XRCID("window_next"                     
),Skeleton::UponWindowNext                   )
+    EVT_MENU(XRCID("window_previous"                 
),Skeleton::UponWindowPrevious               )
+    EVT_MENU(XRCID("window_tile_horizontally"        
),Skeleton::UponWindowTileHorizontally       )
+    EVT_MENU(XRCID("window_tile_vertically"          
),Skeleton::UponWindowTileVertically         )
+    EVT_MENU_OPEN(                                     Skeleton::UponMenuOpen  
                   )
+// TODO ?? There has to be a better way.
+/*
+    EVT_UPDATE_UI(XRCID("edit_cell"            
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("edit_class"           
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("edit_case"            
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("run_cell"             
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("run_class"            
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("run_case"             
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_cell"           
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_class"          
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_case"           
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_group_roster"   
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("paste_census"         
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("add_cell"             
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("delete_cells"         
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("column_width_varying" 
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("column_width_fixed"   
),Skeleton::UponUpdateInapplicable)
+*/
+END_EVENT_TABLE()
+
+/// 'config_' can't be initialized in the initializer list with
+/// wxConfigBase::Get(), which must be called after SetAppName() and
+/// SetVendorName(): otherwise, the configuration object wouldn't
+/// reflect the vendor and application name; on the msw platform,
+/// for instance, that would prevent writing to a registry key based
+/// on the application's name.
+///
+/// The application name contains 'wx' because it may someday become
+/// desirable to maintain different configuration information in a
+/// similar manner for other lmi user interfaces.
+///
+/// The application display name, however, omits 'wx', because:
+///  - it'll always be specific to wx; and
+///  - 'lmi' is all lowercase, but wx capitalizes the first letter of
+///     the "AppName" (but not the "AppDisplayName").
+
+Skeleton::Skeleton()
+    :config_          (0)
+    ,doc_manager_     (0)
+    ,frame_           (0)
+    ,timer_           (this)
+{
+    SetAppName("lmi_wx");
+
+#if wxCHECK_VERSION(2,9,0)
+    SetAppDisplayName("lmi...");
+#endif // wxCHECK_VERSION(2,9,0)
+
+    SetVendorName("lmi");
+    config_ = wxConfigBase::Get();
+    timer_.Start(100);
+}
+
+Skeleton::~Skeleton()
+{
+}
+
+wxMDIChildFrame* Skeleton::CreateChildFrame
+    (wxDocument* doc
+    ,ViewEx*     view
+    )
+{
+// WX !! An exception thrown here does not get caught gracefully, e.g.
+//    throw std::runtime_error("This does not get caught gracefully.");
+    bool maximize_child =
+            frame_->GetActiveChild()
+        &&  frame_->GetActiveChild()->IsMaximized()
+        ;
+    DocMDIChildFrameEx* child_frame = new DocMDIChildFrameEx
+        (doc
+        ,view
+        ,frame_
+        );
+    child_frame->SetIcon(view->Icon());
+    child_frame->SetMenuBar(AdjustMenus(view->MenuBar()));
+
+    // Style flag wxMAXIMIZE could have been used instead, but that
+    // seems to work only with the msw platform.
+    if(maximize_child)
+        {
+        child_frame->Maximize();
+        }
+
+    return child_frame;
+}
+
+/// Adjust menus read from wxxrc resources.
+///
+/// Whatever can be done in wxxrc generally should be done there. Use
+/// this function to add finishing touches. Prefer to call it before
+/// wxFrame::SetMenuBar(), to avoid flicker.
+///
+/// The "Test" menu should not be exposed to end users. All of lmi's
+/// wxxrc resources include it; this function removes it whenever it's
+/// not wanted. Alternatively, it could be coded as a separate wxxrc
+/// resource and conditionally inserted here, but that would be less
+/// flexible: e.g., menu order couldn't be controlled completely in
+/// the wxxrc file.
+
+wxMenuBar* Skeleton::AdjustMenus(wxMenuBar* argument)
+{
+    LMI_ASSERT(argument);
+    wxMenuBar& menu_bar = *argument;
+
+    if(!global_settings::instance().ash_nazg())
+        {
+        int test_menu_index = menu_bar.FindMenu("Test");
+        if(wxNOT_FOUND == test_menu_index)
+            {
+            warning() << "No 'Test' menu found.";
+            }
+        else
+            {
+            delete menu_bar.Remove(test_menu_index);
+            }
+        }
+
+    LMI_ASSERT(argument);
+    return argument;
+}
+
+void Skeleton::InitDocManager()
+{
+    // WX !! At least in wx-2.5.1, this can't be created in the
+    // constructor, because that would try to create an instance of
+    // class wxPageSetupDialogData, which apparently mustn't be done
+    // before the application object is constructed.
+    doc_manager_ = new DocManagerEx;
+    doc_manager_->FileHistoryLoad(*config_);
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Census"
+        ,"*.cns"
+        ,""
+        ,"cns"
+        ,"Census document"
+        ,"Census view"
+        ,CLASSINFO(CensusDocument)
+        ,CLASSINFO(CensusView)
+        );
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Illustration"
+        ,"*.ill"
+        ,""
+        ,"ill"
+        ,"Illustration document"
+        ,"Illustration view"
+        ,CLASSINFO(IllustrationDocument)
+        ,CLASSINFO(IllustrationView)
+        );
+
+    if(!global_settings::instance().mellon())
+        {
+        return;
+        }
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Database"
+        ,"*.database"
+        ,""
+        ,"database"
+        ,"Database document"
+        ,"Database view"
+        ,CLASSINFO(DatabaseDocument)
+        ,CLASSINFO(DatabaseView)
+        );
+
+    // Apparently there's no way to edit a '.funds' file.
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Policy"
+        ,"*.policy"
+        ,""
+        ,"policy"
+        ,"Policy document"
+        ,"Policy view"
+        ,CLASSINFO(PolicyDocument)
+        ,CLASSINFO(PolicyView)
+        );
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Rounding"
+        ,"*.rounding"
+        ,""
+        ,"rounding"
+        ,"Rounding document"
+        ,"Rounding view"
+        ,CLASSINFO(RoundingDocument)
+        ,CLASSINFO(RoundingView)
+        );
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Strata"
+        ,"*.strata"
+        ,""
+        ,"strata"
+        ,"Tier document"
+        ,"Tier view"
+        ,CLASSINFO(TierDocument)
+        ,CLASSINFO(TierView)
+        );
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"MEC testing"
+        ,"*.mec"
+        ,""
+        ,"mec"
+        ,"MEC-testing document"
+        ,"MEC-testing view"
+        ,CLASSINFO(mec_document)
+        ,CLASSINFO(mec_view)
+        );
+
+    if(!global_settings::instance().ash_nazg())
+        {
+        return;
+        }
+
+    new(wx) wxDocTemplate
+        (doc_manager_
+        ,"Te&xt"
+        ,"*.txt"
+        ,""
+        ,"txt"
+        ,"Text document"
+        ,"Text view"
+        ,CLASSINFO(TextEditDocument)
+        ,CLASSINFO(TextEditView)
+        );
+}
+
+/// Initialize help subsystem.
+///
+/// Contextual <help> elements in wxxrc files are made available by
+/// wxSimpleHelpProvider. No fancier version of that class is needed.
+///
+/// An html user manual is displayed by wxLaunchDefaultBrowser(),
+/// which requires no initialization here.
+
+void Skeleton::InitHelp()
+{
+    wxHelpProvider::Set(new(wx) wxSimpleHelpProvider);
+    LMI_ASSERT(wxHelpProvider::Get());
+}
+
+void Skeleton::InitIcon()
+{
+    frame_->SetIcons(wxIconBundle(AddDataDir("lmi.ico"), wxBITMAP_TYPE_ICO));
+}
+
+void Skeleton::InitMenuBar()
+{
+    wxMenuBar* menu_bar = wxXmlResource::Get()->LoadMenuBar("main_menu");
+    if(!menu_bar)
+        {
+        fatal_error() << "Unable to create menubar." << LMI_FLUSH;
+        }
+    else
+        {
+        doc_manager_->AssociateFileHistoryWithFileMenu(menu_bar);
+        }
+    frame_->SetMenuBar(AdjustMenus(menu_bar));
+}
+
+// WX !! It seems odd that LoadMenuBar has two signatures, the simpler
+// of which requires no 'parent' argument, while LoadToolBar does not.
+//
+void Skeleton::InitToolBar()
+{
+    wxToolBar* tool_bar = wxXmlResource::Get()->LoadToolBar(frame_, "toolbar");
+    if(!tool_bar)
+        {
+        fatal_error() << "Unable to create toolbar." << LMI_FLUSH;
+        }
+    frame_->SetToolBar(tool_bar);
+}
+
+void Skeleton::UponAbout(wxCommandEvent&)
+{
+    AboutDialog(frame_).ShowModal();
+}
+
+void Skeleton::UponDropFiles(wxDropFilesEvent& event)
+{
+    wxString const* filenames = event.GetFiles();
+    for(int j = 0; j < event.GetNumberOfFiles(); ++j)
+        {
+        doc_manager_->CreateDocument(filenames[j], wxDOC_SILENT);
+        }
+}
+
+void Skeleton::UponEditDefaultCell(wxCommandEvent&)
+{
+    doc_manager_->CreateDocument
+        (configurable_settings::instance().default_input_filename()
+        ,wxDOC_SILENT
+        );
+}
+
+/// Display user manual in default browser.
+///
+/// If this changes the x86 floating-point control word, suppress the
+/// resulting diagnostic unless it changed to a really bizarre value.
+///
+/// If wxLaunchDefaultBrowser() fails, then it normally displays an
+/// error message of its own, which is suppressed here. See:
+///   http://lists.nongnu.org/archive/html/lmi/2009-03/msg00039.html
+
+void Skeleton::UponHelp(wxCommandEvent&)
+{
+    fenv_guard fg;
+
+    std::string const canonical_url("http://lmi.nongnu.org/user_manual.html";);
+
+    std::string s(AddDataDir("user_manual.html"));
+    fs::path p(fs::system_complete(fs::path(s)));
+    if(fs::exists(p))
+        {
+        s = "file://" + p.native_file_string();
+        }
+    else
+        {
+        warning()
+            << "A local copy of the user manual should have been placed here:"
+            << "\n    " << p.native_file_string()
+            << "\nbut was not. Try reinstalling."
+            << '\n'
+            << "\nMeanwhile, the online user manual will be used if possible."
+            << std::flush
+            ;
+        s = canonical_url;
+        }
+
+    bool r = false;
+    {
+    wxLogNull x;
+    r = wxLaunchDefaultBrowser(s);
+    }
+    if(!r)
+        {
+        fatal_error()
+            << "Unable to open"
+            << "\n    " << s
+            << "\nin default browser."
+            ;
+        if(canonical_url != s)
+            {
+            fatal_error()
+                << '\n'
+                << "\nThe user manual can be read online here:"
+                << "\n    " << canonical_url
+                ;
+            }
+        fatal_error() << std::flush;
+        }
+
+    fenv_validate(e_fenv_indulge_0x027f);
+}
+
+/// Rethrow an exception caught by wx into a local catch clause.
+///
+/// Report the exception, then return 'true' to continue processing.
+///
+/// This virtual function exists only to be overridden. Calling the
+/// base-class implementation would normally be pointless. However,
+/// for MinGW gcc-3.4.4 and earlier
+///   http://article.gmane.org/gmane.comp.gnu.mingw.user/18594
+///     [2006-01-10T22:00:24Z from Danny Smith]
+/// it is crucial that the exception be rethrown from the same shared
+/// library that caught it. That need is met by calling a base class's
+/// OnExceptionInMainLoop() explicitly; since wx-2.7 at least, that
+/// function is provided by class wxAppBase, but some earlier versions
+/// provide it only in class wxAppConsole, and the latter requires a
+/// 'monolithic' wx shared library.
+
+bool Skeleton::OnExceptionInMainLoop()
+{
+    try
+        {
+#if !(defined __GNUC__ && LMI_GCC_VERSION < 30405)
+        throw;
+#else  // defined __GNUC__ && LMI_GCC_VERSION < 30405
+#   if wxCHECK_VERSION(2,7,0)
+        return wxAppBase::OnExceptionInMainLoop();
+#   else  // !wxCHECK_VERSION(2,7,0)
+        return wxAppConsole::OnExceptionInMainLoop();
+#   endif // !wxCHECK_VERSION(2,7,0)
+#endif // defined __GNUC__ && LMI_GCC_VERSION < 30405
+        }
+    catch(...)
+        {
+        report_exception();
+        }
+    return true;
+}
+
+/// wxApp::OnExit() override.
+///
+/// Call the base class's implementation--see:
+///   http://lists.nongnu.org/archive/html/lmi/2013-11/msg00020.html
+
+int Skeleton::OnExit()
+{
+    try
+        {
+        doc_manager_->FileHistorySave(*config_);
+        delete doc_manager_;
+        }
+    catch(...)
+        {
+        report_exception();
+        }
+    return wxApp::OnExit(); // Deletes config_.
+}
+
+// WX !! An exception thrown anywhere in this function, even right
+// before the 'return' statement at the end, either causes a crash
+// (wx-2.5.1) or gets caught by OnUnhandledException() (which loses
+// exception information) instead of by OnExceptionInMainLoop().
+// Therefore, exceptions must be trapped explicitly.
+//
+bool Skeleton::OnInit()
+{
+    try
+        {
+        if(false == ProcessCommandLine(argc, argv))
+            {
+            return false;
+            }
+
+        authenticate_system();
+
+        wxInitAllImageHandlers();
+
+        // For GTK+, native theme takes precedence over local icons.
+        // For other platforms, local icons take precedence.
+#if defined __WXGTK__
+        wxArtProvider::PushBack(new(wx) icon_monger);
+#else  // !defined __WXGTK__
+        wxArtProvider::Push    (new(wx) icon_monger);
+#endif // !defined __WXGTK__
+
+        wxXmlResource& xml_resources = *wxXmlResource::Get();
+
+        xml_resources.InitAllHandlers();
+        xml_resources.AddHandler(new(wx) RoundingButtonsXmlHandler);
+        xml_resources.AddHandler(new(wx) InputSequenceEntryXmlHandler);
+
+        DefaultView const v0;
+#if wxCHECK_VERSION(2,9,0)
+        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(v0.ResourceFileName()))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir(v0.ResourceFileName())))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load xml resources." << LMI_FLUSH;
+            }
+
+        PreferencesView const v1;
+#if wxCHECK_VERSION(2,9,0)
+        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(v1.ResourceFileName()))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir(v1.ResourceFileName())))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load xml resources." << LMI_FLUSH;
+            }
+
+        mec_mvc_view const v2;
+#if wxCHECK_VERSION(2,9,0)
+        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(v2.ResourceFileName()))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir(v2.ResourceFileName())))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load xml resources." << LMI_FLUSH;
+            }
+
+#if wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.LoadFile(wxFileName(AddDataDir("menus.xrc"))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir("menus.xrc")))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load menubar." << LMI_FLUSH;
+            }
+
+#if wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.LoadFile(wxFileName(AddDataDir("toolbar.xrc"))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir("toolbar.xrc")))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load toolbar." << LMI_FLUSH;
+            }
+
+#if wxCHECK_VERSION(2,9,0)
+        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(PolicyView::resource_file_name()))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir(PolicyView::resource_file_name())))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load Policy resources." << LMI_FLUSH;
+            }
+
+#if wxCHECK_VERSION(2,9,0)
+        
if(!xml_resources.LoadFile(wxFileName(AddDataDir(RoundingView::resource_file_name()))))
+#else  // !wxCHECK_VERSION(2,9,0)
+        if(!xml_resources.Load(AddDataDir(RoundingView::resource_file_name())))
+#endif // !wxCHECK_VERSION(2,9,0)
+            {
+            fatal_error() << "Unable to load Rounding resources." << LMI_FLUSH;
+            }
+
+        InitDocManager();
+
+        frame_ = new(wx) wxDocMDIParentFrame
+            (doc_manager_
+            ,NULL
+            ,wxID_ANY
+            ,"lmi"
+            ,wxDefaultPosition
+            ,wxDefaultSize
+            ,   wxDEFAULT_FRAME_STYLE
+            |   wxFRAME_NO_WINDOW_MENU
+            |   wxHSCROLL
+            |   wxVSCROLL
+            );
+
+        InitHelp();
+        InitIcon();
+        InitMenuBar();
+        InitToolBar();
+        frame_->CreateStatusBar();
+#if defined LMI_MSW || wxCHECK_VERSION(2,8,10)
+        frame_->DragAcceptFiles(true);
+#endif // defined LMI_MSW || wxCHECK_VERSION(2,8,10)
+        frame_->Centre(wxBOTH);
+        frame_->Maximize(true);
+
+        if(custom_io_0_run_if_file_exists(doc_manager_))
+            {
+            return false;
+            }
+
+        frame_->Show(true);
+        SetTopWindow(frame_);
+
+        // This handler may write to the statusbar, so connect it only
+        // after the frame has been created.
+        Connect
+            (wxEVT_TIMER
+            ,wxTimerEventHandler(Skeleton::UponTimer)
+            );
+
+        // Intercept 'Text Paste' events for all windows.
+        Connect
+            (wxEVT_COMMAND_TEXT_PASTE
+            ,wxClipboardTextEventHandler(Skeleton::UponPaste)
+            );
+
+        if
+            (!
+                (   global_settings::instance().ash_nazg()
+                ||  global_settings::instance().custom_io_0()
+                )
+            )
+            {
+            wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, wxID_ABOUT);
+            wxPostEvent(frame_, event);
+            }
+        }
+    catch(...)
+        {
+        report_exception();
+        // Orderly termination: see
+        //   http://lists.gnu.org/archive/html/lmi/2005-12/msg00020.html
+        // Returning 'true' here without creating a frame would leave
+        // the application running as an apparent zombie.
+        if(GetTopWindow())
+            {
+            GetTopWindow()->Close();
+            }
+        return false;
+        }
+    return true;
+}
+
+void Skeleton::UponMenuOpen(wxMenuEvent& event)
+{
+    event.Skip();
+
+    int child_frame_count = 0;
+    wxWindowList wl = frame_->GetChildren();
+    for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i)
+        {
+        child_frame_count += !!dynamic_cast<wxMDIChildFrame*>(*i);
+        }
+
+    wxMDIChildFrame* child_frame = frame_->GetActiveChild();
+    if(child_frame)
+        {
+        wxMenuItem* window_next = child_frame->GetMenuBar()->FindItem
+            (XRCID("window_next")
+            );
+        if(window_next)
+            {
+            window_next->Enable(1 < child_frame_count);
+            }
+
+        wxMenuItem* window_previous = child_frame->GetMenuBar()->FindItem
+            (XRCID("window_previous")
+            );
+        if(window_previous)
+            {
+            window_previous->Enable(1 < child_frame_count);
+            }
+        }
+    // (else) Parent menu enablement could be handled here, but, for
+    // now at least, none is required.
+}
+
+namespace
+{
+    std::string redelimit_with_semicolons(std::string const& original_text)
+        {
+        std::string new_text;
+        new_text.reserve(original_text.size());
+
+        std::insert_iterator<std::string> j(new_text, new_text.begin());
+        typedef std::string::const_iterator sci;
+        std::string::const_iterator i = original_text.begin();
+        for(sci i = original_text.begin(); i != original_text.end(); ++i)
+            {
+            switch(*i)
+                {
+                case '\n': {*j++ = ';';} break;
+                case '\r': {           } break;
+                case '\t': {*j++ = ';';} break;
+                default  : {*j++ =  *i;}
+                }
+            }
+
+        new_text.resize(1 + new_text.find_last_not_of(';'));
+
+        return new_text;
+        }
+
+} // Unnamed namespace.
+
+/// Paste "\n"- or "\r\n"-delimited clipboard contents into a control,
+/// replacing nonterminal delimiters with semicolons to form an input
+/// sequence. The motivation is to permit pasting spreadsheet columns.
+///
+/// At least for now, this transformation is performed iff the paste
+/// target is a wxTextCtrl.
+
+void Skeleton::UponPaste(wxClipboardTextEvent& event)
+{
+    event.Skip();
+
+    wxTextCtrl* t = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
+    if(!t)
+        {
+        return;
+        }
+
+    std::string const s(ClipboardEx::GetText());
+    if(s.empty())
+        {
+        return;
+        }
+
+    t->WriteText(redelimit_with_semicolons(s));
+    event.Skip(false);
+}
+
+void Skeleton::UponPreferences(wxCommandEvent&)
+{
+    PreferencesModel preferences;
+    PreferencesView const preferences_view;
+    MvcController controller(frame_, preferences, preferences_view);
+    int const rc = controller.ShowModal();
+    if(wxID_OK == rc && preferences.IsModified())
+        {
+        preferences.Save();
+        configurable_settings::instance().save();
+        UpdateViews();
+        }
+}
+
+void Skeleton::UponTestAppStatus(wxCommandEvent&)
+{
+    status()         << "Test status() ."         << LMI_FLUSH;
+}
+
+void Skeleton::UponTestAppWarning(wxCommandEvent&)
+{
+    warning()        << "Test warning() ."        << LMI_FLUSH;
+}
+
+void Skeleton::UponTestAppHobsons(wxCommandEvent&)
+{
+    hobsons_choice() << "Test hobsons_choice() ." << LMI_FLUSH;
+}
+
+void Skeleton::UponTestAppFatal(wxCommandEvent&)
+{
+    fatal_error()    << "Test fatal_error() ."    << LMI_FLUSH;
+}
+
+void Skeleton::UponTestAppStandardException(wxCommandEvent&)
+{
+    throw std::runtime_error("Test a standard exception.");
+}
+
+void Skeleton::UponTestAppArbitraryException(wxCommandEvent&)
+{
+    throw "Test an arbitrary exception.";
+}
+
+void Skeleton::UponTestLibStatus(wxCommandEvent&)
+{
+    test_status();
+}
+
+void Skeleton::UponTestLibWarning(wxCommandEvent&)
+{
+    test_warning();
+}
+
+void Skeleton::UponTestLibHobsons(wxCommandEvent&)
+{
+    test_hobsons_choice();
+}
+
+void Skeleton::UponTestLibFatal(wxCommandEvent&)
+{
+    test_fatal_error();
+}
+
+void Skeleton::UponTestLibStandardException(wxCommandEvent&)
+{
+    test_standard_exception();
+}
+
+void Skeleton::UponTestLibArbitraryException(wxCommandEvent&)
+{
+    test_arbitrary_exception();
+}
+
+/// Test catastrophic-error report.
+///
+/// This error occurs only when normal error reporting is impossible;
+/// it is internal to 'alert.cpp', so no corresponding application-
+/// level UponTestAppCatastropheReport() can be written.
+
+void Skeleton::UponTestLibCatastropheReport(wxCommandEvent&)
+{
+    test_catastrophe_report();
+}
+
+void Skeleton::UponTestDateConversions(wxCommandEvent&)
+{
+    TestDateConversions();
+}
+
+void Skeleton::UponTestFloatingPointEnvironment(wxCommandEvent&)
+{
+    status() << "Begin test of floating-point environment." << std::flush;
+
+    warning()
+        << "Expect 'Resetting floating-point control word.' on statusbar."
+        << std::flush
+        ;
+    x87_control_word(0x027f);
+    wxMilliSleep(500); wxSafeYield();
+    LMI_ASSERT(fenv_is_valid());
+
+    warning() << "Expect statusbar to be cleared." << std::flush;
+    status() << "" << std::flush;
+    wxMilliSleep(500); wxSafeYield();
+
+    warning()
+        << "Expect a messagebox complaining about '0x007f',"
+        << " and 'Resetting floating-point control word.' on statusbar."
+        << std::flush
+        ;
+    x87_control_word(0x007f);
+    wxMilliSleep(500); wxSafeYield();
+
+    warning() << "Expect statusbar to be cleared." << std::flush;
+    status() << "" << std::flush;
+    wxMilliSleep(500); wxSafeYield();
+
+    {
+    fenv_guard fg;
+    warning()
+        << "Test '0x027f' as if in guarded calculations."
+        << " Expect a messagebox complaining about that."
+        << std::flush
+        ;
+    x87_control_word(0x027f);
+    wxMilliSleep(500); wxSafeYield();
+    LMI_ASSERT(!fenv_is_valid());
+    }
+    LMI_ASSERT(fenv_is_valid());
+
+    {
+    fenv_guard fg;
+    warning()
+        << "Test '0x007f' as if in guarded calculations."
+        << " Expect a messagebox complaining about that."
+        << std::flush
+        ;
+    x87_control_word(0x007f);
+    wxMilliSleep(500); wxSafeYield();
+    LMI_ASSERT(!fenv_is_valid());
+    }
+    LMI_ASSERT(fenv_is_valid());
+
+    status() << "End test of floating-point environment." << std::flush;
+}
+
+namespace
+{
+/// Send a paste message to a window.
+///
+/// Design rationale--see:
+///   http://lists.nongnu.org/archive/html/lmi/2008-02/msg00005.html
+
+void send_paste_message_to(wxWindow const& w)
+{
+#if defined __WXGTK__
+    g_signal_emit_by_name(w.m_focusWidget, "paste_clipboard");
+#elif defined __WXMSW__
+    ::SendMessage(reinterpret_cast<HWND>(w.GetHandle()), WM_PASTE, 0, 0);
+#else  // Unsupported platform.
+#   error Platform not yet supported. Consider contributing support.
+#endif // Unsupported platform.
+}
+} // Unnamed namespace.
+
+/// Test custom handler UponPaste().
+///
+/// See:
+///   http://savannah.nongnu.org/task/?5224
+
+void Skeleton::UponTestPasting(wxCommandEvent&)
+{
+    wxTextCtrl* t = new wxTextCtrl(frame_, wxID_ANY, "Testing...");
+    LMI_ASSERT(t);
+
+    ClipboardEx::SetText("1\r\n2\r\n3\r\n");
+    t->SetSelection(-1L, -1L);
+    send_paste_message_to(*t);
+    if("1;2;3" != t->GetValue())
+        {
+        warning() << "'1;2;3' != '" << t->GetValue() << "'" << LMI_FLUSH;
+        }
+
+    ClipboardEx::SetText("X\tY\tZ\t");
+    t->SetSelection(-1L, -1L);
+    send_paste_message_to(*t);
+    if("X;Y;Z" != t->GetValue())
+        {
+        warning() << "'X;Y;Z' != '" << t->GetValue() << "'" << LMI_FLUSH;
+        }
+
+    t->Destroy();
+    status() << "Pasting test finished." << std::flush;
+}
+
+/// SOMEDAY !! Cancelling the wxGetTextFromUser() dialog causes it to
+/// return an empty string. It might be nicer to use a more elaborate
+/// facility that exits immediately in that case, because wxExecute()
+/// asserts that its first argument is nonempty in wx's debug mode.
+/// However, in the present implementation, it would be wrong to exit
+/// immediately: that would mask any such side effects and make it
+/// impossible to use this function to test the consequences of
+/// attempting to execute an empty command.
+
+void Skeleton::UponTestSystemCommand(wxCommandEvent&)
+{
+    wxString const w = wxGetTextFromUser
+        ("Type a command."
+        ,"Test system_command()"
+        ,""
+        ,&TopWindow()
+        );
+    std::string const z(w.c_str());
+    system_command(z);
+}
+
+/// Periodically test the floating-point control word when no critical
+/// calculation is being performed. If some rogue dll has changed it
+/// to the undesirable but nonegregious value 0x027f, then reset it,
+/// displaying a message on the statusbar; if it has been changed to
+/// any other value, which could interfere with the orderly operation
+/// of the program or even cause a crash, then reset it and pop up a
+/// message box.
+///
+/// If an fenv_guard object exists, do nothing: in that case, some
+/// critical calculation is being performed, so resetting the control
+/// word would prevent the fenv_guard object from detecting a change
+/// when any value but 0x037f is unacceptable.
+
+void Skeleton::UponTimer(wxTimerEvent&)
+{
+    if(0 == fenv_guard::instance_count())
+        {
+        if(!fenv_is_valid())
+            {
+            status() << "Resetting floating-point control word. " << 
std::flush;
+            }
+        fenv_validate(e_fenv_indulge_0x027f);
+        }
+}
+
+// WX !! The wx exception-handling code doesn't seem to permit
+// graceful handling here.
+//
+void Skeleton::OnUnhandledException()
+{
+    wxSafeShowMessage("Terminating due to unhandled exception.", "Fatal 
error");
+}
+
+// TODO ?? An unsuccessful experiment.
+void Skeleton::UponUpdateInapplicable(wxUpdateUIEvent& event)
+{
+// This handler seems to override mdi childrens'.
+//    e.Enable(0 != frame_->GetChildren().GetCount());
+
+/*
+This doesn't undo that override.
+    e.Enable(false);
+    if(0 != frame_->GetChildren().GetCount())
+        {
+        e.Skip();
+        }
+*/
+
+// Presumably we need to use ProcessEvent(), somehow.
+}
+
+void Skeleton::UponWindowCascade(wxCommandEvent&)
+{
+    frame_->Cascade();
+}
+
+void Skeleton::UponWindowNext(wxCommandEvent&)
+{
+    frame_->ActivateNext();
+}
+
+void Skeleton::UponWindowPrevious(wxCommandEvent&)
+{
+    frame_->ActivatePrevious();
+}
+
+void Skeleton::UponWindowTileHorizontally(wxCommandEvent&)
+{
+    frame_->Tile(wxHORIZONTAL);
+}
+
+void Skeleton::UponWindowTileVertically(wxCommandEvent&)
+{
+#if wxCHECK_VERSION(2,6,0)
+    frame_->Tile(wxVERTICAL);
+#else  // !wxCHECK_VERSION(2,6,0)
+    warning()
+        << "Vertical tiling not supported in this old wx version."
+        << LMI_FLUSH
+        ;
+#endif // !wxCHECK_VERSION(2,6,0)
+}
+
+bool Skeleton::ProcessCommandLine(int argc, char* argv[])
+{
+    // TRICKY !! Some long options are aliased to unlikely octal values.
+    static Option long_options[] =
+      {
+        {"ash_nazg"  ,NO_ARG   ,0 ,001 ,0 ,"ash nazg durbatulûk"},
+        {"ash_naz"   ,NO_ARG   ,0 ,003 ,0 ,"fraud"},
+        {"help"      ,NO_ARG   ,0 ,'h' ,0 ,"display this help and exit"},
+        {"mellon"    ,NO_ARG   ,0 ,002 ,0 ,"pedo mellon a minno"},
+        {"mello"     ,NO_ARG   ,0 ,003 ,0 ,"fraud"},
+        {"pyx"       ,REQD_ARG ,0 ,'x' ,0 ,"for docimasy"},
+        {"data_path" ,REQD_ARG ,0 ,'d' ,0 ,"path to data files"},
+        {"print_db"  ,NO_ARG   ,0 ,'p' ,0 ,"print product databases"},
+        {0           ,NO_ARG   ,0 ,0   ,0 ,""}
+      };
+
+    bool show_help        = false;
+
+    int option_index = 0;
+    GetOpt getopt_long
+        (argc
+        ,argv
+        ,""
+        ,long_options
+        ,&option_index
+        ,true
+        );
+
+    int c;
+    while(EOF != (c = getopt_long()))
+        {
+        switch(c)
+            {
+            case 001:
+                {
+                global_settings::instance().set_ash_nazg(true);
+                }
+                break;
+
+            case 002:
+                {
+                global_settings::instance().set_mellon(true);
+                }
+                break;
+
+            case 'd':
+                {
+                global_settings::instance().set_data_directory
+                    (getopt_long.optarg
+                    );
+                }
+                break;
+
+            case 'h':
+                {
+                show_help = true;
+                }
+                break;
+
+            case 'p':
+                {
+                print_databases();
+                }
+                break;
+
+            case 'x':
+                {
+                global_settings::instance().set_pyx(getopt_long.optarg);
+                if(contains(global_settings::instance().pyx(), 
"system_testing"))
+                    {
+                    global_settings::instance().set_regression_testing(true);
+                    }
+                }
+                break;
+
+            case '?':
+                {
+                warning() << "Unrecognized option '";
+                int offset = getopt_long.optind - 1;
+                if(0 < offset)
+                    {
+                    warning() << getopt_long.nargv[offset];
+                    }
+                warning() << "'." << std::flush;
+                }
+                break;
+
+            default:
+                {
+                warning()
+                    << "Unrecognized option character '"
+                    << c
+                    << "'."
+                    << std::flush
+                    ;
+                }
+            }
+        }
+
+    if((c = getopt_long.optind) < argc)
+        {
+        warning() << "Unrecognized parameters:\n";
+        while(c < argc)
+            {
+            warning() << "  '" << argv[c++] << "'\n";
+            }
+        warning() << std::flush;
+        }
+
+    if(show_help)
+        {
+        getopt_long.usage(warning());
+        warning() << std::flush;
+        return false;
+        }
+
+    return true;
+}
+
+// TODO ?? CALCULATION_SUMMARY It would probably be in much better
+// taste to use wxView::OnUpdate() for this purpose.
+
+// TODO ?? CALCULATION_SUMMARY The progress meter's count is wrong.
+// Consider writing a function to get a container of pointers to
+// children of a given type.
+//
+// TODO ?? CALCULATION_SUMMARY Instead, why not just update the
+// topmost window first, then update other windows, putting some
+// progress indication on the statusbar?
+
+void Skeleton::UpdateViews()
+{
+    wxWindowList wl = frame_->GetChildren();
+    boost::shared_ptr<progress_meter> meter
+        (create_progress_meter
+            (wl.size()
+            ,"Updating calculation summaries"
+            )
+        );
+    for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i)
+        {
+        wxDocMDIChildFrame const* c = dynamic_cast<wxDocMDIChildFrame*>(*i);
+        if(c)
+            {
+            IllustrationView* v = 
dynamic_cast<IllustrationView*>(c->GetView());
+            if(v)
+                {
+                v->DisplaySelectedValuesAsHtml();
+                }
+            }
+        if(!meter->reflect_progress())
+            {
+            break;
+            }
+        }
+    meter->culminate();
+}
+
diff --git a/skeleton.hpp b/skeleton.hpp
new file mode 100644
index 0000000..11b144e
--- /dev/null
+++ b/skeleton.hpp
@@ -0,0 +1,134 @@
+// Main file for life insurance illustrations with wx interface.
+//
+// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 
2012, 2013, 2014 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$
+
+// Portions of this file are derived from wxWindows files
+//   samples/docvwmdi/docview.h (C) 1998 Julian Smart and Markus Holzem
+// which is covered by the wxWindows license, and
+//   samples/html/printing/printing.cpp
+// which bears no copyright or license notice.
+//
+// GWC used that code as an application skeleton and printing
+// implementation, modifying it in 2002 and the later years given in
+// the copyright notice above.
+
+#ifndef skeleton_hpp
+#define skeleton_hpp
+
+#include "config.hpp"
+
+#include "obstruct_slicing.hpp"
+#include "uncopyable_lmi.hpp"
+
+#include <wx/app.h>
+#include <wx/timer.h>
+
+class DocManagerEx;
+class ViewEx;
+
+class WXDLLIMPEXP_FWD_CORE wxConfigBase;
+class WXDLLIMPEXP_FWD_CORE wxDocMDIParentFrame;
+class WXDLLIMPEXP_FWD_CORE wxDocument;
+class WXDLLIMPEXP_FWD_CORE wxMDIChildFrame;
+class WXDLLIMPEXP_FWD_CORE wxMenuBar;
+
+class Skeleton
+    :        public  wxApp
+    ,        private lmi::uncopyable <Skeleton>
+    ,virtual private obstruct_slicing<Skeleton>
+{
+  public:
+    Skeleton();
+    ~Skeleton();
+
+    // Called by view classes when they are instantiated.
+    wxMDIChildFrame* CreateChildFrame(wxDocument*, ViewEx*);
+
+  private:
+    wxMenuBar* AdjustMenus(wxMenuBar*);
+
+    void InitDocManager ();
+    void InitHelp       ();
+    void InitIcon       ();
+    void InitMenuBar    ();
+    void InitToolBar    ();
+
+    void UponAbout                        (wxCommandEvent&);
+    void UponDropFiles                    (wxDropFilesEvent&);
+    void UponEditDefaultCell              (wxCommandEvent&);
+    void UponHelp                         (wxCommandEvent&);
+    void UponMenuOpen                     (wxMenuEvent&);
+    void UponPaste                        (wxClipboardTextEvent&);
+    void UponPreferences                  (wxCommandEvent&);
+
+    // Test alerts from application.
+    void UponTestAppStatus                (wxCommandEvent&);
+    void UponTestAppWarning               (wxCommandEvent&);
+    void UponTestAppHobsons               (wxCommandEvent&);
+    void UponTestAppFatal                 (wxCommandEvent&);
+    void UponTestAppStandardException     (wxCommandEvent&);
+    void UponTestAppArbitraryException    (wxCommandEvent&);
+
+    // Test alerts from shared library.
+    void UponTestLibStatus                (wxCommandEvent&);
+    void UponTestLibWarning               (wxCommandEvent&);
+    void UponTestLibHobsons               (wxCommandEvent&);
+    void UponTestLibFatal                 (wxCommandEvent&);
+    void UponTestLibStandardException     (wxCommandEvent&);
+    void UponTestLibArbitraryException    (wxCommandEvent&);
+    void UponTestLibCatastropheReport     (wxCommandEvent&);
+
+    // Miscellaneous tests.
+    void UponTestDateConversions          (wxCommandEvent&);
+    void UponTestFloatingPointEnvironment (wxCommandEvent&);
+    void UponTestPasting                  (wxCommandEvent&);
+    void UponTestSystemCommand            (wxCommandEvent&);
+
+    void UponTimer                        (wxTimerEvent&);
+    void UponUpdateInapplicable           (wxUpdateUIEvent&);
+    void UponWindowCascade                (wxCommandEvent&);
+    void UponWindowNext                   (wxCommandEvent&);
+    void UponWindowPrevious               (wxCommandEvent&);
+    void UponWindowTileHorizontally       (wxCommandEvent&);
+    void UponWindowTileVertically         (wxCommandEvent&);
+
+    // wxApp overrides.
+    virtual bool OnExceptionInMainLoop ();
+    virtual int  OnExit                ();
+    virtual bool OnInit                ();
+    virtual void OnUnhandledException  ();
+
+    bool ProcessCommandLine(int argc, char* argv[]);
+    void UpdateViews();
+
+    wxConfigBase*         config_;
+    DocManagerEx*         doc_manager_;
+    wxDocMDIParentFrame*  frame_;
+    wxTimer               timer_;
+
+    DECLARE_EVENT_TABLE()
+};
+
+DECLARE_APP(Skeleton)
+
+#endif // skeleton_hpp
+
diff --git a/view_ex.cpp b/view_ex.cpp
index 7d821da..f506117 100644
--- a/view_ex.cpp
+++ b/view_ex.cpp
@@ -48,7 +48,7 @@
 #include "alert.hpp"
 #include "assert_lmi.hpp"
 #include "docmanager_ex.hpp"
-#include "main_wx.hpp" // wxGetApp()
+#include "skeleton.hpp" // wxGetApp()
 #include "safely_dereference_as.hpp"
 #include "wx_new.hpp"
 
diff --git a/workhorse.make b/workhorse.make
index 64c424b..426e7a7 100644
--- a/workhorse.make
+++ b/workhorse.make
@@ -96,6 +96,7 @@ default_targets := \
 ifneq (safestdlib,$(findstring safestdlib,$(build_type)))
   default_targets += \
     lmi_wx_shared$(EXEEXT) \
+    lmi_wx_lib_shared$(SHREXT) \
     wx_new$(SHREXT) \
 
 endif
@@ -823,12 +824,16 @@ libantediluvian.a libantediluvian$(SHREXT): 
$(antediluvian_common_objects)
 lmi_wx_monolithic$(EXEEXT): EXTRA_LDFLAGS := $(wx_ldflags)
 lmi_wx_monolithic$(EXEEXT): $(lmi_wx_objects) $(lmi_common_objects) 
wx_new$(SHREXT)
 
+lmi_wx_lib_shared$(SHREXT): lmi_so_attributes := -DLMI_USE_SO
+lmi_wx_lib_shared$(SHREXT): EXTRA_LDFLAGS := $(wx_ldflags)
+lmi_wx_lib_shared$(SHREXT): $(lmi_wx_lib_objects) liblmi$(SHREXT) 
wx_new$(SHREXT)
+
 lmi_wx_shared$(EXEEXT): lmi_so_attributes := -DLMI_USE_SO
 lmi_wx_shared$(EXEEXT): EXTRA_LDFLAGS := $(wx_ldflags)
-lmi_wx_shared$(EXEEXT): $(lmi_wx_objects) liblmi$(SHREXT) wx_new$(SHREXT)
+lmi_wx_shared$(EXEEXT): $(lmi_wx_objects) lmi_wx_lib_shared$(SHREXT) 
liblmi$(SHREXT) wx_new$(SHREXT)
 
 lmi_wx_static$(EXEEXT): EXTRA_LDFLAGS := $(wx_ldflags)
-lmi_wx_static$(EXEEXT): $(lmi_wx_objects) liblmi.a wx_new$(SHREXT)
+lmi_wx_static$(EXEEXT): $(lmi_wx_objects) $(lmi_wx_lib_objects) liblmi.a 
wx_new$(SHREXT)
 
 lmi_cli_monolithic$(EXEEXT): $(cli_objects) $(lmi_common_objects)
 
-- 
1.8.5.5




reply via email to

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