
#include "stdafx.h"

#include "wb_config.h"
#include "wb_module.h"
#include "wb_overview.h"
#include "wb_model_diagram_form.h"
#include "wb_context_ui.h"
#include "wb_context.h"
#include "wb_component.h"

#include "wb_overview_workspace.h"

#include "mdc_back_layer.h"

#include "grt/common.h"

#include "myx_util_public_interface.h"

#include "wbcanvas/model_figure_impl.h"

#include <mforms/mforms.h>

#include "user_defined_type_editor.h"
#include "preferences_form.h"
#include "document_properties_form.h"

#include "grtui/grtdb_connection_editor.h"

using namespace wb;
using namespace grt;

WorkbenchImpl::WorkbenchImpl(CPPModuleLoader *loader)
: super(loader), _wb(0)
{
  _current_user_type_editor= NULL;
}


void WorkbenchImpl::set_context(WBContext *wb)
{
  _wb= wb;
}


#define def_plugin(group, aName, type, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType(type);\
    plugin->groups().insert("Application/Workbench");\
    list.insert(plugin);\
  }

#define def_object_plugin(group, klass, aName, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType("normal");\
    plugin->groups().insert("Application/Workbench");\
    app_PluginObjectInputRef input(get_grt());\
    input->owner(plugin);\
    input->objectStructName(klass::static_class_name());\
    plugin->inputValues().insert(input);\
    list.insert(plugin);\
  }


#define def_view_plugin(group, aName, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType("normal");\
    plugin->groups().insert("Application/Workbench");\
    app_PluginObjectInputRef input(get_grt());\
    input->owner(plugin);\
    input->name("activeDiagram");\
    input->objectStructName(model_Diagram::static_class_name());\
    plugin->inputValues().insert(input);\
    list.insert(plugin);\
  }

#define def_model_plugin(group, aName, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType("normal");\
    plugin->groups().insert("Application/Workbench");\
    app_PluginObjectInputRef input(get_grt());\
    input->owner(plugin);\
    input->name("activeModel");\
    input->objectStructName(model_Model::static_class_name());\
    plugin->inputValues().insert(input);\
    list.insert(plugin);\
  }

#define def_form_model_plugin(group, aName, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType("standalone");\
    plugin->groups().insert("Application/Workbench");\
    app_PluginObjectInputRef input(get_grt());\
    input->owner(plugin);\
    input->name("activeModel");\
    input->objectStructName(model_Model::static_class_name());\
    plugin->inputValues().insert(input);\
    list.insert(plugin);\
  }

#define def_form_plugin(group, aName, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType("standalone");\
    plugin->groups().insert("Application/Workbench");\
    list.insert(plugin);\
  }


#define def_arg_plugin(group, aName, type, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    app_PluginInputDefinitionRef pdef(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType(type);\
    pdef->owner(plugin);\
    plugin->inputValues().insert(pdef);\
    plugin->groups().insert("Application/Workbench");\
    list.insert(plugin);\
  }

