mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-30 14:32:00 +08:00
356 lines
11 KiB
C++
356 lines
11 KiB
C++
///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka
|
|
///|/
|
|
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
|
///|/
|
|
#include "UpdatesUIManager.hpp"
|
|
#include "I18N.hpp"
|
|
#include "wxExtensions.hpp"
|
|
#include "PresetArchiveDatabase.hpp"
|
|
|
|
#include "GUI.hpp"
|
|
#include "GUI_App.hpp"
|
|
#include "MainFrame.hpp"
|
|
#include "MsgDialog.hpp"
|
|
#include "format.hpp"
|
|
|
|
#include "Widgets/CheckBox.hpp"
|
|
#include <wx/wupdlock.h>
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
namespace Slic3r {
|
|
namespace GUI {
|
|
|
|
RepositoryUpdateUIManager::RepositoryUpdateUIManager(wxWindow* parent, PresetArchiveDatabase* pad, int em) :
|
|
m_parent(parent)
|
|
,m_pad(pad)
|
|
,m_main_sizer(new wxBoxSizer(wxVERTICAL))
|
|
{
|
|
auto online_label = new wxStaticText(m_parent, wxID_ANY, _L("Online sources"));
|
|
online_label->SetFont(wxGetApp().bold_font());
|
|
|
|
m_main_sizer->Add(online_label, 0, wxTOP | wxLEFT, 2 * em);
|
|
|
|
m_online_sizer = new wxFlexGridSizer(4, 0.75 * em, 1.5 * em);
|
|
m_online_sizer->AddGrowableCol(2);
|
|
m_online_sizer->AddGrowableCol(3);
|
|
m_online_sizer->SetFlexibleDirection(/*wxHORIZONTAL*/wxBOTH);
|
|
|
|
m_main_sizer->Add(m_online_sizer, 0, wxALL, 2 * em);
|
|
|
|
m_main_sizer->AddSpacer(em);
|
|
|
|
auto offline_label = new wxStaticText(m_parent, wxID_ANY, _L("Local sources"));
|
|
offline_label->SetFont(wxGetApp().bold_font());
|
|
|
|
m_main_sizer->Add(offline_label, 0, wxTOP | wxLEFT, 2 * em);
|
|
|
|
m_offline_sizer = new wxFlexGridSizer(7, 0.75 * em, 1.5 * em);
|
|
m_offline_sizer->AddGrowableCol(1);
|
|
m_offline_sizer->AddGrowableCol(2);
|
|
m_offline_sizer->AddGrowableCol(4);
|
|
m_offline_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
|
|
|
m_main_sizer->Add(m_offline_sizer, 0, wxALL, 2 * em);
|
|
|
|
fill_entries(true);
|
|
fill_grids();
|
|
}
|
|
|
|
void RepositoryUpdateUIManager::fill_entries(bool init_selection/* = false*/)
|
|
{
|
|
m_online_entries.clear();
|
|
m_offline_entries.clear();
|
|
|
|
const SharedArchiveRepositoryVector& archs = m_pad->get_all_archive_repositories();
|
|
for (const auto* archive : archs) {
|
|
const std::string& uuid = archive->get_uuid();
|
|
if (init_selection && m_pad->is_selected_repository_by_uuid(uuid))
|
|
m_selected_uuids.emplace(uuid);
|
|
|
|
const bool is_selected = m_selected_uuids.find(uuid) != m_selected_uuids.end();
|
|
const auto& data = archive->get_manifest();
|
|
|
|
if (data.source_path.empty()) {
|
|
// online repo
|
|
m_online_entries.push_back({ is_selected, uuid, data.name, data.description, data.visibility });
|
|
}
|
|
else {
|
|
// offline repo
|
|
m_offline_entries.push_back({ is_selected, uuid, data.name, data.description, data.source_path.filename().string(), fs::exists(data.source_path), data.source_path });
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void RepositoryUpdateUIManager::fill_grids()
|
|
{
|
|
// clear grids
|
|
m_online_sizer->Clear(true);
|
|
m_offline_sizer->Clear(true);
|
|
|
|
// Fill Online repository
|
|
|
|
if (!m_online_entries.empty()) {
|
|
|
|
auto add = [this](wxWindow* win) { m_online_sizer->Add(win, 0, wxALIGN_CENTER_VERTICAL); };
|
|
|
|
// header
|
|
|
|
// TRN: This string appears in Configuration Wizard in the 'Configuration Manager' step.
|
|
for (const wxString& l : std::initializer_list<wxString>{ "", "", _L("Name"), _L("Description")}) {
|
|
auto text = new wxStaticText(m_parent, wxID_ANY, l);
|
|
text->SetFont(wxGetApp().bold_font());
|
|
add(text);
|
|
}
|
|
|
|
// data
|
|
|
|
for (const auto& entry : m_online_entries)
|
|
{
|
|
auto chb = CheckBox::GetNewWin(m_parent, "");
|
|
CheckBox::SetValue(chb, entry.use);
|
|
chb->Bind(wxEVT_CHECKBOX, [this, chb, &entry](wxCommandEvent e) {
|
|
if (CheckBox::GetValue(chb))
|
|
m_selected_uuids.emplace(entry.id);
|
|
else
|
|
m_selected_uuids.erase(entry.id);
|
|
check_selection();
|
|
});
|
|
add(chb);
|
|
|
|
if (entry.visibility.empty())
|
|
add(new wxStaticText(m_parent, wxID_ANY, ""));
|
|
else {
|
|
wxStaticBitmap* bmp = new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("info"));
|
|
bmp->SetToolTip(from_u8(entry.visibility));
|
|
add(bmp);
|
|
}
|
|
|
|
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.name)));
|
|
|
|
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.description)));
|
|
}
|
|
}
|
|
|
|
if (!m_offline_entries.empty()) {
|
|
|
|
auto add = [this](wxWindow* win) { m_offline_sizer->Add(win, 0, wxALIGN_CENTER_VERTICAL); };
|
|
|
|
// header
|
|
|
|
for (const wxString& l : std::initializer_list<wxString>{ "", _L("Name"), _L("Description"), "", _L("Source file"), "", ""}) {
|
|
auto text = new wxStaticText(m_parent, wxID_ANY, l);
|
|
text->SetFont(wxGetApp().bold_font());
|
|
add(text);
|
|
}
|
|
|
|
// data1
|
|
|
|
for (const auto& entry : m_offline_entries)
|
|
{
|
|
auto chb = CheckBox::GetNewWin(m_parent, "");
|
|
CheckBox::SetValue(chb, entry.use);
|
|
chb->Bind(wxEVT_CHECKBOX, [this, chb, &entry](wxCommandEvent e) {
|
|
if (CheckBox::GetValue(chb))
|
|
m_selected_uuids.emplace(entry.id);
|
|
else
|
|
m_selected_uuids.erase(entry.id);
|
|
check_selection();
|
|
});
|
|
add(chb);
|
|
|
|
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.name)));
|
|
|
|
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.description)));
|
|
|
|
{
|
|
wxStaticBitmap* bmp = new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle(entry.is_ok ? "tick_mark" : "exclamation"));
|
|
bmp->SetToolTip(entry.is_ok ? _L("File exists") : _L("File does NOT exist"));
|
|
add(bmp);
|
|
}
|
|
|
|
{
|
|
auto path_str = new wxStaticText(m_parent, wxID_ANY, from_u8(entry.source));
|
|
path_str->SetToolTip(from_u8(entry.source_path.string()));
|
|
add(path_str);
|
|
}
|
|
|
|
{
|
|
ScalableButton* btn = new ScalableButton(m_parent, wxID_ANY, "open");
|
|
btn->SetToolTip(_L("Open folder"));
|
|
btn->Bind(wxEVT_BUTTON, [&entry](wxCommandEvent& event) {
|
|
GUI::desktop_open_folder(entry.source_path.parent_path().make_preferred());
|
|
});
|
|
add(btn);
|
|
}
|
|
|
|
{
|
|
wxButton* btn = new wxButton(m_parent, wxID_ANY, " " + _L("Remove") + " ");
|
|
wxGetApp().UpdateDarkUI(btn, true);
|
|
btn->Bind(wxEVT_BUTTON, [this, &entry](wxCommandEvent& event) { remove_offline_repos(entry.id); });
|
|
add(btn);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
wxButton* btn = new wxButton(m_parent, wxID_ANY, " " + _L("Load") + "... ");
|
|
wxGetApp().UpdateDarkUI(btn, true);
|
|
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { load_offline_repos(); });
|
|
m_offline_sizer->Add(btn);
|
|
}
|
|
|
|
}
|
|
|
|
void RepositoryUpdateUIManager::update()
|
|
{
|
|
fill_entries();
|
|
|
|
wxWindowUpdateLocker freeze_guard(m_parent);
|
|
|
|
fill_grids();
|
|
|
|
m_parent->GetSizer()->Layout();
|
|
|
|
if (wxDialog* dlg = dynamic_cast<wxDialog*>(m_parent)) {
|
|
m_parent->Layout();
|
|
m_parent->Refresh();
|
|
dlg->Fit();
|
|
}
|
|
else if (wxWindow* top_parent = m_parent->GetParent()) {
|
|
top_parent->Layout();
|
|
top_parent->Refresh();
|
|
}
|
|
}
|
|
|
|
void RepositoryUpdateUIManager::remove_offline_repos(const std::string& id)
|
|
{
|
|
m_pad->remove_local_archive(id);
|
|
m_selected_uuids.erase(id);
|
|
check_selection();
|
|
|
|
if (wxDialog* dlg = dynamic_cast<wxDialog*>(m_parent)) {
|
|
// Invalidate min_size for correct next Layout()
|
|
dlg->SetMinSize(wxDefaultSize);
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
void RepositoryUpdateUIManager::load_offline_repos()
|
|
{
|
|
wxArrayString input_files;
|
|
wxFileDialog dialog(m_parent, _L("Choose one or more ZIP files") + ":",
|
|
from_u8(wxGetApp().app_config->get_last_dir()), "",
|
|
file_wildcards(FT_ZIP), wxFD_OPEN | /*wxFD_MULTIPLE | */wxFD_FILE_MUST_EXIST);
|
|
|
|
if (dialog.ShowModal() == wxID_OK)
|
|
dialog.GetPaths(input_files);
|
|
|
|
if (input_files.IsEmpty())
|
|
return;
|
|
|
|
// Iterate through the input files
|
|
for (size_t i = 0; i < input_files.size(); ++i) {
|
|
std::string input_file = into_u8(input_files.Item(i));
|
|
try {
|
|
fs::path input_path = fs::path(input_file);
|
|
std::string msg;
|
|
std::string uuid = m_pad->add_local_archive(input_path, msg);
|
|
if (uuid.empty()) {
|
|
ErrorDialog(m_parent, msg, false).ShowModal();
|
|
}
|
|
else {
|
|
m_selected_uuids.emplace(uuid);
|
|
check_selection();
|
|
update();
|
|
}
|
|
}
|
|
catch (fs::filesystem_error const& e) {
|
|
std::cerr << e.what() << '\n';
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RepositoryUpdateUIManager::set_selected_repositories()
|
|
{
|
|
std::vector<std::string> used_ids;
|
|
std::copy(m_selected_uuids.begin(), m_selected_uuids.end(), std::back_inserter(used_ids));
|
|
|
|
std::string msg;
|
|
|
|
if (m_pad->set_selected_repositories(used_ids, msg)) {
|
|
check_selection();
|
|
return true;
|
|
}
|
|
|
|
ErrorDialog(m_parent, msg, false).ShowModal();
|
|
// update selection on UI
|
|
update();
|
|
check_selection();
|
|
return false;
|
|
}
|
|
|
|
void RepositoryUpdateUIManager::check_selection()
|
|
{
|
|
for (const auto& [uuid, is_selected] : m_pad->get_selected_repositories_uuid() )
|
|
if ((is_selected && m_selected_uuids.find(uuid) == m_selected_uuids.end() )||
|
|
(!is_selected && m_selected_uuids.find(uuid) != m_selected_uuids.end())) {
|
|
m_is_selection_changed = true;
|
|
return;
|
|
}
|
|
|
|
m_is_selection_changed = false;
|
|
}
|
|
|
|
ManagePresetRepositoriesDialog::ManagePresetRepositoriesDialog(PresetArchiveDatabase* pad)
|
|
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY,
|
|
format_wxstr("%1% - %2%", SLIC3R_APP_NAME, _L("Manage Updates")),
|
|
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
|
{
|
|
this->SetFont(wxGetApp().normal_font());
|
|
const int em = em_unit();
|
|
|
|
m_manager = std::make_unique<RepositoryUpdateUIManager>(this, pad, em);
|
|
|
|
auto sizer = m_manager->get_sizer();
|
|
|
|
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK | wxCLOSE);
|
|
wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton());
|
|
wxGetApp().UpdateDlgDarkUI(this, true);
|
|
this->SetEscapeId(wxID_CLOSE);
|
|
this->Bind(wxEVT_BUTTON, &ManagePresetRepositoriesDialog::onCloseDialog, this, wxID_CLOSE);
|
|
this->Bind(wxEVT_BUTTON, &ManagePresetRepositoriesDialog::onOkDialog, this, wxID_OK);
|
|
sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, em);
|
|
|
|
|
|
buttons->GetAffirmativeButton()->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& event) {
|
|
event.Enable(m_manager->has_selections());
|
|
});
|
|
|
|
SetSizer(sizer);
|
|
sizer->SetSizeHints(this);
|
|
}
|
|
|
|
void ManagePresetRepositoriesDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|
{
|
|
SetMinSize(GetBestSize());
|
|
Fit();
|
|
Refresh();
|
|
}
|
|
|
|
void ManagePresetRepositoriesDialog::onCloseDialog(wxEvent &)
|
|
{
|
|
this->EndModal(wxID_CLOSE);
|
|
}
|
|
|
|
void ManagePresetRepositoriesDialog::onOkDialog(wxEvent&)
|
|
{
|
|
if (m_manager->set_selected_repositories())
|
|
this->EndModal(wxID_OK);
|
|
}
|
|
|
|
} // namespace GUI
|
|
} // namespace Slic3r
|