
#include "stdafx.h"



#include "wb_context_ui.h"
#include "wb_component.h"
#include "wb_component_physical.h"

#include "wb_model_diagram_form.h"

#include "mini_view.h"
#include "wb_overview.h"
#include "wb_overview_physical.h"
#include "wb_overview_workspace.h"
#include "wb_layer_tree.h"
#include "wb_history_tree.h"
#include "wb_find_dialog.h"
#include "wb_user_datatypes.h"
#include "wb_diagram_options.h"

#include "grt/editor_base.h"
#include "grt/clipboard.h"
#include "grtui/gui_plugin_base.h"

#include "mdc_back_layer.h"

#include "mforms/utilities.h"

using namespace wb;
using namespace bec;


WBContextUI::WBContextUI(bool verbose)
  : _wb(new WBContext(this, verbose)), _command_ui(_wb)
{
  _catalog_tree= 0;

  _mini_view= 0;

  _layer_tree= 0;
  _history_tree= 0;
  _usertypes_tree= 0;

  _overview= new PhysicalOverviewBE(_wb);
  _overview->signal_selection_changed().connect(
    sigc::mem_fun(this, &WBContextUI::overview_selection_changed));

  _ws_overview= new WorkspaceOverviewBE(_wb);
//  _ws_overview->signal_selection_changed().connect(
//                                                sigc::mem_fun(this, &WBContextUI::overview_selection_changed));
  
  
  _find_dialog= new FindDialogBE(_wb);
  _find_dialog->set_activate_slot(sigc::mem_fun(this, &WBContextUI::activate_find_result));

  _active_form= 0;
  _active_main_form= 0;
  
  _last_unsaved_changes_state= false;

  // to notify that the save status of the doc has changed
  _wb->get_grt()->get_undo_manager()->signal_changed().connect(sigc::mem_fun(this, &WBContextUI::history_changed));
  
  // used to update the currentDiagram field
  _main_form_change_signal.connect(sigc::mem_fun(this, &WBContextUI::update_current_diagram));

  // stuff to do when the active form is switched in the UI (through set_active_form)
  _form_change_signal.connect(sigc::hide(sigc::mem_fun(this, &WBContextUI::update_layer_tree)));

  _form_change_signal.connect(
    sigc::hide(sigc::bind<RefreshType,std::string,NativeHandle>(sigc::mem_fun(_wb, &WBContext::request_refresh), RefreshLayers, "", (NativeHandle)0)));  

  _form_change_signal.connect(
    sigc::hide(sigc::bind<RefreshType,std::string,NativeHandle>(sigc::mem_fun(_wb, &WBContext::request_refresh), RefreshZoom, "", (NativeHandle)0)));  

  _form_change_signal.connect(
    sigc::hide(sigc::bind<RefreshType,std::string,NativeHandle>(sigc::mem_fun(_wb, &WBContext::request_refresh), RefreshMenubar, "", (NativeHandle)0)));  

  _form_change_signal.connect(
    sigc::hide(sigc::bind<RefreshType,std::string,NativeHandle>(sigc::mem_fun(_wb, &WBContext::request_refresh), RefreshToolbar, "", (NativeHandle)0)));
}


WBContextUI::~WBContextUI()
{
  _wb->close_document(true);

  delete _usertypes_tree;
  delete _find_dialog;
  delete _ws_overview;
  delete _overview;
  delete _mini_view;
  delete _history_tree;
  delete _layer_tree;

  delete _wb;
}


bool WBContextUI::init(WBFrontendCallbacks *callbacks, WBOptions *options)
{
  bool flag= _wb->init_(callbacks, options);

  // has to be called after WBContext is initialized
  add_backend_builtin_commands();

  return flag;
}


void WBContextUI::init_finish(WBOptions *options)
{
  _wb->init_finish_(options);
}


void WBContextUI::finalize()
{
  _wb->close_document(true);
  
  _wb->finalize();
}

bool WBContextUI::request_quit()
{  
  if (!_wb->get_grt_manager()->in_main_thread())
    g_warning("request_quit() called in worker thread");

  if (_wb->has_unsaved_changes())
  {
    int answer= _wb->confirm_action(_("Quit"),
                                    _("Do you want to save pending changes to the document?\n\n"
                                      "If you don't save your changes, they will be lost."),
                                    _("Save"), _("Don't Save"), _("Cancel"));
    if (answer == 1)
    {
      if (!_wb->save_changes())
        return false;
    }
    else if (answer == -1)
      return false;
  }

  return true;
}


void WBContextUI::perform_quit()
{
  _wb->quit_application();
}


