/* 
 * © 2007-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "stdafx.h"

#include <grtpp_module_cpp.h>
#include <grtpp_module_lua.h>

#include "grt/grt_manager.h"
#include "grt/common.h"
#include "glib/gstdio.h"

#include "myx_shared_util_functions.h"

using namespace grt;
using namespace bec;



static GThread *main_thread= 0;

std::map<grt::GRT*,GRTManager*> GRTManager::_instances;


GStaticMutex _instance_mutex = G_STATIC_MUTEX_INIT;

// Now it is in backend/common.h
/*
struct GStaticMutexLock
{
  GStaticMutexLock(GStaticMutex& mtx) : _mtx(mtx)
  {
    g_static_mutex_lock(&_mtx);
  }
  ~GStaticMutexLock()
  {
    g_static_mutex_unlock(&_mtx);
  }
private:
  GStaticMutex& _mtx;
};
*/

int rmdir_recursively(const char *path)
{
  int res= 0;
  GError *error= NULL;
  GDir* dir;
  const char *dir_entry;
  gchar *entry_path;
  
  dir= g_dir_open(path, 0, &error);
  if (!dir && error)
    return error->code;

  while ((dir_entry= g_dir_read_name(dir)))
  {
    entry_path= g_build_filename(path, dir_entry, NULL);
    if (g_file_test(entry_path, G_FILE_TEST_IS_DIR))
      (void) rmdir_recursively(entry_path);
    else
      (void) g_remove(entry_path);
    g_free(entry_path);
  }

  (void) g_rmdir(path);

  g_dir_close(dir);
  return res;
}


static void init_all()
{
  if (!main_thread)
   {
    if (!g_thread_supported()) g_thread_init(NULL);
    main_thread= g_thread_self();
    if (!g_thread_supported())
      throw std::runtime_error("Could not initialize Glib thread support");
  }
}


GRTManager *create_grt_manager(bool threaded, bool verbose = false)
{
  return new GRTManager(threaded, verbose);
}


GRTManager::GRTManager(bool threaded, bool verbose)
: _threaded(threaded), _verbose(verbose)
{
  init_all();

  _idle_mutex= g_mutex_new();
  _timer_mutex= g_mutex_new();

  _grt= new GRT();
  
  _grt->set_verbose(verbose);
  
  _grt->set_message_handler(sigc::mem_fun(this, &GRTManager::grt_default_msg_cb));

  _terminated= false;
  _idle_blocked= false;
  _clipboard= 0;

  // add self to the mgr instances table asap, because the other objects
  // may need to call get_instance_for()
  {
    GStaticMutexLock _lock(_instance_mutex);
    _instances[_grt]= this;
  }
  
  _dispatcher= new GRTDispatcher(_grt, _threaded);

  _shell= new ShellBE(this, _dispatcher);

  _plugin_manager= _grt->get_native_module<PluginManagerImpl>();

  _value_tree= 0;
  _structs_tree= 0;
  _modules_tree= 0;
  _messages_list= 0;

  _log_file= 0;
}


GRTManager *GRTManager::get_instance_for(GRT *grt)
{
  GStaticMutexLock _lock(_instance_mutex);
  std::map<GRT*,GRTManager*>::iterator iter= _instances.find(grt);
  if (iter != _instances.end())
    return iter->second;
  return NULL;
}


