mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 06:38:58 +08:00
SPE-2660: Add information message about possibly incompatible config,
amended by @lukasmatena
This commit is contained in:
parent
a3f75133c8
commit
606d3f1ef4
@ -3940,34 +3940,52 @@ static void handle_legacy_project_loaded(
|
||||
}
|
||||
}
|
||||
|
||||
bool is_project_3mf(const std::string& filename)
|
||||
// Project = either it contains our config OR it is stamped as being produced
|
||||
// by PrusaSlicer (in which case the version is passed out).
|
||||
std::pair<bool, std::optional<Semver>> is_project_3mf(const std::string& filename)
|
||||
{
|
||||
std::pair<bool, std::optional<Semver>> out = std::make_pair(false, std::nullopt);
|
||||
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
||||
if (!open_zip_reader(&archive, filename))
|
||||
return false;
|
||||
return out;
|
||||
ScopeGuard guard([&archive]() {close_zip_reader(&archive); });
|
||||
|
||||
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
|
||||
|
||||
// loop the entries to search for config
|
||||
mz_zip_archive_file_stat stat;
|
||||
bool config_found = false;
|
||||
for (mz_uint i = 0; i < num_entries; ++i) {
|
||||
if (mz_zip_reader_file_stat(&archive, i, &stat)) {
|
||||
if (mz_zip_reader_is_file_a_directory(&archive, i))
|
||||
continue;
|
||||
std::string name(stat.m_filename);
|
||||
std::replace(name.begin(), name.end(), '\\', '/');
|
||||
|
||||
if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE)) {
|
||||
config_found = true;
|
||||
break;
|
||||
if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE))
|
||||
out.first = true;
|
||||
if (boost::algorithm::iequals(name, MODEL_FILE)) {
|
||||
if (auto* iter = mz_zip_reader_extract_iter_new(&archive, i, 0)) {
|
||||
ScopeGuard g([&iter]() { mz_zip_reader_extract_iter_free(iter); });
|
||||
char buffer[1024];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
if (size_t bytes_read = mz_zip_reader_extract_iter_read(iter, buffer, sizeof(buffer)); bytes_read > 0) {
|
||||
std::string header(buffer);
|
||||
boost::regex pattern(R"(^\s*<metadata name="Application".*?PrusaSlicer-(.*?)</metadata>$)");
|
||||
boost::sregex_iterator it(header.begin(), header.end(), pattern);
|
||||
boost::sregex_iterator end;
|
||||
if (it != end) {
|
||||
Semver semver;
|
||||
semver.parse((*it)[1].str());
|
||||
out.second = semver;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close_zip_reader(&archive);
|
||||
|
||||
return config_found;
|
||||
return out;
|
||||
}
|
||||
|
||||
bool load_3mf(
|
||||
|
@ -47,7 +47,7 @@ namespace Slic3r {
|
||||
struct ThumbnailData;
|
||||
|
||||
// Returns true if the 3mf file with the given filename is a PrusaSlicer project file (i.e. if it contains a config).
|
||||
extern bool is_project_3mf(const std::string& filename);
|
||||
extern std::pair<bool, std::optional<Semver>> is_project_3mf(const std::string&);
|
||||
|
||||
// Load the content of a 3mf file into the given model and preset bundle.
|
||||
extern bool load_3mf(
|
||||
|
@ -1376,6 +1376,21 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
config.null_nullables();
|
||||
// and place the loaded config over the base.
|
||||
config += std::move(config_loaded);
|
||||
} else { // config_loaded.empty()
|
||||
// Detection of possible breaking change in 3MF configuration loading sometimes in future.
|
||||
if (prusaslicer_generator_version && // set only when loaded with configuration
|
||||
*prusaslicer_generator_version > Semver(SLIC3R_VERSION)) {
|
||||
wxString title = _L("Configuration was not loaded");
|
||||
const wxString url = "https://prusa.io/3mf-transfer";
|
||||
// TRN: %1% is filename of the project, %2% is url link.
|
||||
wxString message = format_wxstr(_L("<b>Unable to load configuration from project\n\nFile: </b>%1%\n\n"
|
||||
"This project was created in a newer version of PrusaSlicer. Only the geometry was loaded.\n"
|
||||
"Update to the latest version for full compatibility.\nFor more info: <a href=%2%>%2%</a>"),
|
||||
from_path(filename), url);
|
||||
HtmlCapableRichMessageDialog dialog(q, message ,title, wxOK,
|
||||
[&url](const std::string&) { wxGetApp().open_browser_with_warning_dialog(url); });
|
||||
dialog.ShowModal();
|
||||
}
|
||||
}
|
||||
if (!config_substitutions.empty())
|
||||
show_substitutions_info(config_substitutions.substitutions, filename.string());
|
||||
@ -5016,7 +5031,8 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
|
||||
break;
|
||||
}
|
||||
// if 3mf - read archive headers to find project file
|
||||
if ((boost::algorithm::iends_with(filename, ".3mf") && !is_project_3mf(final_path.string())) ||
|
||||
auto [is_project, ps_version] = is_project_3mf(final_path.string());
|
||||
if ((boost::algorithm::iends_with(filename, ".3mf") && !is_project) ||
|
||||
(boost::algorithm::iends_with(filename, ".amf") && !boost::algorithm::iends_with(filename, ".zip.amf"))) {
|
||||
non_project_paths.emplace_back(final_path);
|
||||
break;
|
||||
@ -5236,16 +5252,19 @@ bool Plater::load_files(const wxArrayString& filenames, bool delete_after_load/*
|
||||
std::string filename = (*it).filename().string();
|
||||
|
||||
bool handle_as_project = boost::algorithm::iends_with(filename, ".3mf");
|
||||
if (boost::algorithm::iends_with(filename, ".zip") && is_project_3mf(it->string())) {
|
||||
auto [has_config, ps_version] = is_project_3mf(it->string());
|
||||
|
||||
if (boost::algorithm::iends_with(filename, ".zip") && has_config) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "File with .zip extension is 3mf project, opening as it would have .3mf extension: " << *it;
|
||||
handle_as_project = true;
|
||||
}
|
||||
if (handle_as_project && load_just_one_file) {
|
||||
ProjectDropDialog::LoadType load_type = ProjectDropDialog::LoadType::Unknown;
|
||||
{
|
||||
if (boost::algorithm::iends_with(filename, ".3mf") && !is_project_3mf(it->string()))
|
||||
if (boost::algorithm::iends_with(filename, ".3mf") && (!has_config && !ps_version.has_value())) {
|
||||
// Projects generated by PrusaSlicer is expected to have config. If absent, it will be reported later.
|
||||
load_type = ProjectDropDialog::LoadType::LoadGeometry;
|
||||
else {
|
||||
} else {
|
||||
if (wxGetApp().app_config->get_bool("show_drop_project_dialog")) {
|
||||
ProjectDropDialog dlg(filename);
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user