#define def_model_arg_plugin(group, aName, type, aCaption, descr)\
  {\
    app_PluginRef plugin(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType(type);\
    app_PluginInputDefinitionRef pdef(get_grt());\
      pdef->owner(plugin);\
      pdef->name("string");\
      plugin->inputValues().insert(pdef);\
    app_PluginObjectInputRef model(get_grt());\
      model->owner(plugin);\
      model->name("activeModel");\
      model->objectStructName(model_Model::static_class_name());\
      plugin->inputValues().insert(model);\
    plugin->groups().insert("Application/Workbench");\
    list.insert(plugin);\
  }

#define def_file_plugin(group, aName, ptype, aCaption, descr, aDialogCaption, aType, aExtensions)\
  {\
    app_PluginRef plugin(get_grt());\
    app_PluginFileInputRef pdef(get_grt());\
    plugin->name("wb."group"."aName);\
    plugin->caption(aCaption);\
    plugin->description(descr);\
    plugin->moduleName("Workbench");\
    plugin->moduleFunctionName(aName);\
    plugin->pluginType(ptype);\
    pdef->owner(plugin);\
    pdef->dialogTitle(aDialogCaption);\
    pdef->dialogType(aType);\
    pdef->fileExtensions(aExtensions);\
    plugin->inputValues().insert(pdef);\
    plugin->groups().insert("Application/Workbench");\
    list.insert(plugin);\
  }


ListRef<app_Plugin> WorkbenchImpl::getPluginInfo()
{
  ListRef<app_Plugin> list(get_grt());

  def_plugin      ("file", "newDocument", "internal", "New", "New Document");
  def_file_plugin ("file", "openModel", "internal", "Open", "Open Model from File", "Open Model", "open", "mwb");
  def_plugin      ("file", "saveModel", "internal", "Save", "Save Model to Current File");
  def_arg_plugin  ("file", "openRecentModel", "internal", "Open Model", "Open Model");
  def_file_plugin ("file", "saveModelAs", "internal", "Save As", "Save Model to a New File", "Save Model", "save", "mwb");
  def_plugin      ("file", "exit", "internal", "Exit", "Exit Workbench");
    
  def_file_plugin ("export", "exportPNG", "normal", "Export as PNG", "Export Current Diagram as PNG", "Export as PNG", "save", "png");
  def_file_plugin ("export", "exportPDF", "normal", "Export as PDF", "Export Current Diagram as PDF", "Export as PDF", "save", "pdf");
  def_file_plugin ("export", "exportSVG", "normal", "Export as SVG", "Export Current Diagram as SVG", "Export as SVG", "save", "svg");
  def_file_plugin ("export", "exportPS", "normal", "Export as PS", "Export Current Diagram as PostScript", "Export as PostScript", "save", "ps");

  def_plugin("edit", "selectAll", "internal", "Select All", "Select All Objects in Diagram");
  def_plugin("edit", "selectSimilar", "internal", "Select Similar Figures", "Select Similar Figures in Diagram");
  def_plugin("edit", "selectConnected", "internal", "Select Connected Figures", "Select Figures Connected to the Selected One");

  def_view_plugin("edit", "raiseSelection", "Bring to Front", "Bring Selected Object to Front");
  def_view_plugin("edit", "lowerSelection", "Send to Back", "Send Selected Object to Back");

  def_view_plugin("edit", "toggleGridAlign", "Align to Grid", "Align Objects to Grid");
  def_view_plugin("edit", "toggleGrid", "Toggle Grid", "Toggle Grid");
  def_view_plugin("edit", "togglePageGrid", "Toggle Page Guides", "Toggle Page Guides");
  
  def_view_plugin("edit", "editSelectedFigure", "Edit Selected Objects", "Edit Selected Objects");
  def_view_plugin("edit", "editSelectedFigureInNewWindow", "Edit Selected Objects in New Window", "Edit Selected Objects in New Window");
  
  def_object_plugin("edit", GrtObject, "editObject", "Edit Selected Object", "Edit Selected Object");
  def_object_plugin("edit", GrtObject, "editObjectInNewWindow", "Edit Selected Object in New Window", "Edit Selected Object in New Window");

  def_plugin("edit", "goToNextSelected", "internal", "Go to Next Selected", "Go to Next Selected Object");
  def_plugin("edit", "goToPreviousSelected", "internal", "Go to Previous Selected", "Go to Previous Selected Object");

  def_plugin("view", "zoomIn", "normal", "Zoom In", "Zoom In Diagram");
  def_plugin("view", "zoomOut", "normal", "Zoom Out", "Zoom Out Diagram");
  def_plugin("view", "zoomDefault", "normal", "Zoom 100%", "Zoom Back Diagram to Default");

  def_arg_plugin("view", "goToMarker", "normal", "Go to Marker", "Go to Previously Set Diagram Marker");
  def_arg_plugin("view", "setMarker", "normal", "Set a Marker", "Set a Diagram Marker to the Current Location");

  def_model_arg_plugin("view", "setFigureNotation", "normal", "Set Objects Notation", "Set Object Notation");
  def_model_arg_plugin("view", "setRelationshipNotation", "normal", "Set Relationships Notation", "Set Relationship Notation");

  def_model_plugin("model", "newDiagram", "Add New Diagram", "Add a New Diagram to the Model");

  def_file_plugin("tools", "runScriptFile", "normal", "Run Script File", "Select a Script File to Execute", "Open Script", "open", "lua,py");
  def_file_plugin("tools", "installModuleFile", "normal", "Install Module File", "Select a Module or Plugin File to Install", "Select Module", "open", "lua,py");

  def_form_model_plugin("form", "showUserTypeEditor", "User Types Editor", "Open User Defined Types Editor");
  def_form_model_plugin("form", "showModelOptions", "Show Model Options", "Open Model Options Window");
  def_form_plugin("form", "showDocumentProperties", "Document Properties", "Open Document Properties Window");
  def_form_plugin("form", "showOptions", "Preferences", "Open Options Window");
  def_form_plugin("form", "showConnectionManager", "Manage Database Connections", "Open DB Connection Manager");
  
  def_plugin("debug", "debugValidateGRT", "normal", "Validate GRT Tree", "Validate Consistency of GRT Tree");
  def_plugin("debug", "debugShowInfo", "normal", "Show Debugging Info", "Show various system and application information");
  def_plugin("debug", "debugGrtStats", "normal", "Show GRT Debugging Info", "Show various internal GRT stats");

  return list;
}


int WorkbenchImpl::copyToClipboard(const std::string &astr)
{
  _wb->get_grt_manager()->get_dispatcher()
    ->call_from_main_thread<void>(sigc::bind(sigc::ptr_fun(mforms::Utilities::set_clipboard_text), astr), true);

  return 1;
}


int WorkbenchImpl::hasUnsavedChanges()
{
  return _wb->has_unsaved_changes() ? 1 : 0;
}



int WorkbenchImpl::newDocument()
{
  _wb->new_document();

  return 0;
}


int WorkbenchImpl::openModel(const std::string &filename)
{
  _wb->open_document(filename);

  return 0;
}


int WorkbenchImpl::openRecentModel(const std::string &index)
{
  _wb->open_recent_document(atoi(index.c_str()));

  return 0;
}


int WorkbenchImpl::saveModel()
{
  _wb->save_as(_wb->get_filename());

  return 0;
}


int WorkbenchImpl::saveModelAs(const std::string &filename)
{
  _wb->save_as(bec::append_extension_if_needed(filename, ".mwb"));

  return 0;
}


int WorkbenchImpl::exportPNG(const std::string &filename)
{
  _wb->export_png(bec::append_extension_if_needed(filename, ".png"));

  return 0;
}

int WorkbenchImpl::exportPDF(const std::string &filename)
{
  _wb->export_pdf(bec::append_extension_if_needed(filename, ".pdf"));

  return 0;
}


int WorkbenchImpl::exportSVG(const std::string &filename)
{
  _wb->export_svg(bec::append_extension_if_needed(filename, ".svg"));

  return 0;
}


int WorkbenchImpl::exportPS(const std::string &filename)
{
  _wb->export_ps(bec::append_extension_if_needed(filename, ".ps"));

  return 0;
}


static void quit(WBContext *wb)
{
  if (wb->get_ui()->request_quit())
    wb->get_ui()->perform_quit();
}

int WorkbenchImpl::exit()
{
  _wb->get_grt_manager()->get_dispatcher()->
  call_from_main_thread<void>(sigc::bind(sigc::ptr_fun(quit), _wb), false);

  return 0;
}



int WorkbenchImpl::selectAll()
{
  if (dynamic_cast<ModelDiagramForm*>(_wb->get_active_form()))
  {
    _wb->get_active_form()->select_all();
  }
  return 0;
}


int WorkbenchImpl::selectSimilar()
{
  if (!dynamic_cast<ModelDiagramForm*>(_wb->get_active_form())) return 0;

  model_DiagramRef view(dynamic_cast<ModelDiagramForm*>(_wb->get_active_form())->get_model_diagram());
  std::string figure_type;

  if (view->selection().count() != 1)
    return 0;

  model_ObjectRef object(view->selection().get(0));

  figure_type= object.class_name();

  view->unselectAll();

  if (model_FigureRef::can_wrap(object))
  {
    for (size_t c= view->figures().count(), i= 0; i < c; i++)
    {
      model_FigureRef figure(view->figures().get(i));

      if (figure.is_instance(figure_type))
        view->selectObject(figure);
    }
  }
  else if (model_ConnectionRef::can_wrap(object))
  {
    for (size_t c= view->connections().count(), i= 0; i < c; i++)
    {
      model_ConnectionRef conn(view->connections().get(i));

      if (conn.is_instance(figure_type))
        view->selectObject(conn);
    }
  }
  else if (model_LayerRef::can_wrap(object))
  {
    for (size_t c= view->layers().count(), i= 0; i < c; i++)
    {
      model_LayerRef layer(view->layers().get(i));

      if (layer.is_instance(figure_type))
        view->selectObject(layer);
    }
  }

  return 0;
}



int WorkbenchImpl::selectConnected()
{
  if (!dynamic_cast<ModelDiagramForm*>(_wb->get_active_form())) return 0;

  model_DiagramRef view(dynamic_cast<ModelDiagramForm*>(_wb->get_active_form())->get_model_diagram());
  std::string figure_type;
  model_FigureRef figure;

  if (view->selection().count() != 1)
    return 0;

  if (model_FigureRef::can_wrap(view->selection().get(0)))
    figure= model_FigureRef::cast_from(view->selection().get(0));

  if (figure.is_valid())
  {
    std::set<std::string> added;

    added.insert(figure.id());

    for (size_t c= view->connections().count(), i= 0; i < c; i++)
    {
      model_ConnectionRef conn(view->connections().get(i));

      if (conn->startFigure() == figure)
      {
        if (added.find(conn->endFigure()->id()) == added.end())
        {
          added.insert(conn->endFigure()->id());
          view->selectObject(conn->endFigure());
        }
      }
      else if (conn->endFigure() == figure)
      {
        if (added.find(conn->startFigure()->id()) == added.end())
        {
          added.insert(conn->startFigure()->id());
          view->selectObject(conn->startFigure());
        }
      }
    }
  }

  return 0;
}


static void activate_object(WBComponent *compo, const model_ObjectRef &object, bool newwindow)
{
  if (compo->handles_figure(object))
    compo->activate_canvas_object(object, newwindow);
}


int WorkbenchImpl::editSelectedFigure(const model_DiagramRef &view)
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_form());
  if (form)
  {
    ListRef<model_Object> list(form->get_selection());

    for (size_t c= list.count(), i= 0; i < c; i++)
    {
      _wb->foreach_component(sigc::bind<model_ObjectRef,bool>(sigc::ptr_fun(activate_object), list.get(i), false));
    }
  }
  return 0;
}

