7c571c1d9d
with the following refactorings: 1) Removed the "printhost_slug" config from the Printer config and from all the Printer config related spots. 2) "printhost_slug" renamed to "printhost_port". Slug sounds nasty. 3) Improved error reporting of RepetierHost class. 4) Refactored for the new "Physical Printers" Following refactorings were done independently of the Repetier pull request: 1) Removed PrintHost static print config. 2) Clean-up after conversion of print host configuration from Printer config to Physical Printer config. 3) Fixed some issues, where the Printer config was still queried for host configuration. Vojtech believes that this should not happen after the host configuration is converted to physical printers. Vojtech still feels that more refactoring is needed in regard to porting the host configuration from Printer profile to the new Physical Printer profile.
320 lines
11 KiB
C++
320 lines
11 KiB
C++
#include "PrintHostDialogs.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <wx/frame.h>
|
|
#include <wx/progdlg.h>
|
|
#include <wx/sizer.h>
|
|
#include <wx/stattext.h>
|
|
#include <wx/textctrl.h>
|
|
#include <wx/checkbox.h>
|
|
#include <wx/button.h>
|
|
#include <wx/dataview.h>
|
|
#include <wx/wupdlock.h>
|
|
#include <wx/debug.h>
|
|
|
|
#include "GUI.hpp"
|
|
#include "GUI_App.hpp"
|
|
#include "MsgDialog.hpp"
|
|
#include "I18N.hpp"
|
|
#include "../Utils/PrintHost.hpp"
|
|
#include "wxExtensions.hpp"
|
|
#include "libslic3r/AppConfig.hpp"
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
namespace Slic3r {
|
|
namespace GUI {
|
|
|
|
static const char *CONFIG_KEY_PATH = "printhost_path";
|
|
static const char *CONFIG_KEY_PRINT = "printhost_print";
|
|
static const char *CONFIG_KEY_GROUP = "printhost_group";
|
|
|
|
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print, const wxArrayString &groups)
|
|
: MsgDialog(nullptr, _L("Send G-Code to printer host"), _L("Upload to Printer Host with the following filename:"), wxID_NONE)
|
|
, txt_filename(new wxTextCtrl(this, wxID_ANY))
|
|
, box_print(can_start_print ? new wxCheckBox(this, wxID_ANY, _L("Start printing after upload")) : nullptr)
|
|
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
|
|
{
|
|
#ifdef __APPLE__
|
|
txt_filename->OSXDisableAllSmartSubstitutions();
|
|
#endif
|
|
const AppConfig *app_config = wxGetApp().app_config;
|
|
|
|
auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _L("Use forward slashes ( / ) as a directory separator if needed."));
|
|
label_dir_hint->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
|
|
|
|
content_sizer->Add(txt_filename, 0, wxEXPAND);
|
|
content_sizer->Add(label_dir_hint);
|
|
content_sizer->AddSpacer(VERT_SPACING);
|
|
if (box_print != nullptr) {
|
|
content_sizer->Add(box_print, 0, wxBOTTOM, 2*VERT_SPACING);
|
|
box_print->SetValue(app_config->get("recent", CONFIG_KEY_PRINT) == "1");
|
|
}
|
|
|
|
if (combo_groups != nullptr) {
|
|
// Repetier specific: Show a selection of file groups.
|
|
auto *label_group = new wxStaticText(this, wxID_ANY, _L("Group"));
|
|
content_sizer->Add(label_group);
|
|
content_sizer->Add(combo_groups, 0, wxBOTTOM, 2*VERT_SPACING);
|
|
wxString recent_group = from_u8(app_config->get("recent", CONFIG_KEY_GROUP));
|
|
if (! recent_group.empty())
|
|
combo_groups->SetValue(recent_group);
|
|
}
|
|
|
|
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
|
|
|
|
wxString recent_path = from_u8(app_config->get("recent", CONFIG_KEY_PATH));
|
|
if (recent_path.Length() > 0 && recent_path[recent_path.Length() - 1] != '/') {
|
|
recent_path += '/';
|
|
}
|
|
const auto recent_path_len = recent_path.Length();
|
|
recent_path += path.filename().wstring();
|
|
wxString stem(path.stem().wstring());
|
|
const auto stem_len = stem.Length();
|
|
|
|
txt_filename->SetValue(recent_path);
|
|
txt_filename->SetFocus();
|
|
|
|
Fit();
|
|
|
|
Bind(wxEVT_SHOW, [=](const wxShowEvent &) {
|
|
// Another similar case where the function only works with EVT_SHOW + CallAfter,
|
|
// this time on Mac.
|
|
CallAfter([=]() {
|
|
txt_filename->SetSelection(recent_path_len, recent_path_len + stem_len);
|
|
});
|
|
});
|
|
}
|
|
|
|
fs::path PrintHostSendDialog::filename() const
|
|
{
|
|
return into_path(txt_filename->GetValue());
|
|
}
|
|
|
|
bool PrintHostSendDialog::start_print() const
|
|
{
|
|
return box_print != nullptr ? box_print->GetValue() : false;
|
|
}
|
|
|
|
std::string PrintHostSendDialog::group() const
|
|
{
|
|
if (combo_groups == nullptr) {
|
|
return "";
|
|
} else {
|
|
wxString group = combo_groups->GetValue();
|
|
return into_u8(group);
|
|
}
|
|
}
|
|
|
|
void PrintHostSendDialog::EndModal(int ret)
|
|
{
|
|
if (ret == wxID_OK) {
|
|
// Persist path and print settings
|
|
wxString path = txt_filename->GetValue();
|
|
int last_slash = path.Find('/', true);
|
|
if (last_slash == wxNOT_FOUND)
|
|
path.clear();
|
|
else
|
|
path = path.SubString(0, last_slash);
|
|
|
|
AppConfig *app_config = wxGetApp().app_config;
|
|
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path));
|
|
app_config->set("recent", CONFIG_KEY_PRINT, start_print() ? "1" : "0");
|
|
|
|
if (combo_groups != nullptr) {
|
|
wxString group = combo_groups->GetValue();
|
|
app_config->set("recent", CONFIG_KEY_GROUP, into_u8(group));
|
|
}
|
|
}
|
|
|
|
MsgDialog::EndModal(ret);
|
|
}
|
|
|
|
|
|
|
|
wxDEFINE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
|
wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
|
wxDEFINE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event);
|
|
|
|
PrintHostQueueDialog::Event::Event(wxEventType eventType, int winid, size_t job_id)
|
|
: wxEvent(winid, eventType)
|
|
, job_id(job_id)
|
|
{}
|
|
|
|
PrintHostQueueDialog::Event::Event(wxEventType eventType, int winid, size_t job_id, int progress)
|
|
: wxEvent(winid, eventType)
|
|
, job_id(job_id)
|
|
, progress(progress)
|
|
{}
|
|
|
|
PrintHostQueueDialog::Event::Event(wxEventType eventType, int winid, size_t job_id, wxString error)
|
|
: wxEvent(winid, eventType)
|
|
, job_id(job_id)
|
|
, error(std::move(error))
|
|
{}
|
|
|
|
wxEvent *PrintHostQueueDialog::Event::Clone() const
|
|
{
|
|
return new Event(*this);
|
|
}
|
|
|
|
PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|
: DPIDialog(parent, wxID_ANY, _L("Print host upload queue"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
|
, on_progress_evt(this, EVT_PRINTHOST_PROGRESS, &PrintHostQueueDialog::on_progress, this)
|
|
, on_error_evt(this, EVT_PRINTHOST_ERROR, &PrintHostQueueDialog::on_error, this)
|
|
, on_cancel_evt(this, EVT_PRINTHOST_CANCEL, &PrintHostQueueDialog::on_cancel, this)
|
|
{
|
|
const auto em = GetTextExtent("m").x;
|
|
|
|
auto *topsizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
job_list = new wxDataViewListCtrl(this, wxID_ANY);
|
|
// Note: Keep these in sync with Column
|
|
job_list->AppendTextColumn(_L("ID"), wxDATAVIEW_CELL_INERT);
|
|
job_list->AppendProgressColumn(_L("Progress"), wxDATAVIEW_CELL_INERT);
|
|
job_list->AppendTextColumn(_L("Status"), wxDATAVIEW_CELL_INERT);
|
|
job_list->AppendTextColumn(_L("Host"), wxDATAVIEW_CELL_INERT);
|
|
job_list->AppendTextColumn(_L("Filename"), wxDATAVIEW_CELL_INERT);
|
|
job_list->AppendTextColumn(_L("Error Message"), wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
|
|
|
|
auto *btnsizer = new wxBoxSizer(wxHORIZONTAL);
|
|
btn_cancel = new wxButton(this, wxID_DELETE, _L("Cancel selected"));
|
|
btn_cancel->Disable();
|
|
btn_error = new wxButton(this, wxID_ANY, _L("Show error message"));
|
|
btn_error->Disable();
|
|
// Note: The label needs to be present, otherwise we get accelerator bugs on Mac
|
|
auto *btn_close = new wxButton(this, wxID_CANCEL, _L("Close"));
|
|
btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING);
|
|
btnsizer->Add(btn_error, 0);
|
|
btnsizer->AddStretchSpacer();
|
|
btnsizer->Add(btn_close);
|
|
|
|
topsizer->Add(job_list, 1, wxEXPAND | wxBOTTOM, SPACING);
|
|
topsizer->Add(btnsizer, 0, wxEXPAND);
|
|
SetSizer(topsizer);
|
|
|
|
SetSize(wxSize(HEIGHT * em, WIDTH * em));
|
|
|
|
job_list->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent&) { on_list_select(); });
|
|
|
|
btn_cancel->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
|
int selected = job_list->GetSelectedRow();
|
|
if (selected == wxNOT_FOUND) { return; }
|
|
|
|
const JobState state = get_state(selected);
|
|
if (state < ST_ERROR) {
|
|
// TODO: cancel
|
|
GUI::wxGetApp().printhost_job_queue().cancel(selected);
|
|
}
|
|
});
|
|
|
|
btn_error->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
|
int selected = job_list->GetSelectedRow();
|
|
if (selected == wxNOT_FOUND) { return; }
|
|
GUI::show_error(nullptr, job_list->GetTextValue(selected, COL_ERRORMSG));
|
|
});
|
|
}
|
|
|
|
void PrintHostQueueDialog::append_job(const PrintHostJob &job)
|
|
{
|
|
wxCHECK_RET(!job.empty(), "PrintHostQueueDialog: Attempt to append an empty job");
|
|
|
|
wxVector<wxVariant> fields;
|
|
fields.push_back(wxVariant(wxString::Format("%d", job_list->GetItemCount() + 1)));
|
|
fields.push_back(wxVariant(0));
|
|
fields.push_back(wxVariant(_L("Enqueued")));
|
|
fields.push_back(wxVariant(job.printhost->get_host()));
|
|
fields.push_back(wxVariant(job.upload_data.upload_path.string()));
|
|
fields.push_back(wxVariant(""));
|
|
job_list->AppendItem(fields, static_cast<wxUIntPtr>(ST_NEW));
|
|
}
|
|
|
|
void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|
{
|
|
const int& em = em_unit();
|
|
|
|
msw_buttons_rescale(this, em, { wxID_DELETE, wxID_CANCEL, btn_error->GetId() });
|
|
|
|
SetMinSize(wxSize(HEIGHT * em, WIDTH * em));
|
|
|
|
Fit();
|
|
Refresh();
|
|
}
|
|
|
|
PrintHostQueueDialog::JobState PrintHostQueueDialog::get_state(int idx)
|
|
{
|
|
wxCHECK_MSG(idx >= 0 && idx < job_list->GetItemCount(), ST_ERROR, "Out of bounds access to job list");
|
|
return static_cast<JobState>(job_list->GetItemData(job_list->RowToItem(idx)));
|
|
}
|
|
|
|
void PrintHostQueueDialog::set_state(int idx, JobState state)
|
|
{
|
|
wxCHECK_RET(idx >= 0 && idx < job_list->GetItemCount(), "Out of bounds access to job list");
|
|
job_list->SetItemData(job_list->RowToItem(idx), static_cast<wxUIntPtr>(state));
|
|
|
|
switch (state) {
|
|
case ST_NEW: job_list->SetValue(_L("Enqueued"), idx, COL_STATUS); break;
|
|
case ST_PROGRESS: job_list->SetValue(_L("Uploading"), idx, COL_STATUS); break;
|
|
case ST_ERROR: job_list->SetValue(_L("Error"), idx, COL_STATUS); break;
|
|
case ST_CANCELLING: job_list->SetValue(_L("Cancelling"), idx, COL_STATUS); break;
|
|
case ST_CANCELLED: job_list->SetValue(_L("Cancelled"), idx, COL_STATUS); break;
|
|
case ST_COMPLETED: job_list->SetValue(_L("Completed"), idx, COL_STATUS); break;
|
|
}
|
|
}
|
|
|
|
void PrintHostQueueDialog::on_list_select()
|
|
{
|
|
int selected = job_list->GetSelectedRow();
|
|
if (selected != wxNOT_FOUND) {
|
|
const JobState state = get_state(selected);
|
|
btn_cancel->Enable(state < ST_ERROR);
|
|
btn_error->Enable(state == ST_ERROR);
|
|
Layout();
|
|
} else {
|
|
btn_cancel->Disable();
|
|
}
|
|
}
|
|
|
|
void PrintHostQueueDialog::on_progress(Event &evt)
|
|
{
|
|
wxCHECK_RET(evt.job_id < (size_t)job_list->GetItemCount(), "Out of bounds access to job list");
|
|
|
|
if (evt.progress < 100) {
|
|
set_state(evt.job_id, ST_PROGRESS);
|
|
job_list->SetValue(wxVariant(evt.progress), evt.job_id, COL_PROGRESS);
|
|
} else {
|
|
set_state(evt.job_id, ST_COMPLETED);
|
|
job_list->SetValue(wxVariant(100), evt.job_id, COL_PROGRESS);
|
|
}
|
|
|
|
on_list_select();
|
|
}
|
|
|
|
void PrintHostQueueDialog::on_error(Event &evt)
|
|
{
|
|
wxCHECK_RET(evt.job_id < (size_t)job_list->GetItemCount(), "Out of bounds access to job list");
|
|
|
|
set_state(evt.job_id, ST_ERROR);
|
|
|
|
auto errormsg = from_u8((boost::format("%1%\n%2%") % _utf8(L("Error uploading to print host:")) % std::string(evt.error.ToUTF8())).str());
|
|
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
|
job_list->SetValue(wxVariant(errormsg), evt.job_id, COL_ERRORMSG); // Stashes the error message into a hidden column for later
|
|
|
|
on_list_select();
|
|
|
|
GUI::show_error(nullptr, errormsg);
|
|
}
|
|
|
|
void PrintHostQueueDialog::on_cancel(Event &evt)
|
|
{
|
|
wxCHECK_RET(evt.job_id < (size_t)job_list->GetItemCount(), "Out of bounds access to job list");
|
|
|
|
set_state(evt.job_id, ST_CANCELLED);
|
|
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
|
|
|
on_list_select();
|
|
}
|
|
|
|
|
|
}}
|