void WBContextUI::reset()
{
  if (!dynamic_cast<OverviewBE*>(_active_form))
    _active_form= 0;
  if (!dynamic_cast<OverviewBE*>(_active_main_form))
    _active_main_form= 0;

  _overview->set_model(_wb->get_document()->physicalModels()[0]);
  
  _ws_overview->reset(_wb);

  _wb->request_refresh(RefreshSelection, "", 0);

  _overview->send_refresh_children(bec::NodeId());
  _ws_overview->send_refresh_children(bec::NodeId());
  
  _wb->get_component<WBComponentPhysical>()->update_catalog_tree();

  if (_usertypes_tree)
  {
    _usertypes_tree->set_catalog(_wb->get_document()->physicalModels()[0]->catalog());
    _usertypes_tree->set_rdbms(_wb->get_document()->physicalModels()[0]->rdbms());
  }
}


void WBContextUI::history_changed()
{  
  if (_wb->has_unsaved_changes() != _last_unsaved_changes_state)
    _wb->request_refresh(RefreshDocument, "", (NativeHandle)0);

  _last_unsaved_changes_state= _wb->has_unsaved_changes();

  // Signal that the main menu and the main toolbar should be refreshed.
  _wb->request_refresh(RefreshMenubar, "", (NativeHandle)0);
  _wb->request_refresh(RefreshToolbar, "main", (NativeHandle)0);
}


void WBContextUI::register_diagram_form(ModelDiagramForm *view)
{
  _model_forms[view->get_model_diagram().id()]= view;
}


void WBContextUI::notify_diagram_created(ModelDiagramForm *view)
{
  view->get_view()->get_selection()->signal_changed().connect(
    sigc::bind<ModelDiagramForm*>(sigc::mem_fun(this, &WBContextUI::view_selection_changed), view));

  view->get_model_diagram()->signal_changed().
    connect(sigc::bind<ModelDiagramForm*>(sigc::mem_fun(this, &WBContextUI::diagram_object_changed), view));

  _overview->send_refresh_diagram(model_DiagramRef());
}


void WBContextUI::notify_diagram_destroyed(ModelDiagramForm *view)
{
  std::string id= view->get_model_diagram().id();
  delete _model_forms[id];
  _model_forms.erase(id);

  _overview->send_refresh_diagram(model_DiagramRef());
}


void WBContextUI::update_current_diagram(bec::UIForm *form)
{
  ModelDiagramForm* dform= dynamic_cast<ModelDiagramForm*>(form);
  if (dform)
  {
    model_DiagramRef diagram(dform->get_model_diagram());
    if (diagram.is_valid() && diagram->owner().is_valid())
      diagram->owner()->currentDiagram(diagram);
  }
}


void WBContextUI::diagram_object_changed(const std::string &member, const grt::ValueRef &ovalue, ModelDiagramForm *view)
{
  if (member == "name")
  {
    _wb->request_refresh(RefreshViewName, view->get_model_diagram()->name(), (NativeHandle)view->get_view()->get_user_data());
    _overview->send_refresh_diagram(view->get_model_diagram());
  }
  else if (member == "zoom")
  {
    _wb->request_refresh(RefreshZoom, "");
  }
}


void WBContextUI::overview_selection_changed()
{
  if (get_active_main_form() == _overview)
  {
    _wb->request_refresh(RefreshSelection, "", (NativeHandle)_overview->get_frontend_data());

    _wb->request_refresh(RefreshMenubar, "");
  }
}


void WBContextUI::view_selection_changed(bool, mdc::CanvasItem *item, ModelDiagramForm *view)
{
  if (get_active_main_form() == view)
  {
    if (_layer_tree)
      _layer_tree->refresh_selection_status();

    _wb->request_refresh(RefreshMenubar, "");
    _wb->request_refresh(RefreshSelection, "", 0);
  }
}



void WBContextUI::load_app_options(bool update)
{
  if (!update)
    _command_ui.load_data();
}


std::string WBContextUI::get_view_path_for_active_view()
{
  ModelDiagramForm *vform= dynamic_cast<ModelDiagramForm*>(get_active_main_form());

  if (vform)
  {
    std::string view_id= vform->get_model_diagram().id();

    // look in the physicalModels list for this view
    
    for (size_t c= _wb->get_document()->physicalModels().count(), i= 0; i < c; i++)
    {
      workbench_physical_ModelRef model= _wb->get_document()->physicalModels()[i];

      for (size_t d= model->diagrams().count(), j= 0; j < d; j++)
      {
        if (model->diagrams().get(j).id() == view_id)
          return strfmt("/wb/doc/physicalModels/%i/diagrams/%i", i, j);
      }
    }
  }
  return "";
}


