Initial implementation of the config snapshot dialog.

This commit is contained in:
bubnikv 2018-04-10 16:27:42 +02:00
parent 32c4cddb91
commit 0694fad016
9 changed files with 213 additions and 22 deletions

View File

@ -176,6 +176,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/AppConfig.hpp
${LIBDIR}/slic3r/GUI/BitmapCache.cpp
${LIBDIR}/slic3r/GUI/BitmapCache.hpp
${LIBDIR}/slic3r/GUI/ConfigSnapshotDialog.cpp
${LIBDIR}/slic3r/GUI/ConfigSnapshotDialog.hpp
${LIBDIR}/slic3r/GUI/3DScene.cpp
${LIBDIR}/slic3r/GUI/3DScene.hpp
${LIBDIR}/slic3r/GUI/GLShader.cpp
@ -218,6 +220,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
${LIBDIR}/slic3r/Utils/Bonjour.cpp
${LIBDIR}/slic3r/Utils/Bonjour.hpp
${LIBDIR}/slic3r/Utils/Time.cpp
${LIBDIR}/slic3r/Utils/Time.hpp
)
add_library(admesh STATIC
@ -408,7 +412,7 @@ if(APPLE)
# Ignore undefined symbols of the perl interpreter, they will be found in the caller image.
target_link_libraries(XS "-undefined dynamic_lookup")
endif()
target_link_libraries(XS libslic3r libslic3r_gui admesh miniz clipper nowide polypartition poly2tri)
target_link_libraries(XS libslic3r libslic3r_gui admesh miniz clipper nowide polypartition poly2tri semver)
if(SLIC3R_PROFILE)
target_link_libraries(XS Shiny)
endif()

View File

@ -241,7 +241,7 @@ static void delete_existing_ini_files(const boost::filesystem::path &path)
boost::filesystem::remove(dir_entry.path());
}
const Snapshot& SnapshotDB::make_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment)
const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment)
{
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
boost::filesystem::path snapshot_db_dir = SnapshotDB::create_db_dir();
@ -267,8 +267,10 @@ const Snapshot& SnapshotDB::make_snapshot(const AppConfig &app_config, Snapshot:
}
// Vendor specific config bundles and installed printers.
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
boost::filesystem::create_directory(snapshot_dir);
// Backup the presets.
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
for (const char *subdir : { "print", "filament", "printer", "vendor" })
copy_config_dir_single_level(data_dir / subdir, snapshot_dir / subdir);
snapshot.save_ini((snapshot_dir / "snapshot.ini").string());
@ -322,7 +324,7 @@ boost::filesystem::path SnapshotDB::create_db_dir()
SnapshotDB& SnapshotDB::singleton()
{
static SnapshotDB instance;
bool loaded = false;
static bool loaded = false;
if (! loaded) {
try {
loaded = true;

View File

@ -91,7 +91,7 @@ public:
// Create a snapshot directory, copy the vendor config bundles, user print/filament/printer profiles,
// create an index.
const Snapshot& make_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment);
const Snapshot& take_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment);
void restore_snapshot(const std::string &id, AppConfig &app_config);
void restore_snapshot(const Snapshot &snapshot, AppConfig &app_config);

View File

@ -0,0 +1,110 @@
#include "ConfigSnapshotDialog.hpp"
#include "../Config/Snapshot.hpp"
#include "../Utils/Time.hpp"
#include "../../libslic3r/Utils.hpp"
namespace Slic3r {
namespace GUI {
static std::string generate_html_row(const Config::Snapshot &snapshot, bool row_even)
{
// Start by declaring a row with an alternating background color.
std::string text = "<tr bgcolor=\"";
text += row_even ? "#FFFFFF" : "#C0C0C0";
text += "\">";
text += "<td>";
// text += _(L("ID:")) + " " + snapshot.id + "<br>";
text += _(L("time captured:")) + " " + Utils::format_local_date_time(snapshot.time_captured) + "<br>";
text += _(L("slic3r version:")) + " " + snapshot.slic3r_version_captured.to_string() + "<br>";
if (! snapshot.comment.empty())
text += _(L("user comment:")) + " " + snapshot.comment + "<br>";
// text += "reason: " + snapshot.reason + "<br>";
text += "print: " + snapshot.print + "<br>";
text += "filaments: " + snapshot.filaments.front() + "<br>";
text += "printer: " + snapshot.printer + "<br>";
for (const Config::Snapshot::VendorConfig &vc : snapshot.vendor_configs) {
text += "vendor: " + vc.name + ", ver: " + vc.version.to_string() + ", min slic3r ver: " + vc.min_slic3r_version.to_string() + ", max slic3r ver: " + vc.max_slic3r_version.to_string() + "<br>";
}
text += "<p align=\"right\"><a href=\"" + snapshot.id + "\">Activate</a></p>";
text += "</td>";
text += "</tr>";
return text;
}
static std::string generate_html_page(const Config::SnapshotDB &snapshot_db)
{
std::string text =
"<html>"
"<body bgcolor=\"#ffffff\" cellspacing=\"2\" cellpadding=\"0\" border=\"0\" link=\"#800000\">"
"<font color=\"#000000\">";
text += "<table style=\"width:100%\">";
for (size_t i_row = 0; i_row < snapshot_db.snapshots().size(); ++ i_row) {
const Config::Snapshot &snapshot = snapshot_db.snapshots()[i_row];
text += generate_html_row(snapshot, i_row & 1);
}
text +=
"</table>"
"</font>"
"</body>"
"</html>";
return text;
}
ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db)
: wxDialog(NULL, wxID_ANY, _(L("Configuration Snapshots")), wxDefaultPosition, wxSize(600, 500), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
{
this->SetBackgroundColour(*wxWHITE);
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
this->SetSizer(vsizer);
// text
wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
{
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
#ifdef __WXMSW__
int size[] = {8,8,8,8,8,8,8};
#else
int size[] = {11,11,11,11,11,11,11};
#endif
html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
html->SetBorders(2);
std::string text = generate_html_page(snapshot_db);
FILE *file = ::fopen("d:\\temp\\configsnapshotdialog.html", "wt");
fwrite(text.data(), 1, text.size(), file);
fclose(file);
html->SetPage(text.c_str());
vsizer->Add(html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 0);
html->Bind(wxEVT_HTML_LINK_CLICKED, &ConfigSnapshotDialog::onLinkClicked, this);
}
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE);
this->SetEscapeId(wxID_CLOSE);
this->Bind(wxEVT_BUTTON, &ConfigSnapshotDialog::onCloseDialog, this, wxID_CLOSE);
vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
/*
this->Bind(wxEVT_LEFT_DOWN, &ConfigSnapshotDialog::onCloseDialog, this);
logo->Bind(wxEVT_LEFT_DOWN, &ConfigSnapshotDialog::onCloseDialog, this);
html->Bind(wxEVT_LEFT_DOWN, &ConfigSnapshotDialog::onCloseDialog, this);
*/
}
void ConfigSnapshotDialog::onLinkClicked(wxHtmlLinkEvent &event)
{
wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref());
event.Skip(false);
}
void ConfigSnapshotDialog::onCloseDialog(wxEvent &)
{
this->EndModal(wxID_CLOSE);
this->Close();
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,30 @@
#ifndef slic3r_GUI_ConfigSnapshotDialog_hpp_
#define slic3r_GUI_ConfigSnapshotDialog_hpp_
#include "GUI.hpp"
#include <wx/wx.h>
#include <wx/intl.h>
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
namespace Config {
class SnapshotDB;
}
class ConfigSnapshotDialog : public wxDialog
{
public:
ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db);
private:
void onLinkClicked(wxHtmlLinkEvent &event);
void onCloseDialog(wxEvent &);
};
} // namespace GUI
} // namespace Slic3r
#endif /* slic3r_GUI_ConfigSnapshotDialog_hpp_ */