int WorkbenchImpl::editSelectedFigureInNewWindow(const model_DiagramRef &view)
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_form());
  if (form)
  {
    ListRef<model_Object> list(form->get_selection());

    for (size_t c= list.count(), i= 0; i < c; i++)
    {
      _wb->foreach_component(sigc::bind<model_ObjectRef,bool>(sigc::ptr_fun(activate_object), list.get(i), true));
    }
  }
  return 0;
}


int WorkbenchImpl::editObject(const GrtObjectRef &object)
{
  _wb->open_object_editor(object, false);
  return 0;
}


int WorkbenchImpl::editObjectInNewWindow(const GrtObjectRef &object)
{
  _wb->open_object_editor(object, true);
  return 0;
}



int WorkbenchImpl::goToNextSelected()
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_form());
  if (!form) return 0;

  model_DiagramRef view(form->get_model_diagram());

  if (view->selection().count() == 0)
    return 0;

  for (size_t c= view->selection().count(), i= 0; i < c; i++)
  {
    model_Figure::ImplData *figure= model_FigureRef::cast_from(view->selection().get(i))->get_data();
    if (figure && figure->get_canvas_item())
    {
      if (form->get_view()->get_focused_item() == figure->get_canvas_item())
      {
        if (i < view->selection().count()-1)
        {
          form->focus_and_make_visible(view->selection().get(i+1), false);
          return 0;
        }
        break;
      }
    }
  }

  // focus 1st
  form->focus_and_make_visible(view->selection().get(0), false);
  
  return 0;
}