void GRTManager::set_basedir(const std::string &path)
{
  if (!g_path_is_absolute(path.c_str()))
  {
    gchar *dir= g_get_current_dir();
    _basedir= make_path(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= make_path(dir, path);
    g_free(dir);
  }
  else
    _datadir= path;
}


std::string GRTManager::get_data_file_path(const std::string &file)
{
  return make_path(_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= make_path(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()
{
  {
    GStaticMutexLock _lock(_instance_mutex);
    _instances.erase(_grt);
  }  

  if (_log_file)
    fclose(_log_file);

  _dispatcher->shutdown();
  delete _dispatcher;

  delete _shell;
  delete _value_tree;
  delete _structs_tree;
  delete _modules_tree;
  delete _messages_list;

  delete _grt;

  for (std::list<Timer*>::iterator iter= _timers.begin(); iter != _timers.end(); ++iter)
    delete *iter;

  g_mutex_free(_timer_mutex);
  g_mutex_free(_idle_mutex);
}


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= pathlist_prepend(_module_pathlist, user_module_path);
  _libraries_pathlist= pathlist_prepend(_libraries_pathlist, user_library_path);
}


ShellBE *GRTManager::get_shell()
{
  return _shell;
}


MessageListBE *GRTManager::get_messages_list()
{
  if (!_messages_list)
  {
    _messages_list= new MessageListBE(this);
  }
  return _messages_list;
}


ValueTreeBE *GRTManager::get_shared_value_tree(const std::string &valuespec)
{
  if (!_value_tree)
    _value_tree= new ValueTreeBE(_grt);

  if (!valuespec.empty() && valuespec[0] == '/')
  {
    if (*valuespec.rbegin() == '/' && valuespec != "/")
      _value_tree->set_displayed_global_value(valuespec.substr(0, valuespec.size()-1), false);
    else
      _value_tree->set_displayed_global_value(valuespec, true);
  }
  else
    _value_tree->set_displayed_value(_shell->get_shell_variable(valuespec),
                                     valuespec);

  return _value_tree;
}


ValueInspectorBE *GRTManager::get_new_value_inspector(const grt::ValueRef &value, bool process_editas_flag)
{
  return ValueInspectorBE::create(_grt, value, false, process_editas_flag);
}


ValueInspectorBE *GRTManager::get_new_grouped_object_inspector(const grt::ValueRef &object, bool process_editas_flag)
{
  return ValueInspectorBE::create(_grt, object, true, process_editas_flag);
}


StructsTreeBE *GRTManager::get_shared_structs_tree()
{
  if (!_structs_tree)
    _structs_tree= new StructsTreeBE(_grt);

  return _structs_tree;
}


ModulesTreeBE *GRTManager::get_shared_modules_tree()
{
  if (!_modules_tree)
    _modules_tree= new ModulesTreeBE(_grt);

  return _modules_tree;
}


void GRTManager::set_error_callback(const sigc::slot<void,std::string,std::string> &cb)
{
  _error_cb= cb;
}


void GRTManager::set_message_callback(const sigc::slot<void,grt::Message> &cb)
{
  _message_cb= cb;
}

void GRTManager::set_progress_callback(const sigc::slot<bool,std::string,std::string,float> &cb)
{
  _progress_cb= cb;
}



void GRTManager::task_started_cb(const std::string &title)
{
  if (_progress_cb)
    _progress_cb(title, "", 0.0);
}


void GRTManager::task_finished_cb(const grt::ValueRef &result)
{
  if (_progress_cb)
    _progress_cb("", "", -1);
}


void GRTManager::task_error_cb(const std::exception &error, const std::string &title)
{
  _error_cb(title, error.what());//XXX
}


void GRTManager::task_msg_cb(const grt::Message &msg, const std::string &title, bool show_progress)
{
  switch (msg.type)
  {
  case ErrorMsg:
  case WarningMsg:
    _grt->make_output_visible();
  case InfoMsg:
  case ControlMsg:
  case OutputMsg:
    _message_cb(msg);
    break;
      
  case ProgressMsg:
    if (show_progress)
      _progress_cb(msg.text, msg.detail, msg.progress);
    break;
  default:
    g_message("unhandled message %i: %s", msg.type, msg.format().c_str());
    break;
  }
}


void GRTManager::execute_grt_task(const std::string &title,
                                  const sigc::slot1<grt::ValueRef, grt::GRT*> &function,
                                  const sigc::slot<void,grt::ValueRef> &finished_cb,
                                  bool show_progress)
{
  GRTTask *task= new GRTTask(title, _dispatcher, function);

  if (show_progress)
  {
    task->signal_started().connect(sigc::bind<std::string>(sigc::mem_fun(this,&GRTManager::task_started_cb), title));
    task->signal_finished().connect(sigc::mem_fun(this, &GRTManager::task_finished_cb));
  }

  // connect finished_cb provided by caller (after ours)
  task->signal_finished().connect(finished_cb);

  task->signal_failed().connect(sigc::bind<std::string>(sigc::mem_fun(this, &GRTManager::task_error_cb), title));

  task->signal_message().connect(sigc::bind<std::string,bool>(sigc::mem_fun(this, &GRTManager::task_msg_cb),
    title, show_progress));

  _dispatcher->add_task(task);
}


void GRTManager::dispatch_task(GRTTask *task)
{
  if (!task->signal_message().empty())
  {
    // make msgs be sent to output window as well
    task->signal_message().connect(
      sigc::bind<std::string, bool>(sigc::mem_fun(this, &GRTManager::task_msg_cb), "", false));
  }

  _dispatcher->add_task(task);
}



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);
//XXX redo
  if (important)
    _error_cb(message, detail);
}


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::initialize(const std::string &loader_module_path)
{
  IntegerRef result;

  _dispatcher->start();

  load_structs();
    
  init_module_loaders(loader_module_path);
    
  load_libraries();
    
  load_modules();
}


bool GRTManager::initialize_shell(const std::string &shell_type)
{
  if (!_shell->setup(shell_type.empty() ? grt::LanguageLua : shell_type))
  {
    g_warning("Could not initialize GRT shell of type '%s'", shell_type.c_str());
    return false;
  }
  return true;
}


void GRTManager::perform_idle_tasks()
{
  // flush the dispatcher callback queue
  _dispatcher->flush_pending_callbacks();

  // flush the async notification queue
//QQQ  _grt->flush_notifications();

  if (_shell)
  {
    // flush the shell output buffer
    _shell->flush_shell_output();
  }

  std::list<sigc::slot<bool> > idle_slots;
  if (!_idle_blocked)
  {
    g_mutex_lock(_idle_mutex);
    idle_slots= _idle_slots;
    _idle_slots.clear();
    g_mutex_unlock(_idle_mutex);

    for (std::list<sigc::slot<bool> >::iterator iter= idle_slots.begin();
      iter != idle_slots.end(); ++iter)
    {
      bool flag= (*iter)();

      if (flag)
      {
        g_mutex_lock(_idle_mutex);
        _idle_slots.push_back(*iter);
        g_mutex_unlock(_idle_mutex);
      }
    }
  }
}


void GRTManager::run_when_idle(const sigc::slot<bool> &slot)
{
  g_mutex_lock(_idle_mutex);
  _idle_slots.push_back(slot);
  g_mutex_unlock(_idle_mutex);
}


void GRTManager::block_idle_tasks()
{
  _idle_blocked= true;
}


void GRTManager::unblock_idle_tasks()
{
  _idle_blocked= false;
}


GRTManager::Timer::Timer(const sigc::slot<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();

  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 sigc::slot<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);

  g_mutex_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);
  g_mutex_unlock(_timer_mutex);

  _timeout_request();

  return timer;
}


