backend/wbpublic/grt/grt_manager.cpp (641 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/threading.h"
#include "base/log.h"
#include "base/file_utilities.h"
#include "grtpp_module_python.h"
#include "grtpp_module_cpp.h"
#include "python_context.h"
#include "glib/gstdio.h"
#include "objimpl/wrapper/grt_PyObject_impl.h"
#include "base/notifications.h"
#include "base/file_functions.h"
#include "base/file_utilities.h"
#include "base/string_utilities.h"
#include "mforms/utilities.h"
#include "grt/grt_manager.h"
using namespace grt;
using namespace bec;
using namespace base;
DEFAULT_LOG_DOMAIN("GRTManager");
static GThread *main_thread = nullptr;
static void init_all() {
if (main_thread == nullptr) {
main_thread = g_thread_self();
}
}
GRTManager::GRTManager(bool threaded) : _has_unsaved_changes(false), _threaded(threaded), _verbose(false) {
_grt = grt::GRT::get();
_globals_tree_soft_lock_count = 0;
_current_idle_signal = 0;
init_all();
_grt->set_verbose(_verbose);
_terminated = false;
_idle_blocked = false;
_clipboard = 0;
_dispatcher = GRTDispatcher::create_dispatcher(_threaded, true);
_shell = new ShellBE(_dispatcher);
_plugin_manager = _grt->get_native_module<PluginManagerImpl>();
_messages_list = new MessageListStorage(this);
}
GRTManager::Ref GRTManager::get() {
static GRTManager::Ref instance(new GRTManager(true));
return instance;
}
void GRTManager::setVerbose(bool verbose) {
_verbose = verbose;
_grt->set_verbose(_verbose);
}
bool GRTManager::try_soft_lock_globals_tree() {
// returns true if lock count was 0 and then lock it
#if GLIB_CHECK_VERSION(2, 32, 0)
if (g_atomic_int_add(&_globals_tree_soft_lock_count, 1) == 0)
return true;
#else
if (g_atomic_int_exchange_and_add(&_globals_tree_soft_lock_count, 1) == 0)
return true;
#endif
// lock failed, decrement it back
g_atomic_int_add(&_globals_tree_soft_lock_count, -1);
return false;
}
void GRTManager::soft_lock_globals_tree() {
g_atomic_int_add(&_globals_tree_soft_lock_count, 1);
}
void GRTManager::soft_unlock_globals_tree() {
g_atomic_int_add(&_globals_tree_soft_lock_count, -1);
}
bool GRTManager::is_globals_tree_locked() {
return g_atomic_int_get(&_globals_tree_soft_lock_count) != 0;
}
void GRTManager::set_basedir(const std::string &path) {
if (!g_path_is_absolute(path.c_str())) {
gchar *dir = g_get_current_dir();
_basedir = base::makePath(dir, path);
g_free(dir);
} else
_basedir = path;
}
void GRTManager::set_datadir(const std::string &path) {
if (!g_path_is_absolute(path.c_str())) {
gchar *dir = g_get_current_dir();
_datadir = base::makePath(dir, path);
g_free(dir);
} else
_datadir = path;
}
std::string GRTManager::get_data_file_path(const std::string &file) {
return base::makePath(_datadir, file);
}
void GRTManager::set_user_datadir(const std::string &path) {
if (!g_path_is_absolute(path.c_str())) {
gchar *dir = g_get_current_dir();
_user_datadir = base::makePath(dir, path);
g_free(dir);
} else
_user_datadir = path;
}
void GRTManager::set_module_extensions(const std::list<std::string> &extensions) {
_module_extensions = extensions;
}
void GRTManager::set_clipboard(Clipboard *clipb) {
_clipboard = clipb;
}
bool GRTManager::in_main_thread() {
if (main_thread == g_thread_self())
return true;
return false;
}
GRTManager::~GRTManager() {
_dispatcher->shutdown();
_dispatcher.reset();
delete _shell;
_shell = 0;
delete _messages_list;
_messages_list = 0;
for (std::list<Timer *>::iterator iter = _timers.begin(); iter != _timers.end(); ++iter)
delete *iter;
}
void GRTManager::set_search_paths(const std::string &module_sp, const std::string &struct_sp,
const std::string &libraries_sp) {
_module_pathlist = module_sp;
_struct_pathlist = struct_sp;
_libraries_pathlist = libraries_sp;
}
void GRTManager::set_user_extension_paths(const std::string &user_module_path, const std::string &user_library_path,
const std::string &user_script_path) {
_user_module_path = user_module_path;
_user_library_path = user_library_path;
_user_script_path = user_script_path;
_module_pathlist = base::pathlistPrepend(_module_pathlist, user_module_path);
_libraries_pathlist = base::pathlistPrepend(_libraries_pathlist, user_library_path);
}
ShellBE *GRTManager::get_shell() {
return _shell;
}
MessageListStorage *GRTManager::get_messages_list() {
return _messages_list;
}
void GRTManager::task_error_cb(const std::exception &error, const std::string &title) {
mforms::Utilities::show_error(title, error.what(), _("Close"));
}
void GRTManager::execute_grt_task(const std::string &title, const std::function<grt::ValueRef()> &function,
const std::function<void(grt::ValueRef)> &finished_cb) {
GRTTask::Ref task = GRTTask::create_task(title, _dispatcher, function);
// connect finished_cb provided by caller (after ours)
task->signal_finished()->connect(finished_cb);
scoped_connect(task->signal_failed(), std::bind(&GRTManager::task_error_cb, this, std::placeholders::_1, title));
_dispatcher->add_task(task);
}
void GRTManager::add_dispatcher(const GRTDispatcher::Ref dispatcher) {
if (_dispatcher != dispatcher) {
MutexLock disp_map_mutex(_disp_map_mutex);
_disp_map[dispatcher];
}
}
void GRTManager::remove_dispatcher(const GRTDispatcher::Ref dispatcher) {
MutexLock disp_map_mutex(_disp_map_mutex);
if (_disp_map.find(dispatcher) != _disp_map.end())
_disp_map.erase(dispatcher);
}
void GRTManager::show_error(const std::string &message, const std::string &detail, bool important) {
// If we're being called from the GRT thread, then raise a runtime error.
if (main_thread == _dispatcher->get_thread())
throw grt_runtime_error(message, detail);
_shell->write_line("ERROR:" + message);
if (!detail.empty())
_shell->write_line(" " + detail);
if (important)
mforms::Utilities::show_error(message, detail, _("Close"));
}
void GRTManager::show_warning(const std::string &title, const std::string &message, bool important) {
_shell->write_line("WARNING: " + title);
_shell->write_line(" " + message);
// XXX redo
// if (important)
// _warning_cb(title, message);
}
void GRTManager::show_message(const std::string &title, const std::string &message, bool important) {
_shell->write_line(title + ": " + message);
// XXX redo
// if (important)
// _message_cb(2, title, message);
}
void GRTManager::cleanUpAndReinitialize() {
_dispatcher->shutdown();
_dispatcher.reset();
delete _shell;
_shell = 0;
delete _messages_list;
_messages_list = 0;
base::MutexLock lock(_timer_mutex);
for (auto it: _timers) {
delete it;
}
_timers.clear();
for (auto it: _cancelled_timers) {
delete it;
}
_cancelled_timers.clear();
_dispatcher = GRTDispatcher::create_dispatcher(_threaded, true);
_shell = new ShellBE(_dispatcher);
_plugin_manager = _grt->get_native_module<PluginManagerImpl>();
_messages_list = new MessageListStorage(this);
}
void GRTManager::initialize(bool init_python, const std::string &loader_module_path) {
_dispatcher->start();
load_structs();
init_module_loaders(loader_module_path, init_python);
#ifdef _MSC_VER
add_python_module_dir(_basedir + "\\python");
add_python_module_dir(_basedir + "\\modules");
#elif __APPLE__
add_python_module_dir(_basedir + "/plugins");
#else
std::vector<std::string> path(base::split(_module_pathlist, G_SEARCHPATH_SEPARATOR_S));
for (std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i)
add_python_module_dir(*i);
#endif
pyobject_initialize();
load_libraries();
load_modules();
}
bool GRTManager::initialize_shell(const std::string &shell_type) {
if (!_shell->setup(shell_type.empty() ? grt::LanguagePython : shell_type)) {
logWarning("Could not initialize GRT shell of type '%s'\n", shell_type.c_str());
return false;
}
return true;
}
/**
* Cancels all pending idle tasks. Useful if their execution is no longer necessary and can even cause
* a crash because the used objects are going soon.
* Returns true if the task could be completed, false if the manager is currently in in idle execution.
* Warning: canceling idle tasks unconditionally might lead to other problems, so use with extreme care.
*/
bool GRTManager::cancel_idle_tasks() {
// { TODO
// MutexLock disp_map_mutex(_disp_map_mutex);
// for (DispatcherMap::iterator i = _disp_map.begin(), i_end = _disp_map.end(); i != i_end; ++i)
// i->first->cancel_all_tasks();
// }
if (_idle_blocked)
return false;
block_idle_tasks(); // TODO: use idle mutex.
MutexLock lock(_idle_mutex);
_current_idle_signal = 0;
_idle_signals[0].disconnect_all_slots();
_idle_signals[1].disconnect_all_slots();
unblock_idle_tasks();
return true;
}
static void nothing() {
}
void GRTManager::perform_idle_tasks() {
// flush the dispatcher callback queue
{
DispatcherMap copy;
{
MutexLock disp_map_mutex(_disp_map_mutex);
copy = _disp_map;
}
// We need to call main general dispatcher as it's not on the dispatcher list.
if (_dispatcher)
_dispatcher->flush_pending_callbacks();
for (DispatcherMap::iterator i = copy.begin(), i_end = copy.end(); i != i_end; ++i)
i->first->flush_pending_callbacks();
}
if (_shell) {
// flush the shell output buffer
_shell->flush_shell_output();
}
bool locked = _idle_task_blocker_mutex.tryLock();
if (locked) {
try {
if (!_idle_blocked) {
if (!_idle_signals[_current_idle_signal].empty()) {
block_idle_tasks();
int signal_to_emit = 0;
{
MutexLock lock(_idle_mutex);
signal_to_emit = _current_idle_signal;
_current_idle_signal = _current_idle_signal ? 0 : 1;
}
_idle_signals[signal_to_emit]();
_idle_signals[signal_to_emit].disconnect_all_slots();
// XXX disconnect_all_slots() will somehow leave bound functions hanging around until the signal is
// connected to something.. if they hold shared_refs to objects, those will be kept around until
// the signal is connected again, which sounds like a bug.. so we just do a dummy connection to force
// shared refs to be released immediately.. should investigate why is this happening at all
// how to test: put a bp in ~DbSqlEditorForm() and close the SQL Editor... if it is deleted immediately,
// it works as expected, if it only gets deleted after opening another editor, then its broken
_idle_signals[signal_to_emit].connect(std::bind(nothing));
unblock_idle_tasks();
}
}
} catch (...) {
unblock_idle_tasks();
_idle_task_blocker_mutex.unlock();
throw;
}
_idle_task_blocker_mutex.unlock();
}
}
boost::signals2::connection GRTManager::run_once_when_idle(const std::function<void()> &slot) {
if (!slot)
throw std::invalid_argument("Adding null slot for idle");
MutexLock lock(_idle_mutex);
return _idle_signals[_current_idle_signal].connect(slot);
}
boost::signals2::connection GRTManager::run_once_when_idle(base::trackable *owner, const std::function<void()> &slot) {
if (!slot)
throw std::invalid_argument("Adding null slot for idle");
MutexLock lock(_idle_mutex);
boost::signals2::connection tmp(_idle_signals[_current_idle_signal].connect(slot));
owner->track_connection(tmp);
return tmp;
}
void GRTManager::block_idle_tasks() {
_idle_blocked++;
}
void GRTManager::unblock_idle_tasks() {
_idle_blocked--;
}
GRTManager::Timer::Timer(const std::function<bool()> &slot, double interval) {
this->slot = slot;
this->interval = interval;
g_get_current_time(&next_trigger);
g_time_val_add(&next_trigger, (glong)(interval * G_USEC_PER_SEC));
}
bool GRTManager::Timer::trigger() {
bool flag = slot ? slot() : false;
g_get_current_time(&next_trigger);
g_time_val_add(&next_trigger, (glong)(interval * G_USEC_PER_SEC));
return flag;
}
double GRTManager::Timer::delay_for_next_trigger(const GTimeVal &now) {
double delay;
delay = next_trigger.tv_sec - now.tv_sec;
delay += (double)(next_trigger.tv_usec - now.tv_usec) / G_USEC_PER_SEC;
return delay;
}
GRTManager::Timer *GRTManager::run_every(const std::function<bool()> &slot, double seconds) {
Timer *timer = new Timer(slot, seconds);
GTimeVal now;
g_get_current_time(&now);
double delay = timer->delay_for_next_trigger(now);
{
base::MutexLock lock(_timer_mutex);
// insert it in order of delay for next trigger
bool inserted = false;
for (std::list<Timer *>::iterator iter = _timers.begin(); iter != _timers.end(); ++iter) {
if ((*iter)->delay_for_next_trigger(now) > delay) {
_timers.insert(iter, timer);
inserted = true;
break;
}
}
if (!inserted)
_timers.push_back(timer);
}
_timeout_request();
return timer;
}
void GRTManager::cancel_timer(GRTManager::Timer *timer) {
base::MutexLock lock(_timer_mutex);
std::list<Timer *>::iterator it = std::find(_timers.begin(), _timers.end(), timer);
if (it != _timers.end()) {
delete *it;
_timers.erase(it);
} else
_cancelled_timers.insert(timer);
// if the timer is not in the timers list, then it may be getting executed,
// so add it to a list of timers so it doesn't get readded to the timers list
}
void GRTManager::flush_timers() {
GTimeVal now;
g_get_current_time(&now);
std::list<Timer *> triggered;
// first get a list of timers that trigger now
std::list<Timer *>::iterator next, iter = _timers.begin();
{
base::MutexLock lock(_timer_mutex);
while (iter != _timers.end()) {
next = iter;
++next;
if ((*iter)->delay_for_next_trigger(now) > 0.00001)
break;
triggered.push_back(*iter);
_timers.erase(iter);
iter = next;
}
}
// after this point it's impossible for the timer to be cancelled
// because it is not in the timers list anymore
// and then trigger and reinsert them to the timer list
for (iter = triggered.begin(); iter != triggered.end(); ++iter) {
// the timer can get cancelled at this point or later, if it happens after
// its executed, then it will be deleted in the next iteration
if ((*iter)->trigger()) // if callback returns false, don't readd it
{
double delay = (*iter)->delay_for_next_trigger(now);
base::MutexLock lock(_timer_mutex);
if (_cancelled_timers.find(*iter) == _cancelled_timers.end()) {
// insert it in order of delay for next trigger
bool inserted = false;
for (std::list<Timer *>::iterator jter = _timers.begin(); jter != _timers.end(); ++jter) {
if ((*jter)->delay_for_next_trigger(now) > delay) {
_timers.insert(jter, *iter);
inserted = true;
break;
}
}
if (!inserted)
_timers.push_back(*iter);
} else
delete *iter;
} else {
base::MutexLock lock(_timer_mutex);
delete *iter;
}
}
base::MutexLock lock(_timer_mutex);
_cancelled_timers.clear();
}
double GRTManager::delay_for_next_timeout() {
double delay = -1;
base::MutexLock lock(_timer_mutex);
if (!_timers.empty()) {
GTimeVal now;
g_get_current_time(&now);
delay = _timers.front()->delay_for_next_trigger(now);
if (delay < 0)
delay = 0.0;
}
return delay;
}
void GRTManager::set_timeout_request_slot(const std::function<void()> &slot) {
_timeout_request = slot;
}
bool GRTManager::load_structs() {
if (_verbose)
_shell->write_line(_("Loading struct definitions..."));
int c, count = 0;
gchar **paths = g_strsplit(_struct_pathlist.c_str(), G_SEARCHPATH_SEPARATOR_S, 0);
for (int i = 0; paths[i]; i++) {
if (g_file_test(paths[i], G_FILE_TEST_IS_DIR)) {
if (_verbose)
_shell->writef(_("Looking for struct files in '%s'.\n"), paths[i]);
try {
c = _grt->scan_metaclasses_in(paths[i]);
count += c;
} catch (std::exception &exc) {
_shell->writef(_("Could not load structs from '%s': %s\n"), paths[i], exc.what());
}
}
}
_grt->end_loading_metaclasses();
_shell->writef(_("Registered %i GRT classes.\n"), count);
g_strfreev(paths);
return false;
}
bool GRTManager::init_module_loaders(const std::string &loader_module_path, bool init_python) {
if (_verbose)
_shell->write_line(_("Initializing Loaders..."));
if (!init_loaders(loader_module_path, init_python))
_shell->write_line(_("Failed initializing Loaders."));
return true;
}
bool GRTManager::load_libraries() {
gchar **paths = g_strsplit(_libraries_pathlist.c_str(), G_SEARCHPATH_SEPARATOR_S, 0);
for (size_t i = 0; paths[i]; i++) {
GDir *dir = g_dir_open(paths[i], 0, NULL);
if (dir) {
const gchar *fname;
while ((fname = g_dir_read_name(dir))) {
gchar *path;
path = g_strdup_printf("%s%c%s", paths[i], G_DIR_SEPARATOR, fname);
if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
ModuleLoader *loader = _grt->get_module_loader_for_file(fname);
if (loader) {
if (_verbose)
_shell->write_line(strfmt(_("Loading GRT library %s"), path));
loader->load_library(path);
}
}
g_free(path);
}
g_dir_close(dir);
}
}
g_strfreev(paths);
return true;
}
bool GRTManager::load_modules() {
if (_verbose)
_shell->write_line(_("Loading modules..."));
scan_modules_grt(_module_extensions, false);
return true;
}
void GRTManager::rescan_modules() {
load_modules();
}
bool GRTManager::init_loaders(const std::string &loader_module_path, bool init_python) {
if (init_python) {
try {
if (grt::init_python_support(loader_module_path)) {
if (_verbose)
_shell->write_line(_("Python loader initialized."));
}
} catch (std::exception &exc) {
_shell->write_line(strfmt("Error initializing Python loader: %s", exc.what()));
}
}
return true;
}
int GRTManager::do_scan_modules(const std::string &path, const std::list<std::string> &extensions, bool refresh) {
int c;
if (!g_file_test(path.c_str(), G_FILE_TEST_IS_DIR))
return 0;
if (_verbose)
_grt->send_output(strfmt(_("Looking for modules in '%s'.\n"), path.c_str()));
try {
c = _grt->scan_modules_in(path, _basedir, extensions.empty() ? _module_extensions : extensions, refresh);
} catch (std::exception &exc) {
_grt->send_output(strfmt(_("Error scanning for modules: %s\n"), exc.what()));
return 0;
}
if (_verbose)
_grt->send_output(strfmt(_("%i modules found\n"), c));
return c;
}
void GRTManager::scan_modules_grt(const std::list<std::string> &extensions, bool refresh) {
int c, count = 0;
gchar **paths = g_strsplit(_module_pathlist.c_str(), G_SEARCHPATH_SEPARATOR_S, 0);
for (int i = 0; paths[i]; i++) {
c = do_scan_modules(paths[i], extensions, refresh);
if (c >= 0)
count += c;
}
_grt->end_loading_modules();
_shell->writef(_("Registered %i modules (from %i files).\n"), _grt->get_modules().size(), count);
g_strfreev(paths);
}
void GRTManager::set_app_option_slots(const std::function<grt::ValueRef(std::string)> &slot,
const std::function<void(std::string, grt::ValueRef)> &set_slot) {
_get_app_option_slot = slot;
_set_app_option_slot = set_slot;
}
void GRTManager::set_app_option(const std::string &name, const grt::ValueRef &value) {
if (_set_app_option_slot)
_set_app_option_slot(name, value);
}
grt::ValueRef GRTManager::get_app_option(const std::string &name) {
if (_get_app_option_slot)
return _get_app_option_slot(name);
return grt::ValueRef();
}
std::string GRTManager::get_app_option_string(const std::string &name, std::string default_) {
grt::ValueRef value(get_app_option(name));
if (value.is_valid() && grt::StringRef::can_wrap(value))
return *grt::StringRef::cast_from(value);
return default_;
}
long GRTManager::get_app_option_int(const std::string &name, long default_) {
grt::ValueRef value(get_app_option(name));
if (value.is_valid() && grt::IntegerRef::can_wrap(value))
return (long)*grt::IntegerRef::cast_from(value);
return default_;
}
std::string GRTManager::get_tmp_dir() {
// Add the current process ID to the path to make this unique.
std::string res = g_get_tmp_dir();
if (base::hasSuffix(res, "/") || base::hasSuffix(res, "\\"))
res.resize(res.size() - 1);
res += "/" + std::string("mysql-workbench-");
#ifdef _MSC_VER
res += std::to_string(GetCurrentProcessId()) + "/";
#else
res += std::to_string(::getpid()) + "/";
#endif
base::create_directory(res, 0700, true);
return res;
}
std::string GRTManager::get_unique_tmp_subdir() {
for (;;) {
std::string unique_name = get_guid();
// get_guid returns upper-lower case combined string (base64), which could potentially lead
// to duplicate dirnames in case-insensitive filesystems
std::string path = get_tmp_dir().append(unique_name).append("/");
if (!g_file_test(path.c_str(), G_FILE_TEST_EXISTS))
return path;
}
return "";
}
void GRTManager::cleanup_tmp_dir() {
(void)base_rmdir_recursively(get_tmp_dir().c_str());
}
void GRTManager::push_status_text(const std::string &message) {
_status_text_slot(message);
}
void GRTManager::replace_status_text(const std::string &message) {
// pop_status_text();
push_status_text(message);
}
void GRTManager::pop_status_text() {
_status_text_slot("");
}
void GRTManager::set_status_slot(const std::function<void(std::string)> &slot) {
_status_text_slot = slot;
}
//--------------------------------------------------------------------------------------------------
struct sortpluginbyrating {
bool operator()(const app_PluginRef &a, const app_PluginRef &b) const {
return a->rating() < b->rating();
}
};
bec::MenuItemList GRTManager::get_plugin_context_menu_items(const std::list<std::string> &groups,
const bec::ArgumentPool &argument_pool) {
// get all plugins in wanted groups
std::vector<app_PluginRef> plugins;
for (std::list<std::string>::const_iterator group = groups.begin(); group != groups.end(); ++group) {
std::vector<app_PluginRef> tmp(get_plugin_manager()->get_plugins_for_group(*group));
for (std::vector<app_PluginRef>::const_iterator pl = tmp.begin(); pl != tmp.end(); ++pl) {
if (std::find(plugins.begin(), plugins.end(), *pl) == plugins.end()) {
plugins.push_back(*pl);
}
}
}
// sort by rating
std::sort(plugins.begin(), plugins.end(), sortpluginbyrating());
bec::MenuItemList items;
// filter by available arguments
for (std::vector<app_PluginRef>::const_iterator pl = plugins.begin(); pl != plugins.end(); ++pl) {
// if (check_plugin_runnable(*pl, argument_pool))
{
bec::MenuItem item;
item.caption = *(*pl)->caption() + ((*pl)->pluginType() == "gui" ? "..." : "");
item.internalName = "plugin:" + *(*pl)->name();
item.accessibilityName = *(*pl)->accessibilityName();
item.enabled = check_plugin_runnable(*pl, argument_pool);
item.accessibilityName = (*pl)->accessibilityName();
if (item.caption.empty())
item.caption = item.accessibilityName;
item.type = MenuAction;
items.push_back(item);
}
}
return items;
}
//--------------------------------------------------------------------------------------------------
bool GRTManager::check_plugin_runnable(const app_PluginRef &plugin, const bec::ArgumentPool &argpool,
bool debug_output) {
bool debug_args = strstr(plugin->name().c_str(), "-debugargs-") != 0 || debug_output;
for (size_t c = plugin->inputValues().count(), i = 0; i < c; i++) {
app_PluginInputDefinitionRef pdef(plugin->inputValues()[i]);
std::string searched_key;
if (!argpool.find_match(pdef, searched_key, false).is_valid()) {
if (debug_args) {
_grt->send_output(base::strfmt("Debug: Plugin %s cannot execute because argument %s is not available\n",
plugin->name().c_str(), searched_key.c_str()));
_grt->send_output("Debug: Available arguments:\n");
argpool.dump_keys(
std::bind<void>([this](const std::string &str) { _grt->send_output(str); }, std::placeholders::_1));
}
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
void GRTManager::open_object_editor(const GrtObjectRef &object, bec::GUIPluginFlags flags) {
try {
grt::BaseListRef args(AnyType);
args.ginsert(object);
app_PluginRef plugin(_plugin_manager->select_plugin_for_input("catalog/Editors", args));
if (!plugin.is_valid())
plugin = _plugin_manager->select_plugin_for_input("model/Editors", args);
if (plugin.is_valid())
_plugin_manager->open_gui_plugin(plugin, args, flags);
else {
logError("No suitable editor found for object of type '%s'.",
object.get_metaclass()->get_attribute("caption").c_str());
mforms::Utilities::show_error(_("Edit Object"), strfmt(_("No suitable editor found for object of type '%s'."),
object.get_metaclass()->get_attribute("caption").c_str()),
"OK");
}
} catch (grt::grt_runtime_error &exc) {
logError("Exception in Open object editor: %s\n%s", exc.what(), exc.detail.c_str());
mforms::Utilities::show_error(_("Edit Object"), strfmt("%s\n%s", exc.what(), exc.detail.c_str()), "OK");
} catch (std::exception &exc) {
logException("Open object editor", exc);
mforms::Utilities::show_error(_("Edit Object"), strfmt("%s", exc.what()), "OK");
}
}