int WorkbenchImpl::goToPreviousSelected()
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_form());
  if (!form) return 0;

  model_DiagramRef view(form->get_model_diagram());
  if (view->selection().count() == 0)
    return 0;

  for (size_t c= view->selection().count(), i= 0; i < c; i++)
  {
    model_Figure::ImplData *figure= model_FigureRef::cast_from(view->selection().get(i))->get_data();
    if (figure && figure->get_canvas_item())
    {
      if (form->get_view()->get_focused_item() == figure->get_canvas_item())
      {
        if (i > 0)
        {
          form->focus_and_make_visible(view->selection().get(i-1), false);
          return 0;
        }
        break;
      }
    }
  }
  form->focus_and_make_visible(view->selection().get(view->selection().count()-1), false);
  
  return 0;
}



int WorkbenchImpl::newDiagram(const model_ModelRef &model)
{
  model->addNewDiagram(false);

  return 0;
}


// canvas manipulation

int WorkbenchImpl::raiseSelection(const model_DiagramRef &view)
{
  for (size_t c= view->selection().count(), i= 0; i < c; i++)
  {
    if (view->selection().get(i).is_instance(model_Figure::static_class_name()))
    {
      model_FigureRef figure(model_FigureRef::cast_from(view->selection()[i]));

      figure->layer()->raiseFigure(figure);
    }
  }
  return 0;
}


int WorkbenchImpl::lowerSelection(const model_DiagramRef &view)
{
  for (size_t c= view->selection().count(), i= 0; i < c; i++)
  {
    if (view->selection().get(i).is_instance(model_Figure::static_class_name()))
    {
      model_FigureRef figure(model_FigureRef::cast_from(view->selection()[i]));
      
      figure->layer()->lowerFigure(figure);
    }
  }
  return 0;
}



