First draft of SendSystemInfoDialog

This commit is contained in:
Lukas Matena 2021-08-11 12:03:44 +02:00
parent 37219fe4f3
commit faa808b385
8 changed files with 401 additions and 19 deletions

View File

@ -105,4 +105,42 @@ PlatformFlavor platform_flavor()
return s_platform_flavor; return s_platform_flavor;
} }
std::string platform_to_string(Platform platform)
{
switch (platform) {
case Platform::Uninitialized: return "Unitialized";
case Platform::Unknown : return "Unknown";
case Platform::Windows : return "Windows";
case Platform::OSX : return "OSX";
case Platform::Linux : return "Linux";
case Platform::BSDUnix : return "BSDUnix";
}
assert(false);
return "";
}
std::string platform_flavor_to_string(PlatformFlavor pf)
{
switch (pf) {
case PlatformFlavor::Uninitialized : return "Unitialized";
case PlatformFlavor::Unknown : return "Unknown";
case PlatformFlavor::Generic : return "Generic";
case PlatformFlavor::GenericLinux : return "GenericLinux";
case PlatformFlavor::LinuxOnChromium : return "LinuxOnChromium";
case PlatformFlavor::WSL : return "WSL";
case PlatformFlavor::WSL2 : return "WSL2";
case PlatformFlavor::OpenBSD : return "OpenBSD";
case PlatformFlavor::GenericOSX : return "GenericOSX";
case PlatformFlavor::OSXOnX86 : return "OSXOnX86";
case PlatformFlavor::OSXOnArm : return "OSXOnArm";
}
assert(false);
return "";
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -1,6 +1,8 @@
#ifndef SLIC3R_Platform_HPP #ifndef SLIC3R_Platform_HPP
#define SLIC3R_Platform_HPP #define SLIC3R_Platform_HPP
#include <string>
namespace Slic3r { namespace Slic3r {
enum class Platform enum class Platform
@ -16,24 +18,16 @@ enum class Platform
enum class PlatformFlavor enum class PlatformFlavor
{ {
Uninitialized, Uninitialized,
Unknown, Unknown,
// For Windows and OSX, until we need to be more specific. Generic, // For Windows and OSX, until we need to be more specific.
Generic, GenericLinux, // For Platform::Linux
// For Platform::Linux LinuxOnChromium, // For Platform::Linux
GenericLinux, WSL, // Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel)
LinuxOnChromium, WSL2, // Microsoft's Windows on Linux, version 2 (virtual machine)
// Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel) OpenBSD, // For Platform::BSDUnix
WSL, GenericOSX, // For Platform::OSX
// Microsoft's Windows on Linux, version 2 (virtual machine) OSXOnX86, // For Apple's on Intel X86 CPU
WSL2, OSXOnArm, // For Apple's on Arm CPU
// For Platform::BSDUnix
OpenBSD,
// For Platform::OSX
GenericOSX,
// For Apple's on Intel X86 CPU
OSXOnX86,
// For Apple's on Arm CPU
OSXOnArm,
}; };
// To be called on program start-up. // To be called on program start-up.
@ -42,6 +36,9 @@ void detect_platform();
Platform platform(); Platform platform();
PlatformFlavor platform_flavor(); PlatformFlavor platform_flavor();
std::string platform_to_string(Platform platform);
std::string platform_flavor_to_string(PlatformFlavor pf);
} // namespace Slic3r } // namespace Slic3r
#endif // SLIC3R_Platform_HPP #endif // SLIC3R_Platform_HPP

View File

@ -141,6 +141,8 @@ set(SLIC3R_GUI_SOURCES
GUI/RammingChart.hpp GUI/RammingChart.hpp
GUI/RemovableDriveManager.cpp GUI/RemovableDriveManager.cpp
GUI/RemovableDriveManager.hpp GUI/RemovableDriveManager.hpp
GUI/SendSystemInfoDialog.cpp
GUI/SendSystemInfoDialog.hpp
GUI/BonjourDialog.cpp GUI/BonjourDialog.cpp
GUI/BonjourDialog.hpp GUI/BonjourDialog.hpp
GUI/ButtonsDescription.cpp GUI/ButtonsDescription.cpp

View File

@ -70,6 +70,7 @@
#include "SavePresetDialog.hpp" #include "SavePresetDialog.hpp"
#include "PrintHostDialogs.hpp" #include "PrintHostDialogs.hpp"
#include "DesktopIntegrationDialog.hpp" #include "DesktopIntegrationDialog.hpp"
#include "SendSystemInfoDialog.hpp"
#include "BitmapCache.hpp" #include "BitmapCache.hpp"
#include "Notebook.hpp" #include "Notebook.hpp"
@ -668,6 +669,9 @@ void GUI_App::post_init()
if (app_config->get("show_hints") == "1" && ! is_gcode_viewer()) if (app_config->get("show_hints") == "1" && ! is_gcode_viewer())
plater_->get_notification_manager()->push_hint_notification(true); plater_->get_notification_manager()->push_hint_notification(true);
// 'Send system info' dialog
show_send_system_info_dialog_if_needed();
// The extra CallAfter() is needed because of Mac, where this is the only way // The extra CallAfter() is needed because of Mac, where this is the only way
// to popup a modal dialog on start without screwing combo boxes. // to popup a modal dialog on start without screwing combo boxes.
// This is ugly but I honestly found no better way to do it. // This is ugly but I honestly found no better way to do it.

View File

@ -27,7 +27,7 @@ namespace Slic3r {
namespace GUI { namespace GUI {
// A safe wrapper around glGetString to report a "N/A" string in case glGetString returns nullptr. // A safe wrapper around glGetString to report a "N/A" string in case glGetString returns nullptr.
inline std::string gl_get_string_safe(GLenum param, const std::string& default_value) std::string gl_get_string_safe(GLenum param, const std::string& default_value)
{ {
const char* value = (const char*)::glGetString(param); const char* value = (const char*)::glGetString(param);
return std::string((value != nullptr) ? value : default_value); return std::string((value != nullptr) ? value : default_value);

View File

@ -10,6 +10,7 @@ class wxGLContext;
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
class OpenGLManager class OpenGLManager
{ {
public: public:

View File

@ -0,0 +1,301 @@
#include "SendSystemInfoDialog.hpp"
#include "libslic3r/AppConfig.hpp"
#include "libslic3r/Platform.hpp"
#include "libslic3r/Utils.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/Utils/Http.hpp"
#include "GUI_App.hpp"
#include "I18N.hpp"
#include "MainFrame.hpp"
#include "OpenGLManager.hpp"
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string/split.hpp>
#include "GL/glew.h"
#include <wx/stattext.h>
#include <wx/utils.h>
namespace Slic3r {
namespace GUI {
// Declaration of a free function defined in OpenGLManager.cpp:
std::string gl_get_string_safe(GLenum param, const std::string& default_value);
// Read a string formatted as SLIC3R_VERSION (e.g. "2.4.0-alpha1") and get major and
// minor versions and alpha/beta flags.
static void extract_major_minor(std::string version,
int& major, int& minor,
bool* is_alpha = nullptr, bool* is_beta = nullptr)
{
if (is_alpha)
*is_alpha = version.find("alpha") != std::string::npos;
if (is_beta)
*is_beta = version.find("beta") != std::string::npos;
if (std::count(version.begin(), version.end(), '.') != 2)
return;
std::replace(version.begin(), version.end(), '.', ' ');
std::istringstream ss{version};
ss >> major >> minor;
}
// Last version where the info was sent / dialog dismissed is saved in appconfig.
// Only show the dialog when this info is not found (e.g. fresh install) or when
// current version is newer. Only major and minor versions are compared.
static bool should_dialog_be_shown()
{
std::string last_sent_version = wxGetApp().app_config->get("system_info_sent_version");
int last_sent_major = 0;
int last_sent_minor = 0;
int current_major = 0;
int current_minor = 0;
bool alpha = false;
bool beta = false;
extract_major_minor(SLIC3R_VERSION, current_major, current_minor, &alpha, &beta);
extract_major_minor(last_sent_version, last_sent_major, last_sent_minor);
if (current_major == 0 // This should never happen.
/*|| alpha
|| beta*/)
return false;
return ((current_major > last_sent_major)
|| (current_major == last_sent_major && current_minor > last_sent_minor ));
}
static void send_info(const std::string& data)
{
std::cout << data << std::endl;
}
// Following function saves current PrusaSlicer version into app config.
// It will be later used to decide whether to open the dialog or not.
static void save_version()
{
wxGetApp().app_config->set("system_info_sent_version", SLIC3R_VERSION);
}
// Following function generates one string that will be shown in the preview
// and later sent if confirmed by the user.
static std::string generate_system_info_json()
{
// Calculate hash of datadir path so it is possible to identify duplicates.
// The result is mod 10000 so most of the information is lost and it is
// not possible to unhash the datadir (which usually contains username).
// It is more than enough to help identify duplicate entries.
size_t datadir_hash = std::hash<std::string>{}(std::string(wxGetUserId().ToUTF8().data())) % 10000;
// Get system language.
std::string sys_language = "Unknown";
const wxLanguage lang_system = wxLanguage(wxLocale::GetSystemLanguage());
if (lang_system != wxLANGUAGE_UNKNOWN)
sys_language = wxLocale::GetLanguageInfo(lang_system)->CanonicalName.ToUTF8().data();
// Build a property tree with all the information.
namespace pt = boost::property_tree;
pt::ptree root;
root.put("PrusaSlicerVersion", SLIC3R_VERSION);
root.put("BuildID", SLIC3R_BUILD_ID);
root.put("UsernameHash", datadir_hash);
root.put("Platform", platform_to_string(platform()));
root.put("PlatformFlavor", platform_flavor_to_string(platform_flavor()));
root.put("SystemLanguage", sys_language);
root.put("TranslationLanguage: ", wxGetApp().app_config->get("translation_language"));
pt::ptree hw_node;
hw_node.put("ArchName", wxPlatformInfo::Get().GetArchName());
hw_node.put("RAM_MB", size_t(Slic3r::total_physical_memory()/1000000));
root.add_child("Hardware", hw_node);
pt::ptree opengl_node;
opengl_node.put("Version", OpenGLManager::get_gl_info().get_version());
opengl_node.put("GLSLVersion", OpenGLManager::get_gl_info().get_glsl_version());
opengl_node.put("Vendor", OpenGLManager::get_gl_info().get_vendor());
opengl_node.put("Renderer", OpenGLManager::get_gl_info().get_renderer());
// Generate list of OpenGL extensions:
std::string extensions_str = gl_get_string_safe(GL_EXTENSIONS, "");
std::vector<std::string> extensions_list;
boost::split(extensions_list, extensions_str, boost::is_any_of(" "), boost::token_compress_off);
pt::ptree extensions_node;
for (const std::string& s : extensions_list) {
if (s.empty())
continue;
pt::ptree ext_node; // Create an unnamed node containing the value
ext_node.put("", s);
extensions_node.push_back(std::make_pair("", ext_node)); // Add this node to the list.
}
opengl_node.add_child("Extensions", extensions_node);
root.add_child("OpenGL", opengl_node);
// Serialize the tree into JSON and return it.
std::stringstream ss;
pt::write_json(ss, root);
return ss.str();
//std::cout << wxPlatformInfo::Get().GetOperatingSystemFamilyName() << std::endl; // Unix
//std::cout << wxPlatformInfo::Get().GetOperatingSystemDescription() << std::endl; // Linux 4.15.0-142-generic x86_64
// ? CPU, GPU, UNKNOWN, wxWidgets ???
// tiskárny? budou už nainstalované?
}
SendSystemInfoDialog::SendSystemInfoDialog(wxWindow* parent)
: m_system_info_json{generate_system_info_json()},
GUI::DPIDialog(parent, wxID_ANY, _L("Send system info"), wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{
int version_major = 0;
int version_minor = 0;
bool is_alpha = false;
bool is_beta = false;
extract_major_minor(SLIC3R_VERSION, version_major, version_minor, &is_alpha, &is_beta);
std::string app_name = std::string(SLIC3R_APP_NAME) + " " + std::to_string(version_major)
+ "." + std::to_string(version_minor) + " "
+ (is_alpha ? "Alpha" : is_beta ? "Beta" : "");
const int em = GUI::wxGetApp().em_unit();
m_min_width = MIN_WIDTH * em;
m_min_height = MIN_HEIGHT * em;
const wxFont& mono_font = GUI::wxGetApp().code_font();
auto *panel = new wxPanel(this);
auto *vsizer = new wxBoxSizer(wxVERTICAL);
panel->SetSizer(vsizer);
/*auto *topsizer = new wxBoxSizer(wxVERTICAL);
topsizer->Add(panel, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
SetMinSize(wxSize(m_min_width, m_min_height));
SetSizerAndFit(topsizer);
*/
std::string filename(__FILE__);
size_t last_slash_idx = filename.find_last_of("/");
if (last_slash_idx != std::string::npos)
filename = filename.substr(last_slash_idx+1);
auto* text = new wxStaticText(panel, wxID_ANY, wxEmptyString);
text->SetLabelMarkup(
GUI::format_wxstr(_L("This is the first time you are running %1%. We would like to "
"ask you to send some of your system information to us. This will only "
"happen once and we will not ask you to do this again (only after you "
"upgrade to the next version)."), app_name )
+ "\n\n"
+ "<b>" + _L("Why is it needed") + "</b>"
+ "\n"
+ _L("If we know your hardware, operating system, etc., it will greatly help us "
"in development, prioritization and possible deprecation of features that "
"are no more needed (for example legacy OpenGL support). This will help "
"us to focus our effort more efficiently and spend time on features that "
"are needed the most.")
+ "\n\n"
+ "<b>" + _L("Is it safe?") + "</b>\n"
+ GUI::format_wxstr(
_L("We do not send any personal information nor anything that would allow us "
"to identify you later. To detect duplicate entries, a number derived "
"from your username is sent, but it cannot be used to recover the username. "
"Apart from that, only general data about your OS, hardware and OpenGL "
"installation are sent. PrusaSlicer is open source, if you want to "
"inspect the code actually performing the communication, see %1%."),
std::string("<i>") + filename + "</i>")
+ "\n\n"
+ "<b>" + _L("Verbatim data that will be sent:") + "</b>");
vsizer->Add(text, 1, wxEXPAND);
auto* txt_json = new wxTextCtrl(panel, wxID_ANY, m_system_info_json,
wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
txt_json->SetFont(mono_font);
txt_json->ShowPosition(0);
vsizer->Add(txt_json, 0, wxEXPAND, SPACING);
auto* ask_later_button = new wxButton(panel, wxID_ANY, _L("Ask me next time"));
auto* dont_send_button = new wxButton(panel, wxID_ANY, _L("Do not send anything"));
auto* send_button = new wxButton(panel, wxID_ANY, _L("Send system info"));
auto* hsizer = new wxBoxSizer(wxHORIZONTAL);
hsizer->Add(ask_later_button);
hsizer->AddSpacer(em);
hsizer->Add(dont_send_button);
hsizer->AddSpacer(em);
hsizer->Add(send_button);
vsizer->Add(hsizer, 0, wxALIGN_CENTER_HORIZONTAL, 10);
const auto size = GetSize();
SetSize(std::max(size.GetWidth(), m_min_width),
std::max(size.GetHeight(), m_min_height));
Layout();
send_button->Bind(wxEVT_BUTTON, [this](const wxEvent&)
{
send_info(m_system_info_json);
save_version();
EndModal(0);
});
dont_send_button->Bind(wxEVT_BUTTON, [this](const wxEvent&)
{
save_version();
EndModal(0);
});
ask_later_button->Bind(wxEVT_BUTTON, [this](const wxEvent&) { EndModal(0); });
}
void SendSystemInfoDialog::on_dpi_changed(const wxRect&)
{
/*const int& em = em_unit();
msw_buttons_rescale(this, em, { p->btn_close->GetId(),
p->btn_rescan->GetId(),
p->btn_flash->GetId(),
p->hex_picker->GetPickerCtrl()->GetId()
});
p->min_width = MIN_WIDTH * em;
p->min_height = MIN_HEIGHT * em;
p->min_height_expanded = MIN_HEIGHT_EXPANDED * em;
const int min_height = p->spoiler->IsExpanded() ? p->min_height_expanded : p->min_height;
SetMinSize(wxSize(p->min_width, min_height));
Fit();
Refresh();*/
}
void show_send_system_info_dialog_if_needed()
{
if (wxGetApp().is_gcode_viewer() || ! should_dialog_be_shown())
return;
SendSystemInfoDialog dlg(wxGetApp().mainframe);
dlg.ShowModal();
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,39 @@
#ifndef slic3r_SendSystemInfoDialog_hpp_
#define slic3r_SendSystemInfoDialog_hpp_
#include "GUI_Utils.hpp"
#include <string>
namespace Slic3r {
namespace GUI {
class SendSystemInfoDialog : public DPIDialog
{
enum {
DIALOG_MARGIN = 15,
SPACING = 10,
MIN_WIDTH = 60,
MIN_HEIGHT = 40,
MIN_HEIGHT_EXPANDED = 40,
};
public:
SendSystemInfoDialog(wxWindow* parent);
private:
const std::string m_system_info_json;
int m_min_width;
int m_min_height;
void on_dpi_changed(const wxRect&) override;
};
void show_send_system_info_dialog_if_needed();
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_SendSystemInfoDialog_hpp_