backend/wbprivate/workbench/wb_context.h (334 lines of code) (raw):

/* * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, * as published by the Free Software Foundation. * * This program is designed to work with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, as * designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have either included with * the program or referenced in the documentation. * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License, version 2.0, for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once #ifndef _MSC_VER #include <vector> #endif #include "base/ui_form.h" #include "grt/grt_manager.h" #include "base/notifications.h" #include "wb_context_names.h" #include "grts/structs.workbench.h" #include "wb_backend_public_interface.h" #include "grtpp_undo_manager.h" #include "mforms/utilities.h" #include "base/trackable.h" #include "base/threading.h" #include "base/data_types.h" #define WBContext_VERSION 5 #define WB_DBOBJECT_DRAG_TYPE "com.mysql.workbench.DatabaseObject" #define WB_CONTROL_DRAG_TYPE "com.mysql.workbench.control" const int ONE_MB = 1024*1024; namespace mdc { class CanvasView; class CanvasItem; }; namespace bec { class Clipboard; class IconManager; }; class SqlEditorForm; namespace wb { class WBContextUI; class WBContextModel; class WBContextSQLIDE; class WorkbenchImpl; class WBComponent; class ModelFile; class TunnelManager; enum RefreshType { RefreshNeeded, // Front end should schedule a refresh flush asap (usually called in worker thread). RefreshNothing, RefreshSchemaNoReload, RefreshNewDiagram, RefreshSelection, RefreshCloseEditor, // argument: object-id (close all if "") RefreshNewModel, RefreshOverviewNodeInfo, // argument: node-id, overview ptr (bec::UIForm*) RefreshOverviewNodeChildren, // argument: node-id, overview ptr RefreshDocument, RefreshCloseDocument, RefreshZoom, RefreshTimer, RefreshFinishEdits // Force all ongoing edit operations (eg in TreeView cells) to be committed }; struct MYSQLWBBACKEND_PUBLIC_FUNC WBPaperSize { std::string name; std::string caption; double width; double height; bool margins_set; double margin_top; double margin_bottom; double margin_left; double margin_right; std::string description; }; // basic toolbar names #define WB_TOOLBAR_OPTIONS "options" // main view types #define WB_MAIN_VIEW_DB_QUERY "dbquery" class ModelDiagramForm; class FindDialogBE; enum PageOrientation { Landscape, Portrait }; enum RequestInputFlag { InputPassword = (1 << 0) }; struct MYSQLWBBACKEND_PUBLIC_FUNC WBFrontendCallbacks { // Args: type, title, file extensions std::function<std::string(std::string, std::string, std::string)> show_file_dialog; // Show some text in the application's status bar: must be thread-safe std::function<void(std::string)> show_status_text; // Open an editor // Args: grtmanager, module containing plugin, editor dll, editor class, edited object std::function<NativeHandle(grt::Module *, std::string, std::string, grt::BaseListRef, bec::GUIPluginFlags)> open_editor; // Show/Hide an editor // Args: editor handle (e.g: window handle) std::function<void(NativeHandle)> show_editor; std::function<void(NativeHandle)> hide_editor; // Execute a built-in command std::function<void(std::string)> perform_command; // Create a new diagram. std::function<mdc::CanvasView *(const model_DiagramRef &)> create_diagram; // Destroy a previously created canvas view std::function<void(mdc::CanvasView *)> destroy_view; // Signals the current view has been changed std::function<void(mdc::CanvasView *)> switched_view; // Open the named type of main view tab with the given form object. ownership is passed to frontend // Args: type (eg query), bec::UIForm* std::function<void(std::string, std::shared_ptr<bec::UIForm>)> create_main_form_view; std::function<void(bec::UIForm *)> destroy_main_form_view; // The tool for the view has been changed std::function<void(mdc::CanvasView *)> tool_changed; // Refresh interface std::function<void(RefreshType, std::string, NativeHandle)> refresh_gui; std::function<void(bool)> lock_gui; // Closes the application std::function<bool()> quit_application; }; struct MYSQLWBBACKEND_PUBLIC_FUNC WBOptions { std::string basedir; std::string plugin_search_path; std::string struct_search_path; std::string module_search_path; std::string library_search_path; std::string cdbc_driver_search_path; std::string user_data_dir; std::string open_at_startup_type; // model, query, admin, script std::string open_at_startup; std::string open_connection; std::string run_at_startup; // script to be executed when started std::string run_language; // language of the script in run_at_startup std::string binaryName; bool force_sw_rendering; bool force_opengl_rendering; bool verbose; bool quit_when_done; bool testing; // True if we are currently running unit tests. bool init_python; // True by default. Can be switched off for testing. bool full_init; // True by default. Should be switched off when the options are created for an already running // instance of WB. bool logLevelSet; WBOptions(const std::string &appBinaryName); ~WBOptions(); void analyzeCommandLineArguments(); dataTypes::OptionsList *programOptions; }; #define FOREACH_COMPONENT(list, iter) \ for (std::vector<WBComponent *>::iterator iter = list.begin(); iter != list.end(); ++iter) class MYSQLWBBACKEND_PUBLIC_FUNC WBContext : public base::trackable, base::Observer { friend class WorkbenchImpl; friend class WBComponent; friend class WBContextUI; public: WBContext(bool verbose = false); virtual ~WBContext(); bool software_rendering_enforced(); bool opengl_rendering_enforced(); bool init_(WBFrontendCallbacks *callbacks, WBOptions *options); void init_finish_(WBOptions *options); void finalize(); bool is_commercial(); bec::UIForm *get_active_form(); bec::UIForm *get_active_main_form(); WBContextModel *get_model_context() { return _model_context; } WBContextSQLIDE *get_sqlide_context() { return _sqlide_context; } // Document handling. void new_document(); bool can_close_document(); // returns false for cancelled bool close_document(); void close_document_finish(); void new_model_finish(); // save document bool save_as(const std::string &path); std::string get_filename() const; void report_bug(const std::string &errorInfo); // plugins void execute_plugin(const std::string &plugin_name, const bec::ArgumentPool &argpool = bec::ArgumentPool()); void update_plugin_arguments_pool(bec::ArgumentPool &args); // DB Querying std::shared_ptr<SqlEditorForm> add_new_query_window(const db_mgmt_ConnectionRef &target, bool restore_session = true); std::shared_ptr<SqlEditorForm> add_new_query_window(); // Admin void add_new_admin_window(const db_mgmt_ConnectionRef &target); // Generic plugin tabs void add_new_plugin_window(const std::string &plugin_id, const std::string &caption); // GUI Plugin void register_builtin_plugins(grt::ListRef<app_Plugin> plugins); void close_gui_plugin(NativeHandle handle); // void request_refresh(RefreshType type, const std::string &str, NativeHandle ptr = (NativeHandle)0); const std::string &get_user_datadir() const { return _user_datadir; } // TODO: Temporary solution need to make ModelFile grt class workbench_DocumentRef openModelFile(const std::string &file); std::string getTempDir(); int closeModelFile(); std::string getDbFilePath(); bool open_document(const std::string &file); void open_script_file(const std::string &file); void open_recent_document(int index); bool has_unsaved_changes(); bool save_changes(); bool open_file_by_extension(const std::string &path, bool interactive); bec::PluginManager *get_plugin_manager() { return _plugin_manager; } template <class C> C *get_component() { return dynamic_cast<C *>(get_component_named(C::name())); } WBComponent *get_component_named(const std::string &name); WBComponent *get_component_handling(const model_ObjectRef &object); void foreach_component(const std::function<void(WBComponent *)> &slot); WorkbenchImpl *get_workbench() { return _workbench; }; bec::Clipboard *get_clipboard() const { return _clipboard; } workbench_WorkbenchRef get_root(); workbench_DocumentRef get_document(); grt::DictRef get_wb_options(); std::string get_datadir() const { return _datadir; } bool cancel_idle_tasks(); void flush_idle_tasks(bool force); // utilities for error reporting void show_exception(const std::string &operation, const std::exception &exc); void show_exception(const std::string &operation, const grt::grt_runtime_error &exc); template <class R> R execute_in_main_thread(const std::string &name, const std::function<R()> &function) { return bec::GRTManager::get()->get_dispatcher()->call_from_main_thread /*<R>*/ (function, true, false); } void execute_in_main_thread(const std::string &name, const std::function<void()> &function, bool wait); grt::ValueRef execute_in_grt_thread(const std::string &name, const std::function<grt::ValueRef()> &function); void execute_async_in_grt_thread(const std::string &name, const std::function<grt::ValueRef()> &function); bool activate_live_object(const GrtObjectRef &object); std::string create_attached_file(const std::string &group, const std::string &tmpl); void save_attached_file_contents(const std::string &name, const char *data, size_t size); std::string get_attached_file_contents(const std::string &name); std::string get_attached_file_tmp_path(const std::string &name); void delete_attached_file(const std::string &name); std::string recreate_attached_file(const std::string &name, const std::string &data); int export_attached_file_contents(const std::string &name, const std::string &export_to); void block_user_interaction(bool flag); bool user_interaction_allowed() { return _user_interaction_blocked == 0; } // State handling. std::string read_state(const std::string &name, const std::string &domain, const std::string &default_value); int read_state(const std::string &name, const std::string &domain, const int &default_value); double read_state(const std::string &name, const std::string &domain, const double &default_value); bool read_state(const std::string &name, const std::string &domain, const bool &default_value); grt::ValueRef read_state(const std::string &name, const std::string &domain); void save_state(const std::string &name, const std::string &domain, const std::string &value); void save_state(const std::string &name, const std::string &domain, const int &value); void save_state(const std::string &name, const std::string &domain, const double &value); void save_state(const std::string &name, const std::string &domain, const bool &value); void save_state(const std::string &name, const std::string &domain, grt::ValueRef value); protected: friend class WBContextModel; // to access _components bec::PluginManager *_plugin_manager; int _user_interaction_blocked; bool _send_messages_to_shell; bool _asked_for_saving; bool _initialization_finished; bool _attachments_changed; std::string _datadir; std::string _user_datadir; struct RefreshRequest { RefreshType type; std::string str; NativeHandle ptr; double timestamp; }; // Predicate for pending refresh removal on close. struct CancelRefreshCandidate { bool operator()(RefreshRequest request) { return (request.type == RefreshNewModel || request.type == RefreshNewDiagram || request.type == RefreshOverviewNodeChildren || request.type == RefreshZoom || request.type == RefreshDocument || request.type == RefreshOverviewNodeInfo); } }; std::list<RefreshRequest> _pending_refreshes; base::Mutex _pending_refresh_mutex; base::RecMutex _block_user_interaction_mutex; WBContextModel *_model_context; WBContextSQLIDE *_sqlide_context; std::vector<WBComponent *> _components; WorkbenchImpl *_workbench; bec::Clipboard *_clipboard; ModelFile *_file; std::string _filename; // only used for comparing pointers grt::UndoAction *_save_point; TunnelManager *_tunnel_manager; ModelFile *_model_import_file; bool _force_sw_rendering; // Command line switch. bool _force_opengl_rendering; // Command line switch. grt::ListRef<app_PaperType> get_paper_types(std::shared_ptr<grt::internal::Unserializer> unserializer); std::vector<grt::SlotHolder*> _messageHandlerList; void pushMessageHandler(grt::SlotHolder *slot); bool _other_connections_loaded; // setup void init_templates(); void init_grt_tree(WBOptions *options, std::shared_ptr<grt::internal::Unserializer> unserializer); void init_plugins_grt(WBOptions *options); void init_plugin_groups_grt(WBOptions *options); void init_object_listeners_grt(); void init_properties_grt(workbench_DocumentRef &doc); void init_rdbms_modules(); void do_close_document(bool destroying); grt::ValueRef setup_context_grt(WBOptions *options); void set_default_options(grt::DictRef options); void load_app_options(bool update); bool auto_save_document(); std::string get_auto_save_dir(); void cleanup_options(); public: void save_app_options(); void save_connections(); void save_instances(); protected: void add_recent_file(const std::string &file); void load_app_state(std::shared_ptr<grt::internal::Unserializer> unserializer); void save_app_state(); grt::ValueRef save_grt(); grt::ValueRef execute_plugin_grt(const app_PluginRef &plugin, const grt::BaseListRef &args); void plugin_finished(const grt::ValueRef &result, const app_PluginRef &plugin); bool handle_message(const grt::Message &msg); void reset_document(); void reset_listeners(); void option_dict_changed(grt::internal::OwnedDict *dict = 0, bool added = false, const std::string &key = ""); private: // for base::Observer virtual void handle_notification(const std::string &name, void *sender, std::map<std::string, std::string> &info); public: ModelFile *get_file() { return _file; } bool install_module_file(const std::string &path); bool uninstall_module(grt::Module *module); void run_script_file(const std::string &path); private: bool find_connection_password(const db_mgmt_ConnectionRef &conn, std::string &password); void *do_request_password(const std::string &title, const std::string &service, bool reset_password, std::string *account, std::string *ret_password); void *do_find_connection_password(const std::string &hostId, const std::string &username, std::string *ret_password); void load_other_connections(); void attempt_options_upgrade(xmlDocPtr xmldoc, const std::string &version); bool show_error(const std::string &title, const std::string &message); void setLogLevelFromGuiPreferences(const grt::DictRef &dict); public: std::string request_connection_password(const db_mgmt_ConnectionRef &conn, bool force_asking); public: // front end callbacks WBFrontendCallbacks *_frontendCallbacks; // Internal, used for gui plugins std::function<void(std::string, void *)> show_gui_plugin; private: void warnIfRunningOnUnsupportedOS(); }; struct GUILock { WBContext *_wb; GUILock(WBContext *wb, const std::string &message_title, const std::string &message) : _wb(wb) { mforms::Utilities::show_wait_message(message_title, message); _wb->block_user_interaction(true); } ~GUILock() { _wb->block_user_interaction(false); mforms::Utilities::hide_wait_message(); } }; };