View File

@ -44,10 +44,13 @@
#include "TabIface.hpp"
#include "AboutDialog.hpp"
#include "AppConfig.hpp"
#include "ConfigSnapshotDialog.hpp"
#include "Utils.hpp"
#include "Preferences.hpp"
#include "PresetBundle.hpp"
#include "../Config/Snapshot.hpp"
namespace Slic3r { namespace GUI {
#if __APPLE__
@ -357,6 +360,17 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application Language")));
local_menu->Bind(wxEVT_MENU, [config_id_base, event_language_change, event_preferences_changed](wxEvent &event){
switch (event.GetId() - config_id_base) {
case ConfigMenuTakeSnapshot:
// Take a configuration snapshot.
Slic3r::GUI::Config::SnapshotDB::singleton().take_snapshot(*g_AppConfig, Slic3r::GUI::Config::Snapshot::SNAPSHOT_USER, "");
break;
case ConfigMenuSnapshots:
{
ConfigSnapshotDialog dlg(Slic3r::GUI::Config::SnapshotDB::singleton());
dlg.ShowModal();
dlg.Destroy();
break;
}
case ConfigMenuPreferences:
{
auto dlg = new PreferencesDialog(g_wxMainFrame, event_preferences_changed);

View File

@ -46,11 +46,23 @@ public:
return Semver(ver);
}
Semver(Semver &&other) { *this = std::move(other); }
Semver(const Semver &other) { *this = other; }
Semver(Semver &&other) : ver(other.ver)
{
other.ver.major = other.ver.minor = other.ver.patch = 0;
other.ver.metadata = other.ver.prerelease = nullptr;
}
Semver(const Semver &other) : ver(other.ver)
{
if (other.ver.metadata != nullptr)
std::strcpy(ver.metadata, other.ver.metadata);
if (other.ver.prerelease != nullptr)
std::strcpy(ver.prerelease, other.ver.prerelease);
}
Semver &operator=(Semver &&other)
{
::semver_free(&ver);
ver = other.ver;
other.ver.major = other.ver.minor = other.ver.patch = 0;
other.ver.metadata = other.ver.prerelease = nullptr;

View File

@ -1,13 +1,18 @@
#include "Time.hpp"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif /* WIN32 */
namespace Slic3r {
namespace Utils {
time_t parse_time_ISO8601Z(const std::string &sdate)
{
int y, M, d, h, m;
float s;
if (sscanf(sdate.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s) != 6)
int y, M, d, h, m, s;
if (sscanf(sdate.c_str(), "%04d%02d%02dT%02d%02d%02dZ", &y, &M, &d, &h, &m, &s) != 6)
return (time_t)-1;
struct tm tms;
tms.tm_year = y - 1900; // Year since 1900
@ -15,7 +20,7 @@ time_t parse_time_ISO8601Z(const std::string &sdate)
tms.tm_mday = d; // 1-31
tms.tm_hour = h; // 0-23
tms.tm_min = m; // 0-59
tms.tm_sec = (int)s; // 0-61 (0-60 in C++11)
tms.tm_sec = s; // 0-61 (0-60 in C++11)
return mktime(&tms);
}
@ -23,21 +28,34 @@ std::string format_time_ISO8601Z(time_t time)
{
struct tm tms;
#ifdef WIN32
gmtime_s(time, &tms);
gmtime_s(&tms, &time);
#else
gmtime_r(&tms, time);
gmtime_r(&time, &tms);
#endif
char buf[128];
sprintf(buf, "%d-%d-%dT%d:%d:%fZ",
tms.tm_year + 1900
tms.tm_mon + 1
tms.tm_mday
tms.tm_hour
tms.tm_min
sprintf(buf, "%04d%02d%02dT%02d%02d%02dZ",
tms.tm_year + 1900,
tms.tm_mon + 1,
tms.tm_mday,
tms.tm_hour,
tms.tm_min,
tms.tm_sec);
return buf;
}
std::string format_local_date_time(time_t time)
{
struct tm tms;
#ifdef WIN32
localtime_s(&tms, &time);
#else
localtime_r(&time, &tms);
#endif
char buf[80];
strftime(buf, 80, "%x %X", &tms);
return buf;
}
time_t get_current_time_utc()
{
#ifdef WIN32
@ -59,5 +77,3 @@ time_t get_current_time_utc()
}; // namespace Utils
}; // namespace Slic3r
#endif /* slic3r_Utils_Time_hpp_ */

View File

@ -13,8 +13,11 @@ namespace Utils {
extern time_t parse_time_ISO8601Z(const std::string &s);
extern std::string format_time_ISO8601Z(time_t time);
// Format the date and time from an UTC time according to the active locales and a local time zone.
extern std::string format_local_date_time(time_t time);
// There is no gmtime() on windows.
time_t get_current_time_utc();
extern time_t get_current_time_utc();
}; // namespace Utils
}; // namespace Slic3r