#ifndef __WB_H__
#define __WB_H__

/*#include "myx_grt_private.h"
#include "myx_grtpp.h"*/

#include "wb_config.h"
#include "workbench/wb_context.h"
#include "workbench/wb_context_ui.h"
#include "workbench/wb_model_diagram_form.h"
#include "workbench/wb_history_tree.h"
#include "workbench/wb_diagram_options.h"
#include "workbench/wb_user_datatypes.h"
#include "workbench/wb_overview_workspace.h"
#include "workbench/wb_overview_physical.h"

#include "common/preferences_form.h"
#include "common/document_properties_form.h"

#include "GrtTemplates.h"
#include "SigCSlot.h"
#include "FindDialogBE.h"
#include "Overview.h"
#include "ModelViewForm.h"

#if WBContext_VERSION > 5
# error outdated wrapper Wb.h
#endif

#ifdef _MSC_VER
#include  <vcclr.h> // .net interop helpers
using namespace MySQL::Grt;
using namespace MySQL::GUI::Mdc;
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
#endif

namespace MySQL {
namespace Workbench {


public enum class RefreshType 
{
  RefreshNeeded=    ::wb::RefreshNeeded,

  RefreshNothing=    ::wb::RefreshNothing,
  RefreshLayers=     ::wb::RefreshLayers,
  RefreshSchemaList= ::wb::RefreshSchemaList,
  RefreshSchema=     ::wb::RefreshSchema,
  RefreshNewView=    ::wb::RefreshNewView,
  RefreshSelection=  ::wb::RefreshSelection,
  RefreshToolbar=    ::wb::RefreshToolbar,
  RefreshMessages=   ::wb::RefreshMessages,
  RefreshCloseEditor= ::wb::RefreshCloseEditor,
  RefreshFindOutput= ::wb::RefreshFindOutput,
  RefreshHistory=    ::wb::RefreshHistory,
  RefreshUserTypes=  ::wb::RefreshUserTypes,
  RefreshOverviewNodeInfo=::wb::RefreshOverviewNodeInfo,
  RefreshOverviewNodeChildren=::wb::RefreshOverviewNodeChildren,
  RefreshViewName=   ::wb::RefreshViewName,
  RefreshDocument=   ::wb::RefreshDocument,
  RefreshCloseDocument=::wb::RefreshCloseDocument,
  RefreshZoom=       ::wb::RefreshZoom,
  RefreshMenubar=    ::wb::RefreshMenubar,
  RefreshTimer=      ::wb::RefreshTimer
};


public enum class ToolbarItemType 
{
  ToolbarAction=        ::wb::ToolbarAction,
  ToolbarSeparator=     ::wb::ToolbarSeparator,
  ToolbarToggle=        ::wb::ToolbarToggle,
  ToolbarLabel=         ::wb::ToolbarLabel,
  ToolbarDropDown=      ::wb::ToolbarDropDown,
  ToolbarRadio=         ::wb::ToolbarRadio,
  ToolbarCheck=         ::wb::ToolbarCheck,
  ToolbarSearch=        ::wb::ToolbarSearch
};


public enum class GUIPluginFlags
{
  ForceNewWindowFlag=   ::bec::ForceNewWindowFlag
};


public ref class WbToolbarItem
{
  int icon;
  int alt_icon;
  String^ name;
  String^ caption;
  String^ command;
  String^ tooltip;
  ToolbarItemType type;

  bool enabled;
  bool checked;

public:

  WbToolbarItem(const ::wb::WBToolbarItem& item)
    : icon(item.icon), alt_icon(item.alt_icon),
    name(CppStringToNative(item.name)),
    caption(CppStringToNative(item.caption)),
    command(CppStringToNative(item.command)),
    tooltip(CppStringToNative(item.tooltip)),
    type((ToolbarItemType)item.type),
    enabled(item.enabled),
    checked(item.checked)
  {}

  int get_icon()
  { return icon; }

  int get_alt_icon()
  { return alt_icon; }

  String^ get_name()
  { return name; }

  String^ get_caption()
  { return caption; }

  String^ get_command()
  { return command; }

  String^ get_tooltip()
  { return tooltip; }

  ToolbarItemType get_type()
  { return type; }

  bool get_checked()
  { return checked; }

  bool get_enabled()
  { return enabled; }
};

// ----------------------------------------------------------------------------


public ref class PageSettings
{
public:
  PageSettings()
    : paper_type(nullptr), margin_top(0), margin_bottom(0), margin_left(0), margin_right(0), 
      orientation(nullptr)
  {
  }

  PageSettings(const app_PageSettingsRef &settings)
    : paper_type(CppStringToNative(settings->paperType()->name())),
    margin_top(settings->marginTop()), margin_bottom(settings->marginBottom()),
    margin_left(settings->marginLeft()), margin_right(settings->marginRight()),
    orientation(CppStringToNative(settings->orientation()))
  {
  }

  void update_object(grt::ListRef<app_PaperType> paperTypes, app_PageSettingsRef settings)
  {
    settings->paperType(grt::find_named_object_in_list(paperTypes, NativeToCppString(paper_type)));

    settings->marginTop(grt::DoubleRef(margin_top));
    settings->marginBottom(grt::DoubleRef(margin_bottom));
    settings->marginLeft(grt::DoubleRef(margin_left));
    settings->marginRight(grt::DoubleRef(margin_right));

    settings->orientation(NativeToCppString(orientation));
  }

  String^ paper_type;
  double margin_top;
  double margin_bottom;
  double margin_left;
  double margin_right;
  String^ orientation;
};


public ref class PaperSize
{
public:
  PaperSize(const wb::WBPaperSize &paperSize)
    : name(CppStringToNative(paperSize.name)), 
    caption(CppStringToNative(paperSize.caption)), 
    margins_set(paperSize.margins_set),
    margin_top(paperSize.margin_top), margin_bottom(paperSize.margin_bottom), 
    margin_left(paperSize.margin_left), margin_right(paperSize.margin_right), 
    width(paperSize.width), height(paperSize.height),
    description(CppStringToNative(paperSize.description))
  {
  }

  String^ name;
  String^ caption;
  double width;
  double height;
  bool margins_set;
  double margin_top;
  double margin_bottom;
  double margin_left;
  double margin_right;
  String^ description;
};


// ----------------------------------------------------------------------------


public ref class WbFrontendCallbacks
{
public:
  // ----------------------------------------------------------------------------
  // The delegates used by C#
  delegate void VoidDelegate();
  delegate void VoidBoolDelegate(bool f);
  delegate void VoidStrDelegate(String^ str1);
  delegate void VoidStrStrDelegate(String^ str1, String^ str2);
  delegate String^ StrStrStrStrDelegate(String^ str1, String^ str2, String^ str3);
  delegate bool BoolStrStrStrDelegate(String^ str1, String^ str2, String^ str3);
  delegate bool BoolStrStrStrStrDelegate(String^ str0, String^ str1, String^ str2, String^ str3);
  delegate int IntStrStrStrStrStrDelegate(String^ str0, String^ str1, String^ str2, String^ str3, String^ str4);
  delegate bool BoolStrStrFloatDelegate(String^ str1, String^ str2, float f3);
  delegate bool BoolStrIntStrPtrDelegate(String^ str, int i, [Out] String^ %result);
  delegate BaseWindowsCanvasView^ CanvasViewStringStringDelegate(String^ str1, String^ str2);
  delegate void VoidCanvasViewDelegate(BaseWindowsCanvasView^ canvasView);
  delegate IntPtr IntPtrGRTManagerModuleStrStrGrtListFlagsDelegate(GrtManager^ grtManager, GrtModule^ module, String^ str1, String^ str2, GrtValue^ grtlist, GUIPluginFlags flags);
  delegate void VoidIntPtrDelegate(IntPtr p2);
  delegate void VoidRefreshTypeStringIntPtrDelegate(RefreshType refresh, String^ str, IntPtr ptr);
  delegate void VoidMenuItemListIntIntDelegate(List<MySQL::Grt::MenuItem^>^ plugins, int x, int y);

private:

  ::wb::WBFrontendCallbacks *inner;

  // ----------------------------------------------------------------------------
  // Wrapper delegates used by the C++.net wrapper

  // void ()
  delegate void VoidWrapperDelegate();
  typedef void (*WbFrontendCallbacks::VOID_CB)();
  // void (bool)
  delegate void VoidBoolWrapperDelegate(bool b);
  typedef void (*WbFrontendCallbacks::VOID_BOOL_CB)(bool b);
  // void (string)
  delegate void VoidStrWrapperDelegate(const std::string& str1);
  typedef void (*WbFrontendCallbacks::VOID_STR_CB)(const std::string& str1);
  // void (string, string)
  delegate void VoidStrStrWrapperDelegate(const std::string& str1, const std::string& str2);
  typedef void (*WbFrontendCallbacks::VOID_STR_STR_CB)(const std::string& str1, const std::string& str2);
  // string (string, string, string)
  delegate std::string StrStrStrStrWrapperDelegate(const std::string& str1, const std::string& str2, const std::string& str3);
  typedef std::string (*WbFrontendCallbacks::STR_STR_STR_STR_CB)(const std::string& str1, const std::string& str2, const std::string& str3);
  // bool (string, string, string)
  delegate bool BoolStrStrStrWrapperDelegate(const std::string& str1, const std::string& str2, const std::string& str3);
  typedef bool (*WbFrontendCallbacks::BOOL_STR_STR_STR_CB)(const std::string& str1, const std::string& str2, const std::string& str3);
  // int (string, string, string, string, string)
  delegate int IntStrStrStrStrStrWrapperDelegate(const std::string& title, const std::string& str1, const std::string& str2, const std::string& str3, const std::string& str4);
  typedef int (*WbFrontendCallbacks::INT_STR_STR_STR_STR_STR_CB)(const std::string& title, const std::string& str1, const std::string& str2, const std::string& str3, const std::string& str4);
  // bool (string, string, float)
  delegate bool BoolStrStrFloatWrapperDelegate(const std::string& str1, const std::string& str2, float f3);
  typedef bool (*WbFrontendCallbacks::BOOL_STR_STR_FLOAT_CB)(const std::string& str1, const std::string& str2, float f3);
  // bool (string, int, string&)
  delegate bool BoolStrIntStrPtrWrapperDelegate(const std::string &str, int, std::string &res);
  typedef bool (*WbFrontendCallbacks::BOOL_STR_INT_STRPTR_CB)(const std::string &str, int, std::string &res);
  // CanvasView * (string, string)
  delegate ::mdc::CanvasView * CanvasViewStringStringWrapperDelegate(const std::string& str1, const std::string &str2);
  typedef ::mdc::CanvasView * (*WbFrontendCallbacks::CANVASVIEW_STR_STR_CB)(const std::string& str1, const std::string& str2);
  // void (CanvasView *)
  delegate void VoidCanvasViewWrapperDelegate(::mdc::CanvasView *canvas_view);
  typedef void (*WbFrontendCallbacks::VOID_CANVASVIEW_CB)(::mdc::CanvasView *canvas_view);
  // _int64 (GrtManager *, Module*, string, string, GrtList, GUIPluginFlags)
  delegate __int64 IntGRTManagerModuleStrStrGrtListFlagsWrapperDelegate(::bec::GRTManager* grt_manager, grt::Module *, const std::string& str2, const std::string& str3, const grt::BaseListRef &grt_list, bec::GUIPluginFlags flags);
  typedef __int64 (*WbFrontendCallbacks::INT_GRTMANAGER_MODULE_STR_STR_GRTLIST_FLAGS_CB)(::bec::GRTManager* grt_manager, grt::Module *module, const std::string& str2, const std::string& str3, const grt::BaseListRef &grt_list, bec::GUIPluginFlags flags);
  // void (__int64)
  delegate void VoidIntPtrWrapperDelegate(__int64 native_handle);
  typedef void (*WbFrontendCallbacks::VOID_INT64_CB)(__int64 native_handle);
  // void (RefreshType, string, __int64)
  delegate void VoidRefreshTypeStringIntPtrWrapperDelegate(::wb::RefreshType refresh, const std::string &str, __int64 ptr);
  typedef void (*WbFrontendCallbacks::VOID_REFRESHTYPE_STRING_INTPTR_CB)(::wb::RefreshType refresh, const std::string &str, __int64 ptr);
  // void (bec::MenuItemList, int, int)
  delegate void VoidMenuItemListIntIntWrapperDelegate(::bec::MenuItemList *plugins, int x, int y);
  typedef void (*WbFrontendCallbacks::VOID_MenuItemLIST_INT_INT_CB)(::bec::MenuItemList *plugins, int x, int y);

  // ----------------------------------------------------------------------------
  // Variables used to store the C# delegates and the C++.Net wrapper delegates
  // Intermediate callback that is called from C++ and calls the C# delegate

  VoidStrStrDelegate^ show_internal_error_delegate;
  VoidStrStrWrapperDelegate^ show_internal_error_wrapper_delegate;
  void show_internal_error_wrapper(const std::string& str1, const std::string& str2)
  { show_internal_error_delegate(CppStringToNative(str1), CppStringToNative(str2)); }

  VoidStrStrDelegate^ show_error_delegate;
  VoidStrStrWrapperDelegate^ show_error_wrapper_delegate;
  void show_error_wrapper(const std::string& str1, const std::string& str2)
  { show_error_delegate(CppStringToNative(str1), CppStringToNative(str2)); }

  VoidStrStrDelegate^ show_warning_delegate;
  VoidStrStrWrapperDelegate^ show_warning_wrapper_delegate;
  void show_warning_wrapper(const std::string& str1, const std::string& str2)
  { show_warning_delegate(CppStringToNative(str1), CppStringToNative(str2)); }


  VoidStrStrDelegate^ show_message_delegate;
  VoidStrStrWrapperDelegate^ show_message_wrapper_delegate;
  void show_message_wrapper(const std::string& str1, const std::string& str2)
  { show_message_delegate(CppStringToNative(str1), CppStringToNative(str2)); }

  IntStrStrStrStrStrDelegate^ confirm_action_delegate;
  IntStrStrStrStrStrWrapperDelegate^ confirm_action_wrapper_delegate;
  int confirm_action_wrapper(const std::string &title, const std::string& str1, const std::string& str2, const std::string& str3, const std::string &str4)
  {
    return confirm_action_delegate(CppStringToNative(title), CppStringToNative(str1), CppStringToNative(str2), CppStringToNative(str3), CppStringToNative(str4));
  }

  BoolStrIntStrPtrDelegate^ request_input_delegate;
  BoolStrIntStrPtrWrapperDelegate^ request_input_wrapper_delegate;
  bool request_input_wrapper(const std::string &title, int flags, std::string& res)
  {
    String^ result= nullptr;
    bool flag;

    flag= request_input_delegate(CppStringToNative(title), flags, result);
    if (result != nullptr)
      res= NativeToCppString(result);

    return flag;
  }

  StrStrStrStrDelegate^ show_file_dialog_delegate;
  StrStrStrStrWrapperDelegate^ show_file_dialog_wrapper_delegate;
  std::string show_file_dialog_wrapper(const std::string& str1, const std::string& str2, const std::string& str3)
  { return NativeToCppString(show_file_dialog_delegate(CppStringToNative(str1), CppStringToNative(str2), CppStringToNative(str3))); }

  VoidStrDelegate^ show_status_text_delegate;
  VoidStrWrapperDelegate^ show_status_text_wrapper_delegate;
  void show_status_text_wrapper(const std::string& str1)
  { show_status_text_delegate(CppStringToNative(str1)); }

  BoolStrStrFloatDelegate^ show_progress_delegate;
  BoolStrStrFloatWrapperDelegate^ show_progress_wrapper_delegate;
  bool show_progress_wrapper(const std::string& str1, const std::string& str2, float f3)
  { return show_progress_delegate(CppStringToNative(str1), CppStringToNative(str2), f3); }

  VoidStrDelegate^ print_output_delegate;
  VoidStrWrapperDelegate^ print_output_wrapper_delegate;
  void print_output_wrapper(const std::string& str1)
  { print_output_delegate(CppStringToNative(str1)); }

  VoidStrDelegate^ shell_output_delegate;
  VoidStrWrapperDelegate^ shell_output_wrapper_delegate;
  void shell_output_wrapper(const std::string& str1)
  { shell_output_delegate(CppStringToNative(str1)); }

  // CanvasView
  CanvasViewStringStringDelegate^ create_view_delegate;
  CanvasViewStringStringWrapperDelegate^ create_view_wrapper_delegate;
  ::mdc::CanvasView *create_view_wrapper(const std::string& str1, const std::string &str2)
  {
    BaseWindowsCanvasView ^cv = create_view_delegate(CppStringToNative(str1), CppStringToNative(str2));
    return cv->get_unmanaged_object();
  }

  VoidCanvasViewDelegate^ destroy_view_delegate;
  VoidCanvasViewWrapperDelegate^ destroy_view_wrapper_delegate;
  void destroy_view_wrapper(::mdc::CanvasView *canvas_view)
  {
    BaseWindowsCanvasView^ wcv = 
      BaseWindowsCanvasView::GetFromFixedId((IntPtr)canvas_view->get_user_data());
    destroy_view_delegate(wcv);
  }

  VoidCanvasViewDelegate^ switched_view_delegate;
  VoidCanvasViewWrapperDelegate^ switched_view_wrapper_delegate;
  void switched_view_wrapper(::mdc::CanvasView *canvas_view)
  {
    BaseWindowsCanvasView^ wcv = 
      BaseWindowsCanvasView::GetFromFixedId((IntPtr)canvas_view->get_user_data());
    switched_view_delegate(wcv);
  }

  VoidCanvasViewDelegate^ tool_changed_delegate;
  VoidCanvasViewWrapperDelegate^ tool_changed_wrapper_delegate;
  void tool_changed_wrapper(::mdc::CanvasView *canvas_view)
  {
    BaseWindowsCanvasView^ wcv = 
      BaseWindowsCanvasView::GetFromFixedId((IntPtr)canvas_view->get_user_data());
    tool_changed_delegate(wcv);
  }


  // Shell
  VoidStrDelegate^ print_shell_delegate;
  VoidStrWrapperDelegate^ print_shell_wrapper_delegate;
  void print_shell_wrapper(const std::string& str1)
  { print_shell_delegate(CppStringToNative(str1)); }

  VoidStrDelegate^ next_shell_command_delegate;
  VoidStrWrapperDelegate^ next_shell_command_wrapper_delegate;
  void next_shell_command_wrapper(const std::string& str1)
  { next_shell_command_delegate(CppStringToNative(str1)); }



  // Editors
  IntPtrGRTManagerModuleStrStrGrtListFlagsDelegate^ open_editor_delegate;
  IntGRTManagerModuleStrStrGrtListFlagsWrapperDelegate^ open_editor_wrapper_delegate;
  __int64 open_editor_wrapper(::bec::GRTManager* grt_manager, grt::Module *module, const std::string& str2, const std::string& str3, const grt::BaseListRef &grt_list, bec::GUIPluginFlags flags)
  {
    return open_editor_delegate(gcnew GrtManager(grt_manager), gcnew GrtModule(module), 
      CppStringToNative(str2), CppStringToNative(str3),
      gcnew GrtValue(grt_list), (GUIPluginFlags)flags).ToInt64();
  }

  VoidIntPtrDelegate^ show_editor_delegate;
  VoidIntPtrWrapperDelegate^ show_editor_wrapper_delegate;
  void show_editor_wrapper(__int64 native_handle)
  {
    show_editor_delegate(IntPtr(native_handle));
  }

  VoidIntPtrDelegate^ hide_editor_delegate;
  VoidIntPtrWrapperDelegate^ hide_editor_wrapper_delegate;
  void hide_editor_wrapper(__int64 native_handle)
  {
    hide_editor_delegate(IntPtr(native_handle));
  }

  // Etc

  VoidRefreshTypeStringIntPtrDelegate ^refresh_gui_delegate;
  VoidRefreshTypeStringIntPtrWrapperDelegate ^refresh_gui_wrapper_delegate;
  void refresh_gui_wrapper(::wb::RefreshType refresh, const std::string &str, __int64 ptr)
  { refresh_gui_delegate((RefreshType)refresh, CppStringToNative(str), IntPtr(ptr)); }


  VoidMenuItemListIntIntDelegate ^popup_menu_delegate;
  VoidMenuItemListIntIntWrapperDelegate ^popup_menu_wrapper_delegate;
  void popup_menu_wrapper(::bec::MenuItemList *items, int x, int y)
  {
    popup_menu_delegate(convert_plugin_item_list(items), x, y);
  }


  VoidStrDelegate ^perform_command_delegate;
  VoidStrWrapperDelegate ^perform_command_wrapper_delegate;
  void perform_command_wrapper(const std::string &command)
  { perform_command_delegate(CppStringToNative(command)); }


  VoidBoolDelegate^ lock_gui_delegate;
  VoidBoolWrapperDelegate^ lock_gui_wrapper_delegate;
  void lock_gui_wrapper(bool flag)
  {
    lock_gui_delegate(flag);
  }

  List<MySQL::Grt::MenuItem^>^ convert_plugin_item_list(::bec::MenuItemList *items)
  {
    List<MySQL::Grt::MenuItem^>^ olist= gcnew List<MySQL::Grt::MenuItem^>();

    for (::bec::MenuItemList::const_iterator iter= items->begin(); iter != items->end(); ++iter)
    {
      MySQL::Grt::MenuItem^ item= gcnew MySQL::Grt::MenuItem(*iter);

      olist->Add(item);
    }

    return olist;
  }

  VoidDelegate^ quit_application_delegate;
  VoidWrapperDelegate^ quit_application_wrapper_delegate;
  void quit_application_wrapper()
  {
    quit_application_delegate();
  }

public:

  WbFrontendCallbacks(VoidStrStrDelegate^ show_internal_error,
                      VoidStrStrDelegate^ show_error,
                      VoidStrStrDelegate^ show_warning,
                      VoidStrStrDelegate^ show_message,
                      IntStrStrStrStrStrDelegate^ confirm_action,
                      StrStrStrStrDelegate^ show_file_dialog,
                      VoidStrDelegate^ show_status_text,
                      BoolStrStrFloatDelegate^ show_progress,
                      BoolStrIntStrPtrDelegate^ request_input,
                      VoidStrDelegate^ print_output,
                      VoidStrDelegate^ shell_output,
                      VoidStrDelegate^ next_shell_command,
                      CanvasViewStringStringDelegate^ create_view,
                      VoidCanvasViewDelegate^ destroy_view,
                      VoidCanvasViewDelegate^ switched_view,
                      VoidCanvasViewDelegate^ tool_changed,
                      IntPtrGRTManagerModuleStrStrGrtListFlagsDelegate^ open_editor,
                      VoidIntPtrDelegate^ show_editor,
                      VoidIntPtrDelegate^ hide_editor,
                      VoidRefreshTypeStringIntPtrDelegate^ refresh_gui,
                      VoidBoolDelegate^ lock_gui,
                      VoidMenuItemListIntIntDelegate^ popup_menu,
                      VoidStrDelegate^ perform_command,
                      VoidDelegate^ quit_application)
                      : inner(new ::wb::WBFrontendCallbacks)
  {
    set_show_internal_error(show_internal_error);
    set_show_error(show_error);
    set_show_warning(show_warning);
    set_show_message(show_message);
    set_confirm_action(confirm_action);
    set_show_file_dialog(show_file_dialog);
    set_show_status_text(show_status_text);
    set_show_progress(show_progress);
    set_print_output(print_output);
    set_request_input(request_input);
    set_shell_output(shell_output);
    set_next_shell_command(next_shell_command);

    set_create_view(create_view);
    set_destroy_view(destroy_view);
    set_switched_view(switched_view);
    set_tool_changed(tool_changed);

    set_open_editor(open_editor);
    set_show_editor(show_editor);
    set_hide_editor(hide_editor);

    set_refresh_gui(refresh_gui);
    set_popup_menu(popup_menu);
    set_perform_command(perform_command);

    set_lock_gui(lock_gui);

    set_quit_application(quit_application);
  }

  ~WbFrontendCallbacks()
  {
    //delete inner;
  }

  ::wb::WBFrontendCallbacks *get_unmanaged_object()
  {
    return inner;
  }

  // ----------------------------------------------------------------------------
  // Setting the variables to the correct delegates and callbacks

  void set_show_internal_error(VoidStrStrDelegate^ dt)
  {
    show_internal_error_delegate= dt;
    show_internal_error_wrapper_delegate= 
      gcnew VoidStrStrWrapperDelegate(this, &WbFrontendCallbacks::show_internal_error_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_internal_error_wrapper_delegate);
    VOID_STR_STR_CB cb = static_cast<VOID_STR_STR_CB>(ip.ToPointer());
    inner->show_internal_error= sigc::ptr_fun(cb);
  }

  void set_show_error(VoidStrStrDelegate^ dt)
  {
    show_error_delegate= dt;
    show_error_wrapper_delegate= 
      gcnew VoidStrStrWrapperDelegate(this, &WbFrontendCallbacks::show_error_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_error_wrapper_delegate);
    VOID_STR_STR_CB cb = static_cast<VOID_STR_STR_CB>(ip.ToPointer());
    inner->show_error= sigc::ptr_fun(cb);
  }

  void set_show_warning(VoidStrStrDelegate^ dt)
  {
    show_warning_delegate= dt;
    show_warning_wrapper_delegate= 
      gcnew VoidStrStrWrapperDelegate(this, &WbFrontendCallbacks::show_warning_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_warning_wrapper_delegate);
    VOID_STR_STR_CB cb = static_cast<VOID_STR_STR_CB>(ip.ToPointer());
    inner->show_warning= sigc::ptr_fun(cb);
  }

  void set_show_message(VoidStrStrDelegate^ dt)
  {
    show_message_delegate= dt;
    show_message_wrapper_delegate= 
      gcnew VoidStrStrWrapperDelegate(this, &WbFrontendCallbacks::show_message_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_message_wrapper_delegate);
    VOID_STR_STR_CB cb = static_cast<VOID_STR_STR_CB>(ip.ToPointer());
    inner->show_message= sigc::ptr_fun(cb);
  }

  void set_confirm_action(IntStrStrStrStrStrDelegate^ dt)
  {
    confirm_action_delegate= dt;
    confirm_action_wrapper_delegate= 
      gcnew IntStrStrStrStrStrWrapperDelegate(this, &WbFrontendCallbacks::confirm_action_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(confirm_action_wrapper_delegate);
    INT_STR_STR_STR_STR_STR_CB cb = static_cast<INT_STR_STR_STR_STR_STR_CB>(ip.ToPointer());
    inner->confirm_action= sigc::ptr_fun(cb);
  }

  void set_show_file_dialog(StrStrStrStrDelegate^ dt)
  {
    show_file_dialog_delegate= dt;
    show_file_dialog_wrapper_delegate= 
      gcnew StrStrStrStrWrapperDelegate(this, &WbFrontendCallbacks::show_file_dialog_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_file_dialog_wrapper_delegate);
    STR_STR_STR_STR_CB cb = static_cast<STR_STR_STR_STR_CB>(ip.ToPointer());
    inner->show_file_dialog= sigc::ptr_fun(cb);
  }

  void set_show_status_text(VoidStrDelegate^ dt)
  {
    show_status_text_delegate= dt;
    show_status_text_wrapper_delegate= 
      gcnew VoidStrWrapperDelegate(this, &WbFrontendCallbacks::show_status_text_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_status_text_wrapper_delegate);
    VOID_STR_CB cb = static_cast<VOID_STR_CB>(ip.ToPointer());
    inner->show_status_text= sigc::ptr_fun(cb);
  }

  void set_show_progress(BoolStrStrFloatDelegate^ dt)
  {
    show_progress_delegate= dt;
    show_progress_wrapper_delegate= 
      gcnew BoolStrStrFloatWrapperDelegate(this, &WbFrontendCallbacks::show_progress_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_progress_wrapper_delegate);
    BOOL_STR_STR_FLOAT_CB cb = static_cast<BOOL_STR_STR_FLOAT_CB>(ip.ToPointer());
    inner->show_progress= sigc::ptr_fun(cb);
  }

  void set_print_output(VoidStrDelegate^ dt)
  {
    print_output_delegate= dt;
    print_output_wrapper_delegate= 
      gcnew VoidStrWrapperDelegate(this, &WbFrontendCallbacks::print_output_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(print_output_wrapper_delegate);
    VOID_STR_CB cb = static_cast<VOID_STR_CB>(ip.ToPointer());
    inner->print_output= sigc::ptr_fun(cb);
  }

  void set_request_input(BoolStrIntStrPtrDelegate^ dt)
  {
    request_input_delegate= dt;
    request_input_wrapper_delegate= 
      gcnew BoolStrIntStrPtrWrapperDelegate(this, &WbFrontendCallbacks::request_input_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(request_input_wrapper_delegate);
    BOOL_STR_INT_STRPTR_CB cb = static_cast<BOOL_STR_INT_STRPTR_CB>(ip.ToPointer());
    inner->request_input= sigc::ptr_fun(cb);
  }

  void set_shell_output(VoidStrDelegate^ dt)
  {
    shell_output_delegate= dt;
    shell_output_wrapper_delegate= 
      gcnew VoidStrWrapperDelegate(this, &WbFrontendCallbacks::shell_output_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(shell_output_wrapper_delegate);
    VOID_STR_CB cb = static_cast<VOID_STR_CB>(ip.ToPointer());
    inner->shell_output= sigc::ptr_fun(cb);
  }

  void set_next_shell_command(VoidStrDelegate^ dt)
  {
    next_shell_command_delegate= dt;
    next_shell_command_wrapper_delegate= 
      gcnew VoidStrWrapperDelegate(this, &WbFrontendCallbacks::next_shell_command_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(next_shell_command_wrapper_delegate);
    VOID_STR_CB cb = static_cast<VOID_STR_CB>(ip.ToPointer());
    inner->next_shell_command= sigc::ptr_fun(cb);
  }

  void set_create_view(CanvasViewStringStringDelegate^ dt)
  {
    create_view_delegate= dt;
    create_view_wrapper_delegate=
      gcnew CanvasViewStringStringWrapperDelegate(this, &WbFrontendCallbacks::create_view_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(create_view_wrapper_delegate);
    CANVASVIEW_STR_STR_CB cb = static_cast<CANVASVIEW_STR_STR_CB>(ip.ToPointer());
    inner->create_view= sigc::ptr_fun(cb);
  }

  void set_destroy_view(VoidCanvasViewDelegate^ dt)
  {
    destroy_view_delegate= dt;
    destroy_view_wrapper_delegate=
      gcnew VoidCanvasViewWrapperDelegate(this, &WbFrontendCallbacks::destroy_view_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(destroy_view_wrapper_delegate);
    VOID_CANVASVIEW_CB cb = static_cast<VOID_CANVASVIEW_CB>(ip.ToPointer());
    inner->destroy_view= sigc::ptr_fun(cb);
  }

  void set_switched_view(VoidCanvasViewDelegate^ dt)
  {
    switched_view_delegate= dt;
    switched_view_wrapper_delegate=
      gcnew VoidCanvasViewWrapperDelegate(this, &WbFrontendCallbacks::switched_view_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(switched_view_wrapper_delegate);
    VOID_CANVASVIEW_CB cb = static_cast<VOID_CANVASVIEW_CB>(ip.ToPointer());
    inner->switched_view= sigc::ptr_fun(cb);
  }

  void set_tool_changed(VoidCanvasViewDelegate^ dt)
  {
    tool_changed_delegate= dt;
    tool_changed_wrapper_delegate=
      gcnew VoidCanvasViewWrapperDelegate(this, &WbFrontendCallbacks::tool_changed_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(tool_changed_wrapper_delegate);
    VOID_CANVASVIEW_CB cb = static_cast<VOID_CANVASVIEW_CB>(ip.ToPointer());
    inner->tool_changed= sigc::ptr_fun(cb);
  }





  void set_open_editor(IntPtrGRTManagerModuleStrStrGrtListFlagsDelegate^ dt)
  {
    open_editor_delegate= dt;
    open_editor_wrapper_delegate=
      gcnew IntGRTManagerModuleStrStrGrtListFlagsWrapperDelegate(this, &WbFrontendCallbacks::open_editor_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(open_editor_wrapper_delegate);
    INT_GRTMANAGER_MODULE_STR_STR_GRTLIST_FLAGS_CB cb = static_cast<INT_GRTMANAGER_MODULE_STR_STR_GRTLIST_FLAGS_CB>(ip.ToPointer());
    inner->open_editor= sigc::ptr_fun(cb);
  }

  void set_show_editor(VoidIntPtrDelegate^ dt)
  {
    show_editor_delegate= dt;
    show_editor_wrapper_delegate= 
      gcnew VoidIntPtrWrapperDelegate(this, &WbFrontendCallbacks::show_editor_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(show_editor_wrapper_delegate);
    VOID_INT64_CB cb = static_cast<VOID_INT64_CB>(ip.ToPointer());
    inner->show_editor= sigc::ptr_fun(cb);
  }

  void set_hide_editor(VoidIntPtrDelegate^ dt)
  {
    hide_editor_delegate= dt;
    hide_editor_wrapper_delegate= 
      gcnew VoidIntPtrWrapperDelegate(this, &WbFrontendCallbacks::hide_editor_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(hide_editor_wrapper_delegate);
    VOID_INT64_CB cb = static_cast<VOID_INT64_CB>(ip.ToPointer());
    inner->hide_editor= sigc::ptr_fun(cb);
  }


  void set_refresh_gui(VoidRefreshTypeStringIntPtrDelegate ^ dt)
  {
    refresh_gui_delegate= dt;
    refresh_gui_wrapper_delegate= 
      gcnew VoidRefreshTypeStringIntPtrWrapperDelegate(this, &WbFrontendCallbacks::refresh_gui_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(refresh_gui_wrapper_delegate);
    VOID_REFRESHTYPE_STRING_INTPTR_CB cb = static_cast<VOID_REFRESHTYPE_STRING_INTPTR_CB>(ip.ToPointer());
    inner->refresh_gui= sigc::ptr_fun(cb);
  }

  void set_popup_menu(VoidMenuItemListIntIntDelegate ^ dt)
  {
    popup_menu_delegate= dt;
    popup_menu_wrapper_delegate= 
      gcnew VoidMenuItemListIntIntWrapperDelegate(this, &WbFrontendCallbacks::popup_menu_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(popup_menu_wrapper_delegate);
    VOID_MenuItemLIST_INT_INT_CB cb = static_cast<VOID_MenuItemLIST_INT_INT_CB>(ip.ToPointer());
    inner->popup_menu = sigc::ptr_fun(cb);
  }

  void set_perform_command(VoidStrDelegate ^ dt)
  {
    perform_command_delegate= dt;
    perform_command_wrapper_delegate= 
      gcnew VoidStrWrapperDelegate(this, &WbFrontendCallbacks::perform_command_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(perform_command_wrapper_delegate);
    VOID_STR_CB cb = static_cast<VOID_STR_CB>(ip.ToPointer());
    inner->perform_command = sigc::ptr_fun(cb);
  }

  void set_lock_gui(VoidBoolDelegate^ dt)
  {
    lock_gui_delegate= dt;
    lock_gui_wrapper_delegate=
      gcnew VoidBoolWrapperDelegate(this, &WbFrontendCallbacks::lock_gui_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(lock_gui_wrapper_delegate);
    VOID_BOOL_CB cb = static_cast<VOID_BOOL_CB>(ip.ToPointer());
    inner->lock_gui= sigc::ptr_fun(cb);
  }

  void set_quit_application(VoidDelegate^ dt)
  {
    quit_application_delegate= dt;
    quit_application_wrapper_delegate=
      gcnew VoidWrapperDelegate(this, &WbFrontendCallbacks::quit_application_wrapper);
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(quit_application_wrapper_delegate);
    VOID_CB cb = static_cast<VOID_CB>(ip.ToPointer());
    inner->quit_application= sigc::ptr_fun(cb);
  }
};


public ref class WbOptions
{
  String^ basedir;
  String^ plugin_search_path;
  String^ struct_search_path;
  String^ module_search_path;
  String^ library_search_path;
  String^ user_data_dir;
  String^ open_at_startup;
  bool force_sw_rendering;
  bool force_opengl_rendering;
  bool use_log_file;

public:

  WbOptions(const ::wb::WBOptions& opt)
    : basedir(CppStringToNative(opt.basedir)),
    plugin_search_path(CppStringToNative(opt.plugin_search_path)),
    struct_search_path(CppStringToNative(opt.struct_search_path)),
    module_search_path(CppStringToNative(opt.module_search_path)),
    library_search_path(CppStringToNative(opt.library_search_path)),
    user_data_dir(CppStringToNative(opt.user_data_dir)),
    open_at_startup(CppStringToNative(opt.open_at_startup)),
    force_sw_rendering(opt.force_sw_rendering),
    force_opengl_rendering(opt.force_opengl_rendering),
    use_log_file(opt.use_log_file)
  {}

  WbOptions(String^ basedir, String^ plugin_search_path, String^ struct_search_path,
    String^ module_search_path, String^ library_search_path, String^ user_data_dir, String^ open_at_startup, 
    bool force_sw_rendering, bool force_opengl_rendering, bool use_log_file) 
    : basedir(basedir),
    plugin_search_path(plugin_search_path),
    struct_search_path(struct_search_path),
    module_search_path(module_search_path),
    library_search_path(library_search_path),
    user_data_dir(user_data_dir),
    open_at_startup(open_at_startup),
    force_sw_rendering(force_sw_rendering),
    force_opengl_rendering(force_opengl_rendering),
    use_log_file(use_log_file)
  {
  }

  ::wb::WBOptions *get_unmanaged_object()
  {
    ::wb::WBOptions *opt= new ::wb::WBOptions;
    opt->basedir= NativeToCppString(basedir);
    opt->plugin_search_path= NativeToCppString(plugin_search_path);
    opt->struct_search_path= NativeToCppString(struct_search_path);
    opt->module_search_path= NativeToCppString(module_search_path);
    opt->library_search_path= NativeToCppString(library_search_path);
    opt->user_data_dir= NativeToCppString(user_data_dir);
    opt->open_at_startup= NativeToCppString(open_at_startup);
    opt->force_sw_rendering= force_sw_rendering;
    opt->force_opengl_rendering= force_opengl_rendering;
    opt->use_log_file= use_log_file;
    return opt;
  }

  String^ get_basedir() { return basedir; }
  String^ get_plugin_search_path() { return plugin_search_path; }
  String^ get_struct_search_path() { return struct_search_path; }
  String^ get_module_search_path() { return module_search_path; }
  String^ get_user_data_dir() { return user_data_dir; }
  String^ get_open_at_startup() { return open_at_startup; }
  bool get_force_sw_rendering() { return force_sw_rendering; }
  bool get_force_opengl_rendering() { return force_opengl_rendering; }
  bool get_use_log_file() { return use_log_file; }
};


public ref class WbContext
{
  ::wb::WBContextUI *inner;
  BaseWindowsCanvasView^ mini_view;

  ::MySQL::Grt::GrtManager^ manager;
  ::MySQL::Workbench::Overview^ main_overview;
  ::MySQL::Workbench::Overview^ physical_overview;
  ::MySQL::Grt::GrtValueTree^ catalog_tree;
  ::MySQL::Grt::GrtValueTree^ layer_tree;
  ::MySQL::Grt::TreeModel^ history_tree;
  ::MySQL::Grt::ListModel^ usertypes_tree;

  ::System::Collections::ArrayList open_editor_slot_wrappers;

  DelegateSlot0<void,void> ^copy_delegate;
  DelegateSlot0<bool,bool> ^can_copy_delegate;
  DelegateSlot0<void,void> ^cut_delegate;
  DelegateSlot0<bool,bool> ^can_cut_delegate;
  DelegateSlot0<void,void> ^paste_delegate;
  DelegateSlot0<bool,bool> ^can_paste_delegate;
  DelegateSlot0<void,void> ^select_all_delegate;
  DelegateSlot0<bool,bool> ^can_select_all_delegate;
  DelegateSlot0<void,void> ^delete_delegate;
  DelegateSlot0<bool,bool> ^can_delete_delegate;
  DelegateSlot0<void,void> ^search_delegate;

public:
  delegate NativeHandle OpenEditorSlotDelegate(::MySQL::Grt::GrtManager^ manager, ::MySQL::Grt::GrtValue^ args);

  ref class OpenEditorSlotWrapper
  {

    typedef NativeHandle (*OpenEditorSlotWrapper::OPEN_EDITOR_CB)(bec::GRTManager* mgr, grt::BaseListRef args);
    delegate NativeHandle OpenEditorSlotWrapperDelegate(bec::GRTManager*, grt::BaseListRef);

    IntPtr native_slot_ptr;
    OpenEditorSlotDelegate^ slot;
    OpenEditorSlotWrapperDelegate^ slot_wrapper;

    NativeHandle wrapper(bec::GRTManager* mgr, grt::BaseListRef args)
    {
      return slot(gcnew ::MySQL::Grt::GrtManager(mgr), gcnew ::MySQL::Grt::GrtValue(args));
    }
  public:

    OpenEditorSlotWrapper(OpenEditorSlotDelegate^ s) :
        slot(s)
    {
      slot_wrapper= gcnew OpenEditorSlotWrapperDelegate(this, &OpenEditorSlotWrapper::wrapper);
      native_slot_ptr = Marshal::GetFunctionPointerForDelegate(slot_wrapper);
    }

    //::bec::EditorManagerImpl::OpenEditorSlot get_native_slot()
    //{
    //  OpenEditorSlotDelegate^ sw_delegate= slot;
    //  OpenEditorSlotWrapper::OpenEditorSlotWrapperDelegate^ sw_wrapper_delegate= 
    //    gcnew OpenEditorSlotWrapper::OpenEditorSlotWrapperDelegate(this, &OpenEditorSlotWrapper::wrapper);
    //  IntPtr ip = Marshal::GetFunctionPointerForDelegate(sw_wrapper_delegate);
    //  OPEN_EDITOR_CB cb = static_cast<OPEN_EDITOR_CB>(ip.ToPointer());
    //  return sigc::ptr_fun(cb);
    //}
  };

  //WbContext(::wb::WBContext *inn) : inner(inn), manager(nullptr)
  //{ }

  WbContext(bool verbose) : inner(new ::wb::WBContextUI(verbose)), manager(nullptr)
  { }

  ~WbContext()
  {
    delete mini_view;
  }

  ::wb::WBContextUI *get_unmanaged_object() 
  { return inner; }

  bool init(WbFrontendCallbacks^ callbacks, WbOptions^ options)
  {
    return inner->init(
      callbacks->get_unmanaged_object(), 
      options->get_unmanaged_object());

    //return inner->init(callbacks->get_unmanaged_object(), 
    //  std::auto_ptr<::wb::WBOptions>(options->get_unmanaged_object()).get());
  }

  bool use_opengl()
  {
    return inner->get_wb()->use_opengl();
  }

  bool is_busy()
  {
    return inner->get_wb()->get_grt_manager()->get_dispatcher()->get_busy();
  }

  void finalize()
  {
    inner->finalize();
  }

  GrtManager^ get_grt_manager()
  {
    if (manager == nullptr)
      manager= gcnew GrtManager(inner->get_wb()->get_grt_manager());

    return manager; 
  }

  //bec::IconManager *get_icon_manager() { return bec::IconManager::get_instance(); }

  String^ get_title()
  { return CppStringToNative(inner->get_title()); }

  bool has_unsaved_changes()
  { return inner->get_wb()->has_unsaved_changes(); }

  bool save_changes()
  { return inner->get_wb()->save_changes(); }

  void setup_mini_view(BaseWindowsCanvasView^ view)
  {
    mini_view= view;

    inner->setup_mini_view(mini_view->get_unmanaged_object());
  }


  void update_mini_view_size(int w, int h)
  {
    inner->update_mini_view_size(w, h);
  }

  void flush_idle_tasks()
  { 
    //inner->get_wb()->flush_idle_tasks(); 
    try 
    {
      inner->get_wb()->flush_idle_tasks(); 
    }
    catch(std::exception *ex)
    {
      throw gcnew BackendException(ex);
    }
    catch(std::exception &ex)
    {
      throw gcnew BackendException(&ex);
    }
    catch(...)
    {
      throw gcnew UnknownBackendException(__FILE__, __LINE__);
    }
  }

  double delay_for_next_timer()
  {
    return inner->get_wb()->get_grt_manager()->delay_for_next_timeout();
  }

  void flush_timers()
  {
    return inner->get_wb()->get_grt_manager()->flush_timers();
  }


  // edit menu handling
  void edit_copy()
  {
    if (inner->get_active_form())
      inner->get_active_form()->copy();
  }

  bool edit_can_copy()
  {
    if (inner->get_active_form() && inner->get_active_form()->can_copy())
      return true;
    return false;
  }

  void edit_cut()
  {
    if (inner->get_active_form())
      inner->get_active_form()->cut();
  }

  bool edit_can_cut()
  {
    if (inner->get_active_form() && inner->get_active_form()->can_cut())
      return true;
    return false;
  }

  void edit_paste()
  {
    if (inner->get_active_form())
      inner->get_active_form()->paste();
  }

  bool edit_can_paste()
  {
    if (inner->get_active_form() && inner->get_active_form()->can_paste())
      return true;
    return false;
  }

  void edit_select_all()
  {
    if (inner->get_active_form())
      inner->get_active_form()->select_all();
  }

  bool edit_can_select_all()
  {
    if (inner->get_active_form() && inner->get_active_form()->can_select_all())
      return true;
    return false;
  }

  void edit_delete()
  {
    if (inner->get_active_form())
      inner->get_active_form()->delete_selection();
  }

  bool edit_can_delete()
  {
    if (inner->get_active_form() && inner->get_active_form()->can_delete())
      return true;
    return false;
  }


  bool try_searching_diagram(String ^text)
  {
    bec::UIForm *form= inner->get_active_main_form();
    if (form && dynamic_cast<wb::ModelDiagramForm*>(form))
    {
      dynamic_cast<wb::ModelDiagramForm*>(form)->search_and_focus_object(NativeToCppString(text));
      return true;
    }
    return false;
  }

  
  typedef DelegateSlot0<void, void> CommandActionDelegate;
  typedef DelegateSlot0<bool, bool> CommandValidateDelegate;
  

  void set_edit_menu_delegates(CommandActionDelegate::ManagedDelegate ^copy_delegate,
                               CommandValidateDelegate::ManagedDelegate ^can_copy_delegate,
                               CommandActionDelegate::ManagedDelegate ^cut_delegate,
                               CommandValidateDelegate::ManagedDelegate ^can_cut_delegate,
                               CommandActionDelegate::ManagedDelegate ^paste_delegate,
                               CommandValidateDelegate::ManagedDelegate ^can_paste_delegate,
                               CommandActionDelegate::ManagedDelegate ^select_all_delegate,
                               CommandValidateDelegate::ManagedDelegate ^can_select_all_delegate,
                               CommandActionDelegate::ManagedDelegate ^delete_delegate,
                               CommandValidateDelegate::ManagedDelegate ^can_delete_delegate,
                               CommandActionDelegate::ManagedDelegate ^search_delegate)
  {
    this->copy_delegate= gcnew CommandActionDelegate(copy_delegate);
    this->can_copy_delegate= gcnew CommandValidateDelegate(can_copy_delegate);
    this->cut_delegate= gcnew CommandActionDelegate(cut_delegate);
    this->can_cut_delegate= gcnew CommandValidateDelegate(can_cut_delegate);
    this->paste_delegate= gcnew CommandActionDelegate(paste_delegate);
    this->can_paste_delegate= gcnew CommandValidateDelegate(can_paste_delegate);
    this->select_all_delegate= gcnew CommandActionDelegate(select_all_delegate);
    this->can_select_all_delegate= gcnew CommandValidateDelegate(can_select_all_delegate);
    this->delete_delegate= gcnew CommandActionDelegate(delete_delegate);
    this->can_delete_delegate= gcnew CommandValidateDelegate(can_delete_delegate);
    this->search_delegate= gcnew CommandActionDelegate(search_delegate);

    inner->get_command_ui()->add_builtin_command("copy", 
        this->copy_delegate->get_slot(),
        this->can_copy_delegate->get_slot());
    inner->get_command_ui()->add_builtin_command("cut", 
        this->cut_delegate->get_slot(),
        this->can_cut_delegate->get_slot());
    inner->get_command_ui()->add_builtin_command("paste", 
        this->paste_delegate->get_slot(),
        this->can_paste_delegate->get_slot());
    inner->get_command_ui()->add_builtin_command("selectAll", 
        this->select_all_delegate->get_slot(),
        this->can_select_all_delegate->get_slot());
    inner->get_command_ui()->add_builtin_command("delete", 
        this->delete_delegate->get_slot(),
        this->can_delete_delegate->get_slot());

    inner->get_command_ui()->add_builtin_command("searchbox", 
        this->search_delegate->get_slot());
  }
  


  // plugins
  void add_frontend_commands(List<String^>^ commands)
  {
    inner->get_command_ui()->add_frontend_commands(NativeToCppStringList2(commands));
  }

  List<MySQL::Grt::MenuItem^>^ get_main_menus()
  {
    return CppVectorToObjectList<::bec::MenuItem, MySQL::Grt::MenuItem>
      (inner->get_command_ui()->get_main_menus());
  }

  List<MySQL::Grt::MenuItem^>^ get_items_for_menu(String^ menu)
  { return CppVectorToObjectList<::bec::MenuItem, MySQL::Grt::MenuItem> (inner->get_command_ui()->get_menu_items(NativeToCppString(menu))); }

  List<WbToolbarItem^>^ get_items_for_toolbar(String^ toolbar)
  { return CppVectorToObjectList<::wb::WBToolbarItem, WbToolbarItem> (inner->get_command_ui()->get_toolbar_items(NativeToCppString(toolbar))); }


  void activate_command(String^ name)
  {
    std::string command= NativeToCppString(name);
    inner->get_command_ui()->activate_command(command);
  }


  List<String^>^ get_dropdown_items(String ^name, String^ option, [Out] String^ %selected)
  {
    std::string c_selected;
    List<String^>^ list;
    list= CppStringListToNative(inner->get_command_ui()->get_dropdown_items(NativeToCppString(name), NativeToCppString(option), c_selected));
    selected= CppStringToNative(c_selected);
    return list;
  }


  void select_dropdown_item(String^ name, String^ option, String^ item)
  { inner->get_command_ui()->select_dropdown_item(NativeToCppString(name), NativeToCppString(option), NativeToCppString(item)); }


  void toggle_checkbox_item(String^ name, String^ option, bool state)
  { inner->get_command_ui()->toggle_checkbox_item(NativeToCppString(name), NativeToCppString(option), state); }

  virtual FindDialogBE^ get_find_dialog()
  {
    return gcnew FindDialogBE(inner->get_find_dialog());
  }

  // Overview

  Overview^ get_main_overview()
  {
    if (main_overview == nullptr)
      main_overview= gcnew Overview(inner->get_main_overview());
    return main_overview;
  }

  Overview^ get_physical_overview()
  {
    if (physical_overview == nullptr)
      physical_overview= gcnew Overview(inner->get_physical_overview());
    return physical_overview;
  }

  ::MySQL::Grt::GrtValueTree^ get_catalog_tree()
  {
    if (catalog_tree == nullptr)
      catalog_tree= gcnew ::MySQL::Grt::GrtValueTree(inner->get_catalog_tree());

    return catalog_tree;
  }

  ::MySQL::Grt::GrtValueTree^ get_layer_tree()
  {
    if (layer_tree == nullptr)
      layer_tree= gcnew ::MySQL::Grt::GrtValueTree(inner->get_layer_tree());

    return layer_tree;
  } 

  ::MySQL::Grt::TreeModel^ get_history_tree()
  {
    if (history_tree == nullptr)
      history_tree= gcnew ::MySQL::Grt::TreeModel(inner->get_history_tree());
    
    return history_tree;
  }

  ::MySQL::Grt::ListModel^ get_usertypes_tree()
  {
    if (usertypes_tree == nullptr)
      usertypes_tree= gcnew ::MySQL::Grt::ListModel(inner->get_usertypes_tree());
    
    return usertypes_tree;
  } 

  ::MySQL::Grt::GrtValueInspector^ get_inspector_for_selection(UIForm^ form, [Out] List<String^>^ %items)
  {
    std::vector<std::string> vitems;
    bec::ValueInspectorBE *insp= 
      inner->create_inspector_for_selection(form->get_unmanaged_object(), vitems);
    if (!insp)
      insp= inner->create_inspector_for_selection(vitems);
    if (insp)
    {
      items= CppStringListToNative(vitems);
      return gcnew ::MySQL::Grt::GrtValueInspector(insp, true);
    }
    return nullptr;
  }

  bool are_lists_equal(GrtValue^ v1, GrtValue^ v2)
  {
    if ((nullptr == v1) || (nullptr == v2))
      return (v1 == v2);
    ::grt::ValueRef v1_(v1->get_unmanaged_object());
    ::grt::ValueRef v2_(v2->get_unmanaged_object());
    ::grt::ObjectListRef l1_= ::grt::ObjectListRef::cast_from(v1_);
    ::grt::ObjectListRef l2_= ::grt::ObjectListRef::cast_from(v2_);

    return ::grt::compare_list_contents(l1_, l2_);
  }

  String^ get_description_for_selection(UIForm^ form, [Out] GrtValue^ %activeObjList, [Out] List<String^>^ %items)
  {
    std::vector<std::string> vitems;
    ::grt::ListRef<GrtObject> activeObjList_;
    std::string val= 
      inner->get_description_for_selection(form->get_unmanaged_object(), activeObjList_, vitems);
    activeObjList= gcnew GrtValue(activeObjList_);
    items= CppStringListToNative(vitems);
    return CppStringToNative(val);
  }

  String^ get_description_for_selection([Out] GrtValue^ %activeObjList, [Out] List<String^>^ %items)
  {
    std::vector<std::string> vitems;
    ::grt::ListRef<GrtObject> activeObjList_;
    std::string val= inner->get_description_for_selection(activeObjList_, vitems);
    activeObjList= gcnew GrtValue(activeObjList_);
    items= CppStringListToNative(vitems);
    return CppStringToNative(val);
  }

  void set_description_for_selection(GrtValue^ activeObjList, String^ val)
  {
    std::string val_= NativeToCppString(val);
    ::grt::ListRef<GrtObject> activeObjList_(::grt::ListRef<GrtObject>::cast_from(activeObjList->get_unmanaged_object()));
    inner->set_description_for_selection(activeObjList_, val_);
  }

  ::MySQL::Workbench::ModelViewForm^ get_diagram_form_for_diagram(String^ id)
  {
    return gcnew ModelViewForm(inner->get_diagram_form_for_diagram_id(NativeToCppString(id)));
  }


  void set_active_form(UIForm^ uiform)
  {
    if (uiform == nullptr)
      inner->set_active_form(0);
    else
      inner->set_active_form(uiform->get_unmanaged_object());
  }

  String ^get_active_context()
  { return CppStringToNative(inner->get_active_context()); }

  // View
  void set_zoom(double zoom)
  {
    wb::ModelDiagramForm *form= dynamic_cast<wb::ModelDiagramForm*>(inner->get_active_main_form());
    if (form)
      form->set_zoom(zoom);
  }

  double get_zoom()
  {
    wb::ModelDiagramForm *form= dynamic_cast<wb::ModelDiagramForm*>(inner->get_active_main_form());
    if (form)
      return form->get_zoom();
    return 0.0;
  }

  String^ get_view_path_for_active_view()
  { return CppStringToNative(inner->get_view_path_for_active_view()); }


  void close_gui_plugin(IntPtr handle)
  {
    inner->get_wb()->close_gui_plugin((__int64)handle);
  }
  
  // State support.
  String^ read_state(String^ name, String^ domain, String^ default_value);
  int read_state(String^ name, String^ domain, const int default_value);
  double read_state(String^ name, String^ domain, const double default_value);
  bool read_state(String^ name, String^ domain, const bool default_value);

  void save_state(String^ name, String^ domain, String^ value);
  void save_state(String^ name, String^ domain, const int value);
  void save_state(String^ name, String^ domain, const double value);
  void save_state(String^ name, String^ domain, const bool value);

  // Paper.
  List<PaperSize^>^ get_paper_sizes()
  {
    return MySQL::Grt::CppListToObjectList<::wb::WBPaperSize,PaperSize>(inner->get_paper_sizes(false));
  }


  PageSettings^ get_page_settings()
  {
    return gcnew PageSettings(inner->get_page_settings());
  }


  void set_page_settings(PageSettings^ settings)
  {
    settings->update_object(inner->get_wb()->get_root()->options()->paperTypes(), inner->get_page_settings());
    inner->get_wb()->update_view_page_settings();//XXX
  }

  /**
   * To be called by the front end once the main form is ready.
   */
  void finished_loading(WbOptions^ options)
  {
    inner->init_finish(options->get_unmanaged_object());
  }

  void close_document_finish()
  {
    inner->get_wb()->close_document_finish();
  }
};



public ref class DiagramOptionsBE
{
  wb::DiagramOptionsBE *inner;

  MySQL::Grt::DelegateSlot0<void, void> ^_delegate;

public:
  DiagramOptionsBE(WindowsGDICanvasView ^view, WbContext ^wbContext, MySQL::Grt::DelegateSlot0<void, void>::ManagedDelegate ^deleg)
  {
    _delegate= gcnew MySQL::Grt::DelegateSlot0<void, void>(deleg);

    inner= new wb::DiagramOptionsBE(view->get_unmanaged_object(), 
      wbContext->get_unmanaged_object()->get_active_model_diagram(true), wbContext->get_unmanaged_object()->get_wb());

    inner->signal_changed().connect(_delegate->get_slot());
  }

  ~DiagramOptionsBE()
  {
    delete _delegate;
    delete inner;
  }

  String ^get_name()
  {
    return CppStringToNative(inner->get_name());
  }

  void set_name(String ^name)
  {
    inner->set_name(NativeToCppString(name));
  }

  int get_xpages() 
  {
    return inner->get_xpages();
  }

  int get_ypages()
  {
    return inner->get_ypages();
  }

  void set_xpages(int c)
  {
    inner->set_xpages(c);
  }

  void set_ypages(int c)
  {
    inner->set_ypages(c);
  }

  void commit()
  {
    inner->commit();
  }

  void update_size()
  {
    inner->update_size();
  }
};


} // namespace Workbench
} // namespace MySQL

#endif // __WB_H__