int WorkbenchImpl::toggleGridAlign(const model_DiagramRef &view)
{
  ModelDiagramForm *form= _wb->get_ui()->get_diagram_form_for_diagram_id(view->id());
  if (form)
  {
    form->get_view()->set_grid_snapping(!form->get_view()->get_grid_snapping());

    view->options().gset("AlignToGrid", form->get_view()->get_grid_snapping()?1:0);
  }
  return 0;
}


int WorkbenchImpl::toggleGrid(const model_DiagramRef &view)
{
  ModelDiagramForm *form= _wb->get_ui()->get_diagram_form_for_diagram_id(view->id());
  if (form)
  {    
    form->get_view()->get_background_layer()->set_grid_visible(!form->get_view()->get_background_layer()->get_grid_visible());

    view->options().gset("ShowGrid", form->get_view()->get_background_layer()->get_grid_visible()?1:0);
  }
  return 0;
}


int WorkbenchImpl::togglePageGrid(const model_DiagramRef &view)
{
  ModelDiagramForm *form= _wb->get_ui()->get_diagram_form_for_diagram_id(view->id());
  if (form)
  {    
    form->get_view()->get_background_layer()->set_paper_visible(!form->get_view()->get_background_layer()->get_paper_visible());
    
    view->options().gset("ShowPageGrid", form->get_view()->get_background_layer()->get_paper_visible()?1:0);
  }
  return 0;
}


int WorkbenchImpl::goToMarker(const std::string &marker)
{
  model_ModelRef model(_wb->get_ui()->get_active_model(true));

  if (model.is_valid())
  {
    model_MarkerRef mk;
    
    for (size_t c= model->markers().count(), i= 0; i < c; i++)
      if (*model->markers().get(i)->name() == marker)
      {
        mk= model->markers().get(i);
        break;
      }
    
    if (mk.is_valid())
    {
      ModelDiagramForm *form= _wb->get_ui()->get_diagram_form_for_diagram_id(mk->diagram()->id());
      if (form)
      {
        form->get_view()->set_zoom((float)mk->zoom());
        form->get_view()->set_offset(mdc::Point(*mk->x(), *mk->y()));
        if (form->get_model_diagram() != mk->diagram())
        {
          _wb->get_grt_manager()->get_dispatcher()->call_from_main_thread<void>(
            sigc::bind<model_DiagramRef>(sigc::mem_fun(_wb, &WBContext::switch_diagram), model_DiagramRef::cast_from(mk->diagram())), false);
        }
      }
    }
  }

  return 0;
}


int WorkbenchImpl::setMarker(const std::string &marker)
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_ui()->get_active_main_form());

  if (form)
  {
    model_MarkerRef mk(get_grt());
    
    model_ModelRef model(form->get_model_diagram()->owner());

    for (size_t c= model->markers().count(), i= 0; i < c; i++)
      if (*model->markers().get(i)->name() == marker)
      {
        model->markers().remove(i);
        break;
      }
    
    mk->owner(model);
    mk->name(marker);
    mk->diagram(form->get_model_diagram());
    mk->zoom(form->get_view()->get_zoom());
    mk->x(form->get_view()->get_viewport().xmin());
    mk->y(form->get_view()->get_viewport().ymin());

    model->markers().insert(mk);
  }
  return 0;
}


int WorkbenchImpl::setFigureNotation(const std::string &name, workbench_physical_ModelRef model)
{
//  model_ModelRef model(_wb->get_ui()->get_active_model(true));

  if (model.is_valid() && model.is_instance<workbench_physical_Model>())
    workbench_physical_ModelRef::cast_from(model)->figureNotation(name);

  return 0;
}


int WorkbenchImpl::setRelationshipNotation(const std::string &name, workbench_physical_ModelRef model)
{
//  model_ModelRef model(_wb->get_ui()->get_active_model(true));

  if (model.is_valid() && model.is_instance<workbench_physical_Model>())
    workbench_physical_ModelRef::cast_from(model)->connectionNotation(name);

  return 0;
}


int WorkbenchImpl::zoomIn()
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_main_form());
  if (!form) return 0;

  form->zoom_in();
  return 0;
}


int WorkbenchImpl::zoomOut()
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_main_form());
  if (!form) return 0;

  form->zoom_out();
  
  return 0;
}


int WorkbenchImpl::zoomDefault()
{
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_main_form());
  if (!form) return 0;

  model_DiagramRef view(form->get_model_diagram());

  view->zoom(1.0);

  return 0;
}



int WorkbenchImpl::startTrackingUndo()
{
  get_grt()->begin_undoable_action();
  return 0;
}


