frontend/common/preferences_form.cpp (1,685 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 */ #include "base/ui_form.h" #include "base/string_utilities.h" #include "base/util_functions.h" #include "base/log.h" #include "mforms/widgets.h" #include "mforms/sectionbox.h" #include "mforms/textbox.h" #include "mforms/panel.h" #include "mforms/radiobutton.h" #include "mforms/scrollpanel.h" #include "grt.h" #include "grts/structs.h" #include "grts/structs.app.h" #include "grts/structs.workbench.physical.h" #include "grt/editor_base.h" #include "workbench/wb_context.h" #include "workbench/wb_context_ui.h" #include "preferences_form.h" #include "grtdb/db_helpers.h" #include "snippet_popover.h" #include "grtpp_notifications.h" #if defined(_MSC_VER) || defined(__APPLE__) #define HAVE_BUNDLED_MYSQLDUMP #endif DEFAULT_LOG_DOMAIN("Preferences") using namespace base; using namespace mforms; #include "base/drawing.h" struct LangFontSet { const char *name; // TODO: there are a few fonts missing here. const char *object_title_font; const char *object_section_font; const char *object_item_font; const char *layer_title_font; const char *note_font; }; static LangFontSet font_sets[] = {{ "Default (Western)", DEFAULT_FONT_FAMILY " Bold 12", DEFAULT_FONT_FAMILY " Bold 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11", }, #ifdef _MSC_VER {"Japanese", "Arial Unicode MS Bold 12", "Arial Unicode MS Bold 11", "Arial Unicode MS 11", "Arial Unicode MS 11", "Arial Unicode MS 11"}, {"Korean", "Arial Unicode MS Bold 12", "Arial Unicode MS Bold 11", "Arial Unicode MS 11", "Arial Unicode MS 11", "Arial Unicode MS 11"}, {"Simplified Chinese", "Arial Unicode MS Bold 12", "Arial Unicode MS Bold 11", "Arial Unicode MS 11", "Arial Unicode MS 11", "Arial Unicode MS 11"}, {"Cyrillic", DEFAULT_FONT_FAMILY " Bold 12", DEFAULT_FONT_FAMILY " Bold 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11"}, #elif defined(__APPLE__) {"Japanese", "Osaka Bold 12", "Osaka Bold 11", "Osaka 11", "Osaka 11", "Osaka 11"}, {"Korean", "AppleGothic Bold 12", "AppleGothic Bold 11", "AppleGothic 11", "AppleGothic 11", "AppleGothic 11"}, {"Simplified Chinese", "SimHei Bold 12", "SimHei Bold 11", "SimHei 11", "SimHei 11", "SimHei 11"}, {"Cyrillic", DEFAULT_FONT_FAMILY " Bold 12", DEFAULT_FONT_FAMILY " Bold 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11"}, #else {"Japanese", "VL Gothic Bold 12", "VL Gothic Bold 11", "VL Gothic 11", "VL Gothic 11", "VL Gothic 11"}, {"Korean", "WenQuanYi Zen Hei Bold 12", "WenQuanYi Zen Hei Bold 11", "WenQuanYi Zen Hei 11", "WenQuanYi Zen Hei 11", "WenQuanYi Zen Hei 11"}, {"Simplified Chinese", "WenQuanYi Zen Hei Bold 12", "WenQuanYi Zen Hei Bold 11", "WenQuanYi Zen Hei 11", "WenQuanYi Zen Hei 11", "WenQuanYi Zen Hei 11"}, {"Cyrillic", DEFAULT_FONT_FAMILY " Bold 12", DEFAULT_FONT_FAMILY " Bold 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11", DEFAULT_FONT_FAMILY " 11"}, #endif {NULL, NULL, NULL, NULL, NULL, NULL}}; const std::string VALID_VERSION_TOOLTIP = _("Specify default target MySQL version in format MAJOR.MINOR or MAJOR.MINOR.RELEASE"); const std::string INVALID_VERSION_TOOLTIP = _("This is not valid version of MySQL.\nSpecify default target MySQL version in format MAJOR.MINOR or " "MAJOR.MINOR.RELEASE"); static mforms::Label *new_label(const std::string &text, const std::string &name, bool right_align = false, bool help = false) { mforms::Label *label = mforms::manage(new mforms::Label()); label->set_text(text); label->set_name(name); if (right_align) label->set_text_align(mforms::MiddleRight); if (help) { label->set_style(mforms::SmallHelpTextStyle); label->set_wrap_text(true); label->set_size(50, -1); } return label; } // ------------------------------------------------------------------------------------------------ class OptionTable : public mforms::Panel { PreferencesForm *_owner; mforms::Table _table; int _rows; bool _help_column; public: OptionTable(PreferencesForm *owner, const std::string &title, bool help_column) : mforms::Panel(mforms::TitledBoxPanel), _owner(owner), _rows(0), _help_column(help_column) { set_title(title); add(&_table); _table.set_padding(8); _table.set_row_spacing(12); _table.set_column_spacing(8); _table.set_column_count(_help_column ? 3 : 2); } void add_option(mforms::View *control, const std::string &caption, const std::string &name, const std::string &help) { _table.set_row_count(++_rows); #ifdef _MSC_VER bool right_aligned = false; #else bool right_aligned = true; #endif mforms::Label *label = new_label(caption, name, right_aligned); _table.add(label, 0, 1, _rows - 1, _rows, mforms::HFillFlag); label->set_size(170, -1); _table.add(control, 1, 2, _rows - 1, _rows, mforms::HFillFlag | mforms::HExpandFlag); control->set_size(150, -1); label = new_label(help, name + " Help", false, true); label->set_size(200, -1); _table.add(label, 2, 3, _rows - 1, _rows, mforms::VFillFlag | mforms::HFillFlag | mforms::HExpandFlag); } mforms::TextEntry *add_entry_option(const std::string &option, const std::string &caption, const std::string &name, const std::string &tooltip) { _table.set_row_count(++_rows); mforms::TextEntry *entry = _owner->new_entry_option(option, false); entry->set_tooltip(tooltip); entry->set_size(50, -1); #ifdef _MSC_VER bool right_aligned = false; #else bool right_aligned = true; #endif mforms::Label *label = new_label(caption, name, right_aligned); _table.add(label, 0, 1, _rows - 1, _rows, mforms::HFillFlag); _table.add(entry, 1, 2, _rows - 1, _rows, _help_column ? mforms::HFillFlag : mforms::HFillFlag | mforms::HExpandFlag); if (_help_column) { label = new_label(tooltip, name + " Help", false, true); label->set_size(200, -1); _table.add(label, 2, 3, _rows - 1, _rows, mforms::VFillFlag | mforms::HFillFlag | mforms::HExpandFlag); } return entry; } mforms::CheckBox *add_checkbox_option(const std::string &option, const std::string &caption, const std::string &name, const std::string &tooltip) { _table.set_row_count(++_rows); mforms::CheckBox *cb = _owner->new_checkbox_option(option); cb->set_text(caption); cb->set_name(name); cb->set_tooltip(tooltip); _table.add(cb, 0, 3, _rows - 1, _rows, mforms::HFillFlag); return cb; } }; // ------------------------------------------------------------------------------------------------ static void force_checkbox_on_toggle(mforms::CheckBox *value, mforms::CheckBox *target, bool same_value, bool disable_on_active) { if (value->get_active()) { target->set_active(!same_value); target->set_enabled(!disable_on_active); } else { // target->set_active(same_value); target->set_enabled(disable_on_active); } } //----------------- PreferencesForm ---------------------------------------------------------------- PreferencesForm::PreferencesForm(const workbench_physical_ModelRef &model) : Form(NULL, mforms::FormResizable), _switcher(mforms::TreeNoHeader | mforms::TreeSidebar), _hbox(true), _top_box(false), _bottom_box(true), _tabview(mforms::TabViewTabless), _button_box(true), _font_list(mforms::TreeFlatList) { _model = model; set_name("Workbench Preferences"); setInternalName("preferences"); if (!model.is_valid()) set_title(_("Workbench Preferences")); else set_title(_("Model Options")); #ifdef _MSC_VER set_back_color(base::Color::getApplicationColorAsString(base::AppColorMainBackground, false)); #endif _switcher.add_column(mforms::StringColumnType, "", 150); _switcher.end_columns(); _switcher.signal_changed()->connect(std::bind(&PreferencesForm::switch_page, this)); _switcher.set_size(150, -1); _hbox.add(&_switcher, false, true); _top_box.set_padding(12); _top_box.set_spacing(8); _top_box.add(&_tabview, true, true); _top_box.add(&_bottom_box, false, true); _bottom_box.add_end(&_button_box, false, true); _button_box.set_spacing(8); _button_box.set_homogeneous(true); scoped_connect(_ok_button.signal_clicked(), std::bind(&PreferencesForm::ok_clicked, this)); scoped_connect(_cancel_button.signal_clicked(), std::bind(&PreferencesForm::cancel_clicked, this)); _cancel_button.set_text(_("Cancel")); _cancel_button.enable_internal_padding(true); _ok_button.set_text(_("OK")); _ok_button.enable_internal_padding(true); mforms::Utilities::add_end_ok_cancel_buttons(&_button_box, &_ok_button, &_cancel_button); if (_model.is_valid()) { _use_global.set_text(_("Use defaults from global settings")); #ifdef _MSC_VER if (base::Color::get_active_scheme() == ColorSchemeStandardWin7) _use_global.set_front_color("#FFFFFF"); else _use_global.set_front_color("#000000"); #endif _bottom_box.add(&_use_global, true, true); scoped_connect(_use_global.signal_clicked(), std::bind(&PreferencesForm::toggle_use_global, this)); } mforms::TreeNodeRef node; if (!_model.is_valid()) { add_page(NULL, _("General Editors"), create_general_editor_page()); node = add_page(NULL, _("SQL Editor"), create_sqlide_page()); add_page(node, _("Query Editor"), create_editor_page()); add_page(node, _("Object Editors"), create_object_editor_page()); add_page(node, _("SQL Execution"), create_query_page()); node->expand(); add_page(NULL, _("Administration"), create_admin_page()); } if (_model.is_valid()) node = NULL; else node = add_page(NULL, _("Modeling"), create_model_page()); add_page(node, _("Defaults"), create_model_defaults_page()); add_page(node, _("MySQL"), create_mysql_page()); add_page(node, _("Diagram"), create_diagram_page()); if (!_model.is_valid()) { add_page(node, _("Appearance"), create_appearance_page()); node->expand(); } if (!_model.is_valid()) { #ifdef _MSC_VER add_page(NULL, _("Fonts & Colors"), create_fonts_and_colors_page()); #else // Fonts only for now in Mac/Linux add_page(NULL, _("Fonts"), create_fonts_and_colors_page()); #endif } if (!_model.is_valid()) { add_page(NULL, _("SSH"), createSSHPage()); add_page(NULL, _("Others"), create_others_page()); } _hbox.add(&_top_box, true, true); set_content(&_hbox); grt::DictRef info(true); if (!_model.is_valid()) info.set("options", wb::WBContextUI::get()->get_wb()->get_wb_options()); else { info.set("model-options", wb::WBContextUI::get()->get_model_options(_model.id())); info.set("model", model); } grt::GRTNotificationCenter::get()->send_grt("GRNPreferencesDidCreate", grt::ObjectRef(), info); _switcher.select_node(_switcher.node_at_row(0)); set_size(800, 600); center(); show_values(); } //-------------------------------------------------------------------------------------------------- PreferencesForm::~PreferencesForm() { for (std::list<Option *>::iterator iter = _options.begin(); iter != _options.end(); ++iter) delete *iter; } //-------------------------------------------------------------------------------------------------- mforms::TreeNodeRef PreferencesForm::add_page(mforms::TreeNodeRef parent, const std::string &title, mforms::View *view) { mforms::TreeNodeRef node = parent ? parent->add_child() : _switcher.add_node(); node->set_string(0, title); mforms::ScrollPanel *scroll = mforms::manage(new mforms::ScrollPanel()); scroll->set_autohide_scrollers(true); scroll->set_visible_scrollers(true, false); scroll->add(view); _tabview.add_page(scroll, title); return node; } //-------------------------------------------------------------------------------------------------- bool PreferencesForm::versionIsValid(const std::string &text) { size_t dots_count = 0; for (size_t i = 0; i < text.size(); i++) { if (!(isdigit(text[i]) || text[i] == '.')) return false; if (text[i] == '.') dots_count++; } if (hasPrefix(text, ".") || hasSuffix(text, ".") || dots_count < 1 || dots_count > 2) return false; GrtVersionRef version = bec::parse_version(text); if (!version.is_valid() || version->majorNumber() < 5 || version->majorNumber() > 10 || version->minorNumber() > 20) return false; return true; } void PreferencesForm::version_changed(mforms::TextEntry *entry) { if (versionIsValid(entry->get_string_value())) { entry->set_back_color("#FFFFFF"); entry->set_tooltip(VALID_VERSION_TOOLTIP); } else { entry->set_back_color("#FF5E5E"); entry->set_tooltip(INVALID_VERSION_TOOLTIP); } } //-------------------------------------------------------------------------------------------------- void PreferencesForm::switch_page() { int row = _switcher.get_selected_row(); if (row >= 0) _tabview.set_active_tab(row); } //-------------------------------------------------------------------------------------------------- void PreferencesForm::show() { grt::DictRef info(true); if (!_model.is_valid()) info.set("options", wb::WBContextUI::get()->get_wb()->get_wb_options()); else { info.set("model-options", wb::WBContextUI::get()->get_model_options(_model.id())); info.set("model", _model); } grt::GRTNotificationCenter::get()->send_grt("GRNPreferencesWillOpen", grt::ObjectRef(), info); if (run_modal(&_ok_button, &_cancel_button)) info.set("saved", grt::IntegerRef(1)); else info.set("saved", grt::IntegerRef(0)); grt::GRTNotificationCenter::get()->send_grt("GRNPreferencesDidClose", grt::ObjectRef(), info); } void PreferencesForm::show_values() { for (std::list<Option *>::const_iterator iter = _options.begin(); iter != _options.end(); ++iter) (*iter)->show_value(); if (!_model.is_valid()) { show_colors_and_fonts(); } if (_model.is_valid()) { std::string value; wb::WBContextUI::get()->get_wb_options_value(_model.id(), "useglobal", value); if (value == "1") { _use_global.set_active(true); _tabview.set_enabled(false); } } } void PreferencesForm::update_values() { grt::AutoUndo undo(!_model.is_valid()); if (_model.is_valid()) { wb::WBContextUI::get()->set_wb_options_value(_model.id(), "useglobal", _use_global.get_active() ? "1" : "0"); } if (!_model.is_valid() || !_use_global.get_active()) { for (std::list<Option *>::const_iterator iter = _options.begin(); iter != _options.end(); ++iter) { (*iter)->update_value(); } } if (!_model.is_valid()) updateColorsAndFonts(); undo.end(_("Change Options")); } grt::DictRef PreferencesForm::get_options(bool global) { if (!_model.is_valid() || global) return wb::WBContextUI::get()->get_wb()->get_wb_options(); else return wb::WBContextUI::get()->get_model_options(_model.id()); } void PreferencesForm::show_entry_option(const std::string &option_name, mforms::TextEntry *entry, bool numeric) { std::string value; wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, value); entry->set_value(value); } void PreferencesForm::update_entry_option(const std::string &option_name, mforms::TextEntry *entry, bool numeric) { if (numeric) wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, entry->get_string_value(), grt::IntegerType); else wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, entry->get_string_value(), grt::StringType); } void PreferencesForm::show_path_option(const std::string &option_name, mforms::FsObjectSelector *entry) { std::string value; wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, value); entry->set_filename(value); } void PreferencesForm::update_path_option(const std::string &option_name, mforms::FsObjectSelector *entry) { wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, entry->get_filename(), grt::StringType); } void PreferencesForm::update_entry_option_numeric(const std::string &option_name, mforms::TextEntry *entry, int minrange, int maxrange) { long value = base::atoi<long>(entry->get_string_value(), 0l); if (value < minrange) value = minrange; else if (value > maxrange) value = maxrange; wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, strfmt("%li", (long)value)); } void PreferencesForm::show_checkbox_option(const std::string &option_name, mforms::CheckBox *checkbox) { std::string value; wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, value); checkbox->set_active(base::atoi<int>(value, 0) != 0); } void PreferencesForm::update_checkbox_option(const std::string &option_name, mforms::CheckBox *checkbox) { std::string value = checkbox->get_active() ? "1" : "0"; wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, value, grt::IntegerType); #ifdef _MSC_VER // On Windows we have to write the following value also to the registry as our options are not // available yet when we need that value. if (option_name == "DisableSingleInstance") set_value_to_registry(HKEY_CURRENT_USER, "Software\\Oracle\\MySQL Workbench", "DisableSingleInstance", value.c_str()); #endif } void PreferencesForm::show_selector_option(const std::string &option_name, mforms::Selector *selector, const std::vector<std::string> &choices) { std::string value; wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, value); selector->set_selected((int)(std::find(choices.begin(), choices.end(), value) - choices.begin())); } void PreferencesForm::update_selector_option(const std::string &option_name, mforms::Selector *selector, const std::vector<std::string> &choices, const std::string &default_value, bool as_number) { if (as_number) { if (selector->get_selected_index() < 0) wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, default_value, grt::IntegerType); else wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, choices[selector->get_selected_index()], grt::IntegerType); } else { if (selector->get_selected_index() < 0) wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, default_value); else wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", option_name, choices[selector->get_selected_index()]); } if (option_name == "ColorScheme") { base::Color::set_active_scheme((base::ColorScheme)selector->get_selected_index()); NotificationCenter::get()->send("GNColorsChanged", NULL); } } mforms::TextEntry *PreferencesForm::new_entry_option(const std::string &option_name, bool numeric) { Option *option = new Option(); mforms::TextEntry *entry = new mforms::TextEntry(); option->view = mforms::manage(entry); option->show_value = std::bind(&PreferencesForm::show_entry_option, this, option_name, entry, numeric); option->update_value = std::bind(&PreferencesForm::update_entry_option, this, option_name, entry, numeric); _options.push_back(option); return entry; } mforms::FsObjectSelector *PreferencesForm::new_path_option(const std::string &option_name, bool file) { Option *option = new Option(); mforms::FsObjectSelector *entry = new mforms::FsObjectSelector(); entry->initialize("", file ? mforms::OpenFile : mforms::OpenDirectory, ""); option->view = mforms::manage(entry); option->show_value = std::bind(&PreferencesForm::show_path_option, this, option_name, entry); option->update_value = std::bind(&PreferencesForm::update_path_option, this, option_name, entry); _options.push_back(option); return entry; } mforms::TextEntry *PreferencesForm::new_numeric_entry_option(const std::string &option_name, int minrange, int maxrange) { Option *option = new Option(); mforms::TextEntry *entry = new mforms::TextEntry(); option->view = mforms::manage(entry); option->show_value = std::bind(&PreferencesForm::show_entry_option, this, option_name, entry, true); option->update_value = std::bind(&PreferencesForm::update_entry_option_numeric, this, option_name, entry, minrange, maxrange); _options.push_back(option); return entry; } mforms::CheckBox *PreferencesForm::new_checkbox_option(const std::string &option_name) { Option *option = new Option(); mforms::CheckBox *checkbox = new mforms::CheckBox(); option->view = mforms::manage(checkbox); option->show_value = std::bind(&PreferencesForm::show_checkbox_option, this, option_name, checkbox); option->update_value = std::bind(&PreferencesForm::update_checkbox_option, this, option_name, checkbox); _options.push_back(option); return checkbox; } mforms::Selector *PreferencesForm::new_selector_option(const std::string &option_name, std::string choices_string, bool as_number) { Option *option = new Option(); mforms::Selector *selector = new mforms::Selector(); if (choices_string.empty()) wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", "@" + option_name + "/Items", choices_string); std::vector<std::string> choices, parts = base::split(choices_string, ","); for (std::vector<std::string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) { std::vector<std::string> tmp = base::split(*iter, ":", 1); if (tmp.size() == 1) { selector->add_item(*iter); choices.push_back(*iter); } else { selector->add_item(tmp[0]); choices.push_back(tmp[1]); } } option->view = mforms::manage(selector); option->show_value = std::bind(&PreferencesForm::show_selector_option, this, option_name, selector, choices); option->update_value = std::bind(&PreferencesForm::update_selector_option, this, option_name, selector, choices, choices.empty() ? "" : choices[0], as_number); _options.push_back(option); return selector; } //-------------------------------------------------------------------------------------------------- void PreferencesForm::ok_clicked() { update_values(); mforms::Form::show(false); } //-------------------------------------------------------------------------------------------------- void PreferencesForm::cancel_clicked() { mforms::Form::show(false); } //-------------------------------------------------------------------------------------------------- mforms::View *PreferencesForm::create_admin_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Administration"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Data Export and Import")); mforms::Table *table = mforms::manage(new mforms::Table()); table->set_padding(8); table->set_row_spacing(12); table->set_column_spacing(8); table->set_row_count(3); table->set_column_count(3); frame->add(table); mforms::FsObjectSelector *pathsel; table->add(new_label(_("Path to mysqldump Tool:"), "Path to MySQL Tool", true), 0, 1, 0, 1, mforms::HFillFlag); pathsel = new_path_option("mysqldump", true); pathsel->get_entry()->set_tooltip( _("Specifiy the full path to the mysqldump tool, which is needed for the Workbench Administrator.\nIt usually " "comes bundled with the MySQL server and/or client packages.")); table->add(pathsel, 1, 2, 0, 1, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); #ifdef HAVE_BUNDLED_MYSQLDUMP table->add(new_label(_("Leave blank to use bundled version."), "Leave Blank for Default", false, true), 2, 3, 0, 1, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); #else table->add(new_label(_("Full path to the mysqldump tool\nif it's not in your PATH."), "Leave Blank for Default", false, true), 2, 3, 0, 1, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); #endif table->add(new_label(_("Path to mysql Tool:"), "Path to MySQL Tool", true), 0, 1, 1, 2, mforms::HFillFlag); pathsel = new_path_option("mysqlclient", true); pathsel->get_entry()->set_tooltip( _("Specifiy the full path to the mysql command line client tool, which is needed for the Workbench " "Administrator.\nIt usually comes bundled with the MySQL server and/or client packages.")); table->add(pathsel, 1, 2, 1, 2, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); #ifdef HAVE_BUNDLED_MYSQLDUMP table->add(new_label(_("Leave blank to use bundled version."), "Leave Blank for Default", false, true), 2, 3, 1, 2, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); #else table->add(new_label(_("Full path to the mysql tool\nif it's not in your PATH."), "Leave Blank for Default", false, true), 2, 3, 1, 2, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); #endif table->add(new_label(_("Export Directory Path:"), "Export Directory", true), 0, 1, 2, 3, mforms::HFillFlag); pathsel = new_path_option("dumpdirectory", false); pathsel->get_entry()->set_tooltip( _("Specifiy the full path to the directory where dump files should be placed by default.")); table->add(pathsel, 1, 2, 2, 3, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); table->add(new_label(_("Location where dump files should be placed by default."), "Dump Location", false, true), 2, 3, 2, 3, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); box->add(frame, false); } return box; } mforms::View *PreferencesForm::create_sqlide_page() { // General options for the SQL Editor mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("SQL IDE"); { OptionTable *table = mforms::manage(new OptionTable(this, _("SQL Editor"), true)); { mforms::CheckBox *save_workspace, *discard_unsaved; save_workspace = table->add_checkbox_option("workbench:SaveSQLWorkspaceOnClose", _("Save snapshot of open editors on close"), "Save Snapshot on Close", _("A snapshot of all open scripts is saved when the SQL Editor is closed. Next time " "it is opened to the same connection that state is restored. Unsaved files will " "remain unsaved, but their contents will be preserved.")); { static const char *auto_save_intervals = "disable:0,5 seconds:5,10 seconds:10,15 seconds:15,30 seconds:30,1 minute:60,5 minutes:300,10 minutes:600,20 " "minutes:1200"; mforms::Selector *sel = new_selector_option("workbench:AutoSaveSQLEditorInterval", auto_save_intervals, true); table->add_option(sel, _("Auto-save scripts interval:"), "Auto Save Interval", _("Interval to perform auto-saving of all open script tabs. The scripts will be restored " "from the last auto-saved version if Workbench unexpectedly quits.")); } discard_unsaved = table->add_checkbox_option("DbSqlEditor:DiscardUnsavedQueryTabs", _("Create new tabs as Query tabs instead of File"), "Create New Tabs as Query Tabs", _("Unsaved Query tabs do not get a close confirmation, unlike File tabs.\nHowever, once saved, such tabs will " "also get unsaved change confirmations.\n" "If Snapshot saving is enabled, query tabs are always autosaved to temporary files when the connection is " "closed.")); save_workspace->signal_clicked()->connect( std::bind(force_checkbox_on_toggle, save_workspace, discard_unsaved, true, true)); (*save_workspace->signal_clicked())(); table->add_checkbox_option("DbSqlEditor:SchemaTreeRestoreState", _("Restore expanded state of the active schema objects"), "Restore Expanded States", _("Re-expand (and reload) group nodes that were previously expanded in the active " "schema when the editor was last closed.")); } box->add(table, false, true); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Sidebar")); frame->set_name(_("Side Bar")); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:ShowSchemaTreeSchemaContents"); check->set_text(_("Show Schema Contents in Schema Tree")); check->set_tooltip( _("Whether to show schema contents (tables, views and routine names) in " "schema tree.")); vbox->add(check, false); } { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:ShowMetadataSchemata"); check->set_text(_("Show Metadata and Internal Schemas")); check->set_tooltip( _("Whether to show internal schemas in the schema tree " "(eg INFORMATION_SCHEMA, mysql and schemas starting with '.').")); vbox->add(check, false); } } { OptionTable *otable = new OptionTable(this, _("MySQL Session"), true); mforms::TextEntry *entry; entry = otable->add_entry_option("DbSqlEditor:KeepAliveInterval", _("DBMS connection keep-alive interval (in seconds):"), "Keep Alive Interval", _("Time interval between sending keep-alive messages to DBMS. " "Set to 0 to not send keep-alive messages.")); entry->set_size(100, -1); entry = otable->add_entry_option("DbSqlEditor:ReadTimeOut", _("DBMS connection read timeout interval (in seconds):"), "Connection Read Timeout", _("The maximum amount of time the query can take to return data from the DBMS." "Set 0 to skip the read timeout.")); entry = otable->add_entry_option("DbSqlEditor:ConnectionTimeOut", _("DBMS connection timeout interval (in seconds):"), "Timout Interval", _("Maximum time to wait before a connection attempt is aborted.")); box->add(otable, false, true); } { OptionTable *otable = new OptionTable(this, _("Other"), true); { mforms::TextEntry *entry = new_entry_option("workbench:InternalSchema", false); entry->set_max_length(100); entry->set_size(100, -1); otable->add_option( entry, _("Internal Workbench Schema:"), "Internal Schema", _("This schema will be used by MySQL Workbench to store information required for certain operations.")); } { otable->add_checkbox_option("DbSqlEditor:SafeUpdates", _("Safe Updates (rejects UPDATEs and DELETEs with no restrictions)"), "Safe Updates", _("Enables the SQL_SAFE_UPDATES option for the session. " "If enabled, MySQL aborts UPDATE or DELETE statements " "that do not use a key in the WHERE clause or a LIMIT clause. " "This makes it possible to catch UPDATE or DELETE statements " "where keys are not used properly and that would probably change " "or delete a large number of rows. " "Changing this option requires a reconnection (Query -> Reconnect to Server)")); } box->add(otable, false, true); } return box; } mforms::View *PreferencesForm::create_general_editor_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_name("General Editor"); box->set_spacing(8); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("SQL Parsing in Code Editors")); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Default SQL_MODE for syntax checker:"), "Default Syntax Checker", true), false, false); mforms::TextEntry *entry = new_entry_option("SqlMode", false); entry->set_name("SQL Mode Syntax"); entry->setInternalName("SQL mode syntax"); entry->set_tooltip( _("Value of SQL_MODE DBMS session variable customizes the rules and restrictions for SQL syntax and semantics. " "See MySQL Server reference for details.\n" "This globally defined parameter determines initial value for same named parameter in each newly created " "model. " "Model scoped same named parameter in its turn affects SQL parsing within the model, and defines the value " "of SQL_MODE session variable when connecting to DBMS.\n" "Note: Empty value for this parameter will cause Workbench to treat SQL_MODE as empty string when parsing " "SQL within the model, but will leave DBMS session variable at its default value.\n" "To force Workbench to reset SQL_MODE session variable as well, this parameter needs to be set to a " "whitespace symbol.")); tbox->add(entry, true, true); } { mforms::CheckBox *check = new_checkbox_option("SqlIdentifiersCS"); check->set_text(_("SQL Identifiers are Case Sensitive")); check->set_name("Case Sensitive Identifiers"); check->set_tooltip(_("Whether to treat identifiers separately if their names differ only in letter case.")); vbox->add(check, false); } { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Non-Standard SQL Delimiter:"), "Non Standard Delimiter", true), false, false); mforms::TextEntry *entry = new_entry_option("SqlDelimiter", false); entry->set_name("SQL Delimiter"); entry->set_size(50, -1); entry->set_tooltip( _("Delimiter used for statements that use the semicolon as part of their syntax (e.g. stored routines)")); tbox->add(entry, false, false); } } { OptionTable *table; table = mforms::manage(new OptionTable(this, _("Indentation"), true)); box->add(table, false, true); table->add_checkbox_option("Editor:TabIndentSpaces", _("Tab key inserts spaces instead of tabs"), "Spaces Instead of Tabs", "Check if you want the tab key to indent using the configured amount of spaces."); table->add_entry_option("Editor:IndentWidth", "Indent width:", "Indent Width", "How many spaces to insert when indenting with the tab key."); table->add_entry_option("Editor:TabWidth", "Tab width:", "Tab Width", "How many spaces wide are tab characters."); } return box; } //-------------------------------------------------------------------------------------------------- mforms::View *PreferencesForm::create_editor_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Editor"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Productivity")); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); // Code completion settings. { mforms::Box *subsettings_box = mforms::manage(new mforms::Box(false)); subsettings_box->set_padding(40, 0, 0, 0); subsettings_box->set_spacing(8); { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:CodeCompletionEnabled"); scoped_connect(check->signal_clicked(), std::bind(&PreferencesForm::code_completion_changed, this, check, subsettings_box)); check->set_text(_("Enable Code Completion in Editors")); check->set_tooltip( _("If enabled SQL editors display a code completion list when pressing " "the defined hotkey")); vbox->add(check, false); } { mforms::CheckBox *auto_start_check = new_checkbox_option("DbSqlEditor:AutoStartCodeCompletion"); auto_start_check->set_text(_("Automatically Start Code Completion")); auto_start_check->set_name("Automatically Start Code Completion"); auto_start_check->set_tooltip( _("Available only if code completion is enabled. By activating " "this option code completion will be started automatically when you type something and wait " "a moment")); subsettings_box->add(auto_start_check, false); mforms::CheckBox *upper_case_check = new_checkbox_option("DbSqlEditor:CodeCompletionUpperCaseKeywords"); upper_case_check->set_text(_("Use UPPERCASE keywords on completion")); upper_case_check->set_name("Use Upper Case Keywords"); upper_case_check->set_tooltip( _("Normally keywords are shown and inserted as they come from the " "code editor configuration file. With this swich they are always upper-cased instead.")); subsettings_box->add(upper_case_check, false); // Set initial enabled state of sub settings depending on whether code completion is enabled. std::string value; wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", "DbSqlEditor:CodeCompletionEnabled", value); subsettings_box->set_enabled(base::atoi<int>(value, 0) != 0); vbox->add(subsettings_box, false); } } { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Comment type to use for comment shortcut:"), "Comment Type", true), false, false); std::string comment_types = "--:--,#:#"; mforms::Selector *selector = new_selector_option("DbSqlEditor:SQLCommentTypeForHotkey", comment_types, false); selector->set_name("Comment Types"); selector->set_size(150, -1); selector->set_tooltip( _("Default comment type for SQL Query editor, to be used when the comment shortcut is used.")); tbox->add(selector, false, false); } { mforms::Table *table = mforms::manage(new mforms::Table()); table->set_row_count(2); table->set_column_count(2); table->set_column_spacing(4); table->set_row_spacing(4); vbox->add(table, false); table->add(new_label(_("Max syntax error count:"), "Maximum Error Count", true), 0, 1, 0, 1, mforms::HFillFlag); mforms::TextEntry *entry = new_entry_option("SqlEditor::SyntaxCheck::MaxErrCount", false); entry->set_size(50, -1); entry->set_tooltip( _("Maximum number of errors for syntax checking.\n" "Syntax errors aren't highlighted beyond this threshold.\n" "Set to 0 to show all errors.")); table->add(entry, 1, 2, 0, 1, mforms::HFillFlag); table->add(new_label(_("Max number of result sets:"), "Maximum Result Sets", true), 0, 1, 1, 2, mforms::HFillFlag); entry = new_entry_option("DbSqlEditor::MaxResultsets", false); entry->set_size(50, -1); entry->set_tooltip(_("Maximum number of result sets that can be opened for a single editor.")); table->add(entry, 1, 2, 1, 2, mforms::HFillFlag); } } { OptionTable *table; table = mforms::manage(new OptionTable(this, _("SQL Beautifier"), true)); box->add(table, false, true); { table->add_checkbox_option("DbSqlEditor:Reformatter:UpcaseKeywords", _("Change keywords to UPPER CASE"), "Upper Case Keywords", ""); } } return box; } //-------------------------------------------------------------------------------------------------- mforms::View *PreferencesForm::create_object_editor_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Object Editor"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Online DDL")); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); { mforms::Box *line_box = mforms::manage(new mforms::Box(true)); line_box->set_spacing(4); vbox->add(line_box, false); mforms::Label *label = new_label(_("Default algorithm for ALTER table:"), "Default Alghorithm for Alter Table", true); label->set_size(180, -1); line_box->add(label, false, true); std::string algorithms = "Default:DEFAULT,In place:INPLACE,Copy:COPY"; mforms::Selector *selector = new_selector_option("DbSqlEditor:OnlineDDLAlgorithm", algorithms, false); selector->set_size(150, -1); selector->set_tooltip( _("If the currently connected server supports online DDL then use the selected " "algorithm as default. This setting can also be adjusted for each alter operation.")); line_box->add(selector, false, false); } { mforms::Box *line_box = mforms::manage(new mforms::Box(true)); line_box->set_spacing(4); vbox->add(line_box, false); mforms::Label *label = new_label(_("Default lock for ALTER table:"), "Default Lock for Alter Table", true); label->set_size(180, -1); line_box->add(label, false, true); std::string locks = "Default:DEFAULT,None:NONE,Shared:SHARED,Exclusive:EXCLUSIVE"; mforms::Selector *selector = new_selector_option("DbSqlEditor:OnlineDDLLock", locks, false); selector->set_size(150, -1); selector->set_tooltip( _("If the currently connected server supports online DDL then use the selected " "lock as default. This setting can also be adjusted for each alter operation.")); line_box->add(selector, false, false); } } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Views")); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:ReformatViewDDL"); check->set_text(_("Reformat DDL for Views")); check->set_tooltip( _("Whether to automatically reformat View DDL returned by the server. The MySQL server does not store the " "formatting information for View definitions.")); vbox->add(check, false); } } return box; } //-------------------------------------------------------------------------------------------------- mforms::View *PreferencesForm::create_query_page() { // Options specific for the query/script execution aspect of the SQL Editor mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Query"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("General")); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Max. query length to store in history (in bytes):"), "Maximum History Length", true), false, false); mforms::TextEntry *entry = new_entry_option("DbSqlEditor:MaxQuerySizeToHistory", false); entry->set_size(50, -1); entry->set_tooltip( _("Queries beyond specified size will not be saved in the history when executed.\n" "Set to 0 to save any executed query or script")); tbox->add(entry, false, false); } { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:ContinueOnError"); check->set_text(_("Continue SQL script execution on errors (by default)")); check->set_name("Comtinue on Errors"); check->set_tooltip(_("Whether to continue skipping failed SQL statements when running a script.")); vbox->add(check, false); } { mforms::CheckBox *check= new_checkbox_option("DbSqlEditor:AutocommitMode"); check->set_text(_("New connections use auto commit mode")); check->set_name("Auto Commit on New Connections"); check->set_tooltip(_("Sets the default autocommit mode for connections.\nWhen enabled, each statement will be committed immediately." "\nNOTE: all query tabs in the same connection share the same transaction. " "To have independent transactions, you must open a new connection.")); vbox->add(check, false); } { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Progress status update interval (in milliseconds):"), "Progress Interval", true), false, false); mforms::TextEntry *entry = new_entry_option("DbSqlEditor:ProgressStatusUpdateInterval", false); entry->set_size(50, -1); entry->set_tooltip(_("Time interval between UI updates when running SQL script.")); tbox->add(entry, false, false); } } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("SELECT Query Results")); frame->set_name("Select Query Results"); box->add(frame, false); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); { mforms::CheckBox *check = new_checkbox_option("SqlEditor:LimitRows"); check->set_text(_("Limit Rows")); check->set_tooltip( _("Whether every select query to be implicitly adjusted to limit result set to specified number of rows by " "appending the LIMIT keyword to the query.\n" "If enabled it's still possible to load entire result set by pressing \"Fetch All\" button.")); vbox->add(check, false); } { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Limit Rows Count:"), "Limit Rows", true), false, false); mforms::TextEntry *entry = new_entry_option("SqlEditor:LimitRowsCount", false); entry->set_size(50, -1); entry->set_tooltip( _("Every select query to be implicitly adjusted to limit result set to specified number of rows.")); tbox->add(entry, false, false); } { mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_spacing(4); vbox->add(tbox, false); tbox->add(new_label(_("Max. Field Value Length to Display (in bytes):"), "Maximum Field Length", true), false, false); mforms::TextEntry *entry = new_entry_option("Recordset:FieldValueTruncationThreshold", false); entry->set_size(50, -1); entry->set_tooltip( _("Symbols beyond specified threashold will be truncated when showing in the grid. Doesn't affect editing " "field values.\n" "Set to -1 to disable truncation.")); tbox->add(entry, false, false); } { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:MySQL:TreatBinaryAsText"); check->set_text(_("Treat BINARY/VARBINARY as nonbinary character string")); check->set_name("Treat as Non Binary"); check->set_tooltip( _("Whether to treat binary byte strings as nonbinary character strings.\n" "Binary byte string values do not appear in results grid and are marked as a BLOB values that are supposed " "to be viewed/edited by means of BLOB editor.\n" "Nonbinary character string values are shown right in results grid and can be edited with either cell's " "in-place editor or BLOB editor.\n" "Warning: Since binary byte strings tend to contain zero-bytes in their values, turning this option on may " "lead to data truncation when viewing/editing.\n" "Note: Application restart is needed to get new option value in affect.")); vbox->add(check, false); } { mforms::CheckBox *check = new_checkbox_option("DbSqlEditor:IsDataChangesCommitWizardEnabled"); check->set_text(_("Confirm Data Changes")); check->set_tooltip(_("Whether to show a dialog confirming changes to be made to a table recordset.")); vbox->add(check, false); } { mforms::CheckBox *check = new_checkbox_option("SqlEditor:PreserveRowFilter"); check->set_text(_("Preserve Row Filter")); check->set_tooltip(_("If set, keep row filter active on result set changes. Otherwise the filter is reset.")); vbox->add(check, false); } /*{ mforms::CheckBox *check= new_checkbox_option("DbSqlEditor:IsLiveObjectAlterationWizardEnabled"); check->set_text(_("Enable Live Object Alteration Wizard")); check->set_tooltip(_( "Whether to use wizard providing more control over applying changes to live database object.")); vbox->add(check, false); }*/ } return box; } //-------------------------------------------------------------------------------------------------- /** * Triggered when the user switches the code completion enabled state. We use this to adjust the enabled * state for dependent sub options. */ void PreferencesForm::code_completion_changed(mforms::CheckBox *cc_box, mforms::Box *subsettings_box) { subsettings_box->set_enabled(cc_box->get_active()); } //-------------------------------------------------------------------------------------------------- mforms::View *PreferencesForm::create_model_page() { mforms::Box *top_box = mforms::manage(new mforms::Box(false)); top_box->set_spacing(8); top_box->set_name("Model"); OptionTable *table; table = mforms::manage(new OptionTable(this, _("EER Modeler"), true)); top_box->add(table, false, true); { table->add_checkbox_option("workbench.AutoReopenLastModel", _("Automatically reopen previous model at start"), "Reopen Previous Model", ""); #ifndef __APPLE__ table->add_checkbox_option("workbench:ForceSWRendering", _("Force use of software based rendering for EER diagrams"), "Force Software Redering Diagrams", _("Enable this option if you have drawing problems in Workbench modeling. You must " "restart Workbench for the option to take effect.")); #endif { mforms::TextEntry *entry = new_numeric_entry_option("workbench:UndoEntries", 1, 500); entry->set_max_length(5); entry->set_size(100, -1); table->add_option(entry, _("Model undo history size:"), "Undo History Size", _("Allowed values are from 1 up. Note: using high values (> 100) will increase memory usage " "and slow down operation.")); } { static const char *auto_save_intervals = "disable:0,10 seconds:10,15 seconds:15,30 seconds:30,1 minute:60,5 minutes:300,10 minutes:600,20 minutes:1200"; mforms::Selector *sel = new_selector_option("workbench:AutoSaveModelInterval", auto_save_intervals, true); table->add_option(sel, _("Auto-save model interval:"), "Auto Save Model Interval", _("Interval to perform auto-saving of the open model. The model will be restored from the last " "auto-saved version if Workbench unexpectedly quits.")); } } return top_box; } mforms::View* PreferencesForm::createSSHPage() { Box* content = manage(new Box(false)); content->set_spacing(8); content->set_name("SSH"); OptionTable *timeouts_table; timeouts_table = mforms::manage(new OptionTable(this, _("Timeouts"), true)); content->add(timeouts_table, false, true); { // SSH timeout { mforms::TextEntry *entry = new_numeric_entry_option("SSH:connectTimeout", 0, 500); entry->set_max_length(5); entry->set_size(50, -1); entry->set_tooltip(_( "Determines how long the process waits for connection until timeout")); timeouts_table->add_option(entry, _("SSH Connect Timeout:"), "SSH Connect Timeout", _("SSH connect timeout in seconds.")); } // SSH readWriteTimeout { mforms::TextEntry *entry = new_numeric_entry_option("SSH:readWriteTimeout", 0, 500); entry->set_max_length(5); entry->set_size(50, -1); entry->set_tooltip(_( "Determines how long the process waits for i/o")); timeouts_table->add_option(entry, _("SSH Read Write Timeout:"), "SSH Read and Write Timeout", _("SSH Read/Write Timeout in seconds.")); } // SSH commandtimeout { mforms::TextEntry *entry = new_numeric_entry_option("SSH:commandTimeout", 0, 500); entry->set_max_length(5); entry->set_size(50, -1); entry->set_tooltip(_( "Determines how long the process waits for a command output.\nThis is also affected by SSH Command Retry Count.")); timeouts_table->add_option(entry, _("SSH Command timeout:"), "SSH Command Timeout", _("SSH Command Timeout in second.")); } // SSH commandtimeout { mforms::TextEntry *entry = new_numeric_entry_option("SSH:commandRetryCount", 0, 500); entry->set_max_length(5); entry->set_size(50, -1); entry->set_tooltip(_( "Determines how many times we should retry reading command output after specified SSH Command Timeout option.")); timeouts_table->add_option(entry, _("SSH Command Retry Count:"), "SSH Command Retry Timeout", _("SSH Command Retry count.")); } // SSH buffer { mforms::TextEntry *entry = new_numeric_entry_option("SSH:BufferSize", 0, 10240); entry->set_max_length(5); entry->set_size(50, -1); entry->set_tooltip(_("Buffer size used for tunnel data transfer")); timeouts_table->add_option(entry, _("SSH BufferSize:"), "SSH Buffer Size", _("SSH buffer size in bytes.")); } // SSH maxFileSize { mforms::TextEntry *entry = new_numeric_entry_option("SSH:maxFileSize", 0, 1024*ONE_MB); entry->set_max_length(10); entry->set_size(50, -1); entry->set_tooltip(_("Size used to limit transfering of big files")); timeouts_table->add_option(entry, _("SSH Maximum File Size:"), "SSH Maximum File Size", _("The maximum file that is allowed to be transfered by SSH.")); } // SSH logsize { mforms::TextEntry *entry = new_numeric_entry_option("SSH:logSize", 0, 1024*ONE_MB); entry->set_max_length(10); entry->set_size(50, -1); entry->set_tooltip(_("Size used to limit transfering of big command output log.")); timeouts_table->add_option(entry, _("SSH Command Execution log:"), "SSH Command Execution Log", _("The maximum log size that is allowed to be transfered by SSH.")); } } mforms::Panel *frame= mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); mforms::Table *ssh_table= mforms::manage(new mforms::Table()); ssh_table->set_padding(8); ssh_table->set_row_spacing(12); ssh_table->set_column_spacing(8); ssh_table->set_row_count(2); ssh_table->set_column_count(3); frame->add(ssh_table); { mforms::FsObjectSelector *pathsel; ssh_table->add(new_label(_("Path to SSH config file:"), "Path to SSH Config File", true), 0, 1, 0, 1, mforms::HFillFlag); pathsel= new_path_option("SSH:pathtosshconfig", true); pathsel->get_entry()->set_tooltip(_("Specifiy the full path to the SSH config file.")); ssh_table->add(pathsel, 1, 2, 0, 1, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); } { mforms::FsObjectSelector *pathsel; ssh_table->add(new_label(_("Path to SSH known hosts file:"), "Path to SSH Known Hosts File", true), 0, 1, 1, 2, mforms::HFillFlag); pathsel= new_path_option("SSH:knownhostsfile", true); pathsel->get_entry()->set_tooltip(_("Specifiy the full path to the SSH known hosts file.")); ssh_table->add(pathsel, 1, 2, 1, 2, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); } content->add(frame, false); return content; } mforms::View *PreferencesForm::create_others_page() { Box* content = manage(new Box(false)); content->set_spacing(8); content->set_name("Others"); { mforms::Panel *frame= mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Home Screen")); content->add(frame, false, true); mforms::Box *vbox= mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); mforms::CheckBox *check= new_checkbox_option("HomeScreen:HeadingMessage"); check->set_text(_("Show Welcome Message on Connections Screen")); check->set_tooltip(""); vbox->add(check, true); } OptionTable *timeouts_table; timeouts_table = mforms::manage(new OptionTable(this, _("Timeouts"), true)); content->add(timeouts_table, false, true); // migration connection timeout { mforms::TextEntry *entry = new_numeric_entry_option("Migration:ConnectionTimeOut", 0, 3600); entry->set_max_length(5); entry->set_size(50, -1); entry->set_tooltip(_("The interval in seconds before connection is aborted.")); timeouts_table->add_option(entry, _("Migration Connection Timeout:"), "Migration Connection Timeout", _("Maximum time to wait before a connection is aborted.")); } mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); mforms::Table *optable = mforms::manage(new mforms::Table()); optable->set_padding(8); optable->set_row_spacing(12); optable->set_column_spacing(8); optable->set_row_count(2); optable->set_column_count(3); frame->add(optable); { optable->add(new_label(_("URL location to display geometry point:"), "Geometry Location", true), 0, 1, 1, 2, mforms::HFillFlag); auto opt = new_entry_option("SqlEditor:geographicLocationURL", false); opt->set_tooltip("The URL to a geographic services to be used for showing a point on an earth map.\nUse %LAT% and %LON% as a placeholder for Latitude and Longitude."); optable->add(opt, 1, 2, 1, 2, mforms::HFillFlag | mforms::HExpandFlag | mforms::VFillFlag); } content->add(frame, false); #ifdef _MSC_VER OptionTable *table = mforms::manage(new OptionTable(this, _("Others"), true)); content->add(table, false, true); { table->add_checkbox_option("DisableSingleInstance", _("Allow more than one instance of MySQL Workbench to run"), "Allow More Then One Instance", _("By default only one instance of MySQL Workbench can run at the same time. This is more resource friendly " "and necessary as multiple instances share the same files (settings etc.). Change at your own risk.")); } #endif createLogLevelSelectionPulldown(content); return content; } void PreferencesForm::createLogLevelSelectionPulldown(mforms::Box *content) { OptionTable *logTable = mforms::manage(new OptionTable(this, _("Logs"), true)); content->add(logTable, false, true); // put together comma-separated list of all loglevels (i.e: "none,error,warning,info,debug1,...") std::string logLevels; { logLevels.reserve(10); for (std::size_t i = 0; i < base::Logger::logLevelCount; i++) logLevels += base::Logger::logLevelName(i) + ','; if (logLevels.size() > 0) logLevels.resize(logLevels.size() - 1); } // add dropdown (combo) box mforms::Selector *selector = new_selector_option("workbench.logger:LogLevel", logLevels, false); selector->set_name("Log Level"); selector->set_tooltip( _("Log level determines how serious a message has to be before it gets logged. For example, an error is more " "serious than a warning, a warning is more serious than an info, etc. So if log level is set to error, " "anything less serious (warning, info, etc) will not be logged. If log level is set to warning, both warning " "and error will still be logged, but info and anything lower will not. None disables all logging.")); logTable->add_option(selector, _("Log Level"), "Log Level Information", _("Sets the \"chattyness\" of logs. Choices further down the list " "produce more output than the ones that preceed them.")); // callback: on user selection, set log level selector->signal_changed()->connect([selector]() { bool ok = base::Logger::active_level(selector->get_string_value()); if (ok) logInfo("Logger set to level '%s' in preferences menu\n", base::Logger::active_level().c_str()); assert(ok); }); } mforms::View *PreferencesForm::create_model_defaults_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Model Defaults"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Column Defaults")); mforms::Table *table = mforms::manage(new mforms::Table()); table->set_padding(12); table->set_column_spacing(4); table->set_row_spacing(8); table->set_column_count(4); table->set_row_count(2); frame->add(table); mforms::TextEntry *entry; table->add(new_label(_("PK Column Name:"), "Primary Key Column", true), 0, 1, 0, 1, mforms::HFillFlag); entry = new_entry_option("PkColumnNameTemplate", false); entry->set_tooltip( _("Substitutions:\n" "%table% - name of the table\n" "May be used as %table|upper%, %table|lower%, %table|capitalize%, %table|uncapitalize%")); table->add(entry, 1, 2, 0, 1, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("PK Column Type:"), "Primary Key Type", true), 2, 3, 0, 1, mforms::HFillFlag); entry = new_entry_option("DefaultPkColumnType", false); entry->set_tooltip( _("Default type for use in newly added primary key columns.\nSpecify a column type name or a user defined " "type.\nFlags such as UNSIGNED are not accepted.")); table->add(entry, 3, 4, 0, 1, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("Column Name:"), "Column Name", true), 0, 1, 1, 2, mforms::HFillFlag); entry = new_entry_option("ColumnNameTemplate", false); entry->set_tooltip( _("Substitutions:\n" "%table% - name of the table")); table->add(entry, 1, 2, 1, 2, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("Column Type:"), "Column Type", true), 2, 3, 1, 2, mforms::HFillFlag); entry = new_entry_option("DefaultColumnType", false); entry->set_tooltip( _("Default type for use in newly added columns.\nSpecify a column type name or a user defined type.\nFlags such " "as UNSIGNED are not accepted.")); table->add(entry, 3, 4, 1, 2, mforms::HFillFlag | mforms::HExpandFlag); box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Foreign Key/Relationship Defaults")); frame->set_name("Foreign Key and Relationship Defaults"); mforms::Table *table = mforms::manage(new mforms::Table()); table->set_padding(8); frame->add(table); table->set_row_spacing(8); table->set_column_spacing(8); table->set_row_count(3); table->set_column_count(4); mforms::TextEntry *entry; table->add(new_label(_("FK Name:"), "Foreign Key", true), 0, 1, 0, 1, mforms::HFillFlag); entry = new_entry_option("FKNameTemplate", false); #define SUBS_HELP \ _("Substitutions:\n" \ "%table%, %stable% - name of the source table\n" \ "%dtable% - name of the destination table (where FK is added)\n" \ "%column%, %scolumn% - name of the source column\n" \ "%dcolumn% - name of the destination column\n" \ "May be used as %table|upper%, %table|lower%, %table|capitalize% or %table|uncapitalize%") entry->set_tooltip(SUBS_HELP); table->add(entry, 1, 2, 0, 1, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("Column Name:"), "Column Name", true), 2, 3, 0, 1, mforms::HFillFlag); entry = new_entry_option("FKColumnNameTemplate", false); entry->set_tooltip(SUBS_HELP); table->add(entry, 3, 4, 0, 1, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("ON UPDATE:"), "On Update", true), 0, 1, 1, 2, mforms::HFillFlag); table->add(new_selector_option("db.ForeignKey:updateRule"), 1, 2, 1, 2, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("ON DELETE:"), "On Delete", true), 2, 3, 1, 2, mforms::HFillFlag); table->add(new_selector_option("db.ForeignKey:deleteRule"), 3, 4, 1, 2, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("Associative Table Name:"), "Associative Table Name", true), 0, 1, 2, 3, mforms::HFillFlag); entry = new_entry_option("AuxTableTemplate", false); entry->set_tooltip( _("Substitutions:\n" "%stable% - name of the source table\n" "%dtable% - name of the destination table")); table->add(entry, 1, 2, 2, 3, mforms::HFillFlag | mforms::HExpandFlag); table->add(new_label(_("for n:m relationships"), "For N to M Relationships"), 2, 4, 2, 3, mforms::HFillFlag); box->add(frame, false); } return box; } static void show_target_version(const workbench_physical_ModelRef &model, mforms::TextEntry *entry) { if (*model->catalog()->version()->releaseNumber() < 0) entry->set_value(base::strfmt("%li.%li", (long)*model->catalog()->version()->majorNumber(), (long)*model->catalog()->version()->minorNumber())); else entry->set_value(base::strfmt("%li.%li.%li", (long)*model->catalog()->version()->majorNumber(), (long)*model->catalog()->version()->minorNumber(), (long)*model->catalog()->version()->releaseNumber())); } static void update_target_version(workbench_physical_ModelRef model, mforms::TextEntry *entry) { GrtVersionRef version = bec::parse_version(entry->get_string_value()); model->catalog()->version(version); version->owner(model); } mforms::View *PreferencesForm::create_mysql_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("MySQL"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Model")); mforms::Table *table = mforms::manage(new mforms::Table()); table->set_padding(8); frame->add(table); table->set_row_count(2); table->set_column_count(2); if (!_model.is_valid()) { table->add(new_label(_("Default Target MySQL Version:"), "Default Target version", true), 0, 1, 0, 1, 0); version_entry = new_entry_option("DefaultTargetMySQLVersion", false); version_entry->set_tooltip(VALID_VERSION_TOOLTIP); version_entry->signal_changed()->connect(std::bind(&PreferencesForm::version_changed, this, version_entry)); table->add(version_entry, 1, 2, 0, 1, mforms::HExpandFlag | mforms::HFillFlag); } else { // if editing model options, display the catalog version Option *option = new Option(); mforms::TextEntry *entry = mforms::manage(new mforms::TextEntry()); entry->signal_changed()->connect(std::bind(&PreferencesForm::version_changed, this, entry)); entry->set_tooltip(VALID_VERSION_TOOLTIP); option->view = mforms::manage(entry); option->show_value = std::bind(show_target_version, _model, entry); option->update_value = std::bind(update_target_version, _model, entry); _options.push_back(option); table->add(new_label(_("Target MySQL Version:"), "Target Version", true), 0, 1, 0, 1, 0); table->add(entry, 1, 2, 0, 1, mforms::HExpandFlag | mforms::HFillFlag); } box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Model Table Defaults")); mforms::Box *tbox = mforms::manage(new mforms::Box(true)); tbox->set_padding(8); frame->add(tbox); tbox->add(new_label(_("Default Storage Engine:"), "Default Storage Engine", true), false, false); tbox->add(new_selector_option("db.mysql.Table:tableEngine"), true, true); box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Forward Engineering and Synchronization")); mforms::Box *tbox = mforms::manage(new mforms::Box(true)); mforms::TextEntry *entry; tbox->set_padding(8); frame->add(tbox); tbox->add(new_label(_("SQL_MODE to be used in generated scripts:"), "Mode for Generated Scripts", true), false, false); tbox->add(entry = new_entry_option("SqlGenerator.Mysql:SQL_MODE", false), true, true); entry->set_tooltip(_("The default value of ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION is recommended.")); entry->set_name("SQL Mode Scripts"); box->add(frame, false); } return box; } mforms::View *PreferencesForm::create_diagram_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Diagram"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("All Objects")); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); mforms::CheckBox *check; check = new_checkbox_option("workbench.physical.ObjectFigure:Expanded"); check->set_text(_("Expand New Objects")); check->set_tooltip(_("Set the initial state of newly created objects to expanded (or collapsed)")); vbox->add(check, false); check = new_checkbox_option("SynchronizeObjectColors"); check->set_text(_("Propagate Object Color Changes to All Diagrams")); check->set_tooltip( _("If an object figure's color is changed, all figures in all diagrams that represent the same object are also " "updated")); vbox->add(check, false); box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Tables")); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); mforms::CheckBox *check; check = new_checkbox_option("workbench.physical.TableFigure:ShowColumnTypes"); check->set_text(_("Show Column Types")); check->set_tooltip(_("Show the column types along their names in table figures")); vbox->add(check, false); check = new_checkbox_option("workbench.physical.TableFigure:ShowSchemaName"); check->set_text(_("Show Schema Name")); check->set_tooltip(_("Show owning schema name in the table titlebar figures")); vbox->add(check, false); { mforms::Box *hbox = mforms::manage(new mforms::Box(true)); mforms::TextEntry *entry = new_entry_option("workbench.physical.TableFigure:MaxColumnTypeLength", true); hbox->set_spacing(4); // label->set_size(200, -1); entry->set_max_length(5); entry->set_size(50, -1); hbox->add(new_label(_("Max. Length of ENUMs and SETs to Display:"), "Maximum Length of Enumerates and Sets", true), false, false); hbox->add(entry, false); vbox->add(hbox, false); } check = new_checkbox_option("workbench.physical.TableFigure:ShowColumnFlags"); check->set_text(_("Show Column Flags")); check->set_tooltip(_("Show column flags such as NOT NULL or UNSIGNED along their names in table figures")); vbox->add(check, false); { mforms::Box *hbox = mforms::manage(new mforms::Box(true)); mforms::TextEntry *entry = new_entry_option("workbench.physical.TableFigure:MaxColumnsDisplayed", true); mforms::Label *descr = mforms::manage(new mforms::Label()); hbox->set_spacing(4); // label->set_size(200, -1); entry->set_max_length(5); entry->set_size(50, -1); descr->set_text(_("Larger tables will be truncated.")); descr->set_name("Truncate Large tables"); descr->set_style(mforms::SmallHelpTextStyle); hbox->add(new_label(_("Max. Number of Columns to Display:"), "Maximum Columns", true), false, false); hbox->add(entry, false); hbox->add(descr, true, true); vbox->add(hbox, false); } box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Routines")); mforms::Box *hbox = mforms::manage(new mforms::Box(true)); hbox->set_padding(8); hbox->set_spacing(4); frame->add(hbox); mforms::TextEntry *entry; hbox->add(new_label(_("Trim Routine Names Longer Than"), "Trim Routine Names"), false); entry = new_entry_option("workbench.physical.RoutineGroupFigure:MaxRoutineNameLength", true); entry->set_size(60, -1); entry->set_max_length(3); hbox->add(entry, false); hbox->add(new_label(_("characters"), "Characters"), false); box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Relationships/Connections")); frame->set_name("Relationships and Connections"); mforms::Box *vbox = mforms::manage(new mforms::Box(false)); vbox->set_padding(8); vbox->set_spacing(8); frame->add(vbox); mforms::CheckBox *check; check = new_checkbox_option("workbench.physical.Diagram:DrawLineCrossings"); check->set_text(_("Draw Line Crossings (slow in large diagrams)")); check->set_name("Draw Linw Crossings"); vbox->add(check, false); check = new_checkbox_option("workbench.physical.Connection:ShowCaptions"); check->set_text(_("Show Captions")); check->set_name("Show Captions"); vbox->add(check, false); check = new_checkbox_option("workbench.physical.Connection:CenterCaptions"); check->set_text(_("Center Captions Over Line")); check->set_name("Center Captions Over Line"); vbox->add(check, false); box->add(frame, false); } return box; } static void show_text_option(grt::DictRef options, const std::string &option_name, mforms::TextBox *text) { text->set_value(options.get_string(option_name)); } static void update_text_option(grt::DictRef options, const std::string &option_name, mforms::TextBox *text) { options.gset(option_name, text->get_string_value()); } void PreferencesForm::change_font_option(const std::string &option, const std::string &value) { std::vector<std::string>::const_iterator it; if ((it = std::find(_font_options.begin(), _font_options.end(), option)) != _font_options.end()) { int i = (int)(it - _font_options.begin()); _font_list.node_at_row(i)->set_string(1, value); } } void PreferencesForm::font_preset_changed() { int i = _font_preset.get_selected_index(); if (i >= 0) { wb::WBContextUI::get()->set_wb_options_value(_model.is_valid() ? _model.id() : "", "workbench.physical.FontSet:Name", font_sets[i].name); change_font_option("workbench.physical.TableFigure:TitleFont", font_sets[i].object_title_font); change_font_option("workbench.physical.TableFigure:SectionFont", font_sets[i].object_section_font); change_font_option("workbench.physical.TableFigure:ItemsFont", font_sets[i].object_item_font); change_font_option("workbench.physical.ViewFigure:TitleFont", font_sets[i].object_title_font); change_font_option("workbench.physical.RoutineGroupFigure:TitleFont", font_sets[i].object_title_font); change_font_option("workbench.physical.RoutineGroupFigure:ItemsFont", font_sets[i].object_item_font); change_font_option("workbench.physical.Connection:CaptionFont", font_sets[i].object_item_font); change_font_option("workbench.physical.Layer:TitleFont", font_sets[i].object_item_font); change_font_option("workbench.model.NoteFigure:TextFont", font_sets[i].object_item_font); } } mforms::View *PreferencesForm::create_appearance_page() { mforms::Box *box = mforms::manage(new mforms::Box(false)); box->set_spacing(8); box->set_name("Appearance"); { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Color Presets")); mforms::Table *table = mforms::manage(new mforms::Table()); table->set_padding(8); table->set_row_spacing(4); table->set_column_spacing(4); table->set_row_count(2); table->set_column_count(2); frame->add(table); mforms::TextBox *text; table->add(new_label(_("Colors available when creating tables, views etc"), "Available Colors"), 0, 1, 0, 1, mforms::HFillFlag); text = mforms::manage(new mforms::TextBox(mforms::VerticalScrollBar)); text->set_size(200, 100); table->add(text, 0, 1, 1, 2, mforms::FillAndExpand); Option *option = new Option(); _options.push_back(option); option->view = text; option->show_value = std::bind(show_text_option, get_options(), "workbench.model.ObjectFigure:ColorList", text); option->update_value = std::bind(update_text_option, get_options(), "workbench.model.ObjectFigure:ColorList", text); table->add(new_label(_("Colors available when creating layers, notes etc"), "Available Colors"), 1, 2, 0, 1, mforms::HFillFlag); text = mforms::manage(new mforms::TextBox(mforms::VerticalScrollBar)); text->set_size(200, 100); table->add(text, 1, 2, 1, 2, mforms::FillAndExpand); option = new Option(); _options.push_back(option); option->view = text; option->show_value = std::bind(&show_text_option, get_options(), "workbench.model.Figure:ColorList", text); option->update_value = std::bind(&update_text_option, get_options(), "workbench.model.Figure:ColorList", text); box->add(frame, false); } { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Fonts")); mforms::Box *content = mforms::manage(new mforms::Box(false)); content->set_padding(5); frame->add(content); mforms::Box *hbox = mforms::manage(new mforms::Box(true)); content->add(hbox, false, true); hbox->set_spacing(12); hbox->set_padding(12); _font_preset.set_name("Font"); _font_preset.signal_changed()->connect(std::bind(&PreferencesForm::font_preset_changed, this)); std::string font_name; wb::WBContextUI::get()->get_wb_options_value(_model.is_valid() ? _model.id() : "", "workbench.physical.FontSet:Name", font_name); for (size_t i = 0; font_sets[i].name; i++) { // skip font options that are not modeling specific if (base::hasPrefix(font_sets[i].name, "workbench.general") || base::hasPrefix(font_sets[i].name, "workbench.scripting")) continue; _font_preset.add_item(font_sets[i].name); if (font_sets[i].name == font_name) _font_preset.set_selected((int)i); } mforms::Label *label = mforms::manage(new mforms::Label("Configure Fonts For:")); label->set_name("Configure Fonts"); hbox->add(label, false, true); hbox->add(&_font_preset, true, true); _font_list.add_column(mforms::StringColumnType, _("Location"), 150, false); _font_list.add_column(mforms::StringColumnType, _("Font"), 150, true); _font_list.end_columns(); content->add(&_font_list, true, true); box->add(frame, true, true); } return box; } /** * Theming and colors page. */ mforms::View *PreferencesForm::create_fonts_and_colors_page() { Box *content = manage(new Box(false)); content->set_spacing(8); content->set_name("Fonts and Colors"); { OptionTable *table = new OptionTable(this, _("Fonts"), true); table->add_option(new_entry_option("workbench.general.Editor:Font", false), _("SQL Editor:"), "SQL Editor", _("Global font for SQL text editors")); table->add_option(new_entry_option("workbench.general.Resultset:Font", false), _("Resultset Grid:"), "Resultset Grid", _("Resultset grid in SQL Editor")); table->add_option(new_entry_option("workbench.scripting.ScriptingShell:Font", false), _("Scripting Shell:"), "Scripting Shell", _("Scripting Shell output area")); table->add_option(new_entry_option("workbench.scripting.ScriptingEditor:Font", false), _("Script Editor:"), "Script Editor", _("Code editors in scripting shell")); content->add(table, true, true); } #ifdef _MSC_VER { mforms::Panel *frame = mforms::manage(new mforms::Panel(mforms::TitledBoxPanel)); frame->set_title(_("Color Scheme")); mforms::Box *hbox = mforms::manage(new mforms::Box(true)); hbox->add(new_label(_("Select your scheme:"), "Select Scheme"), false, false); mforms::Selector *selector = new_selector_option("ColorScheme", "", true); selector->set_size(250, -1); hbox->add(selector, true, false); mforms::Label *help = new_label(_("The scheme that determines the core colors."), "", false, true); hbox->add(help, true, false); help->set_size(200, -1); frame->add(hbox); content->add(frame, false, true); } #endif return content; } static std::string separate_camel_word(const std::string &word) { std::string result; for (std::string::const_iterator c = word.begin(); c != word.end(); ++c) { if (!result.empty() && *c >= 'A' && *c <= 'Z') result.append(" "); result.append(1, *c); } return result; } void PreferencesForm::show_colors_and_fonts() { std::vector<std::string> options = wb::WBContextUI::get()->get_wb_options_keys(""); _font_options.clear(); _font_list.clear(); for (std::vector<std::string>::const_iterator iter = options.begin(); iter != options.end(); ++iter) { if (base::hasPrefix(*iter, "workbench.general") || base::hasPrefix(*iter, "workbench.scripting")) continue; if (base::hasSuffix(*iter, "Font") && base::hasPrefix(*iter, "workbench.")) { std::string::size_type pos = iter->find(':'); if (pos != std::string::npos) { try { std::string part = iter->substr(pos + 1); std::string figure = base::split(iter->substr(0, pos), ".")[2]; std::string caption; part = part.substr(0, part.length() - 4); // substitute some figure names figure = base::replaceString(figure, "NoteFigure", "TextFigure"); caption = separate_camel_word(figure) + " " + part; mforms::TreeNodeRef node = _font_list.add_node(); std::string value; wb::WBContextUI::get()->get_wb_options_value("", *iter, value); node->set_string(0, caption); node->set_string(1, value); _font_options.push_back(*iter); } catch (...) { } } } } } //-------------------------------------------------------------------------------------------------- void PreferencesForm::updateColorsAndFonts() { for (int c = _font_list.count(), i = 0; i < c; i++) { std::string value = _font_list.root_node()->get_child(i)->get_string(1); wb::WBContextUI::get()->set_wb_options_value("", _font_options[i], value); } } //-------------------------------------------------------------------------------------------------- void PreferencesForm::toggle_use_global() { _tabview.set_enabled(!_use_global.get_active()); } //-------------------------------------------------------------------------------------------------- static struct RegisterNotifDocs_preferences_form { RegisterNotifDocs_preferences_form() { base::NotificationCenter::get()->register_notification( "GRNPreferencesDidCreate", "preferences", "Sent when the Preferences window is created.", "", "options - the options dictionary being edited\n" "or\n" "model-options - the model specific options dictionary being changed\n" "model-id - the object id of the model for which the options are being changed"); base::NotificationCenter::get()->register_notification( "GRNPreferencesWillOpen", "preferences", "Sent when Preferences window is about to be shown on screen.", "", "options - the options dictionary being edited\n" "or\n" "model-options - the model specific options dictionary being changed\n" "model-id - the object id of the model for which the options are being changed"); base::NotificationCenter::get()->register_notification( "GRNPreferencesDidClose", "preferences", "Sent after Preferences window was closed.", "", "saved - 1 if the user chose to save the options changed or 0 if changes were cancelled\n" "options - the options dictionary being edited\n" "or\n" "model-options - the model specific options dictionary being changed\n" "model-id - the object id of the model for which the options are being changed\n"); } } initdocs_preferences_form;