mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_3dconnexion
This commit is contained in:
		
						commit
						7007d81519
					
				
					 16 changed files with 328 additions and 102 deletions
				
			
		| 
						 | 
				
			
			@ -37,7 +37,7 @@ set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
 | 
			
		|||
 | 
			
		||||
# Proposal for C++ unit tests and sandboxes
 | 
			
		||||
option(SLIC3R_BUILD_SANDBOXES   "Build development sandboxes" OFF)
 | 
			
		||||
option(SLIC3R_BUILD_TESTS       "Build unit tests" OFF)
 | 
			
		||||
option(SLIC3R_BUILD_TESTS       "Build unit tests" ON)
 | 
			
		||||
 | 
			
		||||
# Print out the SLIC3R_* cache options
 | 
			
		||||
get_cmake_property(_cache_vars CACHE_VARIABLES)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,8 +271,6 @@ ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key &opt_key, Con
 | 
			
		|||
	return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ConfigOptionDef::nocli = "~~~noCLI";
 | 
			
		||||
 | 
			
		||||
std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function<bool(const ConfigOptionDef &)> filter) const
 | 
			
		||||
{
 | 
			
		||||
    // prepare a function for wrapping text
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1444,7 +1444,7 @@ public:
 | 
			
		|||
    std::vector<std::string> cli_args(const std::string &key) const;
 | 
			
		||||
 | 
			
		||||
    // Assign this key to cli to disable CLI for this option.
 | 
			
		||||
    static std::string                  nocli;
 | 
			
		||||
    static const constexpr char *nocli =  "~~~noCLI";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Map from a config option name to its definition.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ void SLARasterWriter::set_config(const DynamicPrintConfig &cfg)
 | 
			
		|||
    m_config["printerProfile"] = get_cfg_value(cfg, "printer_settings_id");
 | 
			
		||||
    m_config["printProfile"]   = get_cfg_value(cfg, "sla_print_settings_id");
 | 
			
		||||
 | 
			
		||||
    m_config["fileCreationTimestamp"] = Utils::current_utc_time2str();
 | 
			
		||||
    m_config["fileCreationTimestamp"] = Utils::utc_timestamp();
 | 
			
		||||
    m_config["prusaSlicerVersion"]    = SLIC3R_BUILD_ID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,116 +3,232 @@
 | 
			
		|||
#include <iomanip>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <ctime>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
//#include <boost/date_time/local_time/local_time.hpp>
 | 
			
		||||
//#include <boost/chrono.hpp>
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
#include <map>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
	#include <windows.h>
 | 
			
		||||
	#undef WIN32_LEAN_AND_MEAN
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
#include "libslic3r/Utils.hpp"
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace Utils {
 | 
			
		||||
 | 
			
		||||
namespace  {
 | 
			
		||||
// "YYYY-MM-DD at HH:MM::SS [UTC]"
 | 
			
		||||
// If TimeZone::utc is used with the conversion functions, it will append the
 | 
			
		||||
// UTC letters to the end.
 | 
			
		||||
static const constexpr char *const SLICER_UTC_TIME_FMT = "%Y-%m-%d at %T";
 | 
			
		||||
 | 
			
		||||
// FIXME: after we switch to gcc > 4.9 on the build server, please remove me
 | 
			
		||||
#if defined(__GNUC__) && __GNUC__ <= 4
 | 
			
		||||
std::string put_time(const std::tm *tm, const char *fmt)
 | 
			
		||||
// ISO8601Z representation of time, without time zone info
 | 
			
		||||
static const constexpr char *const ISO8601Z_TIME_FMT = "%Y%m%dT%H%M%SZ";
 | 
			
		||||
 | 
			
		||||
static const char * get_fmtstr(TimeFormat fmt)
 | 
			
		||||
{
 | 
			
		||||
    static const constexpr int MAX_CHARS = 200;
 | 
			
		||||
    char out[MAX_CHARS];
 | 
			
		||||
    std::strftime(out, MAX_CHARS, fmt, tm);
 | 
			
		||||
    return out;
 | 
			
		||||
    switch (fmt) {
 | 
			
		||||
    case TimeFormat::gcode: return SLICER_UTC_TIME_FMT;
 | 
			
		||||
    case TimeFormat::iso8601Z: return ISO8601Z_TIME_FMT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return "";
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
auto put_time(const std::tm *tm, const char *fmt) -> decltype (std::put_time(tm, fmt))
 | 
			
		||||
 | 
			
		||||
namespace __get_put_time_emulation {
 | 
			
		||||
// FIXME: Implementations with the cpp11 put_time and get_time either not
 | 
			
		||||
// compile or do not pass the tests on the build server. If we switch to newer
 | 
			
		||||
// compilers, this namespace can be deleted with all its content.
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
// VS2019 implementation fails with ISO8601Z_TIME_FMT.
 | 
			
		||||
// VS2019 does not have std::strptime either. See bug:
 | 
			
		||||
// https://developercommunity.visualstudio.com/content/problem/140618/c-stdget-time-not-parsing-correctly.html
 | 
			
		||||
 | 
			
		||||
static const std::map<std::string, std::string> sscanf_fmt_map = {
 | 
			
		||||
    {SLICER_UTC_TIME_FMT, "%04d-%02d-%02d at %02d:%02d:%02d"},
 | 
			
		||||
    {std::string(SLICER_UTC_TIME_FMT) + " UTC", "%04d-%02d-%02d at %02d:%02d:%02d UTC"},
 | 
			
		||||
    {ISO8601Z_TIME_FMT, "%04d%02d%02dT%02d%02d%02dZ"}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char * strptime(const char *str, const char *const fmt, std::tm *tms)
 | 
			
		||||
{
 | 
			
		||||
    return std::put_time(tm, fmt);
 | 
			
		||||
    auto it = sscanf_fmt_map.find(fmt);
 | 
			
		||||
    if (it == sscanf_fmt_map.end()) return nullptr;
 | 
			
		||||
 | 
			
		||||
    int y, M, d, h, m, s;
 | 
			
		||||
    if (sscanf(str, it->second.c_str(), &y, &M, &d, &h, &m, &s) != 6)
 | 
			
		||||
        return nullptr;
 | 
			
		||||
 | 
			
		||||
    tms->tm_year = y - 1900;  // Year since 1900
 | 
			
		||||
    tms->tm_mon  = M - 1;     // 0-11
 | 
			
		||||
    tms->tm_mday = d;         // 1-31
 | 
			
		||||
    tms->tm_hour = h;         // 0-23
 | 
			
		||||
    tms->tm_min  = m;         // 0-59
 | 
			
		||||
    tms->tm_sec  = s;         // 0-61 (0-60 in C++11)
 | 
			
		||||
 | 
			
		||||
    return str; // WARN strptime return val should point after the parsed string
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template<class Ttm>
 | 
			
		||||
struct GetPutTimeReturnT {
 | 
			
		||||
    Ttm *tms;
 | 
			
		||||
    const char *fmt;
 | 
			
		||||
    GetPutTimeReturnT(Ttm *_tms, const char *_fmt): tms(_tms), fmt(_fmt) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using GetTimeReturnT = GetPutTimeReturnT<std::tm>;
 | 
			
		||||
using PutTimeReturnT = GetPutTimeReturnT<const std::tm>;
 | 
			
		||||
 | 
			
		||||
std::ostream &operator<<(std::ostream &stream, PutTimeReturnT &&pt)
 | 
			
		||||
{
 | 
			
		||||
    static const constexpr int MAX_CHARS = 200;
 | 
			
		||||
    char _out[MAX_CHARS];
 | 
			
		||||
    strftime(_out, MAX_CHARS, pt.fmt, pt.tms);
 | 
			
		||||
    stream << _out;
 | 
			
		||||
    return stream;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
time_t parse_time_ISO8601Z(const std::string &sdate)
 | 
			
		||||
inline PutTimeReturnT put_time(const std::tm *tms, const char *fmt)
 | 
			
		||||
{
 | 
			
		||||
	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
 | 
			
		||||
	tms.tm_mon  = M - 1;     // 0-11
 | 
			
		||||
	tms.tm_mday = d;         // 1-31
 | 
			
		||||
	tms.tm_hour = h;         // 0-23
 | 
			
		||||
	tms.tm_min  = m;         // 0-59
 | 
			
		||||
	tms.tm_sec  = s;         // 0-61 (0-60 in C++11)
 | 
			
		||||
    return {tms, fmt};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::istream &operator>>(std::istream &stream, GetTimeReturnT &>)
 | 
			
		||||
{
 | 
			
		||||
    std::string line;
 | 
			
		||||
    std::getline(stream, line);
 | 
			
		||||
 | 
			
		||||
    if (strptime(line.c_str(), gt.fmt, gt.tms) == nullptr)
 | 
			
		||||
        stream.setstate(std::ios::failbit);
 | 
			
		||||
 | 
			
		||||
    return stream;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline GetTimeReturnT get_time(std::tm *tms, const char *fmt)
 | 
			
		||||
{
 | 
			
		||||
    return {tms, fmt};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
// Platform independent versions of gmtime and localtime. Completely thread
 | 
			
		||||
// safe only on Linux. MSVC gtime_s and localtime_s sets global errno thus not
 | 
			
		||||
// thread safe.
 | 
			
		||||
struct std::tm * _gmtime_r(const time_t *timep, struct tm *result)
 | 
			
		||||
{
 | 
			
		||||
    assert(timep != nullptr && result != nullptr);
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	return _mkgmtime(&tms);
 | 
			
		||||
    time_t t = *timep;
 | 
			
		||||
    gmtime_s(result, &t);
 | 
			
		||||
    return result;
 | 
			
		||||
#else
 | 
			
		||||
    return gmtime_r(timep, result);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct std::tm * _localtime_r(const time_t *timep, struct tm *result)
 | 
			
		||||
{
 | 
			
		||||
    assert(timep != nullptr && result != nullptr);
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    // Converts a time_t time value to a tm structure, and corrects for the
 | 
			
		||||
    // local time zone.
 | 
			
		||||
    time_t t = *timep;
 | 
			
		||||
    localtime_s(result, &t);
 | 
			
		||||
    return result;
 | 
			
		||||
#else
 | 
			
		||||
    return localtime_r(timep, result);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
time_t _mktime(const struct std::tm *tms)
 | 
			
		||||
{
 | 
			
		||||
    assert(tms != nullptr);
 | 
			
		||||
    std::tm _tms = *tms;
 | 
			
		||||
    return mktime(&_tms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
time_t _timegm(const struct std::tm *tms)
 | 
			
		||||
{
 | 
			
		||||
    std::tm _tms = *tms;
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    return _mkgmtime(&_tms);
 | 
			
		||||
#else /* WIN32 */
 | 
			
		||||
	return timegm(&tms);
 | 
			
		||||
    return timegm(&_tms);
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string format_time_ISO8601Z(time_t time)
 | 
			
		||||
std::string process_format(const char *fmt, TimeZone zone)
 | 
			
		||||
{
 | 
			
		||||
	struct tm tms;
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	gmtime_s(&tms, &time);
 | 
			
		||||
#else
 | 
			
		||||
	gmtime_r(&time, &tms);
 | 
			
		||||
#endif
 | 
			
		||||
	char buf[128];
 | 
			
		||||
	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 fmtstr(fmt);
 | 
			
		||||
 | 
			
		||||
    if (fmtstr == SLICER_UTC_TIME_FMT && zone == TimeZone::utc)
 | 
			
		||||
        fmtstr += " UTC";
 | 
			
		||||
 | 
			
		||||
    return fmtstr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string format_local_date_time(time_t time)
 | 
			
		||||
{
 | 
			
		||||
	struct tm tms;
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	// Converts a time_t time value to a tm structure, and corrects for the local time zone.
 | 
			
		||||
	localtime_s(&tms, &time);
 | 
			
		||||
#else
 | 
			
		||||
	localtime_r(&time, &tms);
 | 
			
		||||
#endif
 | 
			
		||||
    char buf[80];
 | 
			
		||||
 	strftime(buf, 80, "%x %X", &tms);
 | 
			
		||||
    return buf;
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
time_t get_current_time_utc()
 | 
			
		||||
{    
 | 
			
		||||
{
 | 
			
		||||
    using clk = std::chrono::system_clock;
 | 
			
		||||
    return clk::to_time_t(clk::now());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::string tm2str(const std::tm *tm, const char *fmt)
 | 
			
		||||
static std::string tm2str(const std::tm *tms, const char *fmt)
 | 
			
		||||
{
 | 
			
		||||
    std::stringstream ss;
 | 
			
		||||
    ss << put_time(tm, fmt);
 | 
			
		||||
    ss.imbue(std::locale("C"));
 | 
			
		||||
    ss << __get_put_time_emulation::put_time(tms, fmt);
 | 
			
		||||
    return ss.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string time2str(const time_t &t, TimeZone zone, const char *fmt)
 | 
			
		||||
std::string time2str(const time_t &t, TimeZone zone, TimeFormat fmt)
 | 
			
		||||
{
 | 
			
		||||
    std::string ret;
 | 
			
		||||
    
 | 
			
		||||
    std::tm tms = {};
 | 
			
		||||
    tms.tm_isdst = -1;
 | 
			
		||||
    std::string fmtstr = process_format(get_fmtstr(fmt), zone);
 | 
			
		||||
 | 
			
		||||
    switch (zone) {
 | 
			
		||||
    case TimeZone::local: ret = tm2str(std::localtime(&t), fmt); break;
 | 
			
		||||
    case TimeZone::utc:   ret = tm2str(std::gmtime(&t), fmt) + " UTC"; break;
 | 
			
		||||
    case TimeZone::local:
 | 
			
		||||
        ret = tm2str(_localtime_r(&t, &tms), fmtstr.c_str()); break;
 | 
			
		||||
    case TimeZone::utc:
 | 
			
		||||
        ret = tm2str(_gmtime_r(&t, &tms), fmtstr.c_str()); break;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static time_t str2time(std::istream &stream, TimeZone zone, const char *fmt)
 | 
			
		||||
{
 | 
			
		||||
    std::tm tms = {};
 | 
			
		||||
    tms.tm_isdst = -1;
 | 
			
		||||
 | 
			
		||||
    stream >> __get_put_time_emulation::get_time(&tms, fmt);
 | 
			
		||||
    time_t ret = time_t(-1);
 | 
			
		||||
 | 
			
		||||
    switch (zone) {
 | 
			
		||||
    case TimeZone::local: ret = _mktime(&tms); break;
 | 
			
		||||
    case TimeZone::utc:   ret = _timegm(&tms); break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (stream.fail() || ret < time_t(0)) ret = time_t(-1);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
time_t str2time(const std::string &str, TimeZone zone, TimeFormat fmt)
 | 
			
		||||
{
 | 
			
		||||
    std::string fmtstr = process_format(get_fmtstr(fmt), zone).c_str();
 | 
			
		||||
    std::stringstream ss(str);
 | 
			
		||||
 | 
			
		||||
    ss.imbue(std::locale("C"));
 | 
			
		||||
    return str2time(ss, zone, fmtstr.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}; // namespace Utils
 | 
			
		||||
}; // namespace Slic3r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,41 +7,61 @@
 | 
			
		|||
namespace Slic3r {
 | 
			
		||||
namespace Utils {
 | 
			
		||||
 | 
			
		||||
// Utilities to convert an UTC time_t to/from an ISO8601 time format,
 | 
			
		||||
// useful for putting timestamps into file and directory names.
 | 
			
		||||
// Returns (time_t)-1 on error.
 | 
			
		||||
time_t parse_time_ISO8601Z(const std::string &s);
 | 
			
		||||
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.
 | 
			
		||||
// TODO: make sure time2str is a suitable replacement
 | 
			
		||||
std::string format_local_date_time(time_t time);
 | 
			
		||||
 | 
			
		||||
// There is no gmtime() on windows.
 | 
			
		||||
// Should be thread safe.
 | 
			
		||||
time_t get_current_time_utc();
 | 
			
		||||
 | 
			
		||||
const constexpr char *const SLIC3R_TIME_FMT = "%Y-%m-%d at %T";
 | 
			
		||||
 | 
			
		||||
enum class TimeZone { local, utc };
 | 
			
		||||
enum class TimeFormat { gcode, iso8601Z };
 | 
			
		||||
 | 
			
		||||
std::string time2str(const time_t &t, TimeZone zone, const char *fmt = SLIC3R_TIME_FMT);
 | 
			
		||||
// time_t to string functions...
 | 
			
		||||
 | 
			
		||||
inline std::string current_time2str(TimeZone zone, const char *fmt = SLIC3R_TIME_FMT)
 | 
			
		||||
std::string time2str(const time_t &t, TimeZone zone, TimeFormat fmt);
 | 
			
		||||
 | 
			
		||||
inline std::string time2str(TimeZone zone, TimeFormat fmt)
 | 
			
		||||
{
 | 
			
		||||
    return time2str(get_current_time_utc(), zone, fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::string current_local_time2str(const char * fmt = SLIC3R_TIME_FMT)
 | 
			
		||||
inline std::string utc_timestamp(time_t t)
 | 
			
		||||
{
 | 
			
		||||
    return current_time2str(TimeZone::local, fmt);    
 | 
			
		||||
    return time2str(t, TimeZone::utc, TimeFormat::gcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::string current_utc_time2str(const char * fmt = SLIC3R_TIME_FMT)
 | 
			
		||||
inline std::string utc_timestamp()
 | 
			
		||||
{
 | 
			
		||||
    return current_time2str(TimeZone::utc, fmt);
 | 
			
		||||
    return utc_timestamp(get_current_time_utc());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}; // namespace Utils
 | 
			
		||||
}; // namespace Slic3r
 | 
			
		||||
// String to time_t function. Returns time_t(-1) if fails to parse the input.
 | 
			
		||||
time_t str2time(const std::string &str, TimeZone zone, TimeFormat fmt);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// /////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Utilities to convert an UTC time_t to/from an ISO8601 time format,
 | 
			
		||||
// useful for putting timestamps into file and directory names.
 | 
			
		||||
// Returns (time_t)-1 on error.
 | 
			
		||||
 | 
			
		||||
// Use these functions to convert safely to and from the ISO8601 format on
 | 
			
		||||
// all platforms
 | 
			
		||||
 | 
			
		||||
inline std::string iso_utc_timestamp(time_t t)
 | 
			
		||||
{
 | 
			
		||||
    return time2str(t, TimeZone::utc, TimeFormat::gcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::string iso_utc_timestamp()
 | 
			
		||||
{
 | 
			
		||||
    return iso_utc_timestamp(get_current_time_utc());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline time_t parse_iso_utc_timestamp(const std::string &str)
 | 
			
		||||
{
 | 
			
		||||
    return str2time(str, TimeZone::utc, TimeFormat::iso8601Z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// /////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
} // namespace Utils
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
 | 
			
		||||
#endif /* slic3r_Utils_Time_hpp_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
#include <utility>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <system_error>
 | 
			
		||||
 | 
			
		||||
#include "libslic3r.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -543,7 +543,7 @@ std::string string_printf(const char *format, ...)
 | 
			
		|||
 | 
			
		||||
std::string header_slic3r_generated()
 | 
			
		||||
{
 | 
			
		||||
    return std::string("generated by " SLIC3R_APP_NAME " " SLIC3R_VERSION " on " ) + Utils::current_utc_time2str();
 | 
			
		||||
    return std::string("generated by " SLIC3R_APP_NAME " " SLIC3R_VERSION " on " ) + Utils::utc_timestamp();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned get_current_pid()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,7 +66,7 @@ void Snapshot::load_ini(const std::string &path)
 | 
			
		|||
                if (kvp.first == "id")
 | 
			
		||||
                    this->id = kvp.second.data();
 | 
			
		||||
                else if (kvp.first == "time_captured") {
 | 
			
		||||
                	this->time_captured = Slic3r::Utils::parse_time_ISO8601Z(kvp.second.data());
 | 
			
		||||
                	this->time_captured = Slic3r::Utils::parse_iso_utc_timestamp(kvp.second.data());
 | 
			
		||||
					if (this->time_captured == (time_t)-1)
 | 
			
		||||
				        throw_on_parse_error("invalid timestamp");
 | 
			
		||||
                } else if (kvp.first == "slic3r_version_captured") {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +165,7 @@ void Snapshot::save_ini(const std::string &path)
 | 
			
		|||
    // Export the common "snapshot".
 | 
			
		||||
	c << std::endl << "[snapshot]" << std::endl;
 | 
			
		||||
	c << "id = " << this->id << std::endl;
 | 
			
		||||
	c << "time_captured = " << Slic3r::Utils::format_time_ISO8601Z(this->time_captured) << std::endl;
 | 
			
		||||
	c << "time_captured = " << Slic3r::Utils::iso_utc_timestamp(this->time_captured) << std::endl;
 | 
			
		||||
	c << "slic3r_version_captured = " << this->slic3r_version_captured.to_string() << std::endl;
 | 
			
		||||
	c << "comment = " << this->comment << std::endl;
 | 
			
		||||
	c << "reason = " << reason_string(this->reason) << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -365,7 +365,7 @@ const Snapshot&	SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot:
 | 
			
		|||
	Snapshot snapshot;
 | 
			
		||||
	// Snapshot header.
 | 
			
		||||
	snapshot.time_captured 			 = Slic3r::Utils::get_current_time_utc();
 | 
			
		||||
	snapshot.id 					 = Slic3r::Utils::format_time_ISO8601Z(snapshot.time_captured);
 | 
			
		||||
	snapshot.id 					 = Slic3r::Utils::iso_utc_timestamp(snapshot.time_captured);
 | 
			
		||||
	snapshot.slic3r_version_captured = Slic3r::SEMVER;
 | 
			
		||||
	snapshot.comment 				 = comment;
 | 
			
		||||
	snapshot.reason 				 = reason;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,9 +35,14 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
 | 
			
		|||
    text += snapshot_active ? "#B3FFCB" : (row_even ? "#FFFFFF" : "#D5D5D5");
 | 
			
		||||
    text += "\">";
 | 
			
		||||
    text += "<td>";
 | 
			
		||||
    
 | 
			
		||||
    static const constexpr char *LOCALE_TIME_FMT = "%x %X";
 | 
			
		||||
    wxString datetime = wxDateTime(snapshot.time_captured).Format(LOCALE_TIME_FMT);
 | 
			
		||||
    
 | 
			
		||||
    // Format the row header.
 | 
			
		||||
    text += wxString("<font size=\"5\"><b>") + (snapshot_active ? _(L("Active")) + ": " : "") + 
 | 
			
		||||
        Utils::format_local_date_time(snapshot.time_captured) + ": " + format_reason(snapshot.reason);
 | 
			
		||||
    text += wxString("<font size=\"5\"><b>") + (snapshot_active ? _(L("Active")) + ": " : "") +
 | 
			
		||||
            datetime + ": " + format_reason(snapshot.reason);
 | 
			
		||||
    
 | 
			
		||||
    if (! snapshot.comment.empty())
 | 
			
		||||
        text += " (" + wxString::FromUTF8(snapshot.comment.data()) + ")";
 | 
			
		||||
    text += "</b></font><br>";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -819,6 +819,21 @@ bool PresetCollection::delete_current_preset()
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PresetCollection::delete_preset(const std::string& name)
 | 
			
		||||
{
 | 
			
		||||
    auto it = this->find_preset_internal(name);
 | 
			
		||||
 | 
			
		||||
    const Preset& preset = *it;
 | 
			
		||||
    if (preset.is_default)
 | 
			
		||||
        return false;
 | 
			
		||||
    if (!preset.is_external && !preset.is_system) {
 | 
			
		||||
        // Erase the preset file.
 | 
			
		||||
        boost::nowide::remove(preset.file.c_str());
 | 
			
		||||
    }
 | 
			
		||||
    m_presets.erase(it);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name)
 | 
			
		||||
{
 | 
			
		||||
    // XXX: See note in PresetBundle::load_compatible_bitmaps()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -276,6 +276,9 @@ public:
 | 
			
		|||
    // Delete the current preset, activate the first visible preset.
 | 
			
		||||
    // returns true if the preset was deleted successfully.
 | 
			
		||||
    bool            delete_current_preset();
 | 
			
		||||
    // Delete the current preset, activate the first visible preset.
 | 
			
		||||
    // returns true if the preset was deleted successfully.
 | 
			
		||||
    bool            delete_preset(const std::string& name);
 | 
			
		||||
 | 
			
		||||
    // Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
 | 
			
		||||
    void            load_bitmap_default(wxWindow *window, const std::string &file_name);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3019,6 +3019,18 @@ void Tab::save_preset(std::string name /*= ""*/)
 | 
			
		|||
            show_error(this, _(L("Cannot overwrite an external profile.")));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (existing && name != preset.name)
 | 
			
		||||
        {
 | 
			
		||||
            wxString msg_text = GUI::from_u8((boost::format(_utf8(L("Preset with name \"%1%\" already exist."))) % name).str());
 | 
			
		||||
            msg_text += "\n" + _(L("Replace?"));
 | 
			
		||||
            wxMessageDialog dialog(nullptr, msg_text, _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
 | 
			
		||||
 | 
			
		||||
            if (dialog.ShowModal() == wxID_NO)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            // Remove the preset from the list.
 | 
			
		||||
            m_presets->delete_preset(name);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,13 @@
 | 
			
		|||
# TODO Add individual tests as executables in separate directories
 | 
			
		||||
# add_subirectory(<testcase>)
 | 
			
		||||
 | 
			
		||||
# add_subirectory(<testcase>)
 | 
			
		||||
find_package(GTest REQUIRED)
 | 
			
		||||
 | 
			
		||||
set(TEST_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
 | 
			
		||||
file(TO_NATIVE_PATH "${TEST_DATA_DIR}" TEST_DATA_DIR)
 | 
			
		||||
 | 
			
		||||
add_library(test_common INTERFACE)
 | 
			
		||||
target_compile_definitions(test_common INTERFACE TEST_DATA_DIR="${TEST_DATA_DIR}")
 | 
			
		||||
target_link_libraries(test_common INTERFACE GTest::GTest GTest::Main)
 | 
			
		||||
 | 
			
		||||
add_subdirectory(timeutils)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								tests/timeutils/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/timeutils/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
add_executable(timeutils_tests timeutils_tests_main.cpp)
 | 
			
		||||
target_link_libraries(timeutils_tests test_common libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES})
 | 
			
		||||
 | 
			
		||||
add_test(timeutils_tests timeutils_tests)
 | 
			
		||||
#gtest_discover_tests(timeutils_tests TEST_PREFIX timeutils.)
 | 
			
		||||
							
								
								
									
										41
									
								
								tests/timeutils/timeutils_tests_main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/timeutils/timeutils_tests_main.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
#include <gtest/gtest.h>
 | 
			
		||||
#include "libslic3r/Time.hpp"
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <locale>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
void test_time_fmt(Slic3r::Utils::TimeFormat fmt) {
 | 
			
		||||
    using namespace Slic3r::Utils;
 | 
			
		||||
    time_t t = get_current_time_utc();
 | 
			
		||||
    
 | 
			
		||||
    std::string tstr = time2str(t, TimeZone::local, fmt);
 | 
			
		||||
    time_t parsedtime = str2time(tstr, TimeZone::local, fmt);
 | 
			
		||||
    ASSERT_EQ(t, parsedtime);
 | 
			
		||||
    
 | 
			
		||||
    tstr = time2str(t, TimeZone::utc, fmt);
 | 
			
		||||
    parsedtime = str2time(tstr, TimeZone::utc, fmt);
 | 
			
		||||
    ASSERT_EQ(t, parsedtime);
 | 
			
		||||
    
 | 
			
		||||
    parsedtime = str2time("not valid string", TimeZone::local, fmt);
 | 
			
		||||
    ASSERT_EQ(parsedtime, time_t(-1));
 | 
			
		||||
    
 | 
			
		||||
    parsedtime = str2time("not valid string", TimeZone::utc, fmt);
 | 
			
		||||
    ASSERT_EQ(parsedtime, time_t(-1));
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Timeutils, ISO8601Z) {
 | 
			
		||||
    test_time_fmt(Slic3r::Utils::TimeFormat::iso8601Z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Timeutils, Slic3r_UTC_Time_Format) {
 | 
			
		||||
    test_time_fmt(Slic3r::Utils::TimeFormat::gcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
    ::testing::InitGoogleTest(&argc, argv);
 | 
			
		||||
    return RUN_ALL_TESTS();
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue