2023-12-27 18:02:35 +08:00
# include "WifiConfigDialog.hpp"
# include "GUI_App.hpp"
# include "GUI.hpp"
# include "I18N.hpp"
# include "format.hpp"
# include "RemovableDriveManager.hpp"
# include "MsgDialog.hpp"
# include <wx/stattext.h>
# include <wx/button.h>
# include <boost/nowide/convert.hpp>
# include <boost/nowide/fstream.hpp>
# include <boost/log/trivial.hpp>
# include <boost/filesystem.hpp>
# include <boost/property_tree/ini_parser.hpp>
# include "Widgets/ComboBox.hpp"
namespace Slic3r {
namespace GUI {
const char * WIFI_CONFIGFILE_NAME = " prusa_printer_settings.ini " ;
WifiConfigDialog : : WifiConfigDialog ( wxWindow * parent , std : : string & file_path , RemovableDriveManager * removable_manager , const wxString & preffered_drive )
// TRN: This is the dialog title.
: DPIDialog ( parent , wxID_ANY , _L ( " Wi-Fi Configuration File Generator " ) , wxDefaultPosition , wxDefaultSize , wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
, m_wifi_scanner ( new WifiScanner ( ) )
, out_file_path ( file_path )
, m_removable_manager ( removable_manager )
{
wxPanel * panel = new wxPanel ( this ) ;
wxBoxSizer * vsizer = new wxBoxSizer ( wxVERTICAL ) ;
panel - > SetSizer ( vsizer ) ;
// TRN Wifi config dialog explanation line 1.
2023-12-29 16:52:37 +08:00
wxStaticText * explain_label1 = new wxStaticText ( panel , wxID_ANY , _L ( " Generate a file to be loaded by a printer to configure its Wi-Fi connection. " ) ) ;
2023-12-27 18:02:35 +08:00
// TRN Wifi config dialog explanation line 2.
wxStaticText * explain_label2 = new wxStaticText ( panel , wxID_ANY , GUI : : format_wxstr ( _L ( " Write this file on the USB flash drive. Its name will be %1%. " ) , WIFI_CONFIGFILE_NAME ) ) ;
// TRN Wifi config dialog explanation line 3.
2023-12-29 16:52:37 +08:00
wxStaticText * explain_label3 = new wxStaticText ( panel , wxID_ANY , _L ( " Your printer should load this file automatically. " ) ) ;
2023-12-27 18:02:35 +08:00
// TRN Wifi config dialog explanation line 4.
wxStaticText * explain_label4 = new wxStaticText ( panel , wxID_ANY , _L ( " Note: This file will contain the SSID and password in plain text. " ) ) ;
auto * ssid_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
// TRN SSID of WiFi network. It is a standard abbreviation which should probably not change in most languages.
wxStaticText * ssid_label = new wxStaticText ( panel , wxID_ANY , GUI : : format_wxstr ( " %1%: " , _L ( " SSID " ) ) ) ;
m_ssid_combo = new : : ComboBox ( panel , wxID_ANY , wxString ( " " ) , wxDefaultPosition , wxDefaultSize , 0 , nullptr , DD_NO_CHECK_ICON ) ;
# if __APPLE__
m_ssid_combo - > SetToolTip ( _L ( " On some versions of MacOS, this only loads SSID of connected network. " ) ) ;
# endif // __APPLE__
rescan_networks ( false ) ;
m_ssid_button_id = NewControlId ( ) ;
// TRN Text of button to rescan visible networks in Wifi Config dialog.
wxButton * ssid_button = new wxButton ( panel , m_ssid_button_id , _ ( L ( " Rescan " ) ) ) ;
ssid_sizer - > Add ( m_ssid_combo , 1 , wxALIGN_CENTER_VERTICAL | wxRIGHT , 10 ) ;
ssid_sizer - > Add ( ssid_button , 0 ) ;
auto * pass_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
// TRN Password of WiFi network.
wxStaticText * password_label = new wxStaticText ( panel , wxID_ANY , GUI : : format_wxstr ( " %1%: " , _L ( " Password " ) ) ) ;
m_pass_textctrl = new : : TextInput ( panel , " " , " " , " " , wxDefaultPosition , wxDefaultSize ) ;
# if __APPLE__
pass_sizer - > Add ( m_pass_textctrl , 1 , wxALIGN_CENTER_VERTICAL | wxRIGHT , 10 ) ;
m_pass_button_id = NewControlId ( ) ;
// TRN Text of button to retrieve password from keychain in Wifi Config dialog. Only on Mac.
wxButton * pass_button = new wxButton ( panel , m_pass_button_id , _ ( L ( " Retrieve " ) ) ) ;
pass_sizer - > Add ( pass_button , 0 ) ;
pass_button - > Bind ( wxEVT_BUTTON , & WifiConfigDialog : : on_retrieve_password , this ) ;
# else
pass_sizer - > Add ( m_pass_textctrl , 1 , wxALIGN_CENTER_VERTICAL , 10 ) ;
# endif // __APPLE__
// show password if current ssid was selected already
fill_password ( ) ;
auto * drive_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
// TRN description of Combo Box with path to USB drive.
wxStaticText * drive_label = new wxStaticText ( panel , wxID_ANY , GUI : : format_wxstr ( " %1%: " , _L ( " Drive " ) ) ) ;
m_drive_combo = new : : ComboBox ( panel , wxID_ANY , wxString ( " " ) , wxDefaultPosition , wxDefaultSize , 0 , nullptr , DD_NO_CHECK_ICON ) ;
rescan_drives ( preffered_drive ) ;
m_drive_button_id = NewControlId ( ) ;
// TRN Text of button to rescan connect usb drives in Wifi Config dialog.
wxButton * drive_button = new wxButton ( panel , m_drive_button_id , _ ( L ( " Rescan " ) ) ) ;
drive_sizer - > Add ( m_drive_combo , 1 , wxALIGN_CENTER_VERTICAL | wxRIGHT , 10 ) ;
drive_sizer - > Add ( drive_button , 0 ) ;
// TRN Text of button to write config file in Wifi Config dialog.
wxButton * ok_button = new wxButton ( panel , wxID_OK , _L ( " Write " ) ) ;
wxButton * cancel_button = new wxButton ( panel , wxID_CANCEL ) ;
auto * grid = new wxFlexGridSizer ( 2 , 15 , 15 ) ;
grid - > AddGrowableCol ( 1 ) ;
grid - > Add ( ssid_label , 0 , wxALIGN_CENTER_VERTICAL ) ;
grid - > Add ( ssid_sizer , 0 , wxEXPAND ) ;
grid - > Add ( password_label , 0 , wxALIGN_CENTER_VERTICAL ) ;
grid - > Add ( pass_sizer , 0 , wxEXPAND ) ;
grid - > Add ( drive_label , 0 , wxALIGN_CENTER_VERTICAL ) ;
grid - > Add ( drive_sizer , 0 , wxEXPAND ) ;
vsizer - > Add ( explain_label1 , 0 , wxALIGN_CENTER_VERTICAL ) ;
vsizer - > Add ( explain_label2 , 0 , wxALIGN_CENTER_VERTICAL ) ;
vsizer - > Add ( explain_label3 , 0 , wxALIGN_CENTER_VERTICAL ) ;
vsizer - > Add ( explain_label4 , 0 , wxALIGN_CENTER_VERTICAL ) ;
vsizer - > Add ( grid , 0 , wxEXPAND | wxTOP | wxBOTTOM , 15 ) ;
wxBoxSizer * buttons_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
buttons_sizer - > Add ( ok_button , 1 , wxLEFT ) ;
buttons_sizer - > AddStretchSpacer ( ) ;
buttons_sizer - > Add ( cancel_button , 1 , wxRIGHT ) ;
vsizer - > Add ( buttons_sizer , 0 , wxEXPAND ) ;
wxBoxSizer * topsizer = new wxBoxSizer ( wxVERTICAL ) ;
topsizer - > Add ( panel , 1 , wxEXPAND | wxALL , 15 ) ;
SetSizerAndFit ( topsizer ) ;
ok_button - > Bind ( wxEVT_BUTTON , & WifiConfigDialog : : on_ok , this ) ;
m_ssid_combo - > Bind ( wxEVT_TEXT , & WifiConfigDialog : : on_combo , this ) ;
drive_button - > Bind ( wxEVT_BUTTON , & WifiConfigDialog : : on_rescan_drives , this ) ;
ssid_button - > Bind ( wxEVT_BUTTON , & WifiConfigDialog : : on_rescan_networks , this ) ;
wxGetApp ( ) . UpdateDlgDarkUI ( this ) ;
}
WifiConfigDialog : : ~ WifiConfigDialog ( )
{
if ( m_wifi_scanner )
delete m_wifi_scanner ;
}
void WifiConfigDialog : : on_combo ( wxCommandEvent & e )
{
fill_password ( ) ;
}
void WifiConfigDialog : : fill_password ( )
{
assert ( m_ssid_combo & & m_pass_textctrl & & m_wifi_scanner ) ;
if ( auto it = m_wifi_scanner - > get_map ( ) . find ( m_ssid_combo - > GetValue ( ) ) ; it ! = m_wifi_scanner - > get_map ( ) . end ( ) )
m_pass_textctrl - > SetValue ( boost : : nowide : : widen ( it - > second ) ) ;
}
void WifiConfigDialog : : on_retrieve_password ( wxCommandEvent & e )
{
if ( m_ssid_combo - > GetValue ( ) . empty ( ) ) {
return ;
}
std : : string psk = m_wifi_scanner - > get_psk ( boost : : nowide : : narrow ( m_ssid_combo - > GetValue ( ) ) ) ;
if ( psk . empty ( ) ) {
// TRN Alert message when retrieving password for wifi from keychain. Probably will display only on Apple so keychain is MacOS term.
wxString msg = _L ( " No password in the keychain for given SSID. " ) ;
show_info ( nullptr , msg ) ;
return ;
}
m_pass_textctrl - > SetValue ( boost : : nowide : : widen ( psk ) ) ;
}
void WifiConfigDialog : : on_rescan_drives ( wxCommandEvent & e )
{
rescan_drives ( { } ) ;
}
void WifiConfigDialog : : rescan_drives ( const wxString & preffered_drive )
{
assert ( m_drive_combo & & m_removable_manager ) ;
m_drive_combo - > Clear ( ) ;
std : : vector < DriveData > ddata = m_removable_manager - > get_drive_list ( ) ;
for ( const auto & data : ddata ) {
wxString item = boost : : nowide : : widen ( data . path ) ;
m_drive_combo - > Append ( item ) ;
if ( preffered_drive = = item )
m_ssid_combo - > Select ( m_ssid_combo - > GetCount ( ) - 1 ) ;
}
if ( m_drive_combo - > GetSelection ( ) = = - 1 & & m_drive_combo - > GetCount ( ) > 0 ) {
m_drive_combo - > Select ( 0 ) ;
}
}
void WifiConfigDialog : : on_rescan_networks ( wxCommandEvent & e )
{
rescan_networks ( true ) ;
}
void WifiConfigDialog : : rescan_networks ( bool select )
{
assert ( m_ssid_combo & & m_wifi_scanner ) ;
m_wifi_scanner - > scan ( ) ;
std : : string current = m_wifi_scanner - > get_current_ssid ( ) ;
const auto & map = m_wifi_scanner - > get_map ( ) ;
m_ssid_combo - > Clear ( ) ;
for ( const auto pair : map ) {
m_ssid_combo - > Append ( pair . first ) ;
// select ssid of current network (if connected)
if ( current = = pair . first )
m_ssid_combo - > Select ( m_ssid_combo - > GetCount ( ) - 1 ) ;
}
if ( m_ssid_combo - > GetSelection ( ) = = - 1 & & m_ssid_combo - > GetCount ( ) > 0 )
m_ssid_combo - > Select ( 0 ) ;
if ( select & & m_ssid_combo - > GetSelection ( ) ! = - 1 )
fill_password ( ) ;
}
void WifiConfigDialog : : on_ok ( wxCommandEvent & e )
{
assert ( m_ssid_combo & & m_pass_textctrl ) ;
if ( m_ssid_combo - > GetValue ( ) . empty ( ) ) {
// TRN Alert message when writing WiFi configuration file to usb drive.
wxString msg = _L ( " SSID field is empty. " ) ;
show_info ( nullptr , msg ) ;
return ;
}
std : : string selected_path = boost : : nowide : : narrow ( m_drive_combo - > GetValue ( ) ) ;
if ( selected_path . empty ( ) ) {
// TRN Alert message when writing WiFi configuration file to usb drive.
wxString msg = _L ( " Drive field is empty. " ) ;
show_info ( nullptr , msg ) ;
return ;
}
boost : : filesystem : : path file_path = boost : : filesystem : : path ( selected_path ) / WIFI_CONFIGFILE_NAME ;
bool path_on_removable_media = m_removable_manager - > set_and_verify_last_save_path ( file_path . string ( ) ) ;
if ( ! path_on_removable_media ) {
// TRN Alert message when writing WiFi configuration file to usb drive.
wxString msg = _L ( " Selected path is not on removable media. " ) ;
show_info ( nullptr , msg ) ;
return ;
}
if ( boost : : filesystem : : exists ( file_path ) ) {
// TRN placeholder 1 is path to file
wxString msg_text = GUI : : format_wxstr ( _L ( " %1% already exists. Do you want to rewrite it? \n (Other items than Wi-Fi credentials will stay unchanged) " ) , file_path . string ( ) ) ;
WarningDialog dialog ( m_parent , msg_text , _L ( " Warning " ) , wxYES | wxNO ) ;
if ( dialog . ShowModal ( ) = = wxID_NO ) {
return ;
}
}
std : : string data ;
namespace pt = boost : : property_tree ;
pt : : ptree tree ;
// File already exist and we only need to add data to it rather than rewrite it.
if ( boost : : filesystem : : exists ( file_path ) ) {
boost : : nowide : : ifstream ifs ( file_path . string ( ) ) ;
try {
pt : : read_ini ( ifs , tree ) ;
}
catch ( const boost : : property_tree : : ini_parser : : ini_parser_error & err ) {
throw Slic3r : : RuntimeError ( format ( " Failed loading ini file \" %1% \" \n Error: \" %2% \" at line %3% " , file_path , err . message ( ) , err . line ( ) ) . c_str ( ) ) ;
}
if ( auto sub = tree . get_optional < std : : string > ( " wifi " ) ; sub ) {
tree . erase ( " wifi " ) ;
}
}
pt : : ptree subtree ;
subtree . put ( " ssid " , m_ssid_combo - > GetValue ( ) . utf8_string ( ) ) ;
subtree . put ( " psk " , m_pass_textctrl - > GetValue ( ) . utf8_string ( ) ) ;
tree . add_child ( " wifi " , subtree ) ;
data . clear ( ) ;
// manually write ini string (so there is extra line between sections)
for ( const auto & section : tree ) {
data + = " [ " + section . first + " ] " + " \n " ;
for ( const auto & entry : section . second ) {
data + = entry . first + " = " + entry . second . get_value < std : : string > ( ) + " \n " ;
}
data + = " \n " ;
}
m_used_path = boost : : nowide : : widen ( file_path . string ( ) ) ;
FILE * file ;
file = fopen ( file_path . string ( ) . c_str ( ) , " w " ) ;
if ( file = = NULL ) {
BOOST_LOG_TRIVIAL ( error ) < < " Failed to write to file " < < file_path ;
// TODO show error
show_error ( nullptr , _L ( " Failed to open file for writing. " ) ) ;
return ;
}
fwrite ( data . c_str ( ) , 1 , data . size ( ) , file ) ;
fclose ( file ) ;
out_file_path = file_path . string ( ) ;
this - > EndModal ( wxID_OK ) ;
}
void WifiConfigDialog : : on_dpi_changed ( const wxRect & suggested_rect )
{
SetFont ( wxGetApp ( ) . normal_font ( ) ) ;
const int em = em_unit ( ) ;
msw_buttons_rescale ( this , em , { wxID_OK , wxID_CANCEL , m_ssid_button_id , m_pass_button_id , m_drive_button_id } ) ;
Fit ( ) ;
Refresh ( ) ;
}
} } // Slicer::GUI