static void add_script_file(WBContextUI *wbui)
{
  std::string file= wbui->get_wb()->show_file_dialog("open", _("Add SQL Script File"), "sql");
  if (!file.empty())
  {
    workbench_physical_ModelRef model;

    model= workbench_physical_ModelRef::cast_from(wbui->get_active_model(false));
    if (model.is_valid())
      wbui->get_wb()->get_component<WBComponentPhysical>()->add_new_stored_script(model, file);
  }
}


static void add_note_file(WBContextUI *wbui)
{
  std::string file= wbui->get_wb()->show_file_dialog("open", _("Add Note File"), "Text Files (*.txt)|*.txt");
  if (!file.empty())
  {
    workbench_physical_ModelRef model;

    model= workbench_physical_ModelRef::cast_from(wbui->get_active_model(false));
    if (model.is_valid())
      wbui->get_wb()->get_component<WBComponentPhysical>()->add_new_stored_note(model, file);
  }
}


void WBContextUI::call_undo()
{
  _wb->execute_in_grt_thread("Undo",
    sigc::bind_return<grt::ValueRef>(sigc::hide(sigc::mem_fun(_wb->get_grt()->get_undo_manager(),
                                  &grt::UndoManager::undo)), grt::ValueRef()));
}


void WBContextUI::call_redo()
{
  _wb->execute_in_grt_thread("Redo",
    sigc::bind_return<grt::ValueRef>(sigc::hide(sigc::mem_fun(_wb->get_grt()->get_undo_manager(),
                                  &grt::UndoManager::redo)), grt::ValueRef()));
}


/** builtin: commands for use in menus and toolbars that are handled by ourselves
  */