void GRTManager::cancel_timer(GRTManager::Timer *timer)
{
  g_mutex_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
  g_mutex_unlock(_timer_mutex);
}


void GRTManager::flush_timers()
{
  GTimeVal now;
  g_get_current_time(&now);

  std::list<Timer*> triggered;

  // first get a list of timers that trigger now
  g_mutex_lock(_timer_mutex);
  std::list<Timer*>::iterator next, iter= _timers.begin();
  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;
  }
  g_mutex_unlock(_timer_mutex);

  // 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);

      g_mutex_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;

      g_mutex_unlock(_timer_mutex);
    }
    else
    {
      g_mutex_lock(_timer_mutex);
      delete *iter;
      g_mutex_unlock(_timer_mutex);
    }
  }
  g_mutex_lock(_timer_mutex);
  _cancelled_timers.clear();
  g_mutex_unlock(_timer_mutex);
}


double GRTManager::delay_for_next_timeout()
{
  double delay= -1;

  g_mutex_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;
  }
  g_mutex_unlock(_timer_mutex);

  return delay;
}


void GRTManager::set_timeout_request_slot(const sigc::slot<void> &slot)
{
  _timeout_request= slot;
}


void GRTManager::grt_default_msg_cb(const grt::Message &msg)
{
  switch (msg.type)
  {
  case ProgressMsg:
    _progress_cb(msg.text, msg.detail, msg.progress);
    break;

  default:
  case ErrorMsg:
  case WarningMsg:
  case InfoMsg:
  case ControlMsg:
    _message_cb(msg);
    break;
  }
}



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)
{
  if (_verbose)
    _shell->write_line(_("Initializing Loaders..."));
  if (!init_loaders(loader_module_path))
    _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++)
  {
    #ifdef _WIN32
    GDir *dir= g_dir_open_utf8(paths[i], 0, NULL);
    #else
    GDir *dir= g_dir_open(paths[i], 0, NULL);
    #endif

    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(_grt, _module_extensions, false);
  
  return true;
}