int WorkbenchImpl::finishTrackingUndo(const std::string &description)
{
  get_grt()->end_undoable_action(description);
  return 0;
}


int WorkbenchImpl::cancelTrackingUndo()
{
  get_grt()->cancel_undoable_action();
  return 0;
}



int WorkbenchImpl::addUndoListAdd(const BaseListRef &list)
{
  get_grt()->get_undo_manager()->add_undo(new grt::UndoListInsertAction(list));
  return 0;
}

int WorkbenchImpl::addUndoListRemove(const BaseListRef &list, int index)
{
  get_grt()->get_undo_manager()->add_undo(new grt::UndoListRemoveAction(list, index));
  return 0;
}

int WorkbenchImpl::addUndoObjectChange(const ObjectRef &object, const std::string &member)
{
  get_grt()->get_undo_manager()->add_undo(new grt::UndoObjectChangeAction(object, member));
  return 0;
}

int WorkbenchImpl::addUndoDictSet(const DictRef &dict, const std::string &key)
{
  _wb->get_grt()->get_undo_manager()->add_undo(new grt::UndoDictSetAction(dict, key));
  return 0;
}

int WorkbenchImpl::beginUndoGroup()
{
  _wb->get_grt()->get_undo_manager()->begin_undo_group();
  return 0;
}

int WorkbenchImpl::endUndoGroup()
{
  _wb->get_grt()->get_undo_manager()->end_undo_group();
  return 0;
}

int WorkbenchImpl::setUndoDescription(const std::string &text)
{
  _wb->get_grt()->get_undo_manager()->set_action_description(text);
  return 0;
}


std::string WorkbenchImpl::createAttachedFile(const std::string &group, 
                                              const std::string &tmpl)
{
  return _wb->create_attached_file(group, tmpl);
}


int WorkbenchImpl::setAttachedFileContents(const std::string &filename, 
                                           const std::string &text)
{
  _wb->save_attached_file_contents(filename, text.data(), text.size());
  return 0;
}


std::string WorkbenchImpl::getAttachedFileContents(const std::string &filename)
{
  return _wb->get_attached_file_contents(filename);
}


std::string WorkbenchImpl::getAttachedFileTmpPath(const std::string &filename)
{
  return _wb->get_attached_file_tmp_path(filename);
}


int WorkbenchImpl::exportAttachedFileContents(const std::string &filename, 
                                              const std::string &export_to)
{
  return _wb->export_attached_file_contents(filename, export_to);
}


int WorkbenchImpl::runScriptFile(const std::string &filename)
{
  get_grt()->make_output_visible();
  get_grt()->send_output("Executing script "+filename+"...\n");

  _wb->get_grt_manager()->push_status_text("Executing script...");
  
  grt::AutoUndo undo(get_grt());
  
  _wb->get_grt_manager()->get_shell()->run_script(filename);

  char *basename= g_path_get_basename(filename.c_str());
  undo.end_or_cancel_if_empty(strfmt("Execute Script %s", basename));
  g_free(basename);
  
  get_grt()->send_output("\nScript finished.\n");
  _wb->get_grt_manager()->pop_status_text();
  
  return 0;
}


int WorkbenchImpl::installModuleFile(const std::string &filename)
{
  std::string module_dir= _wb->get_grt_manager()->get_user_module_path();
  std::string target_path;
  std::string lang_extension;
  gchar *fname;
  
  fname= g_path_get_basename(filename.c_str());
  {
    gchar *ptr= strrchr(fname, '.');
    if (ptr)
    {
      // get lang extension (.lua, .py) and strip it
      lang_extension= ptr;
      *ptr= 0;
    }
  }
  target_path= module_dir + "/" + fname;
  g_free(fname);
  
  if (!g_str_has_suffix(target_path.c_str(), ".grt")) // if the extension is not .grt, add it
  {
    target_path.append(".grt");
  }
  // add back the lang_extension
  target_path.append(lang_extension);
  
  get_grt()->make_output_visible();
  
  if (g_file_test(target_path.c_str(), G_FILE_TEST_EXISTS))
  {
    get_grt()->send_output(strfmt("ERROR: module '%s' already exists", target_path.c_str()));
  }
  else if (module_dir.empty())
  {
    get_grt()->send_output("ERROR: user module install directory is not known");
  }
  else if (!copy_file(filename.c_str(), target_path.c_str()))
  {
    int err= errno;
    get_grt()->send_output(strfmt("ERROR: could not copy module '%s' to '%s': %s",
                           filename.c_str(), target_path.c_str(), g_strerror(err)));
  }
  else
  {
    get_grt()->send_output(strfmt("Copied module %s to '%s'\n", 
                                  filename.c_str(), 
                                  target_path.c_str()));
    get_grt()->send_output("Please restart Workbench for the change to take effect.\n");
  }
  
  return 0;
}