void WBContextUI::add_backend_builtin_commands()
{
  _command_ui.add_builtin_command("find_next", 
    sigc::hide_return(sigc::mem_fun(_find_dialog, &FindDialogBE::find_next)));
  _command_ui.add_builtin_command("find_previous", 
    sigc::hide_return(sigc::mem_fun(_find_dialog, &FindDialogBE::find_previous)));

  _command_ui.add_builtin_command("add_script_file", 
    sigc::bind<WBContextUI*>(sigc::ptr_fun(add_script_file), this));
  _command_ui.add_builtin_command("add_note_file", 
    sigc::bind<WBContextUI*>(sigc::ptr_fun(add_note_file), this));


  _command_ui.add_builtin_command("undo", 
    sigc::mem_fun(this, &WBContextUI::call_undo),
    sigc::mem_fun(_wb->get_grt()->get_undo_manager(), &grt::UndoManager::can_undo));
  _command_ui.add_builtin_command("redo",
    sigc::mem_fun(this, &WBContextUI::call_redo),
    sigc::mem_fun(_wb->get_grt()->get_undo_manager(), &grt::UndoManager::can_redo));
  
  // handle some url opening stuff ourselves through mforms
  _command_ui.add_builtin_command("community_blog",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://dev.mysql.com/workbench/"));
  _command_ui.add_builtin_command("community_faq",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://dev.mysql.com/workbench/?page_id=7"));
  _command_ui.add_builtin_command("community_learn",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://dev.mysql.com/workbench/?page_id=10"));
  _command_ui.add_builtin_command("community_discuss",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://dev.mysql.com/workbench/?page_id=16"));
  _command_ui.add_builtin_command("community_contribute",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://dev.mysql.com/workbench/?page_id=17"));
  _command_ui.add_builtin_command("web_mysql_home",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://mysql.com/"));
  _command_ui.add_builtin_command("web_home",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://mysql.com/products/tools/workbench/"));
  _command_ui.add_builtin_command("report_a_bug",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://bugs.mysql.com/"));
  _command_ui.add_builtin_command("list_bugs",
    sigc::bind(sigc::ptr_fun(mforms::Utilities::open_url),"http://bugs.mysql.com/saved/workbench"));
  
/* moved to frontend
  _command_ui.add_builtin_form_command("cut", 
    sigc::mem_fun(&bec::UIForm::cut), 
    sigc::mem_fun(&bec::UIForm::can_cut), false);
  _command_ui.add_builtin_form_command("copy", 
    sigc::mem_fun(&bec::UIForm::copy), 
    sigc::mem_fun(&bec::UIForm::can_copy), 
    false);
  _command_ui.add_builtin_form_command("paste", 
    sigc::mem_fun(&bec::UIForm::paste), 
    sigc::mem_fun(&bec::UIForm::can_paste), 
    false);
  _command_ui.add_builtin_form_command("delete", 
    sigc::mem_fun(&bec::UIForm::delete_selection), 
    sigc::mem_fun(&bec::UIForm::can_delete), 
    false);
  _command_ui.add_builtin_form_command("selectAll", 
                                       sigc::mem_fun(&bec::UIForm::select_all), 
                                       sigc::hide(sigc::ptr_fun(return_true)),
                                       false);  
 */
}


#ifndef ___specialforms

//-----------------------------------------------------------------------------------
// special forms


bec::ValueTreeBE *WBContextUI::get_catalog_tree()
{
  if (!_catalog_tree)
  {
    WBComponentPhysical *compo= _wb->get_component<wb::WBComponentPhysical>();
    _catalog_tree= compo->get_catalog_tree();
  }
  return _catalog_tree;
}


UserDatatypeListBE *WBContextUI::get_usertypes_tree()
{
  if (!_usertypes_tree)
  {
    _usertypes_tree= new UserDatatypeListBE(_wb);
  }

  return _usertypes_tree;
}


WorkspaceOverviewBE *WBContextUI::get_main_overview()
{
  return _ws_overview;
}


PhysicalOverviewBE *WBContextUI::get_physical_overview()
{
  return _overview;
}


void WBContextUI::layer_tree_item_activate(const grt::ValueRef &value)
{
  ModelDiagramForm *form= 0;
  if (model_FigureRef::can_wrap(value))
  {
    model_FigureRef figure(model_FigureRef::cast_from(value));
    form= get_diagram_form_for_diagram_id(figure->owner().id());
    if (form)
      form->focus_and_make_visible(figure, true);
  }
  else if (model_ConnectionRef::can_wrap(value))
  {
    model_ConnectionRef conn(model_ConnectionRef::cast_from(value));
    ModelDiagramForm *form= get_diagram_form_for_diagram_id(conn->owner().id());
    if (form)
      form->focus_and_make_visible(conn, true);
  }
  else if (model_LayerRef::can_wrap(value))
  {
    model_LayerRef layer(model_LayerRef::cast_from(value));
    ModelDiagramForm *form= get_diagram_form_for_diagram_id(layer->owner().id());
    if (form)
      form->focus_and_make_visible(layer, true);
  }
}


void WBContextUI::update_layer_tree()
{
  std::string path= get_view_path_for_active_view();
  if (_layer_tree)
  {
    if (!path.empty() && *path.rbegin() == '/' && path != "/")
      _layer_tree->set_displayed_global_value(path.substr(0, path.size()-1), false);
    else
      _layer_tree->set_displayed_global_value(path, false);
  }
}


bec::ValueTreeBE *WBContextUI::get_layer_tree()
{
  if (!_layer_tree)
  {
    _layer_tree= new LayerTreeBE(_wb);//->get_grt());
    _layer_tree->set_activate_callback(sigc::mem_fun(this, &WBContextUI::layer_tree_item_activate));
    
    update_layer_tree();
  }

  return _layer_tree;
}


HistoryTreeBE *WBContextUI::get_history_tree()
{
  if (!_history_tree)
  {
    _history_tree= new HistoryTreeBE(_wb, _wb->get_grt()->get_undo_manager());
    
    _wb->get_grt()->get_undo_manager()->signal_changed().
      connect(sigc::bind<RefreshType, std::string, NativeHandle>(sigc::mem_fun(_wb, &WBContext::request_refresh),
                        RefreshHistory, "", 0));
  }
  return _history_tree;
}


bec::ValueInspectorBE *WBContextUI::create_inspector_for_selection(bec::UIForm *form, std::vector<std::string> &items)
{
  grt::ListRef<model_Object> selection;

  //grt::ListRef<model_Object> selection(form->get_selection());
  
  if (dynamic_cast<ModelDiagramForm*>(form))
    selection= dynamic_cast<ModelDiagramForm*>(form)->get_selection();
  else
    return 0;

  if (selection.is_valid() && selection.count()>0)
  {
    if (selection.count()==1)
    {
      items.push_back(strfmt("%s: %s", selection[0]->name().c_str(), selection[0].get_metaclass()->get_attribute("caption").c_str()));

      return ValueInspectorBE::create(_wb->get_grt_manager()->get_grt(), selection[0], false, true);
    }
    else
    {
      std::vector<grt::ObjectRef> list;

      items.push_back(_("Multiple Items"));
      for (size_t c= selection.count(), i= 0; i < c; i++)
      {
        items.push_back(strfmt("%s: %s", selection[i]->name().c_str(), selection[i].get_metaclass()->get_attribute("caption").c_str()));
        list.push_back(selection.get(i));
      }

      return ValueInspectorBE::create(_wb->get_grt_manager()->get_grt(), list);
    }
  }

  return 0;
}


bec::ValueInspectorBE *WBContextUI::create_inspector_for_selection(std::vector<std::string> &items)
{
  std::string res;

  grt::ListRef<GrtObject> selection(_overview->get_selection());
  std::string name_mem_name("name");

  if (selection.is_valid() && selection.count()>0)
  {
    if (selection.count()==1)
    {
			GrtObjectRef obj= selection[0];
      if (obj.is_valid() && obj->has_member(name_mem_name))
      {
        items.push_back(strfmt("%s: %s", obj.get_string_member(name_mem_name).c_str(), obj.get_metaclass()->get_attribute("caption").c_str()));

        return ValueInspectorBE::create(_wb->get_grt_manager()->get_grt(), selection[0], false, true);
      }
    }
    else
    {
      std::vector<grt::ObjectRef> list;

      items.push_back(_("Multiple Items"));
      for (size_t c= selection.count(), i= 0; i < c; i++)
      {
        if (!selection[i].is_valid())//skip "Add item" entry in objects list
          continue;
        items.push_back(strfmt("%s: %s", selection[i].get_string_member(name_mem_name).c_str(), selection[i].get_metaclass()->get_attribute("caption").c_str()));
        list.push_back(selection.get(i));
      }

      return ValueInspectorBE::create(_wb->get_grt_manager()->get_grt(), list);
    }
  }

  return 0;
}


static std::list<GrtObjectRef> get_selected_objects_from_form(WBContext *wb, bec::UIForm *form)
{
  std::list<GrtObjectRef> objects;

  if (dynamic_cast<ModelDiagramForm*>(form))
  {
    grt::ListRef<model_Object> selection(dynamic_cast<ModelDiagramForm*>(form)->get_selection());

    if (selection.is_valid())
    {
      for (size_t c= selection.count(), i= 0; i < c; i++)
      {
        model_ObjectRef object(selection[i]);
        WBComponent *comp= wb->get_component_handling(object);
        GrtObjectRef dbobject;

        if (comp) 
          dbobject= comp->get_object_for_figure(object);

        if (dbobject.is_valid())
          objects.push_back(dbobject);
        else 
          objects.push_back(object);
      }
    }
  }
  else if (dynamic_cast<OverviewBE*>(form))
  {
    grt::ListRef<GrtObject> selection(dynamic_cast<OverviewBE*>(form)->get_selection());

    if (selection.is_valid())
    {
      for (size_t c= selection.count(), i= 0; i < c; i++)
      {
        GrtObjectRef object(selection[i]);

        if (object.is_valid())
          objects.push_back(object);
      }
    }
  }
  return objects;
}


std::string WBContextUI::get_description_for_selection(grt::ListRef<GrtObject> &activeObjList, std::vector<std::string> &items)
{
  std::string res;

  grt::ListRef<GrtObject> selection(_overview->get_selection());
  activeObjList= selection;
  
  std::string comment_mem_name("comment");
  std::string name_mem_name("name");

  if (selection.is_valid() && selection.count()>0)
  {
    if (selection.count()==1)
    {
      GrtObjectRef obj(selection[0]);
      if (obj.is_valid() && obj.has_member(comment_mem_name) && obj.has_member(name_mem_name))
      {
        items.push_back(strfmt("%s: %s", obj->name().c_str(), obj.get_metaclass()->get_attribute("caption").c_str()));
        res= obj.get_string_member(comment_mem_name);
      }
    }
    else
    {
      items.push_back(_("Multiple Items"));
      for (size_t c= selection.count(), i= 0; i < c; i++)
      {
        GrtObjectRef obj(selection[i]);
        if (obj.is_valid() && obj.has_member(comment_mem_name) && obj.has_member(name_mem_name))
        {
          items.push_back(strfmt("%s: %s", obj->name().c_str(), obj.get_metaclass()->get_attribute("caption").c_str()));
          std::string comment= obj.get_string_member(comment_mem_name);
          if (0 == i)
            res= comment;
          else if (0 != res.compare(comment))
            res= "<Multiple Items>\nThat means not all selected items have same comment.\nBeware applying changes will override comments for all selected objects.";
        }
      }
    }
  }

  return res;
}


std::string WBContextUI::get_description_for_selection(bec::UIForm *form, grt::ListRef<GrtObject> &activeObjList, std::vector<std::string> &items)
{
  grt::ListRef<model_Object> selection;

  if (dynamic_cast<ModelDiagramForm*>(form))
    selection= dynamic_cast<ModelDiagramForm*>(form)->get_selection();
  else
    return get_description_for_selection(activeObjList, items);

  std::string res;

  activeObjList= grt::ListRef<model_Object>(selection.get_grt());

  std::string comment_mem_name("comment");

  if (selection.is_valid() && selection.count()>0)
  {
    bool first= true;
    for (size_t c= selection.count(), i= 0; i < c; i++)
    {
      model_ObjectRef figure(selection[i]);
      WBComponent *comp= _wb->get_component_handling(figure);
      GrtObjectRef dbobject;
      if (comp) dbobject= comp->get_object_for_figure(figure);
      
      if (dbobject.is_valid() && dbobject.has_member(comment_mem_name))
      {
        activeObjList.insert(dbobject);
        
        items.push_back(strfmt("%s: %s", figure->name().c_str(), figure->get_metaclass()->get_attribute("caption").c_str()));
        std::string comment= dbobject.get_string_member(comment_mem_name);
        if (first)
          res= comment;
        else if (0 != res.compare(comment))
          res= _("<Multiple Items>\nThat means not all selected items have same comment.\nBeware applying changes will override comments for all selected objects.");

        first= false;
      }
    }
    if (items.size() > 1)
      items.insert(items.begin(), _("Multiple Items"));
  }

  return res;
}


void WBContextUI::set_description_for_selection(const grt::ListRef<GrtObject> &objList, const std::string &val)
{
  if (objList.is_valid() && objList.count()>0)
  {
    std::string comment_mem_name("comment");

    grt::AutoUndo undo(_wb->get_grt());
    
    if (objList.count()==1)
    {
      GrtObjectRef obj(objList[0]);
      if (obj.is_valid() && obj.has_member(comment_mem_name))
        obj.set_member(comment_mem_name, grt::StringRef(val));
    }
    else
    {
      for (size_t c= objList.count(), i= 0; i < c; i++)
      {
        GrtObjectRef obj(objList[i]);
        if (obj.is_valid() && obj.has_member(comment_mem_name))
          obj.set_member(comment_mem_name, grt::StringRef(val));
      }
    }

    undo.end(_("Set Object Description"));
  }
}


DiagramOptionsBE *WBContextUI::create_diagram_options_be(mdc::CanvasView *view)
{
  model_DiagramRef model_diagram(get_active_model_diagram(false));
  
  if (model_diagram.is_valid())
    return new DiagramOptionsBE(view, model_diagram, _wb);
  else
    return 0;
}


void WBContextUI::setup_mini_view(mdc::CanvasView *view)
{
  if (_mini_view)
    throw std::logic_error("miniview already set");

  _mini_view= new MiniView(view->get_current_layer());

  view->initialize();
  view->get_background_layer()->set_visible(false);
  view->set_page_layout(1, 1);
  view->set_page_size(view->get_viewable_size());

  view->get_current_layer()->add_item(_mini_view);

  int w, h;
  view->get_view_size(w, h);

  update_mini_view_size(w, h);
}


void WBContextUI::update_mini_view_size(int w, int h)
{
  if (_mini_view)
  {
    mdc::CanvasView *view= _mini_view->get_layer()->get_view();

    view->update_view_size(w, h);
    view->set_page_size(view->get_viewable_size());
    
    _mini_view->update_size();
  }
}


std::string WBContextUI::get_active_diagram_info()
{
  wb::ModelDiagramForm *form= dynamic_cast<wb::ModelDiagramForm*>(get_active_main_form());
  
  if (form)
    return form->get_diagram_info_text();
  
  return "";
}


void WBContextUI::activate_find_result(const GrtObjectRef &location, const GrtObjectRef &object, const std::string &text)
{
  _wb->show_status_text(strfmt("Match: %s (%s)", 
    text.c_str(), object.get_metaclass()->get_attribute("caption").c_str()));

  if (location.is_valid())
  {
    model_DiagramRef view;

    if (location.is_instance<model_Diagram>())
      view= model_DiagramRef::cast_from(location);
    else
      view= _wb->get_parent_for_object<model_Diagram>(location);

    if (view.is_valid())
    {
      ModelDiagramForm *form= get_diagram_form_for_diagram_id(view.id());

      if (form)
      {
        _wb->switched_view(form->get_view());
        form->focus_and_make_visible(model_FigureRef::cast_from(location), true);
      }
    }
  }
}

#endif // ___specialforms


#ifndef ___preferences
//-----------------------------------------------------------------------------------
// utility functions for user preferences

void WBContextUI::get_doc_properties(std::string& caption, std::string& version, std::string& author, std::string& project, std::string& date_created, std::string& date_changed, std::string& description)
{
  app_DocumentInfoRef info= _wb->get_document()->info();

  caption= info->caption();
  version= info->version();
  author= info->author();
  project= info->project();
  date_created= info->dateCreated();
  date_changed= info->dateChanged();
  description= info->description();  
}

void WBContextUI::set_doc_properties(const std::string &caption, const std::string &version, const std::string &author, const std::string &project, const std::string &date_created, const std::string &date_changed, const std::string &description)
{
  app_DocumentInfoRef info= _wb->get_document()->info();

  info->caption(caption);
  info->version(version);
  info->author(author);
  info->project(project);
  info->dateCreated(date_created);
  info->dateChanged(date_changed);
  info->description(description);  
}


std::list<WBPaperSize> WBContextUI::get_paper_sizes(bool descr_in_inches)
{
  std::list<WBPaperSize> sizes;

  grt::ListRef<app_PaperType> types(_wb->get_root()->options()->paperTypes());

  for (size_t c= types.count(), i= 0; i < c; i++)
  {
    WBPaperSize size;
    size.name= types[i]->name();
    size.caption= types[i]->caption();
    size.width= types[i]->width();
    size.height= types[i]->height();
    size.margins_set= types[i]->marginsSet() != 0;
    size.margin_top= types[i]->marginTop();
    size.margin_bottom= types[i]->marginBottom();
    size.margin_left= types[i]->marginLeft();
    size.margin_right= types[i]->marginRight();

    if (descr_in_inches)
      size.description= strfmt("%.2f in x %.2f in", size.width*0.03937, size.height*0.03937);
    else
      size.description= strfmt("%.2f cm x %.2f cm", size.width/10, size.height/10);

    sizes.push_back(size);
  }

  return sizes;
}


bool WBContextUI::add_paper_size(const std::string &name, double width, double height,
                                   bool margins, double margin_top, double margin_bottom,
                                   double margin_left, double margin_right)
{
  if (grt::find_named_object_in_list(_wb->get_root()->options()->paperTypes(), name).is_valid())
    return false;

  app_PaperTypeRef type(_wb->get_grt_manager()->get_grt());
  type->owner(_wb->get_root()->options());
  type->name(name);
  type->width(width);
  type->height(height);
  type->marginsSet(margins?1:0);
  type->marginTop(margin_top);
  type->marginBottom(margin_bottom);
  type->marginLeft(margin_left);
  type->marginRight(margin_right);
  _wb->get_root()->options()->paperTypes().insert(type);

  return true;
}


app_PageSettingsRef WBContextUI::get_page_settings()
{
  return _wb->get_document()->pageSettings();
}


void WBContextUI::update_page_settings(const std::string &paper_type, const std::string &orientation)
{
  app_PageSettingsRef settings(get_page_settings());
  app_PaperTypeRef paperType(grt::find_named_object_in_list(_wb->get_root()->options()->paperTypes(), 
                                                            paper_type));
  if (paperType != settings->paperType())
    settings->paperType(paperType);
  
  if (orientation != *settings->orientation())
    settings->orientation(orientation);
  
  _wb->update_view_page_settings();
}


grt::DictRef WBContextUI::get_model_options(const std::string &model_id)
{
  grt::ListRef<workbench_physical_Model> pmodels(_wb->get_document()->physicalModels());

  for (size_t c= pmodels.count(), i= 0; i < c; i++)
  {
    if (pmodels.get(i).id() == model_id)
    {
      return pmodels.get(i)->options();
    }
  }
  return grt::DictRef();
}


std::vector<std::string> WBContextUI::get_wb_options_keys(const std::string &model)
{
  std::vector<std::string> keylist;
  grt::DictRef options= _wb->get_wb_options();

  for (grt::DictRef::const_iterator iter= options.begin(); iter != options.end(); ++iter)
  {
    keylist.push_back(iter->first);
  }

  return keylist;
}


bool WBContextUI::get_wb_options_value(const std::string &model, const std::string &key,
                                              std::string &value)
{
  grt::DictRef options= _wb->get_wb_options();
  grt::ValueRef val;

  // If a model is given check if it is set to use global values or its own.
  if (!model.empty())
  {
    grt::DictRef model_options(get_model_options(model));
    int use_global= model_options.get_int("useglobal", 1);

    if (key == "useglobal")
    {
      if (use_global)
        value= "1";
      else
        value= "0";
      return true;
    }

    if (!use_global && model_options.has_key(key))
      val= model_options.get(key);
  }

  if (!val.is_valid() && options.has_key(key))
    val= options.get(key);

  switch(val.type())
  {
  case grt::StringType: 
  case grt::DoubleType:
  case grt::IntegerType:
      value= val.repr();
      return true;
    default: 
      return false;
  }
}


void WBContextUI::set_wb_options_value(const std::string &model, const std::string &key, const std::string &value)
{
  grt::DictRef options;
  grt::Type type= _wb->get_wb_options().get(key).type();

  if (!model.empty())
  {
    options= get_model_options(model);

    options.gset("useglobal", 0);

    if (options.has_key(key))
      type= options.get(key).type();
  }
  
  if (!options.is_valid())
    options= _wb->get_wb_options();

  switch (type)
  {
  case grt::DoubleType:
      options.set(key, grt::DoubleRef(atof(value.c_str())));
      break;
  case grt::IntegerType:
      options.set(key, grt::IntegerRef(atoi(value.c_str())));
      break;
  case grt::StringType:
      options.set(key, grt::StringRef(value));
      break;
  default:
    throw;
  }
}

void WBContextUI::discard_wb_model_options(const std::string &model)
{
  grt::DictRef opts= get_model_options(model);
  if (opts.is_valid())
  {
    for (grt::DictRef::const_iterator item= opts.begin(); item != opts.end(); ++item)
    {
      opts.set(item->first, grt::ValueRef());
    }
    opts.gset("useglobal", 1);
  }
}


#endif // ___preferences


#ifndef ___forms

//--------------------------------------------------------------------------------
// Form Management


void *WBContextUI::form_destroyed(void *data)
{
  UIForm *form= reinterpret_cast<UIForm*>(data);
  WBContextUI *wb= reinterpret_cast<WBContextUI*>(form->get_owner_data());

  if (wb->_active_form == form)
    wb->set_active_form(0);
  if (wb->_active_main_form == form)
    wb->_active_main_form= 0;

  return 0;
}


ModelDiagramForm *WBContextUI::get_diagram_form(mdc::CanvasView *view)
{
  for (std::map<std::string,ModelDiagramForm*>::const_iterator iter= _model_forms.begin();
    iter != _model_forms.end(); ++iter)
  {
    if (iter->second->get_view() == view)
      return iter->second;
  }
  return 0;
}


std::string WBContextUI::get_active_context(bool main_context)
{
  bec::UIForm *form= main_context ? get_active_main_form() : get_active_form();

  if (form)
    return form->get_form_context_name();
  
  return "";
}


void WBContextUI::set_active_form(bec::UIForm *form)
{
  if (_active_form == form)
    return;
    
  // register callbacks to form if needed
  
  if (_active_form && form)
    _active_form->remove_destroy_notify_callback(_active_form);
  _active_form= form;
  if (form)
  {
    form->add_destroy_notify_callback(reinterpret_cast<void*>(form), &WBContextUI::form_destroyed);
    form->set_owner_data(reinterpret_cast<void*>(this));
  }

  if (form && form->is_main_form())
  {
    ModelDiagramForm *vform= dynamic_cast<ModelDiagramForm*>(form);

    _active_main_form= form;

    if (_mini_view && vform)
      _mini_view->set_active_view(vform->get_view(), vform->get_model_diagram());

    if (vform)
      vform->get_model_diagram()->owner()->currentDiagram(vform->get_model_diagram());
//    else
      //vform->get_model_diagram().owner().currentDiagram(model_Diagram());

    _main_form_change_signal.emit(vform);
  }
  
  _form_change_signal.emit(form);

  if (_mini_view && (!_active_main_form || !dynamic_cast<ModelDiagramForm*>(_active_main_form)))
    _mini_view->set_active_view(0, model_DiagramRef());
}



bec::UIForm *WBContextUI::get_active_main_form()
{
  return _active_main_form;
}


bec::UIForm *WBContextUI::get_active_form()
{
  return _active_form;
}


model_DiagramRef WBContextUI::get_active_model_diagram(bool main_form)
{
  bec::UIForm *form= main_form ? get_active_main_form() : get_active_form();

  if (dynamic_cast<ModelDiagramForm*>(form))
    return dynamic_cast<ModelDiagramForm*>(form)->get_model_diagram();

  return model_DiagramRef();
}


model_ModelRef WBContextUI::get_active_model(bool main_form)
{
  bec::UIForm *form= main_form ? get_active_main_form() : get_active_form();

  if (dynamic_cast<OverviewBE*>(form))
    return dynamic_cast<OverviewBE*>(form)->get_model();
  else if (dynamic_cast<ModelDiagramForm*>(form))
    return dynamic_cast<ModelDiagramForm*>(form)->get_model_diagram()->owner();
  return model_ModelRef();
}


#endif // ___forms


#ifndef ___others

//-----------------------------------------------------------------------------------
// other functionality for UI

std::string WBContextUI::get_document_name()
{
  if (_wb->get_filename().empty())
    return "Untitled";
  else
  {
    gchar *bn= g_path_get_basename(_wb->get_filename().c_str());
    std::string title(bn);
    g_free(bn);
    return title;
  }
}


std::string WBContextUI::get_title()
{
#ifndef __APPLE__
  if (_wb->has_unsaved_changes())
    return get_document_name() + "* - MySQL Workbench";
  else
#endif
    return get_document_name() + " - MySQL Workbench";
}

#endif // ___others