void GRTManager::rescan_modules()
{
  load_modules();
}


bool GRTManager::init_loaders(const std::string &loader_module_path)
{
  try
  {
    _grt->add_module_loader(new LuaModuleLoader(_grt));
    if (_verbose) _shell->write_line(_("Lua loader initialized."));
  }
  catch (std::exception &exc)
  {
    _shell->write_line(strfmt("Error initializing Lua loader: %s", exc.what()));
  }
  
  try
  {
    // temporary code, once the dynamic loading of language support is added, these
    // should go away
    if (grt::init_python_support(_grt, 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))
  {
 //   if (_verbose)
//      _grt->send_output(strfmt(_("Skipping non-existent module directory '%s'.\n"), path.c_str()));
    return 0;
  }

  if (_verbose)
    _grt->send_output(strfmt(_("Looking for modules in '%s'.\n"), path.c_str()));
  
  try
  {
    c= _grt->scan_modules_in(path, 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(grt::GRT *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;
  }

  _shell->writef(_("Registered %i modules (from %i files).\n"),
                 _grt->get_modules().size(), count);

  g_strfreev(paths);
}


void GRTManager::set_app_option_slot(const sigc::slot<grt::ValueRef,std::string> &slot)
{
  _get_app_option_slot= slot;
}


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)
{
  return *grt::StringRef::cast_from(get_app_option(name));
}


std::string GRTManager::get_tmp_dir()
{
  std::string res;
#ifdef _WIN32
  res.append(g_get_tmp_dir()).append("/MySQL Workbench/");
#else
  res.append(g_get_tmp_dir()).append("/mysql-workbench.").append(g_get_user_name()).append("/");
#endif
  g_mkdir(res.c_str(), 0700);
  return res;
}


std::string GRTManager::get_unique_tmp_subdir()
{
  std::string unique_name= get_guid();
  
  return get_tmp_dir().append(unique_name).append("/");
}


void GRTManager::cleanup_tmp_dir()
{
  (void) rmdir_recursively(get_tmp_dir().c_str());
}


void GRTManager::set_use_log_file(bool value)
{
  if (value)
  {
    std::string log_filename;
    log_filename.append(get_tmp_dir()).append("wb.log");
    _log_file= myx_fopen(log_filename.c_str(), "ab+");
  }
}


void GRTManager::add_log_file_entry(const char *text, size_t size)
{
  if (_log_file)
  {
    fwrite(text, size, 1, _log_file);
    fwrite("\n", 1, 1, _log_file);
    fflush(_log_file);
  }
}



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 sigc::slot<void, std::string> &slot)
{
  _status_text_slot= slot;
}


