[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] (no subject)
From: |
Greg Chicares |
Subject: |
[lmi-commits] (no subject) |
Date: |
Sun, 12 Jun 2016 19:58:27 +0000 (UTC) |
branch: master
commit 7666adcc94bdc103d2955e275981cf035df1e8af
Author: Gregory W. Chicares <address@hidden>
Date: Sun Jun 12 19:56:30 2016 +0000
Use native paths with file and directory pickers
Convert paths in 'configurable_settings.xml' to native when loading,
and to generic when saving, so that the GUI always shows backslashes
under msw but they don't leak into the xml.
A normal standalone unit test is insufficient because the actual
behavior of boost::filesystem may differ when a DLL boundary is
crossed:
http://lists.nongnu.org/archive/html/lmi/2016-06/msg00058.html
so, temporarily, a tiny test is included here. Given the apparent
fragility of this library, the msw-specific workaround for file and
directory pickers is platform conditional.
---
preferences_model.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 63 insertions(+), 4 deletions(-)
diff --git a/preferences_model.cpp b/preferences_model.cpp
index e560c89..0c35c47 100644
--- a/preferences_model.cpp
+++ b/preferences_model.cpp
@@ -28,6 +28,9 @@
#include "miscellany.hpp" // begins_with()
#include "value_cast.hpp"
+#include <boost/filesystem/operations.hpp> // fs::system_complete()
+#include <boost/filesystem/path.hpp>
+
#include <cstddef> // std::size_t
#include <sstream>
#include <vector>
@@ -46,12 +49,68 @@ bool is_calculation_summary_column_name(std::string const&
member_name)
{
return begins_with(member_name, "CalculationSummaryColumn");
}
+
+/// Convert "C:\native\path" to "/generic/path". Cf. native_path().
+
+std::string generic_path(std::string const& s)
+{
+#if defined LMI_MSW
+ return fs::system_complete(fs::path(s)).string();
+#else // !defined LMI_MSW
+ return s;
+#endif // !defined LMI_MSW
+}
+
+/// Convert "/generic/path" to "C:\native\path".
+///
+/// wxDirPickerCtrl and wxFilePickerCtrl hold native paths internally,
+/// so calling SetPath("/x/y") on msw changes their internal state to
+/// something like "C:\x\y". However, lmi's MVC framework assumes that
+/// setting a textcontrol from a string establishes the postcondition
+/// that the textcontrol's contents are identical to the string. Thus,
+/// these controls in effect force the use of native paths, while lmi
+/// prefers forward slashes as path delimiters. This function and its
+/// counterpart generic_path() are used to translate between the two
+/// styles, so that backward slashes are sequestered in the GUI and do
+/// not flow into 'configurable_settings.xml'.
+///
+/// At least with the version of boost currently used (2016-06),
+/// native_file_string() and native_directory_string() are identical,
+/// so there is no need to differentiate between directories and
+/// filepaths.
+
+std::string native_path(std::string const& s)
+{
+#if defined LMI_MSW
+ return fs::system_complete(fs::path(s)).native_file_string();
+#else // !defined LMI_MSW
+ return s;
+#endif // !defined LMI_MSW
+}
} // Unnamed namespace.
PreferencesModel::PreferencesModel()
{
AscribeMembers();
Load();
+
+ // Temporary unit test, to be removed before release.
+ std::string const g("/path/to/somewhere");
+ std::string const n("C:\\path\\to\\somewhere");
+ warning()
+ << "Remove this test before release.\n"
+ << g << " g (generic)\n"
+ << n << " n (native)\n"
+ << generic_path(n) << " generic_path(n)\n"
+ << native_path (g) << " native_path(g)\n"
+ << generic_path(g) << " generic_path(g)\n"
+ << native_path (n) << " native_path (n)\n"
+ << "Oh, and BTW...\n"
+ << fs::path("foo\\bar\\data.txt", fs::no_check).string() << " <--
fs::path(\"foo\\bar\\data.txt\", fs::no_check).string()\n"
+ << "...but OTOH...\n"
+ << fs::path("foo\\bar\\data.txt" ).string() << " <--
fs::path(\"foo\\bar\\data.txt\" ).string()\n"
+ << LMI_FLUSH
+ ;
}
PreferencesModel::~PreferencesModel()
@@ -230,8 +289,8 @@ void PreferencesModel::Load()
}
}
- DefaultInputFilename = z.default_input_filename();
- PrintDirectory = z.print_directory();
+ DefaultInputFilename = native_path(z.default_input_filename());
+ PrintDirectory = native_path(z.print_directory());
SecondsToPauseBetweenPrintouts = z.seconds_to_pause_between_printouts();
SkinFileName = z.skin_filename();
UseBuiltinCalculationSummary = z.use_builtin_calculation_summary() ?
"Yes" : "No";
@@ -261,8 +320,8 @@ void PreferencesModel::Save() const
configurable_settings& z = configurable_settings::instance();
z["calculation_summary_columns" ] = string_of_column_names();
- z["default_input_filename" ] = DefaultInputFilename .value();
- z["print_directory" ] = PrintDirectory .value();
+ z["default_input_filename" ] =
generic_path(DefaultInputFilename .value());
+ z["print_directory" ] = generic_path(PrintDirectory
.value());
z["seconds_to_pause_between_printouts"] =
value_cast<std::string>(SecondsToPauseBetweenPrintouts.value());
z["skin_filename" ] = SkinFileName .value();
z["use_builtin_calculation_summary" ] = value_cast<std::string>("Yes" ==
UseBuiltinCalculationSummary);