static int traverse_value(GRT *grt, const ObjectRef &owner, const std::string &member, const ValueRef &value);

static bool traverse_member(const MetaClass::Member *member, const ObjectRef &owner, const ObjectRef &object, GRT *grt)
{      
  std::string k= member->name;
  ValueRef v= object->get_member(k);

  if (!v.is_valid())
  {
    if((member->type.base.type == ListType) || (member->type.base.type == DictType))
      grt->send_output(strfmt("%s[%s] (type: %s, name: '%s', id: %s), has NULL list or dict member: '%s'\n", 
                                owner.class_name().c_str(), k.c_str(), 
                                object.class_name().c_str(), object.get_string_member("name").c_str(), object.id().c_str(),
                                k.c_str()));
  }

  if (k == "owner")
  {
    if (ObjectRef::cast_from(v) != owner)
    {
      if (!v.is_valid())
        grt->send_output(strfmt("%s[%s] (type: %s, name: '%s', id: %s), has no owner set\n", 
                                  owner.class_name().c_str(), member->name.c_str(),
                                  object.class_name().c_str(), object->get_string_member("name").c_str(), object.id().c_str()));
      else
        grt->send_output(strfmt("%s[%s] (type: %s, name: '%s', id: %s), has bad owner (or missing attr:dontfollow)\n", 
                                  owner.class_name().c_str(), member->name.c_str(), 
                                  object.class_name().c_str(), object->get_string_member("name").c_str(), object.id().c_str()));
    }
  }

  if (member->owned_object)
    traverse_value(grt, object, k, v);
  
  return true;
}


static int traverse_value(GRT *grt, const ObjectRef &owner, const std::string &member, const ValueRef &value)
{
  switch (value.type())
  {
  case DictType:
    {
      DictRef dict(DictRef::cast_from(value));

      for (DictRef::const_iterator iter= dict.begin(); iter != dict.end(); ++iter)
      {
        std::string k= iter->first;
        ValueRef v= iter->second;

        traverse_value(grt, owner, k, v);
      }
    }
    break;
  case ListType:
    {
      BaseListRef list(BaseListRef::cast_from(value));

      for (size_t c= list.count(), i= 0; i < c; i++)
      {
        ValueRef v;

        v= list.get(i);

        traverse_value(grt, owner, strfmt("%i", i), v);
      }
    }
    break;
  case ObjectType:
    {
      ObjectRef object(ObjectRef::cast_from(value));
      MetaClass *gstruct= object->get_metaclass();
     
      gstruct->foreach_member(sigc::bind<ObjectRef,ObjectRef,GRT*>(sigc::ptr_fun(traverse_member), owner, object, grt));
    }
    break;

  default:
    break;
  }
  return 0;
}


int WorkbenchImpl::debugValidateGRT()
{
  ValueRef root(get_grt()->root());
  ObjectRef owner;

  get_grt()->send_output("Validating GRT Tree...\n");

//QQQ  get_grt()->lock_tree_read();

  // make sure that all nodes have their owner set to their parent object
  // make sure that all refs that are not owned are marked dontfollow
  traverse_value(get_grt(), owner, "root", root);

//QQQ  get_grt()->unlock_tree_read();

  get_grt()->send_output("GRT Tree Validation Finished.\n");

  return 0;
}


int WorkbenchImpl::debugGrtStats()
{
  return 0;
}


