2018-12-11 09:33:11 +00:00
# include "PrintHostDialogs.hpp"
2018-12-14 14:27:34 +00:00
# include <algorithm>
2018-12-11 09:33:11 +00:00
# include <wx/frame.h>
# include <wx/progdlg.h>
# include <wx/sizer.h>
# include <wx/stattext.h>
# include <wx/textctrl.h>
# include <wx/checkbox.h>
2018-12-14 14:27:34 +00:00
# include <wx/button.h>
# include <wx/dataview.h>
# include <wx/wupdlock.h>
# include <wx/debug.h>
2018-12-11 09:33:11 +00:00
2018-12-14 14:27:34 +00:00
# include "GUI.hpp"
2018-12-20 12:36:49 +00:00
# include "GUI_App.hpp"
2018-12-14 14:27:34 +00:00
# include "MsgDialog.hpp"
# include "I18N.hpp"
# include "../Utils/PrintHost.hpp"
2019-04-25 13:06:44 +00:00
# include "wxExtensions.hpp"
2020-12-04 12:34:44 +00:00
# include "MainFrame.hpp"
2020-08-08 15:03:20 +00:00
# include "libslic3r/AppConfig.hpp"
2018-12-11 09:33:11 +00:00
namespace fs = boost : : filesystem ;
namespace Slic3r {
2018-12-14 14:27:34 +00:00
namespace GUI {
2019-02-18 13:03:02 +00:00
static const char * CONFIG_KEY_PATH = " printhost_path " ;
static const char * CONFIG_KEY_PRINT = " printhost_print " ;
2020-10-28 08:51:05 +00:00
static const char * CONFIG_KEY_GROUP = " printhost_group " ;
2018-12-11 09:33:11 +00:00
2020-10-28 08:51:05 +00:00
PrintHostSendDialog : : PrintHostSendDialog ( const fs : : path & path , bool can_start_print , const wxArrayString & groups )
2020-12-04 12:34:44 +00:00
: MsgDialog ( static_cast < wxWindow * > ( wxGetApp ( ) . mainframe ) , _L ( " Send G-Code to printer host " ) , _L ( " Upload to Printer Host with the following filename: " ) , wxID_NONE )
2019-02-18 13:03:02 +00:00
, txt_filename ( new wxTextCtrl ( this , wxID_ANY ) )
2020-10-28 08:51:05 +00:00
, 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 )
2018-12-11 09:33:11 +00:00
{
2019-01-24 10:53:37 +00:00
# ifdef __APPLE__
txt_filename - > OSXDisableAllSmartSubstitutions ( ) ;
# endif
2019-03-04 15:50:43 +00:00
const AppConfig * app_config = wxGetApp ( ) . app_config ;
2019-01-24 10:53:37 +00:00
2020-10-28 08:51:05 +00:00
auto * label_dir_hint = new wxStaticText ( this , wxID_ANY , _L ( " Use forward slashes ( / ) as a directory separator if needed. " ) ) ;
2019-02-21 17:59:21 +00:00
label_dir_hint - > Wrap ( CONTENT_WIDTH * wxGetApp ( ) . em_unit ( ) ) ;
2018-12-11 09:33:11 +00:00
content_sizer - > Add ( txt_filename , 0 , wxEXPAND ) ;
content_sizer - > Add ( label_dir_hint ) ;
content_sizer - > AddSpacer ( VERT_SPACING ) ;
2019-03-04 15:50:43 +00:00
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 " ) ;
}
2020-10-28 08:51:05 +00:00
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 ) ;
}
2018-12-11 09:33:11 +00:00
btn_sizer - > Add ( CreateStdDialogButtonSizer ( wxOK | wxCANCEL ) ) ;
2019-02-18 13:03:02 +00:00
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 ( ) ;
2018-12-11 09:33:11 +00:00
wxString stem ( path . stem ( ) . wstring ( ) ) ;
2019-02-18 13:03:02 +00:00
const auto stem_len = stem . Length ( ) ;
txt_filename - > SetValue ( recent_path ) ;
txt_filename - > SetFocus ( ) ;
2020-10-28 08:51:05 +00:00
2018-12-11 09:33:11 +00:00
Fit ( ) ;
2020-12-04 12:34:44 +00:00
CenterOnParent ( ) ;
2019-02-18 13:03:02 +00:00
2021-01-06 11:23:42 +00:00
# ifdef __linux__
// On Linux with GTK2 when text control lose the focus then selection (colored background) disappears but text color stay white
// and as a result the text is invisible with light mode
// see https://github.com/prusa3d/PrusaSlicer/issues/4532
// Workaround: Unselect text selection explicitly on kill focus
txt_filename - > Bind ( wxEVT_KILL_FOCUS , [ this ] ( wxEvent & e ) {
e . Skip ( ) ;
txt_filename - > SetInsertionPoint ( txt_filename - > GetLastPosition ( ) ) ;
} , txt_filename - > GetId ( ) ) ;
# endif /* __linux__ */
2019-02-18 13:03:02 +00:00
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 ) ;
} ) ;
} ) ;
2018-12-11 09:33:11 +00:00
}
fs : : path PrintHostSendDialog : : filename ( ) const
{
2019-01-02 14:11:05 +00:00
return into_path ( txt_filename - > GetValue ( ) ) ;
2018-12-11 09:33:11 +00:00
}
bool PrintHostSendDialog : : start_print ( ) const
{
2019-03-04 15:50:43 +00:00
return box_print ! = nullptr ? box_print - > GetValue ( ) : false ;
2018-12-14 14:27:34 +00:00
}
2020-10-28 08:51:05 +00:00
std : : string PrintHostSendDialog : : group ( ) const
{
if ( combo_groups = = nullptr ) {
return " " ;
} else {
wxString group = combo_groups - > GetValue ( ) ;
return into_u8 ( group ) ;
}
}
2019-02-18 13:03:02 +00:00
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 ) ;
2019-05-15 08:24:03 +00:00
if ( last_slash = = wxNOT_FOUND )
path . clear ( ) ;
else
2019-02-18 13:03:02 +00:00
path = path . SubString ( 0 , last_slash ) ;
2020-10-28 08:51:05 +00:00
2019-05-15 08:24:03 +00:00
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 " ) ;
2020-10-28 08:51:05 +00:00
if ( combo_groups ! = nullptr ) {
wxString group = combo_groups - > GetValue ( ) ;
app_config - > set ( " recent " , CONFIG_KEY_GROUP , into_u8 ( group ) ) ;
}
2019-02-18 13:03:02 +00:00
}
MsgDialog : : EndModal ( ret ) ;
}
2018-12-14 14:27:34 +00:00
wxDEFINE_EVENT ( EVT_PRINTHOST_PROGRESS , PrintHostQueueDialog : : Event ) ;
2018-12-20 12:36:49 +00:00
wxDEFINE_EVENT ( EVT_PRINTHOST_ERROR , PrintHostQueueDialog : : Event ) ;
wxDEFINE_EVENT ( EVT_PRINTHOST_CANCEL , PrintHostQueueDialog : : Event ) ;
2018-12-14 14:27:34 +00:00
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 )
2020-10-28 08:51:05 +00:00
: DPIDialog ( parent , wxID_ANY , _L ( " Print host upload queue " ) , wxDefaultPosition , wxDefaultSize , wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
2018-12-14 14:27:34 +00:00
, on_progress_evt ( this , EVT_PRINTHOST_PROGRESS , & PrintHostQueueDialog : : on_progress , this )
, on_error_evt ( this , EVT_PRINTHOST_ERROR , & PrintHostQueueDialog : : on_error , this )
2018-12-20 12:36:49 +00:00
, on_cancel_evt ( this , EVT_PRINTHOST_CANCEL , & PrintHostQueueDialog : : on_cancel , this )
2018-12-14 14:27:34 +00:00
{
2019-02-21 17:59:21 +00:00
const auto em = GetTextExtent ( " m " ) . x ;
2018-12-14 14:27:34 +00:00
auto * topsizer = new wxBoxSizer ( wxVERTICAL ) ;
job_list = new wxDataViewListCtrl ( this , wxID_ANY ) ;
2018-12-20 10:50:08 +00:00
// Note: Keep these in sync with Column
2020-10-28 08:51:05 +00:00
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 ) ;
2018-12-14 14:27:34 +00:00
auto * btnsizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2020-10-28 08:51:05 +00:00
btn_cancel = new wxButton ( this , wxID_DELETE , _L ( " Cancel selected " ) ) ;
2018-12-20 10:50:08 +00:00
btn_cancel - > Disable ( ) ;
2020-10-28 08:51:05 +00:00
btn_error = new wxButton ( this , wxID_ANY , _L ( " Show error message " ) ) ;
2018-12-20 10:50:08 +00:00
btn_error - > Disable ( ) ;
2020-10-28 08:51:05 +00:00
// Note: The label needs to be present, otherwise we get accelerator bugs on Mac
auto * btn_close = new wxButton ( this , wxID_CANCEL , _L ( " Close " ) ) ;
2018-12-14 14:27:34 +00:00
btnsizer - > Add ( btn_cancel , 0 , wxRIGHT , SPACING ) ;
2018-12-20 10:50:08 +00:00
btnsizer - > Add ( btn_error , 0 ) ;
2018-12-14 14:27:34 +00:00
btnsizer - > AddStretchSpacer ( ) ;
btnsizer - > Add ( btn_close ) ;
topsizer - > Add ( job_list , 1 , wxEXPAND | wxBOTTOM , SPACING ) ;
topsizer - > Add ( btnsizer , 0 , wxEXPAND ) ;
SetSizer ( topsizer ) ;
2018-12-20 10:50:08 +00:00
2020-09-15 13:23:39 +00:00
SetSize ( wxSize ( HEIGHT * em , WIDTH * em ) ) ;
2018-12-20 10:50:08 +00:00
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
2018-12-20 12:36:49 +00:00
GUI : : wxGetApp ( ) . printhost_job_queue ( ) . cancel ( selected ) ;
2018-12-20 10:50:08 +00:00
}
} ) ;
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 ) ) ;
} ) ;
2018-12-14 14:27:34 +00:00
}
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 ) ) ;
2020-10-28 08:51:05 +00:00
fields . push_back ( wxVariant ( _L ( " Enqueued " ) ) ) ;
2018-12-14 14:27:34 +00:00
fields . push_back ( wxVariant ( job . printhost - > get_host ( ) ) ) ;
fields . push_back ( wxVariant ( job . upload_data . upload_path . string ( ) ) ) ;
2018-12-20 10:50:08 +00:00
fields . push_back ( wxVariant ( " " ) ) ;
job_list - > AppendItem ( fields , static_cast < wxUIntPtr > ( ST_NEW ) ) ;
2020-12-12 10:26:17 +00:00
// Both strings are UTF-8 encoded.
2020-12-10 09:58:40 +00:00
upload_names . emplace_back ( job . printhost - > get_host ( ) , job . upload_data . upload_path . string ( ) ) ;
2018-12-20 10:50:08 +00:00
}
2019-04-25 13:06:44 +00:00
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 ( ) ;
}
2018-12-20 10:50:08 +00:00
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 ) ) ;
2018-12-20 12:36:49 +00:00
switch ( state ) {
2020-10-28 08:51:05 +00:00
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 ;
2018-12-20 12:36:49 +00:00
}
2018-12-20 10:50:08 +00:00
}
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 ( ) ;
}
2018-12-11 09:33:11 +00:00
}
2018-12-14 14:27:34 +00:00
void PrintHostQueueDialog : : on_progress ( Event & evt )
{
2019-09-06 12:48:31 +00:00
wxCHECK_RET ( evt . job_id < ( size_t ) job_list - > GetItemCount ( ) , " Out of bounds access to job list " ) ;
2018-12-14 14:27:34 +00:00
2018-12-20 10:50:08 +00:00
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 ( ) ;
2018-12-14 14:27:34 +00:00
}
void PrintHostQueueDialog : : on_error ( Event & evt )
{
2019-09-06 12:48:31 +00:00
wxCHECK_RET ( evt . job_id < ( size_t ) job_list - > GetItemCount ( ) , " Out of bounds access to job list " ) ;
2018-12-14 14:27:34 +00:00
2018-12-20 10:50:08 +00:00
set_state ( evt . job_id , ST_ERROR ) ;
2018-12-19 17:43:03 +00:00
2020-03-02 11:46:40 +00:00
auto errormsg = from_u8 ( ( boost : : format ( " %1% \n %2% " ) % _utf8 ( L ( " Error uploading to print host: " ) ) % std : : string ( evt . error . ToUTF8 ( ) ) ) . str ( ) ) ;
2018-12-20 10:50:08 +00:00
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 ( ) ;
2020-02-21 12:38:06 +00:00
GUI : : show_error ( nullptr , errormsg ) ;
2018-12-14 14:27:34 +00:00
}
2018-12-20 12:36:49 +00:00
void PrintHostQueueDialog : : on_cancel ( Event & evt )
{
2019-09-06 12:48:31 +00:00
wxCHECK_RET ( evt . job_id < ( size_t ) job_list - > GetItemCount ( ) , " Out of bounds access to job list " ) ;
2018-12-20 12:36:49 +00:00
set_state ( evt . job_id , ST_CANCELLED ) ;
job_list - > SetValue ( wxVariant ( 0 ) , evt . job_id , COL_PROGRESS ) ;
on_list_select ( ) ;
}
2020-12-10 09:58:40 +00:00
void PrintHostQueueDialog : : get_active_jobs ( std : : vector < std : : pair < std : : string , std : : string > > & ret )
{
int ic = job_list - > GetItemCount ( ) ;
2021-01-14 12:00:03 +00:00
for ( int i = 0 ; i < ic ; i + + )
2020-12-10 09:58:40 +00:00
{
auto item = job_list - > RowToItem ( i ) ;
auto data = job_list - > GetItemData ( item ) ;
JobState st = static_cast < JobState > ( data ) ;
if ( st = = JobState : : ST_NEW | | st = = JobState : : ST_PROGRESS )
ret . emplace_back ( upload_names [ i ] ) ;
}
//job_list->data
}
2018-12-14 14:27:34 +00:00
} }