Merge branch 'dk_notifications'
This commit is contained in:
commit
d2b17f138a
11 changed files with 249 additions and 18 deletions
|
@ -34,8 +34,9 @@
|
|||
#
|
||||
# Open preferences (might add item to highlight)
|
||||
# hypertext_type = preferences
|
||||
# hypertext_preferences_page = 0 (values 0-2 according to prefernces tab to be opened)
|
||||
#
|
||||
# hypertext_preferences_page = 2 (values 0-2 according to prefernces tab to be opened)
|
||||
# hypertext_preferences_item = show_collapse_button (name of variable saved in prusaslicer.ini connected to the setting in preferences)
|
||||
#
|
||||
# Open gallery (no aditional var)
|
||||
# hypertext_type = gallery
|
||||
#
|
||||
|
@ -97,6 +98,7 @@ documentation_link = https://help.prusa3d.com/en/article/reload-from-disk_120427
|
|||
text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut <b>Shift+Tab</b>? You can also enable the icon for this from the<a>Preferences.</a>
|
||||
hypertext_type = preferences
|
||||
hypertext_preferences_page = 2
|
||||
hypertext_preferences_item = show_collapse_button
|
||||
|
||||
[hint:Perspective camera]
|
||||
text = Perspective camera\nDid you know that you can use the <b>K</b> key to quickly switch between an orthographic and perspective camera?
|
||||
|
@ -213,6 +215,7 @@ disabled_tags = SLA
|
|||
text = Settings in non-modal window\nDid you know that you can open the Settings in a new non-modal window? This means you can have settings open on one screen and the G-code Preview on the other. Go to the<a>Preferences</a>and select Settings in non-modal window.
|
||||
hypertext_type = preferences
|
||||
hypertext_preferences_page = 2
|
||||
hypertext_preferences_item = dlg_settings_layout_mode
|
||||
|
||||
[hint:Adaptive infills]
|
||||
text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in the documentation.
|
||||
|
|
|
@ -248,11 +248,11 @@ std::string AppConfig::load()
|
|||
bool recovered = false;
|
||||
|
||||
try {
|
||||
ifs.open(AppConfig::config_path());
|
||||
ifs.open(AppConfig::loading_path());
|
||||
#ifdef WIN32
|
||||
// Verify the checksum of the config file without taking just for debugging purpose.
|
||||
if (!verify_config_file_checksum(ifs))
|
||||
BOOST_LOG_TRIVIAL(info) << "The configuration file " << AppConfig::config_path() <<
|
||||
BOOST_LOG_TRIVIAL(info) << "The configuration file " << AppConfig::loading_path() <<
|
||||
" has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit.";
|
||||
|
||||
ifs.seekg(0, boost::nowide::ifstream::beg);
|
||||
|
@ -262,32 +262,32 @@ std::string AppConfig::load()
|
|||
#ifdef WIN32
|
||||
// The configuration file is corrupted, try replacing it with the backup configuration.
|
||||
ifs.close();
|
||||
std::string backup_path = (boost::format("%1%.bak") % AppConfig::config_path()).str();
|
||||
std::string backup_path = (boost::format("%1%.bak") % AppConfig::loading_path()).str();
|
||||
if (boost::filesystem::exists(backup_path)) {
|
||||
// Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct.
|
||||
boost::nowide::ifstream backup_ifs(backup_path);
|
||||
if (!verify_config_file_checksum(backup_ifs)) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", AppConfig::config_path(), backup_path);
|
||||
BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", AppConfig::loading_path(), backup_path);
|
||||
backup_ifs.close();
|
||||
boost::filesystem::remove(backup_path);
|
||||
} else if (std::string error_message; copy_file(backup_path, AppConfig::config_path(), error_message, false) != SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", AppConfig::config_path(), backup_path, error_message);
|
||||
} else if (std::string error_message; copy_file(backup_path, AppConfig::loading_path(), error_message, false) != SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", AppConfig::loading_path(), backup_path, error_message);
|
||||
backup_ifs.close();
|
||||
boost::filesystem::remove(backup_path);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", AppConfig::config_path(), backup_path);
|
||||
BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", AppConfig::loading_path(), backup_path);
|
||||
// Try parse configuration file after restore from backup.
|
||||
try {
|
||||
ifs.open(AppConfig::config_path());
|
||||
ifs.open(AppConfig::loading_path());
|
||||
pt::read_ini(ifs, tree);
|
||||
recovered = true;
|
||||
} catch (pt::ptree_error& ex) {
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", AppConfig::config_path(), ex.what());
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", AppConfig::loading_path(), ex.what());
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif // WIN32
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", AppConfig::config_path(), ex.what());
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", AppConfig::loading_path(), ex.what());
|
||||
if (! recovered) {
|
||||
// Report the initial error of parsing PrusaSlicer.ini.
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
|
|
|
@ -148,6 +148,9 @@ public:
|
|||
// Does the config file exist?
|
||||
bool exists();
|
||||
|
||||
void set_loading_path(const std::string& path) { m_loading_path = path; }
|
||||
std::string loading_path() { return (m_loading_path.empty() ? config_path() : m_loading_path); }
|
||||
|
||||
std::vector<std::string> get_recent_projects() const;
|
||||
void set_recent_projects(const std::vector<std::string>& recent_projects);
|
||||
|
||||
|
@ -196,6 +199,8 @@ private:
|
|||
Semver m_orig_version;
|
||||
// Whether the existing version is before system profiles & configuration updating
|
||||
bool m_legacy_datadir;
|
||||
|
||||
std::string m_loading_path;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -188,6 +188,61 @@ void PresetBundle::setup_directories()
|
|||
}
|
||||
}
|
||||
|
||||
// recursively copy all files and dirs in from_dir to to_dir
|
||||
static void copy_dir(const boost::filesystem::path& from_dir, const boost::filesystem::path& to_dir)
|
||||
{
|
||||
if(!boost::filesystem::is_directory(from_dir))
|
||||
return;
|
||||
// i assume to_dir.parent surely exists
|
||||
if (!boost::filesystem::is_directory(to_dir))
|
||||
boost::filesystem::create_directory(to_dir);
|
||||
for (auto& dir_entry : boost::filesystem::directory_iterator(from_dir)) {
|
||||
if (!boost::filesystem::is_directory(dir_entry.path())) {
|
||||
std::string em;
|
||||
CopyFileResult cfr = copy_file(dir_entry.path().string(), (to_dir / dir_entry.path().filename()).string(), em, false);
|
||||
if (cfr != SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error when copying files from " << from_dir << " to " << to_dir << ": " << em;
|
||||
}
|
||||
} else {
|
||||
copy_dir(dir_entry.path(), to_dir / dir_entry.path().filename());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PresetBundle::copy_files(const std::string& from)
|
||||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
// list of searched paths based on current directory system in setup_directories()
|
||||
// do not copy cache and snapshots
|
||||
boost::filesystem::path from_data_dir = boost::filesystem::path(from);
|
||||
std::initializer_list<boost::filesystem::path> from_dirs= {
|
||||
from_data_dir / "vendor",
|
||||
from_data_dir / "shapes",
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
data_dir / "presets",
|
||||
data_dir / "presets" / "print",
|
||||
data_dir / "presets" / "filament",
|
||||
data_dir / "presets" / "sla_print",
|
||||
data_dir / "presets" / "sla_material",
|
||||
data_dir / "presets" / "printer",
|
||||
data_dir / "presets" / "physical_printer"
|
||||
#else
|
||||
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
|
||||
from_data_dir / "print",
|
||||
from_data_dir / "filament",
|
||||
from_data_dir / "sla_print",
|
||||
from_data_dir / "sla_material",
|
||||
from_data_dir / "printer",
|
||||
from_data_dir / "physical_printer"
|
||||
#endif
|
||||
};
|
||||
// copy recursively all files
|
||||
for (const boost::filesystem::path& from_dir : from_dirs) {
|
||||
copy_dir(from_dir, data_dir / from_dir.filename());
|
||||
}
|
||||
}
|
||||
|
||||
PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule,
|
||||
const PresetPreferences& preferred_selection/* = PresetPreferences()*/)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
void reset(bool delete_files);
|
||||
|
||||
void setup_directories();
|
||||
void copy_files(const std::string& from);
|
||||
|
||||
struct PresetPreferences {
|
||||
std::string printer_model_id;// name of a preferred printer model
|
||||
|
|
|
@ -743,6 +743,25 @@ bool GUI_App::init_opengl()
|
|||
#endif
|
||||
}
|
||||
|
||||
// gets path to PrusaSlicer.ini, returns semver from first line comment
|
||||
static boost::optional<Semver> parse_semver_from_ini(std::string path)
|
||||
{
|
||||
std::ifstream stream(path);
|
||||
std::stringstream buffer;
|
||||
buffer << stream.rdbuf();
|
||||
std::string body = buffer.str();
|
||||
size_t end_line = body.find_first_of("\n\r");
|
||||
body.resize(end_line);
|
||||
size_t start = body.find("PrusaSlicer ");
|
||||
if (start == std::string::npos)
|
||||
return boost::none;
|
||||
body = body.substr(start + 12);
|
||||
size_t end = body.find_first_of(" \n\r");
|
||||
if (end < body.size())
|
||||
body.resize(end);
|
||||
return Semver::parse(body);
|
||||
}
|
||||
|
||||
void GUI_App::init_app_config()
|
||||
{
|
||||
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
|
||||
|
@ -791,9 +810,110 @@ void GUI_App::init_app_config()
|
|||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
}
|
||||
}
|
||||
// Save orig_version here, so its empty if no app_config existed before this run.
|
||||
m_last_config_version = app_config->orig_version();//parse_semver_from_ini(app_config->config_path());
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if found newer version and user agreed to use it
|
||||
bool GUI_App::check_older_app_config(Semver current_version, bool backup)
|
||||
{
|
||||
// find other version app config (alpha / beta / release)
|
||||
std::string config_path = app_config->config_path();
|
||||
boost::filesystem::path parent_file_path(config_path);
|
||||
std::string filename = parent_file_path.filename().string();
|
||||
parent_file_path.remove_filename().remove_filename();
|
||||
|
||||
std::vector<boost::filesystem::path> candidates;
|
||||
|
||||
if (SLIC3R_APP_KEY "-alpha" != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY "-alpha" / filename);
|
||||
if (SLIC3R_APP_KEY "-beta" != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY "-beta" / filename);
|
||||
if (SLIC3R_APP_KEY != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY / filename);
|
||||
|
||||
Semver last_semver = current_version;
|
||||
for (const auto& candidate : candidates) {
|
||||
if (boost::filesystem::exists(candidate)) {
|
||||
// parse
|
||||
boost::optional<Semver>other_semver = parse_semver_from_ini(candidate.string());
|
||||
if (other_semver && *other_semver > last_semver) {
|
||||
last_semver = *other_semver;
|
||||
m_older_data_dir_path = candidate.parent_path().string();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_older_data_dir_path.empty())
|
||||
return false;
|
||||
BOOST_LOG_TRIVIAL(info) << "last app config file used: " << m_older_data_dir_path;
|
||||
// ask about using older data folder
|
||||
wxRichMessageDialog msg(nullptr, backup ?
|
||||
wxString::Format(_L("PrusaSlicer detected another configuration folder at %s."
|
||||
"\nIts version is %s."
|
||||
"\nLast version you used in current configuration folder is %s."
|
||||
"\nPlease note that PrusaSlicer uses different folders to save configuration of alpha, beta and full release versions."
|
||||
"\nWould you like to copy found configuration to your current configuration folder?"
|
||||
|
||||
"\n\nIf you select yes, PrusaSlicer will copy all profiles and other files from found folder to the current one. Overwriting any existing file with matching name."
|
||||
"\nIf you select no, you will continue with current configuration.")
|
||||
, m_older_data_dir_path, last_semver.to_string(), current_version.to_string())
|
||||
: wxString::Format(_L("PrusaSlicer detected another configuration folder at %s."
|
||||
"\nIts version is %s."
|
||||
"\nThere is no configuration file in current configuration folder."
|
||||
"\nPlease note that PrusaSlicer uses different folders to save configuration of alpha, beta and full release versions."
|
||||
"\nWould you like to copy found configuration to your current configuration folder?"
|
||||
|
||||
"\n\nIf you select yes, PrusaSlicer will copy all profiles and other files from found folder to the current one."
|
||||
"\nIf you select no, you will start with clean installation with configuration wizard.")
|
||||
, m_older_data_dir_path, last_semver.to_string())
|
||||
, _L("PrusaSlicer"), wxICON_QUESTION | wxYES_NO);
|
||||
if (msg.ShowModal() == wxID_YES) {
|
||||
std::string snapshot_id;
|
||||
if (backup) {
|
||||
// configuration snapshot
|
||||
std::string comment;
|
||||
if (const Config::Snapshot* snapshot = Config::take_config_snapshot_report_error(
|
||||
*app_config,
|
||||
Config::Snapshot::SNAPSHOT_USER,
|
||||
comment);
|
||||
snapshot != nullptr)
|
||||
// Is thos correct? Save snapshot id for later, when new app config is loaded.
|
||||
snapshot_id = snapshot->id;
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to take congiguration snapshot: ";
|
||||
}
|
||||
|
||||
// This will tell later (when config folder structure is sure to exists) to copy files from m_older_data_dir_path
|
||||
m_init_app_config_from_older = true;
|
||||
// load app config from older file
|
||||
app_config->set_loading_path((boost::filesystem::path(m_older_data_dir_path) / filename).string());
|
||||
std::string error = app_config->load();
|
||||
if (!error.empty()) {
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
if (is_editor()) {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
}
|
||||
else {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaGCodeViewer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
}
|
||||
}
|
||||
if (!snapshot_id.empty())
|
||||
app_config->set("on_snapshot", snapshot_id);
|
||||
m_app_conf_exists = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GUI_App::copy_older_config()
|
||||
{
|
||||
preset_bundle->copy_files(m_older_data_dir_path);
|
||||
}
|
||||
|
||||
void GUI_App::init_single_instance_checker(const std::string &name, const std::string &path)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "init wx instance checker " << name << " "<< path;
|
||||
|
@ -812,6 +932,29 @@ bool GUI_App::OnInit()
|
|||
|
||||
bool GUI_App::on_init_inner()
|
||||
{
|
||||
// win32 build on win64 and viceversa
|
||||
#ifdef _WIN64
|
||||
if (wxPlatformInfo::Get().GetArchName().substr(0, 2) == "") {
|
||||
wxRichMessageDialog dlg(nullptr,
|
||||
_L("You have started PrusaSlicer for 64-bit architecture on 32-bit system."
|
||||
"\nPlease download and install correct version at https://www.prusa3d.cz/prusaslicer/."
|
||||
"\nDo you wish to continue?"),
|
||||
"PrusaSlicer", wxICON_QUESTION | wxYES_NO);
|
||||
if (dlg.ShowModal() != wxID_YES)
|
||||
return false;
|
||||
}
|
||||
#elif _WIN32
|
||||
if (wxPlatformInfo::Get().GetArchName().substr(0, 2) == "64") {
|
||||
wxRichMessageDialog dlg(nullptr,
|
||||
_L("You have started PrusaSlicer for 32-bit architecture on 64-bit system."
|
||||
"\nPlease download and install correct version at https://www.prusa3d.cz/prusaslicer/."
|
||||
"\nDo you wish to continue?"),
|
||||
"PrusaSlicer", wxICON_QUESTION | wxYES_NO);
|
||||
if (dlg.ShowModal() != wxID_YES)
|
||||
return false;
|
||||
}
|
||||
#endif // _WIN64
|
||||
|
||||
// Forcing back menu icons under gtk2 and gtk3. Solution is based on:
|
||||
// https://docs.gtk.org/gtk3/class.Settings.html
|
||||
// see also https://docs.wxwidgets.org/3.0/classwx_menu_item.html#a2b5d6bcb820b992b1e4709facbf6d4fb
|
||||
|
@ -861,6 +1004,13 @@ bool GUI_App::on_init_inner()
|
|||
}
|
||||
}
|
||||
|
||||
if (m_last_config_version) {
|
||||
if (*m_last_config_version < *Semver::parse(SLIC3R_VERSION))
|
||||
check_older_app_config(*m_last_config_version, true);
|
||||
} else {
|
||||
check_older_app_config(Semver(), false);
|
||||
}
|
||||
|
||||
app_config->set("version", SLIC3R_VERSION);
|
||||
app_config->save();
|
||||
|
||||
|
@ -899,12 +1049,18 @@ bool GUI_App::on_init_inner()
|
|||
scrn->SetText(_L("Loading configuration")+ dots);
|
||||
}
|
||||
|
||||
|
||||
|
||||
preset_bundle = new PresetBundle();
|
||||
|
||||
// just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory
|
||||
// supplied as argument to --datadir; in that case we should still run the wizard
|
||||
preset_bundle->setup_directories();
|
||||
|
||||
|
||||
if (m_init_app_config_from_older)
|
||||
copy_older_config();
|
||||
|
||||
if (is_editor()) {
|
||||
#ifdef __WXMSW__
|
||||
if (app_config->get("associate_3mf") == "1")
|
||||
|
|
|
@ -337,6 +337,8 @@ public:
|
|||
private:
|
||||
bool on_init_inner();
|
||||
void init_app_config();
|
||||
bool check_older_app_config(Semver current_version, bool backup);
|
||||
void copy_older_config();
|
||||
void window_pos_save(wxTopLevelWindow* window, const std::string &name);
|
||||
void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false);
|
||||
void window_pos_sanitize(wxTopLevelWindow* window);
|
||||
|
@ -344,6 +346,10 @@ private:
|
|||
|
||||
bool config_wizard_startup();
|
||||
void check_updates(const bool verbose);
|
||||
|
||||
bool m_init_app_config_from_older { false };
|
||||
std::string m_older_data_dir_path;
|
||||
boost::optional<Semver> m_last_config_version;
|
||||
};
|
||||
|
||||
DECLARE_APP(GUI_App)
|
||||
|
|
|
@ -413,9 +413,9 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
|
|||
// open preferences
|
||||
} else if(dict["hypertext_type"] == "preferences") {
|
||||
int page = static_cast<Preset::Type>(std::atoi(dict["hypertext_preferences_page"].c_str()));
|
||||
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page]() { wxGetApp().open_preferences(page); } };
|
||||
std::string item = dict["hypertext_preferences_item"];
|
||||
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page, item]() { wxGetApp().open_preferences(page, item); } };
|
||||
m_loaded_hints.emplace_back(hint_data);
|
||||
|
||||
} else if (dict["hypertext_type"] == "plater") {
|
||||
std::string item = dict["hypertext_plater_item"];
|
||||
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } };
|
||||
|
|
|
@ -2068,9 +2068,11 @@ bool NotificationManager::update_notifications(GLCanvas3D& canvas)
|
|||
if ((*it).remaining_time > 0)
|
||||
(*it).remaining_time -= time_since_render;
|
||||
if ((*it).remaining_time <= 0) {
|
||||
if ((*it).condition_callback()) { // push notification, erase it from waiting list (frame is scheduled by push)
|
||||
if ((*it).notification && (*it).condition_callback()) { // push notification, erase it from waiting list (frame is scheduled by push)
|
||||
(*it).notification->reset_timer();
|
||||
if (push_notification_data(std::move((*it).notification), 0)) {
|
||||
// if activate_existing returns false, we expect push to return true.
|
||||
if(!this->activate_existing((*it).notification.get()) || (*it).delay_interval == 0) {
|
||||
push_notification_data(std::move((*it).notification), 0);
|
||||
it = m_waiting_notifications.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
@ -2107,11 +2109,13 @@ bool NotificationManager::activate_existing(const NotificationManager::PopNotifi
|
|||
const std::string &new_text = notification->get_data().text1;
|
||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end(); ++it) {
|
||||
if ((*it)->get_type() == new_type && !(*it)->is_finished()) {
|
||||
// multiple of one type allowed, but must have different text
|
||||
if (std::find(m_multiple_types.begin(), m_multiple_types.end(), new_type) != m_multiple_types.end()) {
|
||||
// If found same type and same text, return true - update will be performed on the old notif
|
||||
if ((*it)->compare_text(new_text) == false) {
|
||||
continue;
|
||||
}
|
||||
// multiple of one type allowed, but must have different text nad ObjectID
|
||||
} else if (new_type == NotificationType::SlicingWarning) {
|
||||
auto w1 = dynamic_cast<const ObjectIDNotification*>(notification);
|
||||
auto w2 = dynamic_cast<const ObjectIDNotification*>(it->get());
|
||||
|
|
|
@ -112,7 +112,7 @@ enum class NotificationType
|
|||
// information about netfabb is finished repairing model (blocking proccess)
|
||||
NetfabbFinished,
|
||||
// Short meesage to fill space between start and finish of export
|
||||
ExportOngoing
|
||||
ExportOngoing,
|
||||
};
|
||||
|
||||
class NotificationManager
|
||||
|
@ -706,6 +706,7 @@ private:
|
|||
// Otherwise another delay interval waiting. Timestamp is 0.
|
||||
// Note that notification object is constructed when being added to the waiting list, but there are no updates called on it and its timer is reset at regular push.
|
||||
// Also note that no control of same notification is done during push_delayed_notification_data but if waiting notif fails to push, it continues waiting.
|
||||
// If delay_interval is 0, notification is pushed only after initial_delay no matter the result.
|
||||
void push_delayed_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval);
|
||||
//finds older notification of same type and moves it to the end of queue. returns true if found
|
||||
bool activate_existing(const NotificationManager::PopNotification* notification);
|
||||
|
|
|
@ -3294,6 +3294,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova
|
|||
show_warning_dialog = true;
|
||||
if (! output_path.empty()) {
|
||||
background_process.schedule_export(output_path.string(), output_path_on_removable_media);
|
||||
notification_manager->push_delayed_notification(NotificationType::ExportOngoing, []() {return true; }, 1000, 0);
|
||||
} else {
|
||||
background_process.schedule_upload(std::move(upload_job));
|
||||
}
|
||||
|
@ -4030,7 +4031,6 @@ void Plater::priv::on_export_began(wxCommandEvent& evt)
|
|||
{
|
||||
if (show_warning_dialog)
|
||||
warnings_dialog();
|
||||
notification_manager->push_delayed_notification(NotificationType::ExportOngoing, [](){return true;}, 1000, 1000);
|
||||
}
|
||||
void Plater::priv::on_slicing_began()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue