mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-09-17 03:33:14 +08:00
WebView prototype
Web View has working panel with Connect webpage with Auth token login. Webview2 is used on windows. It uses small dll to find its runtime. WebViewDialog.cpp, WebViewDialog.hpp, WebView.cpp and WebView.hpp were taken from https://github.com/bambulab/BambuStudio and used as protype for future WebView Development. Thank you. Co-authored-by: cmguo <chunmao.guo@bambulab.com> Co-authored-by: lane.wei <lane.wei@bambulab.com>
This commit is contained in:
parent
adc650ef4e
commit
2276cedc10
@ -606,6 +606,13 @@ function(prusaslicer_copy_dlls target)
|
||||
COMMENT "Copy mpfr runtime to build tree"
|
||||
VERBATIM)
|
||||
|
||||
if(DEFINED DESTDIR)
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${DESTDIR}/usr/local/bin/WebView2Loader.dll ${_out_dir}
|
||||
COMMENT "Copy WebView2Loader runtime to build tree"
|
||||
VERBATIM)
|
||||
endif ()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
|
60
deps/+WebView2/WebView2.cmake
vendored
Normal file
60
deps/+WebView2/WebView2.cmake
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
if (MSVC)
|
||||
|
||||
# Update the following variables if updating WebView2 SDK
|
||||
set(WEBVIEW2_VERSION "1.0.705.50")
|
||||
set(WEBVIEW2_URL "https://www.nuget.org/api/v2/package/Microsoft.Web.WebView2/${WEBVIEW2_VERSION}")
|
||||
set(WEBVIEW2_SHA256 "6a34bb553e18cfac7297b4031f3eac2558e439f8d16a45945c22945ac404105d")
|
||||
|
||||
set(WEBVIEW2_DEFAULT_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/dep_WebView2-prefix/packages/Microsoft.Web.WebView2.${WEBVIEW2_VERSION}")
|
||||
set(WEBVIEW2_DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/dep_WebView2-prefix/download")
|
||||
|
||||
#message(STATUS "WEBVIEW2_DEFAULT_PACKAGE_DIR = ${WEBVIEW2_DEFAULT_PACKAGE_DIR}")
|
||||
|
||||
if(NOT EXISTS ${WEBVIEW2_PACKAGE_DIR})
|
||||
unset(WEBVIEW2_PACKAGE_DIR CACHE)
|
||||
endif()
|
||||
|
||||
set(WEBVIEW2_PACKAGE_DIR ${WEBVIEW2_DEFAULT_PACKAGE_DIR} CACHE PATH "WebView2 SDK PATH" FORCE)
|
||||
|
||||
#file(MAKE_DIRECTORY ${DEP_DOWNLOAD_DIR}/WebView2)
|
||||
|
||||
message(STATUS "WEBVIEW2_URL = ${WEBVIEW2_URL}")
|
||||
message(STATUS "WEBVIEW2_DOWNLOAD_DIR = ${WEBVIEW2_DOWNLOAD_DIR}")
|
||||
file(DOWNLOAD
|
||||
${WEBVIEW2_URL}
|
||||
${WEBVIEW2_DOWNLOAD_DIR}/WebView2.nuget
|
||||
EXPECTED_HASH SHA256=${WEBVIEW2_SHA256})
|
||||
|
||||
file(MAKE_DIRECTORY ${WEBVIEW2_PACKAGE_DIR})
|
||||
|
||||
execute_process(COMMAND
|
||||
${CMAKE_COMMAND} -E tar x ${WEBVIEW2_DOWNLOAD_DIR}/WebView2.nuget
|
||||
WORKING_DIRECTORY ${WEBVIEW2_PACKAGE_DIR}
|
||||
)
|
||||
|
||||
set(_srcdir ${WEBVIEW2_PACKAGE_DIR}/build/native)
|
||||
set(_dstdir ${DESTDIR}/usr/local)
|
||||
|
||||
set(_output ${_dstdir}/include/WebView2.h
|
||||
${_dstdir}/bin/WebView2Loader.dll)
|
||||
|
||||
if(NOT EXISTS ${_dstdir}/include)
|
||||
file(MAKE_DIRECTORY ${_dstdir}/include)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${_dstdir}/bin)
|
||||
file(MAKE_DIRECTORY ${_dstdir}/bin)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${_output}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${_srcdir}/include/WebView2.h ${_dstdir}/include/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${_srcdir}/x${DEPS_BITS}/WebView2Loader.dll ${_dstdir}/bin/
|
||||
)
|
||||
|
||||
add_custom_target(dep_WebView2 SOURCES ${_output})
|
||||
|
||||
set(WEBVIEW2_PACKAGE_DIR ${WEBVIEW2_PACKAGE_DIR} CACHE INTERNAL "" FORCE)
|
||||
|
||||
endif ()
|
16
deps/+wxWidgets/wxWidgets.cmake
vendored
16
deps/+wxWidgets/wxWidgets.cmake
vendored
@ -14,6 +14,18 @@ if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for
|
||||
set (_unicode_utf8 ON)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(_wx_webview "-DwxUSE_WEBVIEW_EDGE=ON")
|
||||
else ()
|
||||
set(_wx_webview "-DwxUSE_WEBVIEW=ON")
|
||||
endif ()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
set(_wx_secretstore "-DwxUSE_SECRETSTORE=OFF")
|
||||
else ()
|
||||
set(_wx_secretstore "-DwxUSE_SECRETSTORE=ON")
|
||||
endif ()
|
||||
|
||||
add_cmake_project(wxWidgets
|
||||
URL https://github.com/prusa3d/wxWidgets/archive/78aa2dc0ea7ce99dc19adc1140f74c3e2e3f3a26.zip
|
||||
URL_HASH SHA256=94b7d972373503e380e5a8b0ca63b1ccb956da4006402298dd89a0c5c7041b1e
|
||||
@ -21,7 +33,7 @@ add_cmake_project(wxWidgets
|
||||
"-DCMAKE_DEBUG_POSTFIX:STRING="
|
||||
-DwxBUILD_PRECOMP=ON
|
||||
${_wx_toolkit}
|
||||
-DwxUSE_MEDIACTRL=OFF
|
||||
-DwxUSE_MEDIACTRL=ON
|
||||
-DwxUSE_DETECT_SM=OFF
|
||||
-DwxUSE_UNICODE=ON
|
||||
-DwxUSE_UNICODE_UTF8=${_unicode_utf8}
|
||||
@ -39,6 +51,8 @@ add_cmake_project(wxWidgets
|
||||
-DwxUSE_XTEST=OFF
|
||||
-DwxUSE_GLCANVAS_EGL=OFF
|
||||
-DwxUSE_WEBREQUEST=OFF
|
||||
${_wx_webview}
|
||||
${_wx_secretstore}
|
||||
)
|
||||
|
||||
set(DEP_wxWidgets_DEPENDS ZLIB PNG EXPAT TIFF JPEG NanoSVG)
|
||||
|
5
deps/CMakeLists.txt
vendored
5
deps/CMakeLists.txt
vendored
@ -140,6 +140,11 @@ if (UNIX)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
list(APPEND REQUIRED_PACKAGES WebView2)
|
||||
endif()
|
||||
|
||||
|
||||
list(APPEND SYSTEM_PROVIDED_PACKAGES ${${PROJECT_NAME}_PLATFORM_PACKAGES})
|
||||
list(REMOVE_DUPLICATES SYSTEM_PROVIDED_PACKAGES)
|
||||
|
||||
|
47
deps/wxWidgets/wxWidgets.cmake
vendored
47
deps/wxWidgets/wxWidgets.cmake
vendored
@ -1,47 +0,0 @@
|
||||
set(_wx_toolkit "")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(_gtk_ver 2)
|
||||
if (DEP_WX_GTK3)
|
||||
set(_gtk_ver 3)
|
||||
endif ()
|
||||
set(_wx_toolkit "-DwxBUILD_TOOLKIT=gtk${_gtk_ver}")
|
||||
endif()
|
||||
|
||||
set(_unicode_utf8 OFF)
|
||||
if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for wxString unless its forced to.
|
||||
set (_unicode_utf8 ON)
|
||||
endif()
|
||||
|
||||
prusaslicer_add_cmake_project(wxWidgets
|
||||
URL https://github.com/prusa3d/wxWidgets/archive/78aa2dc0ea7ce99dc19adc1140f74c3e2e3f3a26.zip
|
||||
URL_HASH SHA256=94b7d972373503e380e5a8b0ca63b1ccb956da4006402298dd89a0c5c7041b1e
|
||||
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG dep_NanoSVG
|
||||
CMAKE_ARGS
|
||||
-DwxBUILD_PRECOMP=ON
|
||||
${_wx_toolkit}
|
||||
"-DCMAKE_DEBUG_POSTFIX:STRING="
|
||||
-DwxBUILD_DEBUG_LEVEL=0
|
||||
-DwxUSE_MEDIACTRL=OFF
|
||||
-DwxUSE_DETECT_SM=OFF
|
||||
-DwxUSE_UNICODE=ON
|
||||
-DwxUSE_UNICODE_UTF8=${_unicode_utf8}
|
||||
-DwxUSE_OPENGL=ON
|
||||
-DwxUSE_LIBPNG=sys
|
||||
-DwxUSE_ZLIB=sys
|
||||
-DwxUSE_NANOSVG=sys
|
||||
-DwxUSE_NANOSVG_EXTERNAL=ON
|
||||
-DwxUSE_REGEX=OFF
|
||||
-DwxUSE_LIBXPM=builtin
|
||||
-DwxUSE_LIBJPEG=sys
|
||||
-DwxUSE_LIBTIFF=sys
|
||||
-DwxUSE_EXPAT=sys
|
||||
-DwxUSE_LIBSDL=OFF
|
||||
-DwxUSE_XTEST=OFF
|
||||
-DwxUSE_GLCANVAS_EGL=OFF
|
||||
-DwxUSE_WEBREQUEST=OFF
|
||||
-DwxUSE_SECRETSTORE=ON
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
add_debug_dep(dep_wxWidgets)
|
||||
endif ()
|
@ -48,7 +48,7 @@ if (SLIC3R_GUI)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
||||
endif ()
|
||||
find_package(wxWidgets 3.2 MODULE REQUIRED COMPONENTS base core adv html gl)
|
||||
find_package(wxWidgets 3.2 MODULE REQUIRED COMPONENTS base core adv html gl webview media)
|
||||
|
||||
include(${wxWidgets_USE_FILE})
|
||||
|
||||
|
@ -125,6 +125,7 @@ public:
|
||||
TYPE_PHYSICAL_PRINTER,
|
||||
// This type is here to support search through the Preferences
|
||||
TYPE_PREFERENCES,
|
||||
TYPE_WEBVIEW,
|
||||
};
|
||||
|
||||
Type type = TYPE_INVALID;
|
||||
|
@ -23,6 +23,12 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Auth.hpp
|
||||
GUI/AuthSession.cpp
|
||||
GUI/AuthSession.hpp
|
||||
GUI/UserAccount.cpp
|
||||
GUI/UserAccount.hpp
|
||||
GUI/WebViewDialog.cpp
|
||||
GUI/WebViewDialog.hpp
|
||||
GUI/WebView.cpp
|
||||
GUI/WebView.hpp
|
||||
GUI/SysInfoDialog.cpp
|
||||
GUI/SysInfoDialog.hpp
|
||||
GUI/KBShortcutsDialog.cpp
|
||||
|
@ -2,12 +2,9 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "format.hpp"
|
||||
#include "../Utils/Http.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/beast/core/detail/base64.hpp>
|
||||
#include <curl/curl.h>
|
||||
#include <string>
|
||||
@ -29,6 +26,10 @@
|
||||
#include <wincrypt.h>
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
@ -38,7 +39,7 @@
|
||||
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@ -144,14 +145,13 @@ PrusaAuthCommunication::PrusaAuthCommunication(wxEvtHandler* evt_handler, AppCon
|
||||
refresh_token = app_config->get("refresh_token");
|
||||
shared_session_key = app_config->get("shared_session_key");
|
||||
}
|
||||
|
||||
if (!access_token.empty() || !refresh_token.empty())
|
||||
m_remember_session = true;
|
||||
m_session = std::make_unique<AuthSession>(evt_handler, access_token, refresh_token, shared_session_key);
|
||||
init_session_thread();
|
||||
// perform login at the start - do we want this
|
||||
if (m_remember_session)
|
||||
login();
|
||||
do_login();
|
||||
}
|
||||
|
||||
PrusaAuthCommunication::~PrusaAuthCommunication() {
|
||||
@ -182,7 +182,14 @@ void PrusaAuthCommunication::set_username(const std::string& username, AppConfig
|
||||
app_config->set("refresh_token", m_remember_session ? m_session->get_refresh_token() : std::string());
|
||||
app_config->set("shared_session_key", m_remember_session ? m_session->get_shared_session_key() : std::string());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrusaAuthCommunication::get_access_token()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_session_mutex);
|
||||
return m_session->get_access_token();
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,7 +212,7 @@ bool PrusaAuthCommunication::is_logged()
|
||||
{
|
||||
return !m_username.empty();
|
||||
}
|
||||
void PrusaAuthCommunication::login()
|
||||
void PrusaAuthCommunication::do_login()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_session_mutex);
|
||||
@ -217,7 +224,7 @@ void PrusaAuthCommunication::login()
|
||||
}
|
||||
wakeup_session_thread();
|
||||
}
|
||||
void PrusaAuthCommunication::logout()
|
||||
void PrusaAuthCommunication::do_logout()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_session_mutex);
|
||||
@ -301,78 +308,9 @@ void PrusaAuthCommunication::wakeup_session_thread()
|
||||
m_thread_stop_condition.notify_all();
|
||||
}
|
||||
|
||||
namespace {
|
||||
/*
|
||||
void proccess_tree(const pt::ptree& tree, const std::string depth, std::string& out)
|
||||
{
|
||||
|
||||
for (const auto& section : tree) {
|
||||
printf("%s%s", depth.c_str(), section.first.c_str());
|
||||
if (!section.second.data().empty()) {
|
||||
if (section.first == "printer_type_name") {
|
||||
out += section.second.data();
|
||||
out += " : ";
|
||||
} else if (section.first == "state") {
|
||||
out += section.second.data();
|
||||
out += "\n";
|
||||
}
|
||||
printf(" : %s\n", section.second.data().c_str());
|
||||
} else {
|
||||
printf("\n");
|
||||
proccess_tree(section.second, depth + " ", out);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
typedef std::map<std::string, int> ModelCounter;
|
||||
void proccess_tree(const pt::ptree& tree, const std::string depth, ModelCounter& models)
|
||||
{
|
||||
for (const auto& section : tree) {
|
||||
//printf("%s%s", depth.c_str(), section.first.c_str());
|
||||
if (!section.second.data().empty()) {
|
||||
//printf(" : %s\n", section.second.data().c_str());
|
||||
}
|
||||
else {
|
||||
if (section.first == "printer_type_compatible") {
|
||||
for (const auto& sub : section.second) {
|
||||
if (!sub.second.data().empty()) {
|
||||
//printf(" : %s\n", section.second.data().c_str());
|
||||
if(models.find(sub.second.data()) == models.end())
|
||||
models.emplace(sub.second.data(), 1);
|
||||
else
|
||||
models[sub.second.data()]++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//printf("\n");
|
||||
proccess_tree(section.second, depth + " ", models);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrusaAuthCommunication::proccess_prusaconnect_printers_message(const std::string& message)
|
||||
{
|
||||
std::string out;
|
||||
try {
|
||||
std::stringstream ss(message);
|
||||
pt::ptree ptree;
|
||||
pt::read_json(ss, ptree);
|
||||
|
||||
ModelCounter counter;
|
||||
proccess_tree(ptree, "", counter);
|
||||
for (const auto model : counter)
|
||||
{
|
||||
out += GUI::format("%1%x %2%\n", std::to_string(model.second), model.first);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string CodeChalengeGenerator::generate_chalenge(const std::string& verifier)
|
||||
{
|
||||
@ -458,8 +396,28 @@ std::string CodeChalengeGenerator::sha256(const std::string& input)
|
||||
}
|
||||
return output;
|
||||
}
|
||||
#endif // WIN32
|
||||
#ifdef __linux__
|
||||
#elif __APPLE__
|
||||
std::string CodeChalengeGenerator::sha256(const std::string& input) {
|
||||
// Initialize the context
|
||||
CC_SHA256_CTX sha256;
|
||||
CC_SHA256_Init(&sha256);
|
||||
|
||||
// Update the context with the input data
|
||||
CC_SHA256_Update(&sha256, input.c_str(), static_cast<CC_LONG>(input.length()));
|
||||
|
||||
// Finalize the hash and retrieve the result
|
||||
unsigned char digest[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256_Final(digest, &sha256);
|
||||
|
||||
// Convert the result to a string
|
||||
char hashString[CC_SHA256_DIGEST_LENGTH * 2 + 1];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||
sprintf(&hashString[i * 2], "%02x", digest[i]);
|
||||
}
|
||||
|
||||
return std::string(hashString);
|
||||
}
|
||||
#else
|
||||
std::string CodeChalengeGenerator::sha256(const std::string& input) {
|
||||
EVP_MD_CTX* mdctx;
|
||||
const EVP_MD* md;
|
||||
|
@ -34,14 +34,13 @@ public:
|
||||
// UI Session thread Interface
|
||||
//
|
||||
bool is_logged();
|
||||
void login();
|
||||
void logout();
|
||||
void do_login();
|
||||
void do_logout();
|
||||
// Trigger function starts various remote operations
|
||||
// Each user action is implemented in different UserAction class and stored in m_actions.
|
||||
void enqueue_user_id_action();
|
||||
void enqueue_connect_dummy_action();
|
||||
void enqueue_connect_printers_action();
|
||||
void set_remember_session(bool b) { m_remember_session = b; }
|
||||
|
||||
|
||||
// Callbacks - called from UI after receiving Event from Session thread. Some might use Session thread.
|
||||
//
|
||||
@ -51,13 +50,15 @@ public:
|
||||
|
||||
|
||||
void set_username(const std::string& username, AppConfig* app_config);
|
||||
void set_remember_session(bool b) { m_remember_session = b; }
|
||||
|
||||
std::string get_username() const { return m_username; }
|
||||
|
||||
std::string proccess_prusaconnect_printers_message(const std::string& message);
|
||||
std::string get_access_token();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
std::unique_ptr<AuthSession> m_session;
|
||||
std::unique_ptr<AuthSession> m_session;
|
||||
std::thread m_thread;
|
||||
std::mutex m_session_mutex;
|
||||
std::mutex m_thread_stop_mutex;
|
||||
@ -73,6 +74,9 @@ private:
|
||||
void init_session_thread();
|
||||
void login_redirect();
|
||||
std::string client_id() const { return "UfTRUm5QjWwaQEGpWQBHGHO3reAyuzgOdBaiqO52"; }
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +72,11 @@ void UserActionGetWithEvent::perform(const std::string& access_token, UserAction
|
||||
|
||||
void AuthSession::process_action_queue()
|
||||
{
|
||||
if (m_priority_action_queue.empty() && m_action_queue.empty())
|
||||
BOOST_LOG_TRIVIAL(debug) << "process_action_queue start";
|
||||
if (m_priority_action_queue.empty() && m_action_queue.empty()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "process_action_queue queues empty";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->is_initialized()) {
|
||||
// if priority queue already has some action f.e. to exchange tokens, the test should not be neccessary but also shouldn't be problem
|
||||
@ -86,18 +89,22 @@ void AuthSession::process_action_queue()
|
||||
m_priority_action_queue.pop();
|
||||
}
|
||||
|
||||
if (!this->is_initialized())
|
||||
if (!this->is_initialized()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "process_action_queue not initialized";
|
||||
return;
|
||||
}
|
||||
|
||||
while (!m_action_queue.empty()) {
|
||||
m_actions[m_action_queue.front().action_id]->perform(m_access_token, m_action_queue.front().success_callback, m_action_queue.front().fail_callback, m_action_queue.front().input);
|
||||
if (!m_action_queue.empty())
|
||||
m_action_queue.pop();
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(debug) << "process_action_queue end";
|
||||
}
|
||||
|
||||
void AuthSession::enqueue_action(UserActionID id, UserActionSuccessFn success_callback, UserActionFailFn fail_callback, const std::string& input)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "enqueue_action " << (int)id;
|
||||
m_action_queue.push({ id, success_callback, fail_callback, input });
|
||||
}
|
||||
|
||||
|
@ -103,8 +103,8 @@ public:
|
||||
m_actions[UserActionID::CODE_FOR_TOKEN] = std::make_unique<UserActionPost>("EXCHANGE_TOKENS", "https://test-account.prusa3d.com/o/token/");
|
||||
m_actions[UserActionID::TEST_CONNECTION] = std::make_unique<UserActionGetWithEvent>("TEST_CONNECTION", "https://test-account.prusa3d.com/api/v1/me/", evt_handler, EVT_PA_ID_USER_SUCCESS, EVT_PRUSAAUTH_FAIL);
|
||||
m_actions[UserActionID::USER_ID] = std::make_unique<UserActionGetWithEvent>("USER_ID", "https://test-account.prusa3d.com/api/v1/me/", evt_handler, EVT_PA_ID_USER_SUCCESS, EVT_PRUSAAUTH_FAIL);
|
||||
m_actions[UserActionID::CONNECT_DUMMY] = std::make_unique<UserActionGetWithEvent>("CONNECT_DUMMY", "dev.connect.prusa:8000/slicer/dummy", evt_handler, EVT_PRUSAAUTH_SUCCESS, EVT_PRUSAAUTH_FAIL);
|
||||
m_actions[UserActionID::CONNECT_PRINTERS] = std::make_unique<UserActionGetWithEvent>("CONNECT_PRINTERS", "dev.connect.prusa:8000/slicer/printers", evt_handler, EVT_PRUSACONNECT_PRINTERS_SUCCESS, EVT_PRUSAAUTH_FAIL);
|
||||
m_actions[UserActionID::CONNECT_DUMMY] = std::make_unique<UserActionGetWithEvent>("CONNECT_DUMMY", "https://dev.connect.prusa3d.com/slicer/dummy"/*"dev.connect.prusa:8000/slicer/dummy"*/, evt_handler, EVT_PRUSAAUTH_SUCCESS, EVT_PRUSAAUTH_FAIL);
|
||||
m_actions[UserActionID::CONNECT_PRINTERS] = std::make_unique<UserActionGetWithEvent>("CONNECT_PRINTERS", "https://dev.connect.prusa3d.com/slicer/printers"/*"dev.connect.prusa:8000/slicer/printers"*/, evt_handler, EVT_PRUSACONNECT_PRINTERS_SUCCESS, EVT_PRUSAAUTH_FAIL);
|
||||
}
|
||||
~AuthSession()
|
||||
{
|
||||
|
@ -1536,11 +1536,9 @@ bool PageDownloader::on_finish_downloader() const
|
||||
return m_downloader->on_finish();
|
||||
}
|
||||
|
||||
bool DownloaderUtils::Worker::perform_register(const std::string& path_override/* = {}*/)
|
||||
bool DownloaderUtils::Worker::perform_register(const std::string& path)
|
||||
{
|
||||
boost::filesystem::path aux_dest (GUI::into_u8(path_name()));
|
||||
if (!path_override.empty())
|
||||
aux_dest = boost::filesystem::path(path_override);
|
||||
boost::filesystem::path aux_dest (path);
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::path chosen_dest = boost::filesystem::absolute(aux_dest, ec);
|
||||
if(ec)
|
||||
@ -1549,7 +1547,7 @@ bool DownloaderUtils::Worker::perform_register(const std::string& path_override/
|
||||
if (chosen_dest.empty() || !boost::filesystem::is_directory(chosen_dest, ec) || ec) {
|
||||
std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not exist.") ,chosen_dest.string());
|
||||
BOOST_LOG_TRIVIAL(error) << err_msg;
|
||||
show_error(m_parent, err_msg);
|
||||
show_error(/*m_parent*/ nullptr, err_msg);
|
||||
return false;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Downloader registration: Directory for downloads: " << chosen_dest.string();
|
||||
@ -1613,12 +1611,12 @@ bool DownloaderUtils::Worker::on_finish() {
|
||||
BOOST_LOG_TRIVIAL(debug) << "PageDownloader::on_finish_downloader ac_value " << ac_value << " downloader_checked " << downloader_checked;
|
||||
if (ac_value && downloader_checked) {
|
||||
// already registered but we need to do it again
|
||||
if (!perform_register())
|
||||
if (!perform_register(GUI::into_u8(path_name())))
|
||||
return false;
|
||||
app_config->set("downloader_url_registered", "1");
|
||||
} else if (!ac_value && downloader_checked) {
|
||||
// register
|
||||
if (!perform_register())
|
||||
if (!perform_register(GUI::into_u8(path_name())))
|
||||
return false;
|
||||
app_config->set("downloader_url_registered", "1");
|
||||
} else if (ac_value && !downloader_checked) {
|
||||
|
@ -49,7 +49,7 @@ namespace DownloaderUtils {
|
||||
void set_path_name(const std::string& name);
|
||||
|
||||
bool on_finish();
|
||||
bool perform_register(const std::string& path_override = {});
|
||||
static bool perform_register(const std::string& path);
|
||||
#ifdef __linux__
|
||||
bool get_perform_registration_linux() { return perform_registration_linux; }
|
||||
#endif // __linux__
|
||||
|
@ -98,7 +98,9 @@
|
||||
#include "Downloader.hpp"
|
||||
#include "PhysicalPrinterDialog.hpp"
|
||||
#include "WifiConfigDialog.hpp"
|
||||
#include "Auth.hpp"
|
||||
#include "UserAccount.hpp"
|
||||
#include "MediaControlPanel.hpp"
|
||||
#include "WebViewDialog.hpp"
|
||||
|
||||
#include "BitmapCache.hpp"
|
||||
#include "Notebook.hpp"
|
||||
@ -2501,6 +2503,8 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
updatable_item = local_menu->Append(config_id_base + ConfigMenuConnectDummy, _L("PrusaConnect Printers"), _L(""));
|
||||
updatable_item->Enable(false);
|
||||
m_config_menu_updatable_items.emplace(ConfigMenuIDs::ConfigMenuConnectDummy, updatable_item);
|
||||
local_menu->Append(config_id_base + ConfigMenuConnectDialog, _L("Connect Dialog"), _L("Connect Dialog"));
|
||||
local_menu->Append(config_id_base + ConfigMenuMediaDialog, _L("Media Dialog"), _L("Media Dialog"));
|
||||
#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION)
|
||||
//if (DesktopIntegrationDialog::integration_possible())
|
||||
local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration"));
|
||||
@ -2551,15 +2555,15 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
break;
|
||||
case ConfigMenuAuthLogin:
|
||||
{
|
||||
if (this->plater()->get_auth_communication()->is_logged())
|
||||
this->plater()->get_auth_communication()->logout();
|
||||
if (this->plater()->get_user_account()->is_logged())
|
||||
this->plater()->get_user_account()->do_logout();
|
||||
else
|
||||
this->plater()->get_auth_communication()->login();
|
||||
this->plater()->get_user_account()->do_login();
|
||||
}
|
||||
break;
|
||||
case ConfigMenuConnectDummy:
|
||||
{
|
||||
this->plater()->get_auth_communication()->enqueue_connect_printers_action();
|
||||
this->plater()->get_user_account()->enqueue_connect_printers_action();
|
||||
}
|
||||
break;
|
||||
#ifdef __linux__
|
||||
@ -2661,6 +2665,13 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case ConfigMenuMediaDialog:
|
||||
//MediaDialog(nullptr).ShowModal();
|
||||
wxMediaPlayerDialog("Media").ShowModal();
|
||||
break;
|
||||
case ConfigMenuConnectDialog:
|
||||
WebViewDialog(plater()).ShowModal();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2679,8 +2690,8 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
}
|
||||
void GUI_App::update_config_menu()
|
||||
{
|
||||
m_config_menu_updatable_items[ConfigMenuIDs::ConfigMenuAuthLogin]->SetItemLabel(this->plater()->get_auth_communication()->is_logged() ? _L("PrusaAuth Log out") : _L("PrusaAuth Log in"));
|
||||
m_config_menu_updatable_items[ConfigMenuIDs::ConfigMenuConnectDummy]->Enable(this->plater()->get_auth_communication()->is_logged());
|
||||
m_config_menu_updatable_items[ConfigMenuIDs::ConfigMenuAuthLogin]->SetItemLabel(this->plater()->get_user_account()->is_logged() ? _L("PrusaAuth Log out") : _L("PrusaAuth Log in"));
|
||||
m_config_menu_updatable_items[ConfigMenuIDs::ConfigMenuConnectDummy]->Enable(this->plater()->get_user_account()->is_logged());
|
||||
}
|
||||
void GUI_App::open_preferences(const std::string& highlight_option /*= std::string()*/, const std::string& tab_name/*= std::string()*/)
|
||||
{
|
||||
@ -3465,7 +3476,7 @@ bool GUI_App::open_login_browser_with_dialog(const wxString& url, wxWindow* pare
|
||||
dialog.ShowCheckBox(_L("Remember me"), true);
|
||||
auto answer = dialog.ShowModal();
|
||||
launch = answer == wxID_YES;
|
||||
plater()->get_auth_communication()->set_remember_session(dialog.IsCheckBoxChecked());
|
||||
plater()->get_user_account()->set_remember_session(dialog.IsCheckBoxChecked());
|
||||
|
||||
return launch && wxLaunchDefaultBrowser(url, flags);
|
||||
}
|
||||
@ -3665,5 +3676,72 @@ void GUI_App::open_wifi_config_dialog(bool forced, const wxString& drive_path/*
|
||||
m_wifi_config_dialog_shown = false;
|
||||
}
|
||||
|
||||
void GUI_App::select_printer_with_load(Preset* prst, const std::string& preset_name, const std::string& model_name, const std::string& nozzle_name, const std::string& nozzle)
|
||||
{
|
||||
assert(prst);
|
||||
if (prst->is_visible)
|
||||
bool suc = get_tab(Preset::Type::TYPE_PRINTER)->select_preset(preset_name);
|
||||
else {
|
||||
AppConfig appconfig_new(AppConfig::EAppMode::Editor);
|
||||
appconfig_new.set_vendors(*app_config);
|
||||
prst->vendor->models;
|
||||
if (auto it = std::find_if(prst->vendor->models.begin(), prst->vendor->models.end(), [model_name](const VendorProfile::PrinterModel& a) {
|
||||
if (a.name == model_name)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}); it != prst->vendor->models.end())
|
||||
{
|
||||
appconfig_new.set_variant("PrusaResearch", it->id, nozzle, true);
|
||||
app_config->set_vendors(appconfig_new);
|
||||
|
||||
preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem,
|
||||
{ it->id, nozzle, "", "" });
|
||||
load_current_presets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI_App::handle_web_request(std::string cmd)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Handling web request: " << cmd;
|
||||
// return to plater
|
||||
//this->mainframe->select_tab(size_t(0));
|
||||
// parse message
|
||||
std::string model_name = plater()->get_user_account()->get_model_from_json(cmd);
|
||||
std::string nozzle = plater()->get_user_account()->get_nozzle_from_json(cmd);
|
||||
std::string nozzle_name = nozzle.empty() ? "" : (nozzle +" nozzle");
|
||||
assert(!model_name.empty());
|
||||
assert(!nozzle_name.empty());
|
||||
if (model_name.empty() && nozzle_name.empty())
|
||||
return;
|
||||
// select printer
|
||||
std::string preset_name = nozzle.empty() ? model_name : format("%1% %2%",model_name, nozzle_name);
|
||||
Preset* prst = preset_bundle->printers.find_preset(preset_name, false);
|
||||
if (!prst) {
|
||||
model_name = std::string(*preset_bundle->printers.get_preset_name_renamed(model_name));
|
||||
preset_name = nozzle.empty() ? model_name : format("%1% %2%", model_name, nozzle_name);
|
||||
prst = preset_bundle->printers.find_preset(preset_name, false);
|
||||
}
|
||||
if (!prst) {
|
||||
preset_name = model_name;
|
||||
prst = preset_bundle->printers.find_preset(preset_name, false);
|
||||
}
|
||||
if (prst) {
|
||||
select_printer_with_load(prst, preset_name, model_name, nozzle_name, nozzle);
|
||||
// notification
|
||||
std::string out = GUI::format("Select Printer:\n%1%", preset_name);
|
||||
this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::PrusaAuthUserID);
|
||||
this->plater()->get_notification_manager()->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out);
|
||||
} else {
|
||||
// notification
|
||||
std::string out = GUI::format("Printer not found:\n%1%", preset_name);
|
||||
this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::PrusaAuthUserID);
|
||||
this->plater()->get_notification_manager()->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // GUI
|
||||
} //Slic3r
|
||||
|
@ -98,8 +98,10 @@ enum ConfigMenuIDs {
|
||||
ConfigMenuTakeSnapshot,
|
||||
ConfigMenuUpdateConf,
|
||||
ConfigMenuUpdateApp,
|
||||
ConfigMenuMediaDialog,
|
||||
ConfigMenuAuthLogin,
|
||||
ConfigMenuConnectDummy,
|
||||
ConfigMenuConnectDialog,
|
||||
ConfigMenuDesktopIntegration,
|
||||
ConfigMenuPreferences,
|
||||
ConfigMenuModeSimple,
|
||||
@ -401,6 +403,24 @@ public:
|
||||
|
||||
void open_wifi_config_dialog(bool forced, const wxString& drive_path = {});
|
||||
bool get_wifi_config_dialog_shown() const { return m_wifi_config_dialog_shown; }
|
||||
|
||||
void request_login(bool show_user_info = false) {}
|
||||
bool check_login() { return false; }
|
||||
void get_login_info() {}
|
||||
bool is_user_login() { return true; }
|
||||
|
||||
void request_user_login(int online_login) {}
|
||||
void request_user_logout() {}
|
||||
int request_user_unbind(std::string dev_id) { return 0; }
|
||||
void handle_web_request(std::string cmd);
|
||||
void select_printer_with_load(Preset* prst, const std::string& preset_name, const std::string& printer_name, const std::string& nozzle_name, const std::string& nozzle );
|
||||
void handle_script_message(std::string msg) {}
|
||||
void request_model_download(std::string import_json) {}
|
||||
void download_project(std::string project_id) {}
|
||||
void request_project_download(std::string project_id) {}
|
||||
void request_open_project(std::string project_id) {}
|
||||
void request_remove_project(std::string project_id) {}
|
||||
|
||||
private:
|
||||
bool on_init_inner();
|
||||
void init_app_config();
|
||||
|
@ -62,6 +62,9 @@
|
||||
#include "GalleryDialog.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
#include "Preferences.hpp"
|
||||
#include "WebViewDialog.hpp"
|
||||
#include "MediaControlPanel.hpp"
|
||||
#include "MediaControl.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <dbt.h>
|
||||
@ -724,6 +727,10 @@ void MainFrame::init_tabpanel()
|
||||
if (panel == nullptr || (tab != nullptr && !tab->supports_printer_technology(m_plater->printer_technology())))
|
||||
return;
|
||||
|
||||
// temporary fix - WebViewPanel is not inheriting from Tab -> would jump to select Plater
|
||||
if (panel && !tab)
|
||||
return;
|
||||
|
||||
auto& tabs_list = wxGetApp().tabs_list;
|
||||
if (tab && std::find(tabs_list.begin(), tabs_list.end(), tab) != tabs_list.end()) {
|
||||
// On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered
|
||||
@ -739,6 +746,13 @@ void MainFrame::init_tabpanel()
|
||||
select_tab(size_t(0)); // select Plater
|
||||
});
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
|
||||
//m_webview = new WebViewPanel(m_tabpanel);
|
||||
//m_tabpanel->AddPage(m_webview, "web", "cog"/*, "tab_home_active"*/);
|
||||
//m_param_panel = new ParamsPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
|
||||
}
|
||||
|
||||
m_plater = new Plater(this, this);
|
||||
m_plater->Hide();
|
||||
|
||||
@ -823,6 +837,13 @@ void MainFrame::create_preset_tabs()
|
||||
add_created_tab(new TabSLAPrint(m_tabpanel), "cog");
|
||||
add_created_tab(new TabSLAMaterial(m_tabpanel), "resin");
|
||||
add_created_tab(new TabPrinter(m_tabpanel), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF ? "printer" : "sla_printer");
|
||||
|
||||
m_webview = new WebViewPanel(m_tabpanel);
|
||||
m_tabpanel->AddPage(m_webview, "Web View");
|
||||
/*
|
||||
m_media = new MediaMainPanel(this);
|
||||
m_tabpanel->AddPage(m_media, "Media");
|
||||
*/
|
||||
}
|
||||
|
||||
void MainFrame::add_created_tab(Tab* panel, const std::string& bmp_name /*= ""*/)
|
||||
@ -1510,6 +1531,9 @@ void MainFrame::init_menubar_as_editor()
|
||||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse Sidebar") + sep + "Shift+" + sep_space + "Tab", _L("Collapse sidebar"),
|
||||
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
|
||||
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
|
||||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Load URL"), _L("Load URL"),
|
||||
[this](wxCommandEvent&) { wxString url = "https://dev.connect.prusa3d.com/"/*"file:///C:/Projects/BambuStudio/resources/web/homepage/index.html"*/; m_webview->load_url(url); }, this,
|
||||
[]() { return true; }, []() { return true; }, this);
|
||||
#ifndef __APPLE__
|
||||
// OSX adds its own menu item to toggle fullscreen.
|
||||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Fullscreen") + "\t" + "F11", _L("Fullscreen"),
|
||||
|
@ -43,6 +43,8 @@ class Plater;
|
||||
class MainFrame;
|
||||
class PreferencesDialog;
|
||||
class GalleryDialog;
|
||||
class WebViewPanel;
|
||||
class MediaMainPanel;
|
||||
|
||||
enum QuickSlice
|
||||
{
|
||||
@ -219,6 +221,8 @@ public:
|
||||
PreferencesDialog* preferences_dialog { nullptr };
|
||||
PrintHostQueueDialog* m_printhost_queue_dlg;
|
||||
GalleryDialog* m_gallery_dialog{ nullptr };
|
||||
WebViewPanel* m_webview{ nullptr };
|
||||
MediaMainPanel* m_media{ nullptr};
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::unique_ptr<wxTaskBarIcon> m_taskbar_icon;
|
||||
|
@ -129,7 +129,7 @@ enum class NotificationType
|
||||
// MacOS specific - PS comes forward even when downloader is not allowed
|
||||
URLNotRegistered,
|
||||
// Config file was detected during startup, open wifi config dialog via hypertext
|
||||
WifiConfigFileDetected
|
||||
WifiConfigFileDetected,
|
||||
//
|
||||
PrusaAuthUserID,
|
||||
};
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
@ -119,7 +121,7 @@
|
||||
#include "Gizmos/GLGizmoSVG.hpp" // Drop SVG file
|
||||
#include "Gizmos/GLGizmoCut.hpp"
|
||||
#include "FileArchiveDialog.hpp"
|
||||
#include "Auth.hpp"
|
||||
#include "UserAccount.hpp"
|
||||
#include "DesktopIntegrationDialog.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -264,7 +266,7 @@ struct Plater::priv
|
||||
GLToolbar collapse_toolbar;
|
||||
Preview *preview;
|
||||
std::unique_ptr<NotificationManager> notification_manager;
|
||||
std::unique_ptr<PrusaAuthCommunication> auth_communication;
|
||||
std::unique_ptr<UserAccount> user_account;
|
||||
|
||||
ProjectDirtyStateManager dirty_state;
|
||||
|
||||
@ -611,7 +613,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
}))
|
||||
, sidebar(new Sidebar(q))
|
||||
, notification_manager(std::make_unique<NotificationManager>(q))
|
||||
, auth_communication(std::make_unique<PrusaAuthCommunication>(q, wxGetApp().app_config))
|
||||
, user_account(std::make_unique<UserAccount>(q, wxGetApp().app_config))
|
||||
, m_worker{q, std::make_unique<NotificationProgressIndicator>(notification_manager.get()), "ui_worker"}
|
||||
, m_sla_import_dlg{new SLAImportDialog{q}}
|
||||
, delayed_scene_refresh(false)
|
||||
@ -860,7 +862,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
});
|
||||
this->q->Bind(EVT_LOGIN_OTHER_INSTANCE, [this](LoginOtherInstanceEvent& evt) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Received login from other instance event.";
|
||||
auth_communication->on_login_code_recieved(evt.data);
|
||||
user_account->on_login_code_recieved(evt.data);
|
||||
});
|
||||
|
||||
this->q->Bind(EVT_INSTANCE_GO_TO_FRONT, [this](InstanceGoToFrontEvent &) {
|
||||
@ -870,8 +872,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
this->q->Bind(EVT_OPEN_PRUSAAUTH, [this](OpenPrusaAuthEvent& evt) {
|
||||
BOOST_LOG_TRIVIAL(info) << "open browser: " << evt.data;
|
||||
// first register url to be sure to get the code back
|
||||
auto downloader_worker = new DownloaderUtils::Worker(nullptr);
|
||||
downloader_worker->perform_register(wxGetApp().app_config->get("url_downloader_dest"));
|
||||
//auto downloader_worker = new DownloaderUtils::Worker(nullptr);
|
||||
DownloaderUtils::Worker::perform_register(wxGetApp().app_config->get("url_downloader_dest"));
|
||||
#ifdef __linux__
|
||||
if (downloader_worker->get_perform_registration_linux())
|
||||
DesktopIntegrationDialog::perform_downloader_desktop_integration();
|
||||
@ -881,7 +883,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
});
|
||||
|
||||
this->q->Bind(EVT_LOGGEDOUT_PRUSAAUTH, [this](PrusaAuthSuccessEvent& evt) {
|
||||
auth_communication->set_username({}, wxGetApp().app_config);
|
||||
user_account->on_logout(wxGetApp().app_config);
|
||||
std::string text = _u8L("Logged out.");
|
||||
this->notification_manager->close_notification_of_type(NotificationType::PrusaAuthUserID);
|
||||
this->notification_manager->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, text);
|
||||
@ -889,30 +891,15 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
});
|
||||
|
||||
this->q->Bind(EVT_PA_ID_USER_SUCCESS, [this](PrusaAuthSuccessEvent& evt) {
|
||||
std::string text;
|
||||
try {
|
||||
std::stringstream ss(evt.data);
|
||||
boost::property_tree::ptree ptree;
|
||||
boost::property_tree::read_json(ss, ptree);
|
||||
std::string public_username;
|
||||
const auto public_username_optional = ptree.get_optional<std::string>("public_username");
|
||||
|
||||
if (public_username_optional)
|
||||
public_username = *public_username_optional;
|
||||
text = format(_u8L("Logged as %1%."), public_username);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
BOOST_LOG_TRIVIAL(error) << "UserIDUserAction Could not parse server response.";
|
||||
}
|
||||
assert(!text.empty());
|
||||
|
||||
auth_communication->set_username(evt.data, wxGetApp().app_config);
|
||||
std::string username = user_account->on_user_id_success(evt.data, wxGetApp().app_config);
|
||||
std::string text = format(_u8L("Logged as %1%."), username);
|
||||
this->notification_manager->close_notification_of_type(NotificationType::PrusaAuthUserID);
|
||||
this->notification_manager->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, text);
|
||||
wxGetApp().update_config_menu();
|
||||
});
|
||||
this->q->Bind(EVT_PRUSAAUTH_FAIL, [this](PrusaAuthFailEvent& evt) {
|
||||
auth_communication->set_username({}, wxGetApp().app_config);
|
||||
BOOST_LOG_TRIVIAL(error) << "Network error message: " << evt.data;
|
||||
user_account->on_communication_fail(evt.data, wxGetApp().app_config);
|
||||
this->notification_manager->close_notification_of_type(NotificationType::PrusaAuthUserID);
|
||||
this->notification_manager->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::WarningNotificationLevel, evt.data);
|
||||
});
|
||||
@ -921,7 +908,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
this->notification_manager->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, evt.data);
|
||||
});
|
||||
this->q->Bind(EVT_PRUSACONNECT_PRINTERS_SUCCESS, [this](PrusaAuthSuccessEvent& evt) {
|
||||
std::string out = GUI::format( "Printers in your PrusaConnect team:\n%1%", auth_communication->proccess_prusaconnect_printers_message(evt.data));
|
||||
BOOST_LOG_TRIVIAL(error) << "PrusaConnect printers message: " << evt.data;
|
||||
std::string text = user_account->on_connect_printers_success(evt.data, wxGetApp().app_config);
|
||||
std::string out = GUI::format( "Printers in your PrusaConnect team:\n%1%", text);
|
||||
this->notification_manager->close_notification_of_type(NotificationType::PrusaAuthUserID);
|
||||
this->notification_manager->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out);
|
||||
});
|
||||
@ -6648,14 +6637,14 @@ const NotificationManager * Plater::get_notification_manager() const
|
||||
return p->notification_manager.get();
|
||||
}
|
||||
|
||||
PrusaAuthCommunication* Plater::get_auth_communication()
|
||||
UserAccount* Plater::get_user_account()
|
||||
{
|
||||
return p->auth_communication.get();
|
||||
return p->user_account.get();
|
||||
}
|
||||
|
||||
const PrusaAuthCommunication* Plater::get_auth_communication() const
|
||||
const UserAccount* Plater::get_user_account() const
|
||||
{
|
||||
return p->auth_communication.get();
|
||||
return p->user_account.get();
|
||||
}
|
||||
|
||||
void Plater::init_notification_manager()
|
||||
|
@ -62,7 +62,7 @@ class Mouse3DController;
|
||||
class NotificationManager;
|
||||
struct Camera;
|
||||
class GLToolbar;
|
||||
class PrusaAuthCommunication;
|
||||
class UserAccount;
|
||||
|
||||
class Plater: public wxPanel
|
||||
{
|
||||
@ -351,8 +351,8 @@ public:
|
||||
NotificationManager* get_notification_manager();
|
||||
const NotificationManager* get_notification_manager() const;
|
||||
|
||||
PrusaAuthCommunication* get_auth_communication();
|
||||
const PrusaAuthCommunication* get_auth_communication() const;
|
||||
UserAccount* get_user_account();
|
||||
const UserAccount* get_user_account() const;
|
||||
|
||||
void init_notification_manager();
|
||||
|
||||
|
217
src/slic3r/GUI/UserAccount.cpp
Normal file
217
src/slic3r/GUI/UserAccount.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include "UserAccount.hpp"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
UserAccount::UserAccount(wxEvtHandler* evt_handler, AppConfig* app_config)
|
||||
: m_auth_communication(std::make_unique<PrusaAuthCommunication>(evt_handler, app_config))
|
||||
{}
|
||||
|
||||
UserAccount::~UserAccount()
|
||||
{}
|
||||
|
||||
void UserAccount::set_username(const std::string& username, AppConfig* app_config)
|
||||
{
|
||||
m_username = username;
|
||||
m_auth_communication->set_username(username, app_config);
|
||||
}
|
||||
|
||||
void UserAccount::set_remember_session(bool remember)
|
||||
{
|
||||
m_auth_communication->set_remember_session(remember);
|
||||
}
|
||||
|
||||
bool UserAccount::is_logged()
|
||||
{
|
||||
return m_auth_communication->is_logged();
|
||||
}
|
||||
void UserAccount::do_login()
|
||||
{
|
||||
m_auth_communication->do_login();
|
||||
}
|
||||
void UserAccount::do_logout()
|
||||
{
|
||||
m_auth_communication->do_logout();
|
||||
}
|
||||
|
||||
std::string UserAccount::get_access_token()
|
||||
{
|
||||
return m_auth_communication->get_access_token();
|
||||
}
|
||||
|
||||
#if 0
|
||||
void UserAccount::enqueue_user_id_action()
|
||||
{
|
||||
m_auth_communication->enqueue_user_id_action();
|
||||
}
|
||||
void UserAccount::enqueue_connect_dummy_action()
|
||||
{
|
||||
m_auth_communication->enqueue_connect_dummy_action();
|
||||
}
|
||||
#endif
|
||||
|
||||
void UserAccount::enqueue_connect_printers_action()
|
||||
{
|
||||
m_auth_communication->enqueue_connect_printers_action();
|
||||
}
|
||||
|
||||
void UserAccount::on_login_code_recieved(const std::string& url_message)
|
||||
{
|
||||
m_auth_communication->on_login_code_recieved(url_message);
|
||||
}
|
||||
|
||||
std::string UserAccount::on_user_id_success(const std::string data, AppConfig* app_config)
|
||||
{
|
||||
std::string public_username;
|
||||
try {
|
||||
std::stringstream ss(data);
|
||||
boost::property_tree::ptree ptree;
|
||||
boost::property_tree::read_json(ss, ptree);
|
||||
const auto public_username_optional = ptree.get_optional<std::string>("public_username");
|
||||
if (public_username_optional)
|
||||
public_username = *public_username_optional;
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
BOOST_LOG_TRIVIAL(error) << "UserIDUserAction Could not parse server response.";
|
||||
}
|
||||
assert(!public_username.empty());
|
||||
set_username(public_username, app_config);
|
||||
return public_username;
|
||||
}
|
||||
|
||||
void UserAccount::on_communication_fail(const std::string data, AppConfig* app_config)
|
||||
{
|
||||
// TODO: should we just declare disconnect on every fail?
|
||||
//set_username({}, app_config);
|
||||
}
|
||||
|
||||
void UserAccount::on_logout( AppConfig* app_config)
|
||||
{
|
||||
set_username({}, app_config);
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param)
|
||||
{
|
||||
for (const auto& section : tree) {
|
||||
if (section.first == param) {
|
||||
return section.second.data();
|
||||
} else {
|
||||
if (std::string res = parse_tree_for_param(section.second, param); !res.empty())
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::string UserAccount::on_connect_printers_success(const std::string data, AppConfig* app_config)
|
||||
{
|
||||
|
||||
pt::ptree ptree;
|
||||
try {
|
||||
std::stringstream ss(data);
|
||||
pt::read_json(ss, ptree);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
|
||||
return {};
|
||||
}
|
||||
// fill m_printer_map with data from ptree
|
||||
// tree string is in format {"printers": [{..}, {..}]}
|
||||
m_printer_map.clear();
|
||||
assert(ptree.front().first == "printers");
|
||||
for (const auto& printer_tree : ptree.front().second) {
|
||||
std::string name;
|
||||
ConnectPrinterState state;
|
||||
std::string type_string = parse_tree_for_param(printer_tree.second, "printer_type");
|
||||
std::string state_string = parse_tree_for_param(printer_tree.second, "connect_state");
|
||||
|
||||
assert(!type_string.empty());
|
||||
assert(!state_string.empty());
|
||||
if (type_string.empty() || state_string.empty())
|
||||
continue;
|
||||
// name of printer needs to be taken from translate table, if missing
|
||||
if (auto pair = printer_type_and_name_table.find(type_string); pair != printer_type_and_name_table.end()) {
|
||||
name = pair->second;
|
||||
} else {
|
||||
assert(true); // On this assert, printer_type_and_name_table needs to be updated with type_string and correct printer name
|
||||
continue;
|
||||
}
|
||||
// translate state string to enum value
|
||||
if (auto pair = printer_state_table.find(state_string); pair != printer_state_table.end()) {
|
||||
state = pair->second;
|
||||
} else {
|
||||
assert(true); // On this assert, printer_state_table and ConnectPrinterState needs to be updated
|
||||
continue;
|
||||
}
|
||||
if (auto counter = m_printer_map.find(name); counter != m_printer_map.end()) {
|
||||
m_printer_map[name][static_cast<size_t>(state)]++;
|
||||
} else {
|
||||
m_printer_map[name].reserve(static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) {
|
||||
m_printer_map[name].push_back(i == static_cast<size_t>(state) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string out;
|
||||
for (const auto& it : m_printer_map)
|
||||
{
|
||||
out += GUI::format("%1%: O%2% I%3% P%4% F%5% \n"
|
||||
, it.first
|
||||
, std::to_string(it.second[static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_OFFLINE)])
|
||||
, std::to_string(it.second[static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_IDLE)])
|
||||
, std::to_string(it.second[static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_PRINTING)])
|
||||
, std::to_string(it.second[static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_FINISHED)]));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string UserAccount::get_model_from_json(const std::string& message) const
|
||||
{
|
||||
std::string out;
|
||||
try {
|
||||
std::stringstream ss(message);
|
||||
pt::ptree ptree;
|
||||
pt::read_json(ss, ptree);
|
||||
|
||||
std::string printer_type = parse_tree_for_param(ptree, "printer_type");
|
||||
if (auto pair = printer_type_and_name_table.find(printer_type); pair != printer_type_and_name_table.end()) {
|
||||
out = pair->second;
|
||||
}
|
||||
else {
|
||||
out = parse_tree_for_param(ptree, "printer_type_name");
|
||||
}
|
||||
//assert(!out.empty());
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string UserAccount::get_nozzle_from_json(const std::string& message) const
|
||||
{
|
||||
std::string out;
|
||||
try {
|
||||
std::stringstream ss(message);
|
||||
pt::ptree ptree;
|
||||
pt::read_json(ss, ptree);
|
||||
|
||||
out = parse_tree_for_param(ptree, "nozzle_diameter");
|
||||
//assert(!out.empty());
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}} // namespace slic3r::GUI
|
78
src/slic3r/GUI/UserAccount.hpp
Normal file
78
src/slic3r/GUI/UserAccount.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef slic3r_UserAccount_hpp_
|
||||
#define slic3r_UserAccount_hpp_
|
||||
|
||||
#include "Auth.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace Slic3r{
|
||||
namespace GUI{
|
||||
|
||||
enum class ConnectPrinterState {
|
||||
CONNECT_PRINTER_OFFLINE,
|
||||
CONNECT_PRINTER_IDLE,
|
||||
CONNECT_PRINTER_PRINTING,
|
||||
CONNECT_PRINTER_FINISHED,
|
||||
CONNECT_PRINTER_STATE_COUNT
|
||||
};
|
||||
|
||||
typedef std::map<std::string, std::vector<size_t>> ConnectPrinterStateMap;
|
||||
// Class UserAccount should handle every request for entities outside PrusaSlicer like PrusaAuth or PrusaConnect.
|
||||
// Outside communication is implemented in class PrusaAuthCommunication in Auth.hpp.
|
||||
// All incoming data shoud be stored in UserAccount.
|
||||
class UserAccount {
|
||||
public:
|
||||
UserAccount(wxEvtHandler* evt_handler, Slic3r::AppConfig* app_config);
|
||||
~UserAccount();
|
||||
|
||||
bool is_logged();
|
||||
void do_login();
|
||||
void do_logout();
|
||||
|
||||
void set_remember_session(bool remember);
|
||||
|
||||
#if 0
|
||||
void enqueue_user_id_action();
|
||||
void enqueue_connect_dummy_action();
|
||||
#endif
|
||||
void enqueue_connect_printers_action();
|
||||
|
||||
void on_login_code_recieved(const std::string& url_message);
|
||||
std::string on_user_id_success(const std::string data, AppConfig* app_config);
|
||||
void on_communication_fail(const std::string data, AppConfig* app_config);
|
||||
void on_logout(AppConfig* app_config);
|
||||
std::string on_connect_printers_success(const std::string data, AppConfig* app_config);
|
||||
|
||||
std::string get_username() const { return m_username; }
|
||||
std::string get_access_token();
|
||||
const ConnectPrinterStateMap& get_printer_state_map() const { return m_printer_map; }
|
||||
|
||||
// standalone utility methods
|
||||
std::string get_model_from_json(const std::string& message) const;
|
||||
std::string get_nozzle_from_json(const std::string& message) const;
|
||||
private:
|
||||
void set_username(const std::string& username, AppConfig* app_config);
|
||||
|
||||
std::unique_ptr<Slic3r::GUI::PrusaAuthCommunication> m_auth_communication;
|
||||
|
||||
std::string m_username;
|
||||
ConnectPrinterStateMap m_printer_map;
|
||||
|
||||
const std::map<std::string, std::string> printer_type_and_name_table = {
|
||||
{"1.3.0", "Original Prusa i3 MK3"},
|
||||
{"1.3.1", "Original Prusa i3 MK3S & MK3S+"},
|
||||
{"1.4.0", "Original Prusa MK4"},
|
||||
{"2.1.0", "Original Prusa MINI & MINI+"},
|
||||
};
|
||||
|
||||
const std::map<std::string, ConnectPrinterState> printer_state_table = {
|
||||
{"OFFLINE" , ConnectPrinterState::CONNECT_PRINTER_OFFLINE},
|
||||
{"IDLE" , ConnectPrinterState::CONNECT_PRINTER_IDLE},
|
||||
{"PRINTING" , ConnectPrinterState::CONNECT_PRINTER_PRINTING},
|
||||
{"FINISHED" , ConnectPrinterState::CONNECT_PRINTER_FINISHED},
|
||||
};
|
||||
};
|
||||
}} // namespace slic3r::GUI
|
||||
#endif // slic3r_UserAccount_hpp_
|
178
src/slic3r/GUI/WebView.cpp
Normal file
178
src/slic3r/GUI/WebView.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "WebView.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/Utils/MacDarkMode.hpp"
|
||||
|
||||
#include <wx/webviewarchivehandler.h>
|
||||
#include <wx/webviewfshandler.h>
|
||||
#include <wx/msw/webview_edge.h>
|
||||
#include <wx/uri.h>
|
||||
#include "wx/private/jsscriptwrapper.h"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <WebView2.h>
|
||||
#elif defined __linux__
|
||||
#include <gtk/gtk.h>
|
||||
#define WEBKIT_API
|
||||
struct WebKitWebView;
|
||||
struct WebKitJavascriptResult;
|
||||
extern "C" {
|
||||
WEBKIT_API void
|
||||
webkit_web_view_run_javascript (WebKitWebView *web_view,
|
||||
const gchar *script,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
WEBKIT_API WebKitJavascriptResult *
|
||||
webkit_web_view_run_javascript_finish (WebKitWebView *web_view,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
WEBKIT_API void
|
||||
webkit_javascript_result_unref (WebKitJavascriptResult *js_result);
|
||||
}
|
||||
#endif
|
||||
|
||||
class FakeWebView : public wxWebView
|
||||
{
|
||||
virtual bool Create(wxWindow* parent, wxWindowID id, const wxString& url, const wxPoint& pos, const wxSize& size, long style, const wxString& name) override { return false; }
|
||||
virtual wxString GetCurrentTitle() const override { return wxString(); }
|
||||
virtual wxString GetCurrentURL() const override { return wxString(); }
|
||||
virtual bool IsBusy() const override { return false; }
|
||||
virtual bool IsEditable() const override { return false; }
|
||||
virtual void LoadURL(const wxString& url) override { }
|
||||
virtual void Print() override { }
|
||||
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) override { }
|
||||
virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) override { }
|
||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const override { return false; }
|
||||
virtual void SetEditable(bool enable = true) override { }
|
||||
virtual void Stop() override { }
|
||||
virtual bool CanGoBack() const override { return false; }
|
||||
virtual bool CanGoForward() const override { return false; }
|
||||
virtual void GoBack() override { }
|
||||
virtual void GoForward() override { }
|
||||
virtual void ClearHistory() override { }
|
||||
virtual void EnableHistory(bool enable = true) override { }
|
||||
virtual wxVector<wxSharedPtr<wxWebViewHistoryItem>> GetBackwardHistory() override { return {}; }
|
||||
virtual wxVector<wxSharedPtr<wxWebViewHistoryItem>> GetForwardHistory() override { return {}; }
|
||||
virtual void LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item) override { }
|
||||
virtual bool CanSetZoomType(wxWebViewZoomType type) const override { return false; }
|
||||
virtual float GetZoomFactor() const override { return 0.0f; }
|
||||
virtual wxWebViewZoomType GetZoomType() const override { return wxWebViewZoomType(); }
|
||||
virtual void SetZoomFactor(float zoom) override { }
|
||||
virtual void SetZoomType(wxWebViewZoomType zoomType) override { }
|
||||
virtual bool CanUndo() const override { return false; }
|
||||
virtual bool CanRedo() const override { return false; }
|
||||
virtual void Undo() override { }
|
||||
virtual void Redo() override { }
|
||||
virtual void* GetNativeBackend() const override { return nullptr; }
|
||||
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) override { }
|
||||
};
|
||||
|
||||
wxWebView* WebView::CreateWebView(wxWindow * parent, wxString const & url)
|
||||
{
|
||||
#if wxUSE_WEBVIEW_EDGE
|
||||
// WebView2Loader.dll in exe folder is enough?
|
||||
/*
|
||||
// Check if a fixed version of edge is present in
|
||||
// $executable_path/edge_fixed and use it
|
||||
wxFileName edgeFixedDir(wxStandardPaths::Get().GetExecutablePath());
|
||||
edgeFixedDir.SetFullName("");
|
||||
edgeFixedDir.AppendDir("edge_fixed");
|
||||
if (edgeFixedDir.DirExists()) {
|
||||
wxWebViewEdge::MSWSetBrowserExecutableDir(edgeFixedDir.GetFullPath());
|
||||
wxLogMessage("Using fixed edge version");
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
wxString correct_url = url;
|
||||
#ifdef __WIN32__
|
||||
correct_url.Replace("\\", "/");
|
||||
#endif
|
||||
if (!correct_url.empty())
|
||||
correct_url = wxURI(correct_url).BuildURI();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << correct_url.ToUTF8();
|
||||
|
||||
auto webView = wxWebView::New();
|
||||
if (webView) {
|
||||
#ifdef __WIN32__
|
||||
webView->SetUserAgent(wxString::Format("PrusaSlicer/v%s", SLIC3R_VERSION));
|
||||
webView->Create(parent, wxID_ANY, correct_url, wxDefaultPosition, wxDefaultSize);
|
||||
//We register the wxfs:// protocol for testing purposes
|
||||
//webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
|
||||
//And the memory: file system
|
||||
//webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
|
||||
#else
|
||||
// With WKWebView handlers need to be registered before creation
|
||||
//webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
|
||||
// And the memory: file system
|
||||
//webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
|
||||
webView->Create(parent, wxID_ANY, url2, wxDefaultPosition, wxDefaultSize);
|
||||
webView->SetUserAgent(wxString::Format("PrusaSlicer/v%s", SLIC3R_VERSION));
|
||||
#endif
|
||||
#ifndef __WIN32__
|
||||
Slic3r::GUI::wxGetApp().CallAfter([webView] {
|
||||
#endif
|
||||
if (!webView->AddScriptMessageHandler("wx")) {
|
||||
// TODO: dialog to user
|
||||
//wxLogError("Could not add script message handler");
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not add script message handler";
|
||||
}
|
||||
#ifndef __WIN32__
|
||||
});
|
||||
#endif
|
||||
webView->EnableContextMenu(false);
|
||||
} else {
|
||||
// TODO: dialog to user
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to create wxWebView object. Using Dummy object instead. Webview won't be working.";
|
||||
webView = new FakeWebView;
|
||||
}
|
||||
return webView;
|
||||
}
|
||||
|
||||
void WebView::LoadUrl(wxWebView * webView, wxString const &url)
|
||||
{
|
||||
auto url2 = url;
|
||||
#ifdef __WIN32__
|
||||
url2.Replace("\\", "/");
|
||||
#endif
|
||||
if (!url2.empty()) { url2 = wxURI(url2).BuildURI(); }
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << url2.ToUTF8();
|
||||
webView->LoadURL(url2);
|
||||
}
|
||||
|
||||
bool WebView::run_script(wxWebView *webView, wxString const &javascript)
|
||||
{
|
||||
try {
|
||||
#ifdef __WIN32__
|
||||
ICoreWebView2 * webView2 = (ICoreWebView2 *) webView->GetNativeBackend();
|
||||
if (webView2 == nullptr)
|
||||
return false;
|
||||
int count = 0;
|
||||
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::OutputType::JS_OUTPUT_STRING);
|
||||
wxString wrapped_code = wrapJS.GetWrappedCode();
|
||||
return webView2->ExecuteScript(wrapJS.GetWrappedCode(), NULL) == 0;
|
||||
#elif defined __WXMAC__
|
||||
WKWebView * wkWebView = (WKWebView *) webView->GetNativeBackend();
|
||||
int count = 0;
|
||||
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::OutputType::JS_OUTPUT_STRING);
|
||||
Slic3r::GUI::WKWebView_evaluateJavaScript(wkWebView, wrapJS.GetWrappedCode(), nullptr);
|
||||
return true;
|
||||
#else
|
||||
WebKitWebView *wkWebView = (WebKitWebView *) webView->GetNativeBackend();
|
||||
webkit_web_view_run_javascript(
|
||||
wkWebView, javascript.utf8_str(), NULL,
|
||||
[](GObject *wkWebView, GAsyncResult *res, void *) {
|
||||
GError * error = NULL;
|
||||
auto result = webkit_web_view_run_javascript_finish((WebKitWebView*)wkWebView, res, &error);
|
||||
if (!result)
|
||||
g_error_free (error);
|
||||
else
|
||||
webkit_javascript_result_unref (result);
|
||||
}, NULL);
|
||||
return true;
|
||||
#endif
|
||||
} catch (std::exception &e) {
|
||||
return false;
|
||||
}
|
||||
}
|
16
src/slic3r/GUI/WebView.hpp
Normal file
16
src/slic3r/GUI/WebView.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef slic3r_GUI_WebView_hpp_
|
||||
#define slic3r_GUI_WebView_hpp_
|
||||
|
||||
#include <wx/webview.h>
|
||||
|
||||
class WebView
|
||||
{
|
||||
public:
|
||||
static wxWebView *CreateWebView(wxWindow *parent, wxString const &url);
|
||||
|
||||
static void LoadUrl(wxWebView * webView, wxString const &url);
|
||||
|
||||
static bool run_script(wxWebView * webView, wxString const & msg);
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_WebView_hpp_
|
472
src/slic3r/GUI/WebViewDialog.cpp
Normal file
472
src/slic3r/GUI/WebViewDialog.cpp
Normal file
@ -0,0 +1,472 @@
|
||||
#include "WebViewDialog.hpp"
|
||||
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "slic3r/GUI/UserAccount.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/toolbar.h>
|
||||
#include <wx/textdlg.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "slic3r/GUI/WebView.hpp"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
WebViewPanel::WebViewPanel(wxWindow *parent)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
|
||||
{
|
||||
wxString url = "https://dev.connect.prusa3d.com/prusa-slicer/printers";
|
||||
//std::string strlang = wxGetApp().app_config->get("language");
|
||||
//if (strlang != "")
|
||||
// url = wxString::Format("file://%s/web/homepage/index.html?lang=%s", from_u8(resources_dir()), strlang);
|
||||
//m_bbl_user_agent = wxString::Format("BBL-Slicer/v%s", SLIC3R_VERSION);
|
||||
|
||||
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
// Create the button
|
||||
bSizer_toolbar = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_button_back = new wxButton(this, wxID_ANY, wxT("Back"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_button_back->Enable(false);
|
||||
bSizer_toolbar->Add(m_button_back, 0, wxALL, 5);
|
||||
|
||||
m_button_forward = new wxButton(this, wxID_ANY, wxT("Forward"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_button_forward->Enable(false);
|
||||
bSizer_toolbar->Add(m_button_forward, 0, wxALL, 5);
|
||||
|
||||
m_button_stop = new wxButton(this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
|
||||
bSizer_toolbar->Add(m_button_stop, 0, wxALL, 5);
|
||||
|
||||
m_button_reload = new wxButton(this, wxID_ANY, wxT("Reload"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
bSizer_toolbar->Add(m_button_reload, 0, wxALL, 5);
|
||||
|
||||
m_url = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
bSizer_toolbar->Add(m_url, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
m_button_tools = new wxButton(this, wxID_ANY, wxT("Tools"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
bSizer_toolbar->Add(m_button_tools, 0, wxALL, 5);
|
||||
|
||||
// Create panel for find toolbar.
|
||||
wxPanel* panel = new wxPanel(this);
|
||||
topsizer->Add(bSizer_toolbar, 0, wxEXPAND, 0);
|
||||
topsizer->Add(panel, wxSizerFlags().Expand());
|
||||
|
||||
// Create sizer for panel.
|
||||
wxBoxSizer* panel_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(panel_sizer);
|
||||
|
||||
// Create the info panel
|
||||
m_info = new wxInfoBar(this);
|
||||
topsizer->Add(m_info, wxSizerFlags().Expand());
|
||||
#endif
|
||||
|
||||
// Create the webview
|
||||
m_browser = WebView::CreateWebView(this, url);
|
||||
if (m_browser == nullptr) {
|
||||
wxLogError("Could not init m_browser");
|
||||
return;
|
||||
}
|
||||
|
||||
SetSizer(topsizer);
|
||||
|
||||
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
// Create the Tools menu
|
||||
m_tools_menu = new wxMenu();
|
||||
wxMenuItem* viewSource = m_tools_menu->Append(wxID_ANY, _L("View Source"));
|
||||
wxMenuItem* viewText = m_tools_menu->Append(wxID_ANY, _L("View Text"));
|
||||
m_tools_menu->AppendSeparator();
|
||||
|
||||
wxMenu* script_menu = new wxMenu;
|
||||
|
||||
m_script_custom = script_menu->Append(wxID_ANY, "Custom script");
|
||||
m_tools_menu->AppendSubMenu(script_menu, _L("Run Script"));
|
||||
wxMenuItem* addUserScript = m_tools_menu->Append(wxID_ANY, _L("Add user script"));
|
||||
wxMenuItem* setCustomUserAgent = m_tools_menu->Append(wxID_ANY, _L("Set custom user agent"));
|
||||
|
||||
#endif
|
||||
//Zoom
|
||||
m_zoomFactor = 100;
|
||||
|
||||
|
||||
Bind(wxEVT_SHOW, &WebViewPanel::on_show, this);
|
||||
|
||||
// Connect the webview events
|
||||
Bind(wxEVT_WEBVIEW_ERROR, &WebViewPanel::on_error, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebViewPanel::on_script_message, this, m_browser->GetId());
|
||||
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
// Connect the button events
|
||||
Bind(wxEVT_BUTTON, &WebViewPanel::on_back, this, m_button_back->GetId());
|
||||
Bind(wxEVT_BUTTON, &WebViewPanel::on_forward, this, m_button_forward->GetId());
|
||||
Bind(wxEVT_BUTTON, &WebViewPanel::on_stop, this, m_button_stop->GetId());
|
||||
Bind(wxEVT_BUTTON, &WebViewPanel::on_reload, this, m_button_reload->GetId());
|
||||
Bind(wxEVT_BUTTON, &WebViewPanel::on_tools_clicked, this, m_button_tools->GetId());
|
||||
Bind(wxEVT_TEXT_ENTER, &WebViewPanel::on_url, this, m_url->GetId());
|
||||
|
||||
// Connect the menu events
|
||||
Bind(wxEVT_MENU, &WebViewPanel::on_view_source_request, this, viewSource->GetId());
|
||||
Bind(wxEVT_MENU, &WebViewPanel::on_view_text_request, this, viewText->GetId());
|
||||
|
||||
Bind(wxEVT_MENU, &WebViewPanel::on_run_script_custom, this, m_script_custom->GetId());
|
||||
Bind(wxEVT_MENU, &WebViewPanel::on_add_user_script, this, addUserScript->GetId());
|
||||
#endif
|
||||
//Connect the idle events
|
||||
Bind(wxEVT_IDLE, &WebViewPanel::on_idle, this);
|
||||
Bind(wxEVT_CLOSE_WINDOW, &WebViewPanel::on_close, this);
|
||||
|
||||
m_LoginUpdateTimer = nullptr;
|
||||
}
|
||||
|
||||
WebViewPanel::~WebViewPanel()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Start";
|
||||
SetEvtHandlerEnabled(false);
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
delete m_tools_menu;
|
||||
|
||||
if (m_LoginUpdateTimer != nullptr) {
|
||||
m_LoginUpdateTimer->Stop();
|
||||
delete m_LoginUpdateTimer;
|
||||
m_LoginUpdateTimer = NULL;
|
||||
}
|
||||
#endif
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End";
|
||||
}
|
||||
|
||||
|
||||
void WebViewPanel::load_url(wxString& url)
|
||||
{
|
||||
this->Show();
|
||||
this->Raise();
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
m_url->SetLabelText(url);
|
||||
#endif
|
||||
m_browser->LoadURL(url);
|
||||
m_browser->SetFocus();
|
||||
}
|
||||
|
||||
void WebViewPanel::on_show(wxShowEvent& evt)
|
||||
{
|
||||
// run script with access token to login
|
||||
if (evt.IsShown()) {
|
||||
std::string token = wxGetApp().plater()->get_user_account()->get_access_token();
|
||||
wxString script = GUI::format_wxstr("window.setAccessToken(\'%1%\')", token);
|
||||
// TODO: should this be happening every OnShow?
|
||||
run_script(script);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WebViewPanel::on_idle(wxIdleEvent& WXUNUSED(evt))
|
||||
{
|
||||
if (m_browser->IsBusy())
|
||||
wxSetCursor(wxCURSOR_ARROWWAIT);
|
||||
else
|
||||
wxSetCursor(wxNullCursor);
|
||||
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
m_button_stop->Enable(m_browser->IsBusy());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when user entered an URL and pressed enter
|
||||
*/
|
||||
void WebViewPanel::on_url(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
m_browser->LoadURL(m_url->GetValue());
|
||||
m_browser->SetFocus();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when user pressed the "back" button
|
||||
*/
|
||||
void WebViewPanel::on_back(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->GoBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when user pressed the "forward" button
|
||||
*/
|
||||
void WebViewPanel::on_forward(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->GoForward();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when user pressed the "stop" button
|
||||
*/
|
||||
void WebViewPanel::on_stop(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->Stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when user pressed the "reload" button
|
||||
*/
|
||||
void WebViewPanel::on_reload(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->Reload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WebViewPanel::on_close(wxCloseEvent& evt)
|
||||
{
|
||||
this->Hide();
|
||||
}
|
||||
|
||||
|
||||
void WebViewPanel::on_script_message(wxWebViewEvent& evt)
|
||||
{
|
||||
wxGetApp().handle_web_request(evt.GetString().ToUTF8().data());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Invoked when user selects the "View Source" menu item
|
||||
*/
|
||||
void WebViewPanel::on_view_source_request(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
SourceViewDialog dlg(this, m_browser->GetPageSource());
|
||||
dlg.ShowModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when user selects the "View Text" menu item
|
||||
*/
|
||||
void WebViewPanel::on_view_text_request(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxDialog textViewDialog(this, wxID_ANY, "Page Text",
|
||||
wxDefaultPosition, wxSize(700, 500),
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
|
||||
|
||||
wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, m_browser->GetPageText(),
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE |
|
||||
wxTE_RICH |
|
||||
wxTE_READONLY);
|
||||
|
||||
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(text, 1, wxEXPAND);
|
||||
SetSizer(sizer);
|
||||
textViewDialog.ShowModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when user selects the "Menu" item
|
||||
*/
|
||||
void WebViewPanel::on_tools_clicked(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
wxPoint position = ScreenToClient(wxGetMousePosition());
|
||||
PopupMenu(m_tools_menu, position.x, position.y);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebViewPanel::run_script(const wxString& javascript)
|
||||
{
|
||||
// Remember the script we run in any case, so the next time the user opens
|
||||
// the "Run Script" dialog box, it is shown there for convenient updating.
|
||||
m_javascript = javascript;
|
||||
|
||||
if (!m_browser) return;
|
||||
|
||||
bool res = WebView::run_script(m_browser, javascript);
|
||||
BOOST_LOG_TRIVIAL(debug) << "RunScript " << javascript << " " << res;
|
||||
}
|
||||
|
||||
|
||||
void WebViewPanel::on_run_script_custom(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxTextEntryDialog dialog
|
||||
(
|
||||
this,
|
||||
"Please enter JavaScript code to execute",
|
||||
wxGetTextFromUserPromptStr,
|
||||
m_javascript,
|
||||
wxOK | wxCANCEL | wxCENTRE | wxTE_MULTILINE
|
||||
);
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
run_script(dialog.GetValue());
|
||||
}
|
||||
|
||||
void WebViewPanel::on_add_user_script(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxString userScript = "window.wx_test_var = 'wxWidgets webview sample';";
|
||||
wxTextEntryDialog dialog
|
||||
(
|
||||
this,
|
||||
"Enter the JavaScript code to run as the initialization script that runs before any script in the HTML document.",
|
||||
wxGetTextFromUserPromptStr,
|
||||
userScript,
|
||||
wxOK | wxCANCEL | wxCENTRE | wxTE_MULTILINE
|
||||
);
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
if (!m_browser->AddUserScript(dialog.GetValue()))
|
||||
wxLogError("Could not add user script");
|
||||
}
|
||||
|
||||
void WebViewPanel::on_set_custom_user_agent(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxString customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1";
|
||||
wxTextEntryDialog dialog
|
||||
(
|
||||
this,
|
||||
"Enter the custom user agent string you would like to use.",
|
||||
wxGetTextFromUserPromptStr,
|
||||
customUserAgent,
|
||||
wxOK | wxCANCEL | wxCENTRE
|
||||
);
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
if (!m_browser->SetUserAgent(customUserAgent))
|
||||
wxLogError("Could not set custom user agent");
|
||||
}
|
||||
|
||||
void WebViewPanel::on_clear_selection(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->ClearSelection();
|
||||
}
|
||||
|
||||
void WebViewPanel::on_delete_selection(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->DeleteSelection();
|
||||
}
|
||||
|
||||
void WebViewPanel::on_select_all(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_browser->SelectAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when a loading error occurs
|
||||
*/
|
||||
void WebViewPanel::on_error(wxWebViewEvent& evt)
|
||||
{
|
||||
#define WX_ERROR_CASE(type) \
|
||||
case type: \
|
||||
category = #type; \
|
||||
break;
|
||||
|
||||
wxString category;
|
||||
switch (evt.GetInt())
|
||||
{
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CONNECTION);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CERTIFICATE);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_AUTH);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_SECURITY);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_NOT_FOUND);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_REQUEST);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_USER_CANCELLED);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_OTHER);
|
||||
}
|
||||
|
||||
//Show the info bar with an error
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
|
||||
m_info->ShowMessage(_L("An error occurred loading ") + evt.GetURL() + "\n" +
|
||||
"'" + category + "'", wxICON_ERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SourceViewDialog::SourceViewDialog(wxWindow* parent, wxString source) :
|
||||
wxDialog(parent, wxID_ANY, "Source Code",
|
||||
wxDefaultPosition, wxSize(700,500),
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, source,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE |
|
||||
wxTE_RICH |
|
||||
wxTE_READONLY);
|
||||
|
||||
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(text, 1, wxEXPAND);
|
||||
SetSizer(sizer);
|
||||
}
|
||||
|
||||
|
||||
WebViewDialog::WebViewDialog(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "Webview Dialog", wxDefaultPosition, wxSize(1366, 768)/* wxSize(100 * wxGetApp().em_unit(), 100 * wxGetApp().em_unit())*/)
|
||||
{
|
||||
wxString url = "https://dev.connect.prusa3d.com/prusa-slicer/printers";
|
||||
////std::string strlang = wxGetApp().app_config->get("language");
|
||||
////if (strlang != "")
|
||||
//// url = wxString::Format("file://%s/web/homepage/index.html?lang=%s", from_u8(resources_dir()), strlang);
|
||||
////m_bbl_user_agent = wxString::Format("BBL-Slicer/v%s", SLIC3R_VERSION);
|
||||
|
||||
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
|
||||
|
||||
// Create the webview
|
||||
m_browser = WebView::CreateWebView(this, url);
|
||||
if (m_browser == nullptr) {
|
||||
wxLogError("Could not init m_browser");
|
||||
return;
|
||||
}
|
||||
|
||||
SetSizer(topsizer);
|
||||
|
||||
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
Bind(wxEVT_SHOW, &WebViewDialog::on_show, this);
|
||||
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebViewDialog::on_script_message, this, m_browser->GetId());
|
||||
}
|
||||
|
||||
WebViewDialog::~WebViewDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WebViewDialog::on_show(wxShowEvent& evt)
|
||||
{
|
||||
if (evt.IsShown()) {
|
||||
std::string token = wxGetApp().plater()->get_user_account()->get_access_token();
|
||||
wxString script = GUI::format_wxstr("window.setAccessToken(\'%1%\')", token);
|
||||
// TODO: should this be happening every OnShow?
|
||||
run_script(script);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WebViewDialog::run_script(const wxString& javascript)
|
||||
{
|
||||
if (!m_browser)
|
||||
return;
|
||||
bool res = WebView::run_script(m_browser, javascript);
|
||||
}
|
||||
|
||||
void WebViewDialog::on_script_message(wxWebViewEvent& evt)
|
||||
{
|
||||
this->EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
124
src/slic3r/GUI/WebViewDialog.hpp
Normal file
124
src/slic3r/GUI/WebViewDialog.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef slic3r_WebViewDialog_hpp_
|
||||
#define slic3r_WebViewDialog_hpp_
|
||||
|
||||
|
||||
#include "wx/artprov.h"
|
||||
#include "wx/cmdline.h"
|
||||
#include "wx/notifmsg.h"
|
||||
#include "wx/settings.h"
|
||||
#include "wx/webview.h"
|
||||
|
||||
#if wxUSE_WEBVIEW_EDGE
|
||||
#include "wx/msw/webview_edge.h"
|
||||
#endif
|
||||
|
||||
#include "wx/webviewarchivehandler.h"
|
||||
#include "wx/webviewfshandler.h"
|
||||
#include "wx/numdlg.h"
|
||||
#include "wx/infobar.h"
|
||||
#include "wx/filesys.h"
|
||||
#include "wx/fs_arc.h"
|
||||
#include "wx/fs_mem.h"
|
||||
#include "wx/stdpaths.h"
|
||||
#include <wx/panel.h>
|
||||
#include <wx/tbarbase.h>
|
||||
#include "wx/textctrl.h"
|
||||
#include <wx/timer.h>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#define DEBUG_URL_PANEL
|
||||
class WebViewPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
WebViewPanel(wxWindow *parent);
|
||||
virtual ~WebViewPanel();
|
||||
|
||||
void load_url(wxString& url);
|
||||
|
||||
void on_show(wxShowEvent& evt);
|
||||
|
||||
void on_idle(wxIdleEvent& evt);
|
||||
void on_url(wxCommandEvent& evt);
|
||||
void on_back(wxCommandEvent& evt);
|
||||
void on_forward(wxCommandEvent& evt);
|
||||
void on_stop(wxCommandEvent& evt);
|
||||
void on_reload(wxCommandEvent& evt);
|
||||
|
||||
void on_script_message(wxWebViewEvent& evt);
|
||||
void on_view_source_request(wxCommandEvent& evt);
|
||||
void on_view_text_request(wxCommandEvent& evt);
|
||||
void on_tools_clicked(wxCommandEvent& evt);
|
||||
void on_error(wxWebViewEvent& evt);
|
||||
|
||||
void run_script(const wxString& javascript);
|
||||
void on_run_script_custom(wxCommandEvent& evt);
|
||||
void on_add_user_script(wxCommandEvent& evt);
|
||||
void on_set_custom_user_agent(wxCommandEvent& evt);
|
||||
void on_clear_selection(wxCommandEvent& evt);
|
||||
void on_delete_selection(wxCommandEvent& evt);
|
||||
void on_select_all(wxCommandEvent& evt);
|
||||
|
||||
void on_close(wxCloseEvent& evt);
|
||||
|
||||
wxTimer * m_LoginUpdateTimer{nullptr};
|
||||
|
||||
private:
|
||||
|
||||
wxWebView* m_browser;
|
||||
#ifdef DEBUG_URL_PANEL
|
||||
|
||||
wxBoxSizer *bSizer_toolbar;
|
||||
wxButton * m_button_back;
|
||||
wxButton * m_button_forward;
|
||||
wxButton * m_button_stop;
|
||||
wxButton * m_button_reload;
|
||||
wxTextCtrl *m_url;
|
||||
wxButton * m_button_tools;
|
||||
|
||||
wxMenu* m_tools_menu;
|
||||
wxMenuItem* m_script_custom;
|
||||
|
||||
|
||||
wxInfoBar *m_info;
|
||||
wxStaticText* m_info_text;
|
||||
#endif
|
||||
long m_zoomFactor;
|
||||
|
||||
// Last executed JavaScript snippet, for convenience.
|
||||
wxString m_javascript;
|
||||
wxString m_response_js;
|
||||
|
||||
wxString m_bbl_user_agent;
|
||||
|
||||
//DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
||||
class WebViewDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
WebViewDialog(wxWindow* parent);
|
||||
virtual ~WebViewDialog();
|
||||
|
||||
void on_show(wxShowEvent& evt);
|
||||
void run_script(const wxString& javascript);
|
||||
void on_script_message(wxWebViewEvent& evt);
|
||||
|
||||
private:
|
||||
wxWebView* m_browser;
|
||||
};
|
||||
|
||||
|
||||
class SourceViewDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
SourceViewDialog(wxWindow* parent, wxString source);
|
||||
};
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif /* slic3r_Tab_hpp_ */
|
@ -5,12 +5,15 @@
|
||||
#ifndef slic3r_MacDarkMode_hpp_
|
||||
#define slic3r_MacDarkMode_hpp_
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if __APPLE__
|
||||
extern bool mac_dark_mode();
|
||||
extern double mac_max_scaling_factor();
|
||||
void WKWebView_evaluateJavaScript(void * web, wxString const & script, void (*callback)(wxString const &));
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#import "MacDarkMode.hpp"
|
||||
|
||||
#include "wx/osx/core/cfstring.h"
|
||||
|
||||
#import <algorithm>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@ -33,6 +35,16 @@ double mac_max_scaling_factor()
|
||||
return scaling;
|
||||
}
|
||||
|
||||
void WKWebView_evaluateJavaScript(void * web, wxString const & script, void (*callback)(wxString const &))
|
||||
{
|
||||
[(WKWebView*)web evaluateJavaScript:wxCFStringRef(script).AsNSString() completionHandler: ^(id result, NSError *error) {
|
||||
if (callback && error != nil) {
|
||||
wxString err = wxCFStringRef(error.localizedFailureReason).AsString();
|
||||
callback(err);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user