diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d44bfcde0..297d2e3ff 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -131,6 +131,8 @@ set(SLIC3R_SOURCES Format/AnycubicSLA.cpp Format/STEP.hpp Format/STEP.cpp + Format/SLAArchiveFormatRegistry.hpp + Format/SLAArchiveFormatRegistry.cpp GCode/ThumbnailData.cpp GCode/ThumbnailData.hpp GCode/Thumbnails.cpp diff --git a/src/libslic3r/Format/AnycubicSLA.hpp b/src/libslic3r/Format/AnycubicSLA.hpp index 46eb68d00..d1f8adf8a 100644 --- a/src/libslic3r/Format/AnycubicSLA.hpp +++ b/src/libslic3r/Format/AnycubicSLA.hpp @@ -4,44 +4,14 @@ #include #include "SLAArchiveWriter.hpp" +#include "SLAArchiveFormatRegistry.hpp" #include "libslic3r/PrintConfig.hpp" -#define ANYCUBIC_SLA_FORMAT_VERSION_1 1 -#define ANYCUBIC_SLA_FORMAT_VERSION_515 515 -#define ANYCUBIC_SLA_FORMAT_VERSION_516 516 -#define ANYCUBIC_SLA_FORMAT_VERSION_517 517 - -#define ANYCUBIC_SLA_FORMAT_VERSIONED(FILEFORMAT, NAME, VERSION) \ - { FILEFORMAT, { FILEFORMAT, [] (const auto &cfg) { return std::make_unique(cfg, VERSION); } } } - -#define ANYCUBIC_SLA_FORMAT(FILEFORMAT, NAME) \ - ANYCUBIC_SLA_FORMAT_VERSIONED(FILEFORMAT, NAME, ANYCUBIC_SLA_FORMAT_VERSION_1) - -/** - // Supports only ANYCUBIC_SLA_VERSION_1 - ANYCUBIC_SLA_FORMAT_VERSIONED("pws", "Photon / Photon S", ANYCUBIC_SLA_VERSION_1), - ANYCUBIC_SLA_FORMAT_VERSIONED("pw0", "Photon Zero", ANYCUBIC_SLA_VERSION_1), - ANYCUBIC_SLA_FORMAT_VERSIONED("pwx", "Photon X", ANYCUBIC_SLA_VERSION_1), - - // Supports ANYCUBIC_SLA_VERSION_1 and ANYCUBIC_SLA_VERSION_515 - ANYCUBIC_SLA_FORMAT_VERSIONED("pwmo", "Photon Mono", ANYCUBIC_SLA_VERSION_1), - ANYCUBIC_SLA_FORMAT_VERSIONED("pwms", "Photon Mono SE", ANYCUBIC_SLA_VERSION_1), - ANYCUBIC_SLA_FORMAT_VERSIONED("dlp", "Photon Ultra", ANYCUBIC_SLA_VERSION_1), - ANYCUBIC_SLA_FORMAT_VERSIONED("pwmx", "Photon Mono X", ANYCUBIC_SLA_VERSION_1), - ANYCUBIC_SLA_FORMAT_VERSIONED("pmsq", "Photon Mono SQ", ANYCUBIC_SLA_VERSION_1), - - // Supports ANYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516 - ANYCUBIC_SLA_FORMAT_VERSIONED("pwma", "Photon Mono 4K", ANYCUBIC_SLA_VERSION_515), - ANYCUBIC_SLA_FORMAT_VERSIONED("pm3", "Photon M3", ANYCUBIC_SLA_VERSION_515), - ANYCUBIC_SLA_FORMAT_VERSIONED("pm3m", "Photon M3 Max", ANYCUBIC_SLA_VERSION_515), - - // Supports NYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516 and ANYCUBIC_SLA_VERSION_517 - ANYCUBIC_SLA_FORMAT_VERSIONED("pwmb", "Photon Mono X 6K / Photon M3 Plus", ANYCUBIC_SLA_VERSION_515), - ANYCUBIC_SLA_FORMAT_VERSIONED("dl2p", "Photon Photon D2", ANYCUBIC_SLA_VERSION_515), - ANYCUBIC_SLA_FORMAT_VERSIONED("pmx2", "Photon Mono X2", ANYCUBIC_SLA_VERSION_515), - ANYCUBIC_SLA_FORMAT_VERSIONED("pm3r", "Photon M3 Premium", ANYCUBIC_SLA_VERSION_515), -*/ +constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_1 = 1; +constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_515 = 515; +constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_516 = 516; +constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_517 = 517; namespace Slic3r { @@ -75,6 +45,21 @@ public: const std::string &projectname = "") override; }; +inline Slic3r::ArchiveEntry anycubic_sla_format_versioned(const char *fileformat, const char *desc, uint16_t version) +{ + Slic3r::ArchiveEntry entry(fileformat); + + entry.desc = desc; + entry.ext = fileformat; + entry.wrfactoryfn = [version] (const auto &cfg) { return std::make_unique(cfg, version); }; + + return entry; +} + +inline Slic3r::ArchiveEntry anycubic_sla_format(const char *fileformat, const char *desc) +{ + return anycubic_sla_format_versioned(fileformat, desc, ANYCUBIC_SLA_FORMAT_VERSION_1); +} } // namespace Slic3r::sla diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index 4a5a25b08..e9fc058e8 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -17,6 +17,7 @@ #include "libslic3r/GCode/ThumbnailData.hpp" #include "SLAArchiveReader.hpp" +#include "SLAArchiveFormatRegistry.hpp" #include "ZipperArchiveImport.hpp" #include "libslic3r/MarchingSquares.hpp" @@ -26,6 +27,7 @@ #include "libslic3r/SLA/RasterBase.hpp" + #include #include #include diff --git a/src/libslic3r/Format/SLAArchiveFormatRegistry.cpp b/src/libslic3r/Format/SLAArchiveFormatRegistry.cpp new file mode 100644 index 000000000..5c40a5c51 --- /dev/null +++ b/src/libslic3r/Format/SLAArchiveFormatRegistry.cpp @@ -0,0 +1,147 @@ +#include +#include +#include + +#include "SL1.hpp" +#include "SL1_SVG.hpp" +#include "AnycubicSLA.hpp" + +#include "SLAArchiveFormatRegistry.hpp" + +namespace Slic3r { + +static std::mutex arch_mtx; + +class Registry { + static std::unique_ptr registry; + + std::set entries; +public: + + Registry () + { + entries = { + { + "SL1", // id + L("SL1 archive format"), // description + "sl1", // main extension + {"sl1s", "zip"}, // extension aliases + + // Writer factory + [] (const auto &cfg) { return std::make_unique(cfg); }, + + // Reader factory + [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { + return std::make_unique(fname, quality, progr); + } + }, + { + "SL1SVG", + L("SL1SVG archive files"), + "sl1_svg", + {}, + [] (const auto &cfg) { return std::make_unique(cfg); }, + [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { + return std::make_unique(fname, quality, progr); + } + }, + { + "SL2", + "", + "sl1_svg", + {}, + [] (const auto &cfg) { return std::make_unique(cfg); }, + nullptr + }, + anycubic_sla_format("pwmo", "Photon Mono"), + anycubic_sla_format("pwmx", "Photon Mono X"), + anycubic_sla_format("pwms", "Photon Mono SE"), + + /** + // Supports only ANYCUBIC_SLA_VERSION_1 + anycubic_sla_format_versioned("pws", "Photon / Photon S", ANYCUBIC_SLA_VERSION_1), + anycubic_sla_format_versioned("pw0", "Photon Zero", ANYCUBIC_SLA_VERSION_1), + anycubic_sla_format_versioned("pwx", "Photon X", ANYCUBIC_SLA_VERSION_1), + + // Supports ANYCUBIC_SLA_VERSION_1 and ANYCUBIC_SLA_VERSION_515 + anycubic_sla_format_versioned("pwmo", "Photon Mono", ANYCUBIC_SLA_VERSION_1), + anycubic_sla_format_versioned("pwms", "Photon Mono SE", ANYCUBIC_SLA_VERSION_1), + anycubic_sla_format_versioned("dlp", "Photon Ultra", ANYCUBIC_SLA_VERSION_1), + anycubic_sla_format_versioned("pwmx", "Photon Mono X", ANYCUBIC_SLA_VERSION_1), + anycubic_sla_format_versioned("pmsq", "Photon Mono SQ", ANYCUBIC_SLA_VERSION_1), + + // Supports ANYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516 + anycubic_sla_format_versioned("pwma", "Photon Mono 4K", ANYCUBIC_SLA_VERSION_515), + anycubic_sla_format_versioned("pm3", "Photon M3", ANYCUBIC_SLA_VERSION_515), + anycubic_sla_format_versioned("pm3m", "Photon M3 Max", ANYCUBIC_SLA_VERSION_515), + + // Supports NYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516 and ANYCUBIC_SLA_VERSION_517 + anycubic_sla_format_versioned("pwmb", "Photon Mono X 6K / Photon M3 Plus", ANYCUBIC_SLA_VERSION_515), + anycubic_sla_format_versioned("dl2p", "Photon Photon D2", ANYCUBIC_SLA_VERSION_515), + anycubic_sla_format_versioned("pmx2", "Photon Mono X2", ANYCUBIC_SLA_VERSION_515), + anycubic_sla_format_versioned("pm3r", "Photon M3 Premium", ANYCUBIC_SLA_VERSION_515), + */ + }; + } + + static Registry& get_instance() + { + if (!registry) + registry = std::make_unique(); + + return *registry; + } + + static std::set& get() + { + return get_instance().entries; + } + + std::set& get_entries() { return entries; } +}; + +std::unique_ptr Registry::registry = nullptr; + +std::set registered_sla_archives() +{ + std::lock_guard lk{arch_mtx}; + + return Registry::get(); +} + +std::vector get_extensions(const ArchiveEntry &entry) +{ + auto ret = reserve_vector(entry.ext_aliases.size() + 1); + + ret.emplace_back(entry.ext); + for (const char *alias : entry.ext_aliases) + ret.emplace_back(alias); + + return ret; +} + +ArchiveWriterFactory get_writer_factory(const char *formatid) +{ + std::lock_guard lk{arch_mtx}; + + ArchiveWriterFactory ret; + auto entry = Registry::get().find(ArchiveEntry{formatid}); + if (entry != Registry::get().end()) + ret = entry->wrfactoryfn; + + return ret; +} + +ArchiveReaderFactory get_reader_factory(const char *formatid) +{ + std::lock_guard lk{arch_mtx}; + + ArchiveReaderFactory ret; + auto entry = Registry::get().find(ArchiveEntry{formatid}); + if (entry != Registry::get().end()) + ret = entry->rdfactoryfn; + + return ret; +} + +} // namespace Slic3r::sla diff --git a/src/libslic3r/Format/SLAArchiveFormatRegistry.hpp b/src/libslic3r/Format/SLAArchiveFormatRegistry.hpp new file mode 100644 index 000000000..fb1a18ca5 --- /dev/null +++ b/src/libslic3r/Format/SLAArchiveFormatRegistry.hpp @@ -0,0 +1,71 @@ +#ifndef SLA_ARCHIVE_FORMAT_REGISTRY_HPP +#define SLA_ARCHIVE_FORMAT_REGISTRY_HPP + +#include "SLAArchiveWriter.hpp" +#include "SLAArchiveReader.hpp" +#include + +namespace Slic3r { + +// Factory function that returns an implementation of SLAArchiveWriter given +// a printer configuration. +using ArchiveWriterFactory = std::function< + std::unique_ptr(const SLAPrinterConfig &) +>; + +// Factory function that returns an implementation of SLAArchiveReader +using ArchiveReaderFactory = std::function< + std::unique_ptr(const std::string &fname, + SLAImportQuality quality, + const ProgrFn & progr) +>; + +struct ArchiveEntry { + // Main ID for the format, for internal unique identification + const char *id; + + // Generic description (usable in GUI) about an archive format. Should only + // be marked for localization (macro L). + const char *desc = ""; + + // Main extension of the format. + const char *ext = "zip"; + + ArchiveWriterFactory wrfactoryfn; + ArchiveReaderFactory rdfactoryfn; + + // Secondary, alias extensions + std::vector ext_aliases; + + explicit ArchiveEntry(const char *formatid) : id{formatid} {} + + ArchiveEntry(const char *formatid, + const char *description, + const char *extension, + std::initializer_list extaliases, + const ArchiveWriterFactory &wrfn, + const ArchiveReaderFactory &rdfn) + : id{formatid} + , desc{description} + , ext{extension} + , ext_aliases{extaliases} + , wrfactoryfn{wrfn} + , rdfactoryfn{rdfn} + {} + + bool operator <(const ArchiveEntry &other) const + { + return std::strcmp(id, other.id) < 0; + } +}; + +std::vector get_extensions(const ArchiveEntry &entry); + +std::set registered_sla_archives(); + +ArchiveWriterFactory get_writer_factory(const char *formatid); +ArchiveReaderFactory get_reader_factory(const char *formatid); + +} // namespace Slic3r + +#endif // ARCHIVEREGISTRY_HPP diff --git a/src/libslic3r/Format/SLAArchiveReader.cpp b/src/libslic3r/Format/SLAArchiveReader.cpp index b931ea0e4..c8a15bc5a 100644 --- a/src/libslic3r/Format/SLAArchiveReader.cpp +++ b/src/libslic3r/Format/SLAArchiveReader.cpp @@ -8,44 +8,13 @@ #include #include +#include "SLAArchiveFormatRegistry.hpp" #include #include namespace Slic3r { -namespace { - -// Factory function that returns an implementation of SLAArchiveReader. -using ArchiveFactory = std::function< - std::unique_ptr(const std::string &fname, - SLAImportQuality quality, - const ProgrFn & progr)>; - -// Entry in the global registry of readable archive formats. -struct ArchiveEntry { - const char *descr; - std::vector extensions; - ArchiveFactory factoryfn; -}; - -// This is where the readable archive formats are registered. -static const std::map REGISTERED_ARCHIVES { - { - "SL1", - { L("SL1 / SL1S archive files"), {"sl1", "sl1s", "zip"}, - [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique(fname, quality, progr); } } - }, - { - "SL1SVG", - { L("SL1SVG archive files"), {"sl1_svg"/*, "zip"*/}, // also a zip but unnecessary hassle to implement single extension for multiple archives - [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique(fname, quality, progr); }} - }, - // TODO: pwmx and future others. -}; - -} // namespace - std::unique_ptr SLAArchiveReader::create( const std::string &fname, const std::string &format_id, @@ -64,11 +33,13 @@ std::unique_ptr SLAArchiveReader::create( std::unique_ptr ret; - auto arch_from = REGISTERED_ARCHIVES.begin(); - auto arch_to = REGISTERED_ARCHIVES.end(); + auto registry = registered_sla_archives(); - auto arch_it = REGISTERED_ARCHIVES.find(format_id); - if (arch_it != REGISTERED_ARCHIVES.end()) { + auto arch_from = registry.begin(); + auto arch_to = registry.end(); + + auto arch_it = registry.find(ArchiveEntry{format_id.c_str()}); + if (arch_it != registry.end()) { arch_from = arch_it; arch_to = arch_it; } @@ -77,52 +48,23 @@ std::unique_ptr SLAArchiveReader::create( if (ext.front() == '.') ext.erase(ext.begin()); - auto extcmp = [&ext](const auto &e) { return e == ext; }; - - for (auto it = arch_from; it != arch_to; ++it) { - const auto &[format_id, entry] = *it; - if (std::any_of(entry.extensions.begin(), entry.extensions.end(), extcmp)) - ret = entry.factoryfn(fname, quality, progr); + for (auto it = arch_from; !ret && it != arch_to; ++it) { + const auto &entry = *it; + if (entry.rdfactoryfn) { + auto extensions = get_extensions(entry); + for (const std::string& supportedext : extensions) { + if (ext == supportedext) { + ret = entry.rdfactoryfn(fname, quality, progr); + break; + } + } + } } } return ret; } -const std::vector &SLAArchiveReader::registered_archives() -{ - static std::vector archnames; - - if (archnames.empty()) { - archnames.reserve(REGISTERED_ARCHIVES.size()); - - for (auto &[name, _] : REGISTERED_ARCHIVES) - archnames.emplace_back(name.c_str()); - } - - return archnames; -} - -std::vector SLAArchiveReader::get_extensions(const char *archtype) -{ - auto it = REGISTERED_ARCHIVES.find(archtype); - - if (it != REGISTERED_ARCHIVES.end()) - return it->second.extensions; - - return {}; -} - -const char *SLAArchiveReader::get_description(const char *archtype) -{ - auto it = REGISTERED_ARCHIVES.find(archtype); - - if (it != REGISTERED_ARCHIVES.end()) - return it->second.descr; - - return nullptr; -} - struct SliceParams { double layerh = 0., initial_layerh = 0.; }; static SliceParams get_slice_params(const DynamicPrintConfig &cfg) diff --git a/src/libslic3r/Format/SLAArchiveReader.hpp b/src/libslic3r/Format/SLAArchiveReader.hpp index e7a99b043..df93ba1ba 100644 --- a/src/libslic3r/Format/SLAArchiveReader.hpp +++ b/src/libslic3r/Format/SLAArchiveReader.hpp @@ -47,15 +47,6 @@ public: const std::string &format_id, SLAImportQuality quality = SLAImportQuality::Balanced, const ProgrFn &progr = [](int) { return false; }); - - // Get the names of currently known archive reader implementations - static const std::vector & registered_archives(); - - // Get the understood file extensions belonging to an archive format - static std::vector get_extensions(const char *archtype); - - // Generic description (usable in GUI) about an archive format - static const char * get_description(const char *archtype); }; // Raised in import_sla_archive when a nullptr reader is returned by diff --git a/src/libslic3r/Format/SLAArchiveWriter.cpp b/src/libslic3r/Format/SLAArchiveWriter.cpp index 7546d7c46..5d3cee7cf 100644 --- a/src/libslic3r/Format/SLAArchiveWriter.cpp +++ b/src/libslic3r/Format/SLAArchiveWriter.cpp @@ -1,77 +1,18 @@ #include "SLAArchiveWriter.hpp" - -#include "SL1.hpp" -#include "SL1_SVG.hpp" -#include "AnycubicSLA.hpp" - -#include "libslic3r/libslic3r.h" - -#include -#include -#include -#include +#include "SLAArchiveFormatRegistry.hpp" namespace Slic3r { -using ArchiveFactory = std::function(const SLAPrinterConfig&)>; - -struct ArchiveEntry { - const char *ext; - ArchiveFactory factoryfn; -}; - -static const std::map REGISTERED_ARCHIVES { - { - "SL1", - { "sl1", [] (const auto &cfg) { return std::make_unique(cfg); } } - }, - { - "SL1SVG", - { "sl1_svg", [] (const auto &cfg) { return std::make_unique(cfg); } } - }, - { - "SL2", - { "sl1_svg", [] (const auto &cfg) { return std::make_unique(cfg); } } - }, - ANYCUBIC_SLA_FORMAT("pwmo", "Photon Mono"), - ANYCUBIC_SLA_FORMAT("pwmx", "Photon Mono X"), - ANYCUBIC_SLA_FORMAT("pwms", "Photon Mono SE"), -}; - std::unique_ptr SLAArchiveWriter::create(const std::string &archtype, const SLAPrinterConfig &cfg) { - auto entry = REGISTERED_ARCHIVES.find(archtype); + std::unique_ptr ret; + auto factory = get_writer_factory(archtype.c_str()); - if (entry != REGISTERED_ARCHIVES.end()) - return entry->second.factoryfn(cfg); + if (factory) + ret = factory(cfg); - return nullptr; -} - -const std::vector& SLAArchiveWriter::registered_archives() -{ - static std::vector archnames; - - if (archnames.empty()) { - archnames.reserve(REGISTERED_ARCHIVES.size()); - - for (auto &[name, _] : REGISTERED_ARCHIVES) - archnames.emplace_back(name.c_str()); - } - - return archnames; -} - -const char *SLAArchiveWriter::get_extension(const char *archtype) -{ - constexpr const char* DEFAULT_EXT = "zip"; - - auto entry = REGISTERED_ARCHIVES.find(archtype); - if (entry != REGISTERED_ARCHIVES.end()) - return entry->second.ext; - - return DEFAULT_EXT; + return ret; } } // namespace Slic3r diff --git a/src/libslic3r/Format/SLAArchiveWriter.hpp b/src/libslic3r/Format/SLAArchiveWriter.hpp index 86132cceb..1e6ed649b 100644 --- a/src/libslic3r/Format/SLAArchiveWriter.hpp +++ b/src/libslic3r/Format/SLAArchiveWriter.hpp @@ -53,12 +53,6 @@ public: // Factory method to create an archiver instance static std::unique_ptr create( const std::string &archtype, const SLAPrinterConfig &); - - // Get the names of currently known archiver implementations - static const std::vector & registered_archives(); - - // Get the default file extension belonging to an archive format - static const char *get_extension(const char *archtype); }; } // namespace Slic3r diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 0eb009c77..d53b3e785 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -4558,7 +4558,7 @@ static void draw_branches( } // Subtract top contact layer polygons from support base. - SupportGeneratorLayer *top_contact_layer = top_contacts[layer_idx]; + SupportGeneratorLayer *top_contact_layer = top_contacts.empty() ? nullptr : top_contacts[layer_idx]; if (top_contact_layer && ! top_contact_layer->polygons.empty() && ! base_layer_polygons.empty()) { base_layer_polygons = diff(base_layer_polygons, top_contact_layer->polygons); if (! bottom_contact_polygons.empty()) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 11b116a05..866d5a817 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -57,6 +57,7 @@ #include "UnsavedChangesDialog.hpp" #include "slic3r/Utils/AppUpdater.hpp" #include "slic3r/GUI/I18N.hpp" +#include "slic3r/Config/Version.hpp" #if defined(__linux__) && defined(__WXGTK3__) #define wxLinux_gtk3 true @@ -118,7 +119,7 @@ BundleMap BundleMap::load() const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred(); const auto archive_dir = (boost::filesystem::path(Slic3r::data_dir()) / "cache" / "vendor").make_preferred(); const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); - + const auto cache_dir = boost::filesystem::path(Slic3r::data_dir()) / "cache"; // for Index // Load Prusa bundle from the datadir/vendor directory or from datadir/cache/vendor (archive) or from resources/profiles. auto prusa_bundle_path = (vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini"); BundleLocation prusa_bundle_loc = BundleLocation::IN_VENDOR; @@ -138,7 +139,7 @@ BundleMap BundleMap::load() // Load the other bundles in the datadir/vendor directory // and then additionally from datadir/cache/vendor (archive) and resources/profiles. - // Should we concider case where archive has older profiles than resources (shouldnt happen)? + // Should we concider case where archive has older profiles than resources (shouldnt happen)? -> YES, it happens during re-configuration when running older PS after newer version typedef std::pair DirData; std::vector dir_list { {vendor_dir, BundleLocation::IN_VENDOR}, {archive_dir, BundleLocation::IN_ARCHIVE}, {rsrc_vendor_dir, BundleLocation::IN_RESOURCES} }; for ( auto dir : dir_list) { @@ -151,6 +152,42 @@ BundleMap BundleMap::load() // Don't load this bundle if we've already loaded it. if (res.find(id) != res.end()) { continue; } + // Fresh index should be in archive_dir, otherwise look for it in cache + fs::path idx_path (archive_dir / (id + ".idx")); + if (!boost::filesystem::exists(idx_path)) { + BOOST_LOG_TRIVIAL(warning) << format("Missing index %1% when loading bundle %2%.", idx_path.string(), id); + idx_path = fs::path(cache_dir / (id + ".idx")); + } + if (!boost::filesystem::exists(idx_path)) { + BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to missing index %1%.", id, idx_path.string()); + continue; + } + Slic3r::GUI::Config::Index index; + try { + index.load(idx_path); + } + catch (const std::exception& /* err */) { + BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to invalid index %1%.", id, idx_path.string()); + continue; + } + const auto recommended_it = index.recommended(); + if (recommended_it == index.end()) { + BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to no recommended version in index %2%.", id, idx_path.string()); + continue; + } + const auto recommended = recommended_it->config_version; + VendorProfile vp; + try { + vp = VendorProfile::from_ini(dir_entry, true); + } + catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to corrupted profile file %2%. Message: %3%", id, dir_entry.path().string(), e.what()); + continue; + } + // Don't load + if (vp.config_version > recommended) + continue; + Bundle bundle; if (bundle.load(dir_entry.path(), dir.second)) res.emplace(std::move(id), std::move(bundle)); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index a5584692c..9cbcbc323 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1192,6 +1192,13 @@ void ObjectList::key_event(wxKeyEvent& event) void ObjectList::OnBeginDrag(wxDataViewEvent &event) { + if (m_is_editing_started) + m_is_editing_started = false; +#ifdef __WXGTK__ + const auto renderer = dynamic_cast(GetColumn(colName)->GetRenderer()); + renderer->FinishEditing(); +#endif + const wxDataViewItem item(event.GetItem()); const bool mult_sel = multiple_selection(); @@ -1225,18 +1232,11 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) m_objects_model->GetInstanceIdByItem(item), type); - /* Under MSW or OSX, DnD moves an item to the place of another selected item - * But under GTK, DnD moves an item between another two items. - * And as a result - call EVT_CHANGE_SELECTION to unselect all items. - * To prevent such behavior use m_prevent_list_events - **/ - m_prevent_list_events = true;//it's needed for GTK - /* Under GTK, DnD requires to the wxTextDataObject been initialized with some valid value, * so set some nonempty string */ wxTextDataObject* obj = new wxTextDataObject; - obj->SetText("Some text");//it's needed for GTK + obj->SetText(mult_sel ? "SomeText" : m_objects_model->GetItemName(item));//it's needed for GTK event.SetDataObject(obj); event.SetDragFlags(wxDrag_DefaultMove); // allows both copy and move; @@ -1299,11 +1299,8 @@ bool ObjectList::can_drop(const wxDataViewItem& item) const void ObjectList::OnDropPossible(wxDataViewEvent &event) { const wxDataViewItem& item = event.GetItem(); - - if (!can_drop(item)) { + if (!can_drop(item)) event.Veto(); - m_prevent_list_events = false; - } } void ObjectList::OnDrop(wxDataViewEvent &event) @@ -1317,6 +1314,13 @@ void ObjectList::OnDrop(wxDataViewEvent &event) return; } + /* Under MSW or OSX, DnD moves an item to the place of another selected item + * But under GTK, DnD moves an item between another two items. + * And as a result - call EVT_CHANGE_SELECTION to unselect all items. + * To prevent such behavior use m_prevent_list_events + **/ + m_prevent_list_events = true;//it's needed for GTK + if (m_dragged_data.type() == itInstance) { Plater::TakeSnapshot snapshot(wxGetApp().plater(),_(L("Instances to Separated Objects"))); @@ -4819,6 +4823,9 @@ void ObjectList::sys_color_changed() void ObjectList::ItemValueChanged(wxDataViewEvent &event) { + if (!m_is_editing_started) + return; + if (event.GetColumn() == colName) update_name_in_model(event.GetItem()); else if (event.GetColumn() == colExtruder) { @@ -4841,6 +4848,9 @@ void ObjectList::OnEditingStarted(wxDataViewEvent &event) void ObjectList::OnEditingDone(wxDataViewEvent &event) { + if (!m_is_editing_started) + return; + m_is_editing_started = false; if (event.GetColumn() != colName) return; diff --git a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp index fed84600c..aa2fb48c1 100644 --- a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp +++ b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp @@ -11,6 +11,7 @@ #include "libslic3r/AppConfig.hpp" #include "libslic3r/Format/SLAArchiveReader.hpp" +#include "libslic3r/Format/SLAArchiveFormatRegistry.hpp" #include "slic3r/GUI/I18N.hpp" @@ -29,11 +30,16 @@ std::string get_readers_wildcard() { std::string ret; - for (const char *archtype : SLAArchiveReader::registered_archives()) { - ret += into_u8(_(SLAArchiveReader::get_description(archtype))); + auto registry = registered_sla_archives(); + + for (const ArchiveEntry &entry : registry) { + if (!entry.rdfactoryfn) + continue; + + ret += into_u8(_(entry.desc)); ret += " ("; - auto extensions = SLAArchiveReader::get_extensions(archtype); - for (const char * ext : extensions) { + std::vector extensions = get_extensions(entry); + for (const std::string &ext : extensions) { ret += "*."; ret += ext; ret += ", "; diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index fe57d7d5a..38747d08d 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -1042,6 +1042,16 @@ int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer return GetLayerIdByItem(item); } +wxString ObjectDataViewModel::GetItemName(const wxDataViewItem &item) const +{ + if (!item.IsOk()) + return wxEmptyString; + ObjectDataViewModelNode* node = static_cast(item.GetID()); + if (!node) + return wxEmptyString; + return node->GetName(); +} + int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const { if(!item.IsOk()) diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index 993b67842..bc5b485a3 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -311,6 +311,7 @@ public: wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx); wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); + wxString GetItemName(const wxDataViewItem& item) const; int GetIdByItem(const wxDataViewItem& item) const; int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetObjectIdByItem(const wxDataViewItem& item) const; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 028c7ce0a..995891db9 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -961,7 +961,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version BOOST_LOG_TRIVIAL(error) << format("Cannot load the installed index at `%1%`: %2%", bundle_path_idx, err.what()); } } - +#if 0 // Check if the update is already present in a snapshot if(!current_not_supported) { @@ -974,7 +974,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version continue; } } - +#endif // 0 updates.updates.emplace_back(std::move(new_update)); // 'Install' the index in the vendor directory. This is used to memoize // offered updates and to not offer the same update again if it was cancelled by the user. @@ -1320,7 +1320,35 @@ bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vectorcache_path / idx_path.filename()); + } + if (!boost::filesystem::exists(idx_path)) { + std::string msg = GUI::format(_L("Couldn't locate index file for vendor %1% when performing updates. The profile will not be installed."), bundle); + BOOST_LOG_TRIVIAL(error) << msg; + GUI::show_error(nullptr, msg); + continue; + } + Slic3r::GUI::Config::Index index; + try { + index.load(idx_path); + } + catch (const std::exception& /* err */) { + std::string msg = GUI::format(_L("Couldn't load index file for vendor %1% when performing updates. The profile will not be installed. Reason: Corrupted index file %2%."), bundle, idx_path.string()); + BOOST_LOG_TRIVIAL(error) << msg; + GUI::show_error(nullptr, msg); + continue; + } + const auto recommended_it = index.recommended(); + const auto recommended = recommended_it->config_version; + if (is_in_cache_vendor) { Semver version_cache = Semver::zero(); try { @@ -1329,13 +1357,11 @@ bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector recommended) + version_cache = Semver::zero(); + Semver version_rsrc = Semver::zero(); try { if (is_in_rsrc) { @@ -1345,26 +1371,33 @@ bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector recommended) + version_rsrc = Semver::zero(); - if (!is_in_rsrc || version_cache > version_rsrc) { - // in case we are installing from cache / vendor. we should also copy index to cache - // This needs to be done now bcs the current one would be missing this version on next start - // dk: Should we copy it to vendor dir too? - auto path_idx_cache_vendor(path_in_cache_vendor); - path_idx_cache_vendor.replace_extension(".idx"); - auto path_idx_cache = (p->cache_path / bundle).replace_extension(".idx"); - // DK: do this during perform_updates() too? - if (fs::exists(path_idx_cache_vendor)) - copy_file_fix(path_idx_cache_vendor, path_idx_cache); - else // Should we dialog this? - BOOST_LOG_TRIVIAL(error) << GUI::format(_L("Couldn't locate idx file %1% when performing updates."), path_idx_cache_vendor.string()); + if (version_cache == Semver::zero() && version_rsrc == Semver::zero()) { + std::string msg = GUI::format(_L("Couldn't open profile file for vendor %1% when performing updates. The profile will not be installed. This installation might be corrupted."), bundle); + BOOST_LOG_TRIVIAL(error) << msg; + GUI::show_error(nullptr, msg); + continue; + } else if (version_cache == Semver::zero()) { + // cache vendor cannot be used, use resources + updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", ""); + } else if (version_rsrc == Semver::zero()) { + // resources cannto be used, use cache vendor + updates.updates.emplace_back(std::move(path_in_cache_vendor), std::move(path_in_vendors), Version(), "", ""); + } else if (version_cache > version_rsrc) { + // in case we are installing from cache / vendor. we should also copy index to cache + // This needs to be done now bcs the current one would be missing this version on the next start + auto path_idx_cache = (p->cache_path / bundle).replace_extension(".idx"); + if (idx_path != path_idx_cache) + copy_file_fix(idx_path, path_idx_cache); updates.updates.emplace_back(std::move(path_in_cache_vendor), std::move(path_in_vendors), Version(), "", ""); - } else { - if (is_in_rsrc) - updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", ""); + updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", ""); } } else { if (! is_in_rsrc) { diff --git a/tests/sla_print/sla_archive_readwrite_tests.cpp b/tests/sla_print/sla_archive_readwrite_tests.cpp index a7ed7f0a4..fb1af3d7f 100644 --- a/tests/sla_print/sla_archive_readwrite_tests.cpp +++ b/tests/sla_print/sla_archive_readwrite_tests.cpp @@ -3,6 +3,7 @@ #include "libslic3r/SLAPrint.hpp" #include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Format/SLAArchiveFormatRegistry.hpp" #include "libslic3r/Format/SLAArchiveWriter.hpp" #include "libslic3r/Format/SLAArchiveReader.hpp" @@ -11,16 +12,18 @@ using namespace Slic3r; TEST_CASE("Archive export test", "[sla_archives]") { + auto registry = registered_sla_archives(); + for (const char * pname : {"20mm_cube", "extruder_idler"}) - for (auto &archname : SLAArchiveWriter::registered_archives()) { - INFO(std::string("Testing archive type: ") + archname + " -- writing..."); + for (const ArchiveEntry &entry : registry) { + INFO(std::string("Testing archive type: ") + entry.id + " -- writing..."); SLAPrint print; SLAFullPrintConfig fullcfg; auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(pname) + ".obj", nullptr); fullcfg.printer_technology.setInt(ptSLA); // FIXME this should be ensured - fullcfg.set("sla_archive_format", archname); + fullcfg.set("sla_archive_format", entry.id); fullcfg.set("supports_enable", false); fullcfg.set("pad_enable", false); @@ -32,7 +35,7 @@ TEST_CASE("Archive export test", "[sla_archives]") { print.process(); ThumbnailsList thumbnails; - auto outputfname = std::string("output_") + pname + "." + SLAArchiveWriter::get_extension(archname); + auto outputfname = std::string("output_") + pname + "." + entry.ext; print.export_print(outputfname, thumbnails, pname); @@ -41,12 +44,8 @@ TEST_CASE("Archive export test", "[sla_archives]") { double vol_written = m.mesh().volume(); - auto readable_formats = SLAArchiveReader::registered_archives(); - if (std::any_of(readable_formats.begin(), readable_formats.end(), - [&archname](const std::string &a) { return a == archname; })) { - - INFO(std::string("Testing archive type: ") + archname + " -- reading back..."); - + if (entry.rdfactoryfn) { + INFO(std::string("Testing archive type: ") + entry.id + " -- reading back..."); indexed_triangle_set its; DynamicPrintConfig cfg;