int WorkbenchImpl::debugShowInfo()
{
  grt::GRT *grt= get_grt();

  grt->make_output_visible();

#ifdef EDITION_OSS
#define EDITION_NAME "OSS"
#elif defined(EDITION_SE)
#define EDITION_NAME "SE"
#else
#define EDITION_NAME "unknown edition"
#endif

#ifdef _WIN32
#define PLATFORM_NAME "Windows"
#define NATIVE_RENDERER "GDI"
#elif defined(__APPLE__)
#define PLATFORM_NAME "Mac OS X"
#define NATIVE_RENDERER "Quartz"
#else
#define PLATFORM_NAME "Linux/Unix"
#define NATIVE_RENDERER "Native"
#endif

  grt->send_output(strfmt("MySQL Workbench "EDITION_NAME" for "PLATFORM_NAME" version %i.%i.%i\n", APP_MAJOR_NUMBER, APP_MINOR_NUMBER, APP_RELEASE_NUMBER));

  int cver= cairo_version();
  grt->send_output(strfmt("Cairo Version: %i.%i.%i\n", (cver/10000)%100, (cver/100)%100, cver%100));

  gchar *tmp;
  gchar *render_mode = "Unknown";
  switch (_wb->using_opengl())
  {
      case 0: render_mode= NATIVE_RENDERER; break;
      case 1: render_mode= "OpenGL"; break;
      case -1: 
        if (_wb->use_opengl())
          render_mode= "OpenGL requested (create a diagram to confirm)"; 
        else
          render_mode= NATIVE_RENDERER" requested (create a diagram to confirm)";
        break;
  }
  grt->send_output(strfmt("Rendering Mode: %s\n", render_mode));
  if (_wb->using_opengl() != 0)
  {
    if (_wb->is_opengl_available())
      grt->send_output(strfmt("OpenGL Driver Version: %s\n", _wb->_opengl_version.c_str()));
    else
      grt->send_output(strfmt("OpenGL Driver Version: Not Detected\n"));
  }
  grt->send_output(strfmt("OS: %s\n", tmp= get_local_os_name()));
  g_free(tmp);
  grt->send_output(strfmt("CPU: %s\n", tmp= get_local_hardware_info()));
  g_free(tmp);

#ifdef _WIN32
  tmp= get_video_driver_info();
  grt->send_output(tmp);
  g_free(tmp);
#elif defined(__APPLE__)
#warning NOT IMPLEMENTED
#else
#warning not implemented
#endif

  return 0;
}


std::string WorkbenchImpl::request_input_m(const std::string &caption)
{
  std::string result;

  if (_wb->request_input(caption, 0, result))
    return result;
  return "";
}


std::string WorkbenchImpl::input(const std::string &caption)
{
  return _wb->get_grt_manager()->get_dispatcher()->call_from_main_thread<std::string>(
    sigc::bind<std::string>(sigc::mem_fun(this, &WorkbenchImpl::request_input_m), caption), true);
}


int WorkbenchImpl::confirm(const std::string &title, const std::string &caption)
{
  return _wb->get_grt_manager()->get_dispatcher()->
  call_from_main_thread<int>(sigc::bind(_wb->confirm_action, title, caption, _("OK"), _("Cancel"), ""), true);
}


std::string WorkbenchImpl::requestFileOpen(const std::string &caption, const std::string &extensions)
{
  return _wb->get_grt_manager()->get_dispatcher()->
  call_from_main_thread<std::string>(sigc::bind(_wb->show_file_dialog, "open", caption, extensions), true);
}


std::string WorkbenchImpl::requestFileSave(const std::string &caption, const std::string &extensions)
{
  return _wb->get_grt_manager()->get_dispatcher()->
  call_from_main_thread<std::string>(sigc::bind(_wb->show_file_dialog, "save", caption, extensions), true);
}



int WorkbenchImpl::showUserTypeEditor(const workbench_physical_ModelRef &model)
{
  if ( _current_user_type_editor == NULL)
  {
    _current_user_type_editor = new UserDefinedTypeEditor(_wb->get_ui(), model);
    _current_user_type_editor->signal_closed().connect(sigc::mem_fun(this, &WorkbenchImpl::userTypeEditorClosed));
  }
  _current_user_type_editor->show_modal(NULL, NULL);
  
  return 0;
}

/**
 * Called by the front end when the user data type editor has been closed. We can then remove our reference to it.
 */
void WorkbenchImpl::userTypeEditorClosed()
{
  _current_user_type_editor= NULL;
}

int WorkbenchImpl::showDocumentProperties()
{
  DocumentPropertiesForm props(_wb->get_ui());
    
  props.show();
  
  return 0;
}


static void delete_preferences(PreferencesForm *form)
{
  delete form;
}


int WorkbenchImpl::showModelOptions(const workbench_physical_ModelRef &model)
{
  PreferencesForm *prefs= new PreferencesForm(_wb->get_ui(), model.id());
  prefs->set_closed_handler(sigc::bind(sigc::ptr_fun(delete_preferences), prefs));
  prefs->show();
  
  return 0;
}


int WorkbenchImpl::showOptions()
{
  PreferencesForm *prefs= new PreferencesForm(_wb->get_ui());
  prefs->set_closed_handler(sigc::bind(sigc::ptr_fun(delete_preferences), prefs));
  prefs->show();
  
  return 0;
}


int WorkbenchImpl::showConnectionManager()
{
  grtui::DbConnectionEditor editor(_wb->get_root()->rdbmsMgmt());
  
  editor.run();
  
  _wb->get_ui()->get_main_overview()->send_refresh_connections();
  
  return 0;
}

