backend/wbprivate/sqlide/query_side_palette.cpp (550 lines of code) (raw):

/* * Copyright (c) 2011, 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 <boost/signals2/signal.hpp> #include "wb_sql_editor_form.h" #include "wb_sql_editor_panel.h" #include "query_side_palette.h" #include "wb_sql_editor_snippets.h" #include "wb_sql_editor_help.h" #include "grt/tree_model.h" #include "snippet_popover.h" #include "snippet_list.h" #include "grt/grt_manager.h" #include "base/geometry.h" #include "base/notifications.h" #include "base/drawing.h" #include "base/log.h" #include "mforms/toolbar.h" #include "mforms/hypertext.h" #include "mforms/scrollpanel.h" #include "mforms/drawbox.h" #include "mforms/utilities.h" #include "mforms/code_editor.h" DEFAULT_LOG_DOMAIN("QuerySidebar"); using namespace mforms; using namespace base; //----------------- SnippetListView ------------------------------------------------------------------------------------ /** * Internal class containing a list of snippet entries in a scrollable list. */ class SnippetListView : public BaseSnippetList { private: friend class QuerySidePalette; wb::SnippetPopover *_snippetPopover; bool _user_snippets_active; bool _shared_snippets_active; private: DbSqlEditorSnippets *model() { return dynamic_cast<DbSqlEditorSnippets *>(_model); } void popover_closed() { if (getPopover()->has_changed()) { std::string title = getPopover()->get_heading(); model()->set_field(bec::NodeId(_selected_index), DbSqlEditorSnippets::Description, title); std::string sub_title = getPopover()->get_text(); model()->set_field(bec::NodeId(_selected_index), DbSqlEditorSnippets::Script, sub_title); if (_selected_snippet) set_snippet_info(_selected_snippet, title, sub_title); model()->save(); refresh_snippets(); set_needs_repaint(); } } //-------------------------------------------------------------------------------------------------------------------- void prepare_context_menu() { _context_menu = manage(new Menu()); _context_menu->set_handler(std::bind(&SnippetListView::on_action, this, std::placeholders::_1)); _context_menu->signal_will_show()->connect(std::bind(&SnippetListView::menu_will_show, this)); _context_menu->add_item(_("Insert Snippet at Cursor"), "insert_text"); _context_menu->add_item(_("Replace Editor Content with Snippet"), "replace_text"); _context_menu->add_item(_("Execute Snippet"), "exec_snippet"); _context_menu->add_separator(); _context_menu->add_item(_("Copy Snippet to Clipboard"), "copy_to_clipboard"); _context_menu->add_separator(); _context_menu->add_item(_("Edit Snippet"), "edit_snippet"); _context_menu->add_item(_("Add Snippet from Editor Content"), "add_snippet"); _context_menu->add_item(_("Delete Snippet"), "del_snippet"); _context_menu->add_separator(); _context_menu->add_item(_("Restore Original Snippet List"), "restore_snippets"); } //-------------------------------------------------------------------------------------------------------------------- void menu_will_show() { bool shared_usable = model()->shared_snippets_usable(); _context_menu->set_item_enabled(0, _selected_index > -1); _context_menu->set_item_enabled(1, _selected_index > -1); _context_menu->set_item_enabled(2, _selected_index > -1); _context_menu->set_item_enabled(4, _selected_index > -1); _context_menu->set_item_enabled(6, _selected_index > -1 && (!_shared_snippets_active || shared_usable)); _context_menu->set_item_enabled(7, (!_shared_snippets_active || shared_usable)); _context_menu->set_item_enabled(8, _selected_index > -1 && (!_shared_snippets_active || shared_usable)); _context_menu->set_item_enabled(10, !_user_snippets_active && !_shared_snippets_active); } //-------------------------------------------------------------------------------------------------------------------- void on_action(const std::string &action) { if (action == "edit_snippet") { if (_selected_snippet) edit_snippet(_selected_snippet); } else model()->activate_toolbar_item(bec::NodeId(_selected_index), action); // Refresh display if we added or removed a snippet. if (action == "add_snippet" || action == "del_snippet" || action == "restore_snippets") refresh_snippets(); } //-------------------------------------------------------------------------------------------------------------------- public: SnippetListView(const std::string &icon_name) : BaseSnippetList(icon_name, DbSqlEditorSnippets::get_instance()), _snippetPopover(nullptr) { _user_snippets_active = false; _shared_snippets_active = false; _defaultSnippetActionCb = [&](int x, int y) { Snippet *snippet = snippet_from_point(x, y); if (snippet != nullptr) { set_selected(snippet); edit_snippet(snippet); } }; prepare_context_menu(); } //-------------------------------------------------------------------------------------------------------------------- wb::SnippetPopover* getPopover() { if (_snippetPopover != nullptr) { return _snippetPopover; } _snippetPopover = new wb::SnippetPopover(this); _snippetPopover->set_size(376, 257); _snippetPopover->signal_closed()->connect(std::bind(&SnippetListView::popover_closed, this)); return _snippetPopover; } //-------------------------------------------------------------------------------------------------------------------- ~SnippetListView() { delete _snippetPopover; _context_menu->release(); } //-------------------------------------------------------------------------------------------------------------------- void edit_new_snippet() { if (!_snippets.empty()) { _selected_index = 0; _selected_snippet = _snippets.front(); edit_snippet(_selected_snippet); getPopover()->set_read_only(false); } } //-------------------------------------------------------------------------------------------------------------------- std::string selected_category() { return model()->selected_category(); } bool shared_snippets_active() const { return _shared_snippets_active; } //-------------------------------------------------------------------------------------------------------------------- /** * Updates the content depending on the selected snippet group. */ void show_category(std::string category) { _user_snippets_active = (category == USER_SNIPPETS); _shared_snippets_active = (category == SHARED_SNIPPETS); try { model()->select_category(category); } catch (std::exception &exc) { logWarning("Error switching snippet category: %s\n", exc.what()); } refresh_snippets(); } //-------------------------------------------------------------------------------------------------------------------- void edit_snippet(Snippet *snippet) { base::Rect bounds = snippet_bounds(snippet); std::pair<int, int> left_top = client_to_screen((int)bounds.left(), (int)bounds.top()); std::pair<int, int> bottom = client_to_screen(0, (int)bounds.bottom()); left_top.second = (left_top.second + bottom.second) / 2; std::string title, description; get_snippet_info(snippet, title, description); getPopover()->set_heading(title); getPopover()->set_read_only(false); getPopover()->set_text(description); getPopover()->set_read_only(true); getPopover()->show(left_top.first, left_top.second, mforms::StartLeft); } //-------------------------------------------------------------------------------------------------------------------- virtual bool mouse_double_click(mforms::MouseButton button, int x, int y) { bool result = BaseSnippetList::mouse_double_click(button, x, y); if (!result) { if (button == MouseButtonLeft) { Snippet *snippet = snippet_from_point(x, y); if (snippet != NULL && snippet == _selected_snippet) { edit_snippet(snippet); result = true; } } } return result; } //-------------------------------------------------------------------------------------------------------------------- void close_popover() { // Check if it's at least created cause maybe we don't need to close it. if (_snippetPopover != nullptr) { getPopover()->close(); } } //-------------------------------------------------------------------------------------------------------------------- // End of internal class SnippetListView. }; //----------------- QuerySidePalette ----------------------------------------------------------------------------------- QuerySidePalette::QuerySidePalette(const SqlEditorForm::Ref &owner) : #ifdef _MSC_VER TabView(mforms::TabViewPalette), #else TabView(mforms::TabViewSelectorSecondary), #endif _owner(owner) { _help_timer = NULL; _automatic_help = bec::GRTManager::get()->get_app_option_int("DbSqlEditor:DisableAutomaticContextHelp", 0) == 0; _switching_help = false; _helpContext = new help::HelpContext(owner->rdbms()->characterSets(), owner->sql_mode(), owner->server_version()); set_name("Query Side Palette"); setInternalName("querySidePalette"); _pending_snippets_refresh = true; mforms::Box *help_page = manage(new Box(false)); _help_toolbar = prepare_help_toolbar(); _help_text = manage(new mforms::HyperText()); // Separate box since we need a border around the content, but not the toolbar. _contentBorder = manage(new Box(false)); // No scoped_connect needed since _help_text is a member variable. scoped_connect(_help_text->signal_link_click(), std::bind(&QuerySidePalette::click_link, this, std::placeholders::_1)); #if _MSC_VER std::string backgroundColor = base::Color::getApplicationColorAsString(AppColorPanelContentArea, false); _help_text->set_font("Tahoma 8"); #elif __APPLE__ std::string backgroundColor = Color::getSystemColor(base::SystemColor::WindowBackgroundColor).to_html(); #else std::string backgroundColor = "#ebebeb"; #endif _help_text->set_back_color(backgroundColor); _contentBorder->set_back_color(backgroundColor); _contentBorder->set_padding(3, 3, 3, 3); _help_text->set_markup_text(""); _current_topic_index = -1; help_page->add(_help_toolbar, false, true); _contentBorder->add(_help_text, true, true); help_page->add(_contentBorder, true, true); add_page(help_page, _("Context Help")); Box *snippet_page = manage(new Box(false)); Box *content_border = manage(new Box(false)); _snippet_list = manage(new SnippetListView("snippet_sql.png")); _snippet_list->set_name("Snippet List"); _snippet_list->setInternalName("Snippet list"); _snippet_box = manage(new ScrollPanel()); _snippet_box->add(_snippet_list); DbSqlEditorSnippets *snippets_model = DbSqlEditorSnippets::get_instance(); std::vector<std::string> snippet_categories = snippets_model->get_category_list(); if (snippet_categories.size() > 0) _snippet_list->show_category(snippet_categories[0]); else _snippet_list->show_category(USER_SNIPPETS); _snippet_toolbar = prepare_snippet_toolbar(); snippet_page->add(_snippet_toolbar, false, true); content_border->add(_snippet_box, true, true); snippet_page->add(content_border, true, true); add_page(snippet_page, "Snippets"); scoped_connect(_snippet_list->signal_selection_changed(), std::bind(&QuerySidePalette::snippet_selection_changed, this)); std::string old_category = bec::GRTManager::get()->get_app_option_string("DbSqlEditor:SelectedSnippetCategory"); if (!old_category.empty()) { mforms::ToolBarItem *item = _snippet_toolbar->find_item("select_category"); item->set_text(old_category); snippet_toolbar_item_activated(item); } snippet_selection_changed(); show_help_hint_or_update(); updateColors(); base::NotificationCenter::get()->add_observer(this, "GNTextSelectionChanged"); base::NotificationCenter::get()->add_observer(this, "GNColorsChanged"); } //---------------------------------------------------------------------------------------------------------------------- QuerySidePalette::~QuerySidePalette() { base::NotificationCenter::get()->remove_observer(this); cancel_timer(); delete _helpContext; } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::cancel_timer() { if (_help_timer != NULL) bec::GRTManager::get()->cancel_timer(_help_timer); } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::handle_notification(const std::string &name, void *sender, base::NotificationInfo &info) { // Selection and caret changes notification. // Only act if this side palette is actually visible. if ((name == "GNTextSelectionChanged") && _automatic_help && (get_active_tab() == 0) && is_fully_visible()) { mforms::Object *object = (mforms::Object *)sender; mforms::CodeEditor *code_editor = dynamic_cast<mforms::CodeEditor *>(object); if (code_editor == NULL) return; MySQLEditor *editor = static_cast<MySQLEditor *>(code_editor->get_host()); if (editor != NULL && editor->grtobj().is_valid()) { SqlEditorForm::Ref form = _owner.lock(); cancel_timer(); _help_timer = bec::GRTManager::get()->run_every( std::bind(&QuerySidePalette::find_context_help, this, editor), 0.5); } } else if (name == "GNColorsChanged") { updateColors(); } } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::updateColors() { #if _MSC_VER std::string backgroundColor = base::Color::getApplicationColorAsString(AppColorPanelContentArea, false); _help_text->set_font("Tahoma 8"); #elif __APPLE__ std::string backgroundColor = Color::getSystemColor(base::SystemColor::WindowBackgroundColor).to_html(); #else std::string backgroundColor = "#ebebeb"; #endif _help_text->set_back_color(backgroundColor); _contentBorder->set_back_color(backgroundColor); #ifdef _MSC_VER _contentBorder->set_padding(3, 3, 3, 3); _snippet_list->set_back_color(base::Color::getApplicationColorAsString(AppColorPanelContentArea, false)); #elif __APPLE__ _snippet_list->set_back_color(backgroundColor); #else _snippet_list->set_back_color("#f2f2f2"); #endif // Also reload any help text, to update HTML colors. if (!_currentHelpTopic.empty()) { std::string text; help::DbSqlEditorContextHelp::get()->helpTextForTopic(_helpContext, _currentHelpTopic, text); _help_text->set_markup_text(text); } } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::show_help_text_for_topic(const std::string &topic) { if (_currentHelpTopic != topic) { _currentHelpTopic = topic; if (_currentHelpTopic.empty()) { _help_text->set_markup_text(std::string("<hmtl><body style=\"font-family:'") + DEFAULT_FONT_FAMILY + "'; \">" "<div style='text-align: center;'><b style='color: gray; font-size: 16pt;'>No Context Help</b></div></body></html>"); } else { std::string text; help::DbSqlEditorContextHelp::get()->helpTextForTopic(_helpContext, _currentHelpTopic, text); _help_text->set_markup_text(text); _switching_help = true; _quick_jump_item->set_text(_currentHelpTopic); _switching_help = false; } } } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::show_help_hint_or_update() { if (!_automatic_help) { _help_text->set_markup_text( std::string("<hmtl><body style=\"font-family:") + DEFAULT_FONT_FAMILY + ";\">" "<div style='text-align: center;'><b style='color: gray; font-size: 12pt;'>" "Automatic context help is disabled. Use the toolbar to manually get help for the current caret " "position or to toggle automatic help.</b></div></body></html>"); } else { show_help_text_for_topic(_current_topic_index > 0 ? _topic_history[_current_topic_index] : ""); } } //---------------------------------------------------------------------------------------------------------------------- /** * Triggered by timer or manually to find a help topic from the given editor's text + position. */ bool QuerySidePalette::find_context_help(MySQLEditor *editor) { _help_timer = nullptr; // If no editor was given use the currently active one in the SQL editor form. if (editor == nullptr) { SqlEditorForm::Ref form = _owner.lock(); SqlEditorPanel *panel = form->active_sql_editor_panel(); if (panel != nullptr) editor = panel->editor_be().get(); else return false; } size_t caretPosition = editor->cursor_pos(); size_t start, stop; editor->get_current_statement_range(start, stop); // To convert the caret position to a local statement position. std::string topic = help::DbSqlEditorContextHelp::get()->helpTopicFromPosition(_helpContext, editor->current_statement(), caretPosition - start); update_help_history(topic); show_help_text_for_topic(topic); return false; // Don't re-run this task, it's a single-shot. } //---------------------------------------------------------------------------------------------------------------------- /** * Adds the given topic to the topic history if the current topic is not the same and updates * the forward/backward buttons. */ void QuerySidePalette::update_help_history(const std::string &topic) { std::string topic_upper = base::toupper(topic); if (_current_topic_index > 0 && _topic_history[_current_topic_index] == topic_upper) return; if (!topic.empty()) { _current_topic_index++; // Remove everything after the new topic position. _topic_history.erase(_topic_history.begin() + _current_topic_index, _topic_history.end()); _topic_history.push_back(topic_upper); _back_item->set_enabled(_current_topic_index > 0); _forward_item->set_enabled(false); } } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::click_link(const std::string &link) { if (link.find("local:") == 0) { // Internal link. std::string topic = base::trim(link.substr(6, link.size() - 6)); base::replaceStringInplace(topic, "%20", " "); while (topic.find(" ") != std::string::npos) base::replaceStringInplace(topic, " ", " "); update_help_history(topic); show_help_text_for_topic(topic); } else mforms::Utilities::open_url(link); } //---------------------------------------------------------------------------------------------------------------------- ToolBar *QuerySidePalette::prepare_snippet_toolbar() { ToolBar *toolbar = manage(new ToolBar(mforms::SecondaryToolBar)); toolbar->set_name("Snippet Toolbar"); toolbar->setInternalName("snippet_toolbar"); #ifndef __APPLE__ toolbar->set_padding(0, 0, 0, 0); toolbar->set_size(-1, 27); #endif ToolBarItem *item; item = mforms::manage(new ToolBarItem(mforms::SelectorItem)); item->set_name("Select Category"); item->setInternalName("select_category"); DbSqlEditorSnippets *snippets_model = DbSqlEditorSnippets::get_instance(); item->set_selector_items(snippets_model->get_category_list()); scoped_connect(item->signal_activated(), std::bind(&QuerySidePalette::snippet_toolbar_item_activated, this, std::placeholders::_1)); item->set_text(USER_SNIPPETS); item->set_tooltip(_("Select a snippet category for display")); toolbar->add_item(item); item = mforms::manage(new ToolBarItem(mforms::SeparatorItem)); toolbar->add_item(item); item = mforms::manage(new ToolBarItem(mforms::ActionItem)); item->set_name("Replace Text"); item->setInternalName("replace_text"); item->set_icon(App::get()->get_resource_path("snippet_use.png")); item->set_tooltip(_("Replace the current text by this snippet")); scoped_connect(item->signal_activated(), std::bind(&QuerySidePalette::snippet_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(item); item = mforms::manage(new ToolBarItem(mforms::ActionItem)); item->set_name("Insert Text"); item->setInternalName("insert_text"); item->set_icon(App::get()->get_resource_path("snippet_insert.png")); item->set_tooltip(_("Insert the snippet text at the current caret position replacing selected text if there is any")); scoped_connect(item->signal_activated(), std::bind(&QuerySidePalette::snippet_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(item); item = manage(new ToolBarItem(mforms::ActionItem)); item->set_name("Copy To Clipboard"); item->setInternalName("copy_to_clipboard"); item->set_icon(App::get()->get_resource_path("snippet_clipboard.png")); item->set_tooltip(_("Copy the snippet text to the clipboard")); scoped_connect(item->signal_activated(), std::bind(&QuerySidePalette::snippet_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(item); return toolbar; } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::snippet_toolbar_item_activated(ToolBarItem *item) { std::string action = item->getInternalName(); if (action == "select_category") { _snippet_list->show_category(item->get_text()); bec::GRTManager::get()->set_app_option("DbSqlEditor:SelectedSnippetCategory", grt::StringRef(item->get_text())); } else { DbSqlEditorSnippets *snippets_model = DbSqlEditorSnippets::get_instance(); snippets_model->activate_toolbar_item(bec::NodeId(_snippet_list->selected_index()), action); // Refresh display if we added or removed a snippet. if (action == "add_snippet" || action == "del_snippet") _snippet_list->refresh_snippets(); } } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::snippet_selection_changed() { bool has_selection = _snippet_list->selected_index() > -1; _snippet_toolbar->set_item_enabled("copy_to_clipboard", has_selection); _snippet_toolbar->set_item_enabled("replace_text", has_selection); _snippet_toolbar->set_item_enabled("insert_text", has_selection); } //---------------------------------------------------------------------------------------------------------------------- /** * Called by the owning form if the main form changes to remove the popover. */ void QuerySidePalette::close_popover() { _snippet_list->close_popover(); } //---------------------------------------------------------------------------------------------------------------------- ToolBar *QuerySidePalette::prepare_help_toolbar() { ToolBar *toolbar = manage(new ToolBar(mforms::SecondaryToolBar)); toolbar->set_name("Help Toolbar"); toolbar->setInternalName("help_toolbar"); #ifndef __APPLE__ toolbar->set_padding(0, 0, 0, 0); toolbar->set_size(-1, 27); #endif _back_item = manage(new ToolBarItem(mforms::ActionItem)); _back_item->set_name("Back"); _back_item->setInternalName("back"); _back_item->set_icon(App::get()->get_resource_path("wb-toolbar_nav-back.png")); _back_item->set_tooltip(_("One topic back")); _back_item->set_enabled(false); scoped_connect(_back_item->signal_activated(), std::bind(&QuerySidePalette::help_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(_back_item); _forward_item = manage(new ToolBarItem(mforms::ActionItem)); _forward_item->set_name("Forward"); _forward_item->setInternalName("forward"); _forward_item->set_icon(App::get()->get_resource_path("wb-toolbar_nav-forward.png")); _forward_item->set_tooltip(_("One topic forward")); _forward_item->set_enabled(false); scoped_connect(_forward_item->signal_activated(), std::bind(&QuerySidePalette::help_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(_forward_item); toolbar->add_item(manage(new ToolBarItem(mforms::SeparatorItem))); ToolBarItem *item = manage(new ToolBarItem(mforms::ToggleItem)); item->set_name("Toggle Auto Context Help"); item->setInternalName("toggle-auto-context-help"); item->set_icon(App::get()->get_resource_path("wb-toolbar_automatic-help-off.png")); item->set_alt_icon(App::get()->get_resource_path("wb-toolbar_automatic-help-on.png")); item->set_tooltip(_("Toggle automatic context help")); item->set_checked(_automatic_help); scoped_connect(item->signal_activated(), std::bind(&QuerySidePalette::help_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(item); _manual_help_item = manage(new ToolBarItem(mforms::ActionItem)); _manual_help_item->set_name("Manual Context Help"); _manual_help_item->setInternalName("manual-context-help"); _manual_help_item->set_icon(App::get()->get_resource_path("wb-toolbar_manual-help.png")); _manual_help_item->set_tooltip(_("Get context help for the item at the current caret position")); _manual_help_item->set_enabled(!_automatic_help); scoped_connect(_manual_help_item->signal_activated(), std::bind(&QuerySidePalette::help_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(_manual_help_item); toolbar->add_item(manage(new ToolBarItem(mforms::SeparatorItem))); _quick_jump_item = manage(new ToolBarItem(mforms::SelectorItem)); _quick_jump_item->set_name("Quick Jump"); _quick_jump_item->setInternalName("quick_jump"); std::vector<std::string> topic_entries; topic_entries.push_back(_("Jump to")); topic_entries.push_back("SELECT"); topic_entries.push_back("UPDATE"); topic_entries.push_back("INSERT"); topic_entries.push_back("DELETE"); topic_entries.push_back("CREATE TABLE"); topic_entries.push_back("CREATE VIEW"); topic_entries.push_back("CREATE PROCEDURE"); topic_entries.push_back("CREATE FUNCTION"); topic_entries.push_back("ALTER TABLE"); _quick_jump_item->set_selector_items(topic_entries); _quick_jump_item->set_text(_("Jump To")); scoped_connect(_quick_jump_item->signal_activated(), std::bind(&QuerySidePalette::help_toolbar_item_activated, this, std::placeholders::_1)); toolbar->add_item(_quick_jump_item); return toolbar; } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::help_toolbar_item_activated(ToolBarItem *item) { if (_switching_help) return; std::string action = item->getInternalName(); if (action == "back" && _current_topic_index > 0) { std::string topic = _topic_history[--_current_topic_index]; _back_item->set_enabled(_current_topic_index > 0); _forward_item->set_enabled(true); show_help_text_for_topic(topic); return; } if (action == "forward" && _current_topic_index < (int)_topic_history.size() - 1) { std::string topic = _topic_history[++_current_topic_index]; _back_item->set_enabled(true); _forward_item->set_enabled(_current_topic_index < (int)_topic_history.size() - 1); show_help_text_for_topic(topic); return; } if (action == "quick_jump") { std::string topic = _quick_jump_item->get_text(); update_help_history(topic); show_help_text_for_topic(topic); return; } if (action == "toggle-auto-context-help") { _automatic_help = item->get_checked(); _manual_help_item->set_enabled(!_automatic_help); bec::GRTManager::get()->set_app_option("DbSqlEditor:DisableAutomaticContextHelp", grt::IntegerRef(_automatic_help ? 0 : 1)); show_help_hint_or_update(); return; } if (action == "manual-context-help") find_context_help(NULL); if (_current_topic_index >= 0) { if (action == "copy_to_clipboard") { std::pair<std::string, std::string> entry = _topic_cache[_topic_history[_current_topic_index]]; mforms::Utilities::set_clipboard_text(entry.first); } if (action == "copy_html_to_clipboard") { std::pair<std::string, std::string> entry = _topic_cache[_topic_history[_current_topic_index]]; mforms::Utilities::set_clipboard_text(entry.second); } } } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::refresh_snippets() { if (_pending_snippets_refresh && _snippet_list->shared_snippets_active()) { SqlEditorForm::Ref owner(_owner.lock()); try { _snippet_list->model()->load_from_db(owner.get()); _pending_snippets_refresh = false; } catch (std::exception &exc) { logError("Error loading DB snippets: %s\n", exc.what()); } } _snippet_list->refresh_snippets(); } //---------------------------------------------------------------------------------------------------------------------- void QuerySidePalette::edit_last_snippet() { _snippet_list->edit_new_snippet(); } //----------------------------------------------------------------------------------------------------------------------