~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to backend/wbprivate/model/wb_component_physical.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License as
 
6
 * published by the Free Software Foundation; version 2 of the
 
7
 * License.
 
8
 * 
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 * GNU General Public License for more details.
 
13
 * 
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
17
 * 02110-1301  USA
 
18
 */
 
19
 
 
20
#include "stdafx.h"
 
21
 
 
22
#include "wb_config.h"
 
23
 
 
24
#include "wb_component_physical.h"
 
25
#include "workbench/wb_find_dialog.h"
 
26
#include "wb_model_diagram_form.h"
 
27
#include "wb_catalog_tree.h"
 
28
#include "workbench/wb_context_ui.h"
 
29
#include "wb_overview_physical.h"
 
30
#include "base/wb_iterators.h"
 
31
 
 
32
#include "grts/structs.workbench.physical.h"
 
33
#include "grts/structs.db.mgmt.h"
 
34
#include "grts/structs.db.mysql.h"
 
35
 
 
36
#include "grtdb/db_helpers.h"
 
37
#include "grtdb/db_object_helpers.h"
 
38
#include "grtui/db_conn_be.h"
 
39
 
 
40
#include "mdc.h"
 
41
 
 
42
#include "wbcanvas/workbench_physical_model_impl.h"
 
43
#include "wbcanvas/workbench_physical_diagram_impl.h"
 
44
#include "wbcanvas/workbench_physical_tablefigure_impl.h"
 
45
#include "wbcanvas/workbench_physical_viewfigure_impl.h"
 
46
#include "wbcanvas/workbench_physical_routinegroupfigure_impl.h"
 
47
#include "wbcanvas/workbench_physical_connection_impl.h"
 
48
 
 
49
#include "base/string_utilities.h"
 
50
 
 
51
#define FILE_CONNECTION_LIST "connections.xml"
 
52
 
 
53
using namespace grt;
 
54
using namespace bec;
 
55
using namespace wb;
 
56
using namespace base;
 
57
using namespace MySQL::Geometry;
 
58
using namespace MySQL::Drawing;
 
59
 
 
60
WBComponentPhysical::WBComponentPhysical(WBContext *wb)
 
61
: WBComponent(wb)
 
62
{
 
63
  _catalog_tree= 0;
 
64
  base::NotificationCenter::get()->add_observer(this, "GNMainFormChanged");
 
65
}
 
66
 
 
67
 
 
68
WBComponentPhysical::~WBComponentPhysical()
 
69
{
 
70
  base::NotificationCenter::get()->remove_observer(this);
 
71
  close_document();
 
72
  delete _catalog_tree;
 
73
}
 
74
 
 
75
 
 
76
void WBComponentPhysical::load_app_options(bool update)
 
77
{
 
78
  grt::GRT *grt= get_grt();
 
79
 
 
80
  if (!update)
 
81
  {
 
82
    app_ToolbarRef toolbar;
 
83
    toolbar= app_ToolbarRef::cast_from(
 
84
      grt->unserialize(make_path(_wb->get_datadir(),"data/model_option_toolbar_physical_table.xml")));
 
85
    _toolbars[toolbar->name()]= toolbar;
 
86
 
 
87
    toolbar= app_ToolbarRef::cast_from(
 
88
      grt->unserialize(make_path(_wb->get_datadir(),"data/model_option_toolbar_physical_view.xml")));
 
89
    _toolbars[toolbar->name()]= toolbar;
 
90
 
 
91
    toolbar= app_ToolbarRef::cast_from(
 
92
      grt->unserialize(make_path(_wb->get_datadir(),"data/model_option_toolbar_physical_routinegroup.xml")));
 
93
    _toolbars[toolbar->name()]= toolbar;
 
94
 
 
95
    toolbar= app_ToolbarRef::cast_from(
 
96
      grt->unserialize(make_path(_wb->get_datadir(),"data/model_option_toolbar_physical_relationship.xml")));
 
97
    _toolbars["main/"WB_TOOL_PREL11_NOID]= toolbar;
 
98
    _toolbars["main/"WB_TOOL_PREL1n_NOID]= toolbar;
 
99
    _toolbars["main/"WB_TOOL_PREL11]= toolbar;
 
100
    _toolbars["main/"WB_TOOL_PREL1n]= toolbar;
 
101
    _toolbars["main/"WB_TOOL_PRELnm]= toolbar;
 
102
    _toolbars["main/"WB_TOOL_PREL_PICK]= toolbar;
 
103
 
 
104
    _shortcuts= grt::ListRef<app_ShortcutItem>::cast_from(
 
105
      grt->unserialize(make_path(_wb->get_datadir(),"data/shortcuts_physical.xml")));
 
106
  }
 
107
 
 
108
  // this needs to be loaded after drivers list has been loaded
 
109
  db_mgmt_ManagementRef mgmt= _wb->get_root()->rdbmsMgmt();
 
110
  std::string conn_list_xml= make_path(_wb->get_user_datadir(), FILE_CONNECTION_LIST);
 
111
  if (g_file_test(conn_list_xml.c_str(), G_FILE_TEST_EXISTS))
 
112
  {
 
113
    try
 
114
    {
 
115
      grt::ListRef<db_mgmt_Connection> 
 
116
        list(grt::ListRef<db_mgmt_Connection>::cast_from(grt->unserialize(conn_list_xml)));
 
117
 
 
118
      if (list.is_valid())
 
119
      {
 
120
        bool changed = false;
 
121
        while (mgmt->storedConns().count() > 0)
 
122
          mgmt->storedConns().remove(0);
 
123
        for (size_t c= list.count(), i= 0; i < c; i++)
 
124
        {
 
125
          db_mgmt_ConnectionRef conn(list.get(i));
 
126
 
 
127
          // starting from 5.2.16 we do not store passwords for MySQL or SSH in the connections file anymore
 
128
          // so we strip the password, update the hostIdentifier field and store the password in the keychain
 
129
          if (*conn->hostIdentifier() == "")
 
130
          {
 
131
            conn->hostIdentifier(bec::get_host_identifier_for_connection(conn));
 
132
            
 
133
            // save the MySQL password if its set
 
134
            if (conn->parameterValues().get_string("password") != "")
 
135
            {
 
136
              try
 
137
              {
 
138
                mforms::Utilities::store_password(conn->hostIdentifier(), 
 
139
                                                  conn->parameterValues().get_string("userName"),
 
140
                                                  conn->parameterValues().get_string("password"));
 
141
              }
 
142
              catch (std::exception &exc)
 
143
              {
 
144
                g_warning("Could not store password for %s: %s", conn->hostIdentifier().c_str(), exc.what());
 
145
              }
 
146
              conn->parameterValues().gset("password", "");
 
147
              changed = true;
 
148
            }
 
149
 
 
150
            // save the SSH tunnel password if its set
 
151
            if (conn->parameterValues().get_string("sshPassword") != "")
 
152
            {
 
153
              if (conn->parameterValues().get_string("sshHost") != "")
 
154
              {
 
155
                std::string service = strfmt("ssh@%s", conn->parameterValues().get_string("sshHost").c_str());
 
156
                try
 
157
                {
 
158
                  mforms::Utilities::store_password(service, 
 
159
                                                    conn->parameterValues().get_string("sshUserName"),
 
160
                                                    conn->parameterValues().get_string("sshPassword"));
 
161
                }
 
162
                catch (std::exception &exc)
 
163
                {
 
164
                  g_warning("Could not store password for %s: %s", service.c_str(), exc.what());
 
165
                }
 
166
              }
 
167
              conn->parameterValues().gset("sshPassword", "");
 
168
              changed = true;
 
169
            }
 
170
          }
 
171
 
 
172
          mgmt->storedConns().insert(conn);
 
173
        }      
 
174
        if (changed)
 
175
          save_app_options();
 
176
      }
 
177
    }
 
178
    catch (std::exception &exc)
 
179
    {
 
180
      grt->send_warning(strfmt("Error loading '%s': %s", conn_list_xml.c_str(), exc.what()));
 
181
    }
 
182
  }
 
183
}
 
184
 
 
185
 
 
186
void WBComponentPhysical::save_app_options()
 
187
{
 
188
  get_grt()->serialize(_wb->get_root()->rdbmsMgmt()->storedConns(),
 
189
    make_path(_wb->get_user_datadir(), FILE_CONNECTION_LIST));
 
190
}
 
191
 
 
192
 
 
193
 
 
194
 
 
195
void WBComponentPhysical::setup_context_grt(grt::GRT *grt, WBOptions *options)
 
196
{
 
197
  //XXX must be loaded from DB module
 
198
  db_mgmt_RdbmsRef rdbms= db_mgmt_RdbmsRef::cast_from(grt->unserialize(make_path(options->basedir, "modules/data/mysql_rdbms_info.xml")));
 
199
  
 
200
  _wb->get_root()->rdbmsMgmt()->rdbms().insert(rdbms);
 
201
 
 
202
  std::string engines;
 
203
  // fill engine types list
 
204
  grt::Module *module= get_grt()->get_module("DbMySQL");
 
205
  if (module)
 
206
  {
 
207
    grt::ListRef<db_mysql_StorageEngine> engines_ret(grt::ListRef<db_mysql_StorageEngine>::cast_from(module->call_function("getKnownEngines", grt::BaseListRef(get_grt()))));
 
208
 
 
209
    for (size_t c= engines_ret.count(), i= 0; i < c; i++)
 
210
    {
 
211
      engines.append(",").append(engines_ret[i]->name());
 
212
    }
 
213
    engines= engines.substr(1);
 
214
    // this is also used by WBA
 
215
    _wb->get_wb_options().gset("@db.mysql.Table:tableEngine/Items", engines.c_str());
 
216
  }
 
217
  // fill fk types
 
218
  _wb->get_wb_options().gset("@db.ForeignKey:updateRule/Items", "NO ACTION,CASCADE,SET NULL,RESTRICT");
 
219
  _wb->get_wb_options().gset("@db.ForeignKey:deleteRule/Items", "NO ACTION,CASCADE,SET NULL,RESTRICT");
 
220
 
 
221
  // fill delete object options
 
222
  _wb->get_wb_options().gset("@workbench.physical:DeleteObjectConfirmation/Items", 
 
223
                             _("Delete Database Object from Catalog:delete,"
 
224
                               "Keep Database Object in Catalog:keep,"
 
225
                               "Ask:ask"));
 
226
}
 
227
 
 
228
 
 
229
void WBComponentPhysical::init_catalog_grt(const db_mgmt_RdbmsRef &rdbms,
 
230
                                 const std::string &db_version,
 
231
                                 workbench_physical_ModelRef &model)
 
232
{
 
233
  grt::GRT *grt= get_grt();
 
234
  
 
235
  std::string db_package= rdbms->databaseObjectPackage();
 
236
 
 
237
  // assemble struct name for catalog and schema for the requested db type
 
238
 
 
239
  std::string catalog_struct= db_package+".Catalog";
 
240
  std::string schema_struct= db_package+".Schema";
 
241
  
 
242
  if (!grt->get_metaclass(catalog_struct) ||
 
243
      !grt->get_metaclass(schema_struct))
 
244
  {
 
245
    // Struct definition for '%s' and/or '%s' cannot be found
 
246
    throw grt_runtime_error("Support for RDBMS "+db_package+" not found.",
 
247
                            "Struct definition for "+catalog_struct+" and/or "+schema_struct+" could not be found");
 
248
  }
 
249
 
 
250
  db_CatalogRef catalog(grt->create_object<db_Catalog>(catalog_struct));
 
251
      
 
252
  catalog->name("default");
 
253
  catalog->owner(model);
 
254
 
 
255
  //catalog.oldName(catalog.name());
 
256
 
 
257
  // set version
 
258
  GrtVersionRef version(grt);
 
259
  version->name("Version");
 
260
  version->owner(catalog);
 
261
 
 
262
  char **toks= g_strsplit(db_version.c_str(), ".", 0);
 
263
 
 
264
  if (toks[0])
 
265
    version->majorNumber(atoi(toks[0]));
 
266
  if (toks[1])
 
267
    version->minorNumber(atoi(toks[1]));
 
268
  if (toks[2])
 
269
    version->releaseNumber(atoi(toks[2]));
 
270
 
 
271
  g_strfreev(toks);
 
272
 
 
273
  append_contents(catalog->simpleDatatypes(), rdbms->simpleDatatypes());
 
274
  append_contents(catalog->characterSets(), rdbms->characterSets());
 
275
 
 
276
  model->catalog(catalog);
 
277
 
 
278
  replace_contents(catalog->userDatatypes(), create_builtin_user_datatypes(catalog, rdbms));
 
279
  
 
280
  // add listener for any operation on the schema list
 
281
  reset_document();
 
282
  
 
283
  // add standard tag categories
 
284
  {
 
285
    GrtObjectRef category(grt);
 
286
   
 
287
    category->name("Business Rule");
 
288
    category->owner(model);
 
289
    
 
290
    model->tagCategories().insert(category);
 
291
  }
 
292
#if 1
 
293
  // create an initial schema
 
294
  db_SchemaRef schema(grt->create_object<db_Schema>(schema_struct));
 
295
  
 
296
  schema->name(StringRef("mydb"));
 
297
  schema->owner(catalog);
 
298
  schema->defaultCharacterSetName("latin1");
 
299
  schema->defaultCollationName("latin1_swedish_ci");
 
300
 
 
301
  //schema->oldName(schema->name());
 
302
 
 
303
  catalog->schemata().insert(schema);
 
304
#endif
 
305
}
 
306
 
 
307
 
 
308
 
 
309
grt::ListRef<db_UserDatatype> WBComponentPhysical::create_builtin_user_datatypes(const db_CatalogRef &catalog,
 
310
                                                                                 const db_mgmt_RdbmsRef &rdbms)
 
311
{
 
312
  grt::Module *module= get_grt()->get_module("DbMySQL");
 
313
  if (module)
 
314
  {
 
315
    grt::BaseListRef args(get_grt());
 
316
    args.ginsert(rdbms);
 
317
    grt::ListRef<db_UserDatatype> user_types(grt::ListRef<db_UserDatatype>::cast_from(module->call_function("getDefaultUserDatatypes", args)));
 
318
    
 
319
    if (user_types.is_valid())
 
320
    {
 
321
      GRTLIST_FOREACH(db_UserDatatype, user_types, ut)
 
322
      {
 
323
        (*ut)->owner(catalog);
 
324
      }
 
325
    }
 
326
    return user_types;
 
327
  }
 
328
  
 
329
  return grt::ListRef<db_UserDatatype>();
 
330
}
 
331
 
 
332
 
 
333
 
 
334
void WBComponentPhysical::setup_physical_model(grt::GRT *grt, workbench_DocumentRef &doc, 
 
335
                                     const std::string &rdbms_name, const std::string &rdbms_version)
 
336
{
 
337
  // init physical model
 
338
  workbench_physical_ModelRef pmodel(grt);
 
339
  pmodel->owner(doc);
 
340
  
 
341
  pmodel->connectionNotation(_wb->get_wb_options().get_string("DefaultConnectionNotation"));
 
342
  pmodel->figureNotation(_wb->get_wb_options().get_string("DefaultFigureNotation"));
 
343
 
 
344
  doc->physicalModels().insert(pmodel);
 
345
 
 
346
  db_mgmt_ManagementRef mgmt= db_mgmt_ManagementRef::cast_from(grt->get("/wb/rdbmsMgmt"));
 
347
  
 
348
  // find the rdbms module for the db we want
 
349
  db_mgmt_RdbmsRef rdbms;
 
350
 
 
351
  rdbms= grt::find_named_object_in_list<db_mgmt_Rdbms>(mgmt->rdbms(), rdbms_name);
 
352
  if (!rdbms.is_valid())
 
353
  {
 
354
    throw grt_runtime_error("Could not locate RDBMS support object for "+rdbms_name,
 
355
                            "new_physical(): There is no RDBMS object with the name "+rdbms_name+" in the /rdbmsMgmt/rdbms list.");
 
356
  }
 
357
  pmodel->rdbms(rdbms);
 
358
 
 
359
  init_catalog_grt(rdbms, rdbms_version, pmodel);
 
360
}
 
361
 
 
362
 
 
363
//--------------------------------------------------------------------------------
 
364
// Model Management
 
365
 
 
366
grt::ValueRef WBComponentPhysical::add_new_db_schema_grt(grt::GRT *grt,
 
367
                                                const workbench_physical_ModelRef &model)
 
368
{
 
369
  
 
370
  db_SchemaRef schema;
 
371
  std::string name;
 
372
  std::string class_name;
 
373
  
 
374
  grt::AutoUndo undo(grt);
 
375
 
 
376
  class_name= *model->rdbms()->databaseObjectPackage()+".Schema";
 
377
 
 
378
  name= grt::get_name_suggestion_for_list_object(
 
379
    grt::ObjectListRef::cast_from(model->catalog()->schemata()), "new_schema");
 
380
 
 
381
  schema= grt->create_object<db_Schema>(class_name);
 
382
  schema->owner(model->catalog());
 
383
  schema->name(name);
 
384
 
 
385
  schema->createDate(bec::fmttime(0, DATETIME_FMT));
 
386
  schema->lastChangeDate(bec::fmttime(0, DATETIME_FMT));
 
387
 
 
388
  model->catalog()->schemata().insert(schema);
 
389
 
 
390
  undo.end(_("Create New Schema"));
 
391
 
 
392
  return schema;
 
393
}
 
394
 
 
395
 
 
396
void WBComponentPhysical::add_new_db_schema(const workbench_physical_ModelRef &model)
 
397
{
 
398
  grt::ValueRef res;
 
399
 
 
400
  res= _wb->execute_in_grt_thread("Create new schema",
 
401
                        boost::bind(&WBComponentPhysical::add_new_db_schema_grt, this, _1, model));
 
402
 
 
403
  if (res.is_valid())
 
404
  {
 
405
    _wb->show_status_text(strfmt(_("Schema '%s' created."), db_SchemaRef::cast_from(res)->name().c_str()));
 
406
 
 
407
    _wb->open_object_editor(GrtObjectRef::cast_from(res));
 
408
  }
 
409
  else
 
410
    _wb->show_status_text(_("Could not create new schema."));
 
411
}
 
412
 
 
413
 
 
414
grt::ValueRef WBComponentPhysical::delete_db_schema_grt(grt::GRT *grt, const db_SchemaRef &schema, 
 
415
                                                          bool check_empty)
 
416
{
 
417
  std::map<std::string, bool> options;
 
418
 
 
419
  options["deletedbobjects"]= false;
 
420
 
 
421
  if (check_empty && 
 
422
      (schema->tables().count() > 0 || schema->views().count() > 0 || schema->routines().count() > 0))
 
423
  {
 
424
    grt::DictRef dict(grt);
 
425
    
 
426
    dict.gset("name", schema->name());
 
427
    dict.gset("tables", (long)schema->tables().count());
 
428
    dict.gset("views", (long)schema->views().count());
 
429
    dict.gset("routines", (long)schema->routines().count());
 
430
    
 
431
    return dict;
 
432
  }
 
433
 
 
434
  workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(schema));
 
435
  if (model.is_valid())
 
436
  {
 
437
    workbench_physical_DiagramRef view;
 
438
 
 
439
    if (model->catalog()->schemata().get_index(schema) == grt::BaseListRef::npos)
 
440
      return grt::ValueRef();
 
441
 
 
442
    grt::AutoUndo undo(grt);
 
443
 
 
444
    for (size_t vc= model->diagrams().count(), vi= 0; vi < vc; vi++)
 
445
    {
 
446
      view= model->diagrams().get(vi);
 
447
      std::list<model_FigureRef> figures;
 
448
 
 
449
      // remove canvas objects for schema contents
 
450
      for (size_t c= schema->tables().count(), i= 0; i < c; i++)
 
451
      {
 
452
        db_TableRef table= schema->tables().get(i);
 
453
        model_FigureRef figure= view->getFigureForDBObject(table);
 
454
        if (figure.is_valid())
 
455
          figures.push_back(figure);
 
456
      }
 
457
      for (size_t c= schema->views().count(), i= 0; i < c; i++)
 
458
      {
 
459
        db_ViewRef v= schema->views().get(i);
 
460
        model_FigureRef figure= view->getFigureForDBObject(v);
 
461
        if (figure.is_valid())
 
462
          figures.push_back(figure);
 
463
      }
 
464
      for (size_t c= schema->routineGroups().count(), i= 0; i < c; i++)
 
465
      {
 
466
        db_RoutineGroupRef rgroup= schema->routineGroups().get(i); 
 
467
        model_FigureRef figure= view->getFigureForDBObject(rgroup);
 
468
        if (figure.is_valid())
 
469
          figures.push_back(figure);
 
470
      }
 
471
 
 
472
      for (std::list<model_FigureRef>::const_iterator f= figures.begin(); f != figures.end(); ++f)
 
473
        delete_model_object(*f, options);
 
474
    }
 
475
    // remove schema
 
476
    model->catalog()->schemata().remove_value(schema);
 
477
 
 
478
    undo.end(_("Delete Schema"));
 
479
  }
 
480
 
 
481
  return grt::ValueRef();
 
482
}
 
483
 
 
484
 
 
485
void WBComponentPhysical::delete_db_schema(const db_SchemaRef &schema)
 
486
{
 
487
  grt::ValueRef result;
 
488
  
 
489
  _wb->show_status_text(_("Deleting schema..."));
 
490
 
 
491
  result= _wb->execute_in_grt_thread("Delete schema",
 
492
            boost::bind(&WBComponentPhysical::delete_db_schema_grt, this, _1, schema, true));
 
493
 
 
494
  if (result.is_valid() && result.type() == DictType)
 
495
  {
 
496
    grt::DictRef info(grt::DictRef::cast_from(result));
 
497
    int res;
 
498
    std::string objects;
 
499
 
 
500
    if (info.get_int("tables") > 0)
 
501
      objects+= strfmt("%li tables, ", info.get_int("tables"));
 
502
    if (info.get_int("views") > 0)
 
503
      objects+= strfmt("%li views, ", info.get_int("views"));
 
504
    if (info.get_int("routines") > 0)
 
505
      objects+= strfmt("%li routines, ", info.get_int("routines"));
 
506
 
 
507
    if (!objects.empty())
 
508
      objects= objects.substr(0, objects.length()-2);
 
509
    
 
510
    res= mforms::Utilities::show_message(_("Delete Schema"),
 
511
      strfmt(_("The schema '%s' contains objects (%s).\n"
 
512
      "Do you want to delete it with all its contents?"),
 
513
      info.get_string("name").c_str(), objects.c_str()),
 
514
      _("Delete"), _("Cancel"));
 
515
    if (res != mforms::ResultOk)
 
516
    {
 
517
      _wb->show_status_text(_("Delete schema cancelled."));
 
518
      return;
 
519
    }
 
520
 
 
521
    result= _wb->execute_in_grt_thread("Delete schema",
 
522
             boost::bind(&WBComponentPhysical::delete_db_schema_grt, this, _1, schema, false));
 
523
  }
 
524
 
 
525
  if (!result.is_valid())
 
526
    _wb->show_status_text(_("Schema deleted."));
 
527
  else
 
528
    _wb->show_status_text(_("Could not delete schema."));
 
529
}
 
530
 
 
531
#include "grts/structs.meta.h"
 
532
 
 
533
grt::ValueRef WBComponentPhysical::add_new_db_table_grt(grt::GRT *grt,
 
534
                                                  const db_SchemaRef &schema)
 
535
{
 
536
  grt::AutoUndo undo(grt);
 
537
 
 
538
  db_TableRef table= schema->addNewTable(*_wb->get_parent_for_object<workbench_physical_Model>(schema)->rdbms()->databaseObjectPackage());
 
539
 
 
540
  if (table.has_member("tableEngine"))
 
541
    table.set_member("tableEngine", _wb->get_grt_manager()->get_app_option("db.mysql.Table:tableEngine"));
 
542
 
 
543
  undo.end(_("Create Table"));
 
544
  
 
545
  return table;
 
546
}
 
547
 
 
548
 
 
549
 
 
550
void WBComponentPhysical::add_new_db_table(const db_SchemaRef &schema)
 
551
{
 
552
  grt::ValueRef res;
 
553
 
 
554
  res= _wb->execute_in_grt_thread("Create new table",
 
555
                        boost::bind(&WBComponentPhysical::add_new_db_table_grt, this, _1, schema));
 
556
 
 
557
  if (res.is_valid())
 
558
  {
 
559
    db_TableRef table(db_TableRef::cast_from(res));
 
560
 
 
561
    _wb->show_status_text(strfmt(_("Table '%s' created in schema '%s'"), table->name().c_str(),
 
562
                         table->owner()->name().c_str()));
 
563
 
 
564
    _wb->open_object_editor(GrtObjectRef::cast_from(res));
 
565
  }
 
566
  else
 
567
    _wb->show_status_text(_("Could not create new table."));
 
568
}
 
569
 
 
570
 
 
571
grt::ValueRef WBComponentPhysical::add_new_db_view_grt(grt::GRT *grt,
 
572
                                                         const db_SchemaRef &schema)
 
573
{
 
574
  grt::AutoUndo undo(grt);
 
575
 
 
576
  db_ViewRef view= 
 
577
    schema->addNewView(*_wb->get_parent_for_object<workbench_physical_Model>(schema)->rdbms()->databaseObjectPackage());
 
578
 
 
579
  undo.end(_("Create View"));
 
580
 
 
581
  return view;
 
582
}
 
583
 
 
584
 
 
585
 
 
586
void WBComponentPhysical::add_new_db_view(const db_SchemaRef &schema)
 
587
{
 
588
  grt::ValueRef res;
 
589
 
 
590
  res= _wb->execute_in_grt_thread("Create new view",
 
591
                        boost::bind(&WBComponentPhysical::add_new_db_view_grt, this, _1, schema));
 
592
  if (res.is_valid())
 
593
  {
 
594
    db_ViewRef view(db_ViewRef::cast_from(res));
 
595
 
 
596
    _wb->show_status_text(strfmt(_("View '%s' created in schema '%s'"), view->name().c_str(),
 
597
                         view->owner()->name().c_str()));
 
598
 
 
599
    _wb->open_object_editor(GrtObjectRef::cast_from(res));
 
600
  }
 
601
  else
 
602
    _wb->show_status_text(_("Could not create new view"));
 
603
}
 
604
 
 
605
 
 
606
 
 
607
 
 
608
grt::ValueRef WBComponentPhysical::add_new_db_routine_group_grt(grt::GRT *grt,
 
609
                                                         const db_SchemaRef &schema)
 
610
{
 
611
  grt::AutoUndo undo(grt);
 
612
 
 
613
  db_RoutineGroupRef rgroup=
 
614
    schema->addNewRoutineGroup(*_wb->get_parent_for_object<workbench_physical_Model>(schema)->rdbms()->databaseObjectPackage());
 
615
 
 
616
  undo.end(_("Create Routine Group"));
 
617
 
 
618
  return rgroup;
 
619
}
 
620
 
 
621
 
 
622
 
 
623
void WBComponentPhysical::add_new_db_routine_group(const db_SchemaRef &schema)
 
624
{
 
625
  grt::ValueRef res;
 
626
 
 
627
  res= _wb->execute_in_grt_thread("Create new routine group",
 
628
                        boost::bind(&WBComponentPhysical::add_new_db_routine_group_grt, this, _1, schema));
 
629
  if (res.is_valid())
 
630
  {
 
631
    db_RoutineGroupRef rgroup(db_RoutineGroupRef::cast_from(res));
 
632
 
 
633
    _wb->show_status_text(strfmt(_("Routine group '%s' created in schema '%s'"), rgroup->name().c_str(),
 
634
                         rgroup->owner()->name().c_str()));
 
635
 
 
636
    _wb->open_object_editor(GrtObjectRef::cast_from(res));
 
637
  }
 
638
  else
 
639
    _wb->show_status_text(_("Could not create new routine group"));
 
640
}
 
641
 
 
642
 
 
643
 
 
644
grt::ValueRef WBComponentPhysical::add_new_db_routine_grt(grt::GRT *grt, const db_SchemaRef &schema)
 
645
{
 
646
  grt::AutoUndo undo(grt);
 
647
 
 
648
  db_RoutineRef routine= 
 
649
    schema->addNewRoutine(*_wb->get_parent_for_object<workbench_physical_Model>(schema)->rdbms()->databaseObjectPackage());
 
650
 
 
651
  undo.end(_("Create Routine"));
 
652
 
 
653
  return routine;
 
654
}
 
655
 
 
656
 
 
657
 
 
658
void WBComponentPhysical::add_new_db_routine(const db_SchemaRef &schema)
 
659
{
 
660
  grt::ValueRef res;
 
661
 
 
662
  res= _wb->execute_in_grt_thread("Create new routine",
 
663
                        boost::bind(&WBComponentPhysical::add_new_db_routine_grt, this, _1, schema));
 
664
  if (res.is_valid())
 
665
  {
 
666
    db_RoutineRef routine(db_RoutineRef::cast_from(res));
 
667
 
 
668
    _wb->show_status_text(strfmt(_("Routine '%s' created in schema '%s'"), routine->name().c_str(),
 
669
                         routine->owner()->name().c_str()));
 
670
 
 
671
    _wb->open_object_editor(GrtObjectRef::cast_from(res));
 
672
  }
 
673
  else
 
674
    _wb->show_status_text(_("Could not create new routine"));
 
675
}
 
676
 
 
677
 
 
678
 
 
679
 
 
680
grt::ValueRef WBComponentPhysical::add_new_stored_script_grt(grt::GRT *grt, const workbench_physical_ModelRef &model,
 
681
                                                                 const std::string &path)
 
682
{
 
683
  db_ScriptRef script(grt);
 
684
  std::string name= "script";
 
685
  if (!path.empty())
 
686
    name= g_basename(path.c_str());
 
687
  script->owner(model);
 
688
  script->name(grt::get_name_suggestion_for_list_object(
 
689
    grt::ObjectListRef::cast_from(model->scripts()), name, false));
 
690
  script->createDate(bec::fmttime(0, DATETIME_FMT));
 
691
  script->lastChangeDate(bec::fmttime(0, DATETIME_FMT));
 
692
  script->filename(_wb->create_attached_file("script", path));
 
693
 
 
694
  grt::AutoUndo undo(grt);
 
695
  // insertion will trigger the creation of the file
 
696
  model->scripts().insert(script);
 
697
  if (path.empty())
 
698
    undo.end(_("Add SQL Script"));
 
699
  else
 
700
    undo.end(strfmt(_("Add Script File '%s'"), name.c_str()));
 
701
 
 
702
  return script;
 
703
}
 
704
 
 
705
 
 
706
void WBComponentPhysical::add_new_stored_script(const workbench_physical_ModelRef &model, const std::string &path)
 
707
{
 
708
  _wb->execute_in_grt_thread("Create new stored script",
 
709
    boost::bind(&WBComponentPhysical::add_new_stored_script_grt, this, _1, model, path));
 
710
}
 
711
 
 
712
 
 
713
grt::ValueRef WBComponentPhysical::add_new_stored_note_grt(grt::GRT *grt, const workbench_physical_ModelRef &model,
 
714
                                                               const std::string &path)
 
715
{
 
716
  GrtStoredNoteRef note(grt);
 
717
  std::string name= _("New Note");
 
718
  if (!path.empty())
 
719
    name= g_basename(path.c_str());
 
720
  note->owner(model);
 
721
  note->name(grt::get_name_suggestion_for_list_object(
 
722
    grt::ObjectListRef::cast_from(model->notes()), name, false));
 
723
  note->createDate(bec::fmttime(0, DATETIME_FMT));
 
724
  note->lastChangeDate(bec::fmttime(0, DATETIME_FMT));
 
725
  note->filename(_wb->create_attached_file("note", path));
 
726
 
 
727
  grt::AutoUndo undo(grt);
 
728
  // insertion will trigger the creation of the file
 
729
  model->notes().insert(note);
 
730
  if (path.empty())
 
731
    undo.end(_("Add Text Note"));
 
732
  else
 
733
    undo.end(strfmt(_("Add Note File '%s'"), name.c_str()));
 
734
 
 
735
  return note;
 
736
}
 
737
 
 
738
 
 
739
void WBComponentPhysical::add_new_stored_note(const workbench_physical_ModelRef &model, const std::string &path)
 
740
{
 
741
  _wb->execute_in_grt_thread("Create new stored note",
 
742
    boost::bind(&WBComponentPhysical::add_new_stored_note_grt, this, _1, model, path));
 
743
}
 
744
 
 
745
 
 
746
void WBComponentPhysical::clone_db_object_to_schema(const db_SchemaRef &schema, const db_DatabaseObjectRef &object,
 
747
                                                    grt::CopyContext &context)
 
748
{
 
749
  grt::AutoUndo undo(get_grt());
 
750
 
 
751
  if (object.is_instance(db_Table::static_class_name()))
 
752
  {
 
753
    db_TableRef dbtable(db_TableRef::cast_from(context.copy(object)));
 
754
 
 
755
    if (grt::find_named_object_in_list(schema->tables(), dbtable->name()).is_valid())
 
756
      dbtable->name(grt::get_name_suggestion_for_list_object(schema->tables(),
 
757
        *dbtable->name()+"_copy"));
 
758
 
 
759
    dbtable->owner(schema);
 
760
    dbtable->oldName("");
 
761
    schema->tables().insert(dbtable);
 
762
    undo.end(strfmt(_("Duplicate '%s'"), dbtable->name().c_str()));
 
763
  }
 
764
  else if (object.is_instance(db_View::static_class_name()))
 
765
  {
 
766
    db_ViewRef dbview(db_ViewRef::cast_from(context.copy(object)));
 
767
 
 
768
    if (grt::find_named_object_in_list(schema->views(), dbview->name()).is_valid())
 
769
      dbview->name(grt::get_name_suggestion_for_list_object(schema->views(),
 
770
        *dbview->name()+"_copy"));
 
771
 
 
772
    dbview->owner(schema);
 
773
    dbview->oldName("");
 
774
    schema->views().insert(dbview);
 
775
    undo.end(strfmt(_("Duplicate '%s'"), dbview->name().c_str()));
 
776
  }
 
777
  else if (object.is_instance(db_Routine::static_class_name()))
 
778
  {
 
779
    db_RoutineRef dbroutine(db_RoutineRef::cast_from(context.copy(object)));
 
780
 
 
781
    if (grt::find_named_object_in_list(schema->routines(), dbroutine->name()).is_valid())
 
782
      dbroutine->name(grt::get_name_suggestion_for_list_object(schema->routines(),
 
783
        *dbroutine->name()+"_copy"));
 
784
 
 
785
    dbroutine->owner(schema);
 
786
    dbroutine->oldName("");
 
787
    schema->routines().insert(dbroutine);
 
788
    undo.end(strfmt(_("Duplicate '%s'"), dbroutine->name().c_str()));
 
789
  }
 
790
  else if (object.is_instance(db_RoutineGroup::static_class_name()))
 
791
  {
 
792
    db_RoutineGroupRef dbroutineGroup(db_RoutineGroupRef::cast_from(context.copy(object)));
 
793
 
 
794
    if (grt::find_named_object_in_list(schema->routineGroups(), dbroutineGroup->name()).is_valid())
 
795
      dbroutineGroup->name(grt::get_name_suggestion_for_list_object(schema->routineGroups(),
 
796
        *dbroutineGroup->name()+"_copy"));
 
797
 
 
798
    dbroutineGroup->owner(schema);
 
799
    dbroutineGroup->oldName("");
 
800
    schema->routineGroups().insert(dbroutineGroup);
 
801
    undo.end(strfmt(_("Duplicate '%s'"), dbroutineGroup->name().c_str()));
 
802
  }
 
803
}
 
804
 
 
805
 
 
806
//--------------------------------------------------------------------------------
 
807
// Canvas Object Management
 
808
 
 
809
 
 
810
grt::ValueRef WBComponentPhysical::place_db_object_grt(grt::GRT *grt, ModelDiagramForm *view,
 
811
                                                       const Point &pos,
 
812
                                                       const db_DatabaseObjectRef &object,
 
813
                                                       bool select_figure)
 
814
{
 
815
  workbench_physical_DiagramRef pview(workbench_physical_DiagramRef::cast_from(view->get_model_diagram()));
 
816
  model_FigureRef figure;
 
817
  std::string object_member;
 
818
 
 
819
  if (object.is_instance(db_Table::static_class_name()))
 
820
  {
 
821
    figure= pview->placeTable(db_TableRef::cast_from(object), pos.x, pos.y);
 
822
    object_member= "table";
 
823
  }
 
824
  else if (object.is_instance(db_View::static_class_name()))
 
825
  {
 
826
    figure= pview->placeView(db_ViewRef::cast_from(object), pos.x, pos.y);
 
827
    object_member= "view";
 
828
  }
 
829
  else if (object.is_instance(db_RoutineGroup::static_class_name()))
 
830
  {
 
831
    figure= pview->placeRoutineGroup(db_RoutineGroupRef::cast_from(object), pos.x, pos.y);
 
832
    object_member= "routineGroup";
 
833
  }
 
834
  else
 
835
    throw std::invalid_argument("trying to place invalid object on view");
 
836
 
 
837
  grt::AutoUndo undo(get_grt());
 
838
 
 
839
  if ((*figure->color()).empty())
 
840
  {
 
841
    if (!view->get_tool_argument(figure.class_name()+":Color").empty())
 
842
      figure->color(grt::StringRef(view->get_tool_argument(figure.class_name()+":Color")));
 
843
    else
 
844
      figure->color(_wb->get_wb_options().get_string(figure.class_name()+":Color", ""));
 
845
  }
 
846
 
 
847
  if (view->get_model_options().get_int("workbench.physical.ObjectFigure:Expanded", 
 
848
        _wb->get_wb_options().get_int("workbench.physical.ObjectFigure:Expanded")))
 
849
    figure->expanded(1);
 
850
  else
 
851
    figure->expanded(0);
 
852
 
 
853
  if (select_figure)
 
854
  {
 
855
    pview->unselectAll();
 
856
    pview->selectObject(figure);
 
857
  }
 
858
  undo.end(strfmt(_("Place '%s'"), object->name().c_str()));
 
859
 
 
860
  return figure;
 
861
}
 
862
 
 
863
 
 
864
model_FigureRef WBComponentPhysical::place_db_object(ModelDiagramForm *view, const Point &pos, 
 
865
                                          const db_DatabaseObjectRef &object,
 
866
                                          bool select_figure)
 
867
{
 
868
  grt::ValueRef r;
 
869
  
 
870
  try {
 
871
    r= _wb->execute_in_grt_thread("Place existing object in model",
 
872
      boost::bind(&WBComponentPhysical::place_db_object_grt, this, _1, view, pos, object, select_figure));
 
873
  }
 
874
  catch (std::invalid_argument &)
 
875
  {
 
876
    _wb->show_status_text(_("Cannot place object."));
 
877
    return model_FigureRef();
 
878
  }
 
879
  catch (grt::grt_runtime_error &exc)
 
880
  {
 
881
    _wb->show_exception(_("Place Object on Canvas"), exc);
 
882
    return model_FigureRef();
 
883
  }
 
884
 
 
885
  if (r.is_valid())
 
886
    _wb->show_status_text(strfmt(_("Placed %s"), GrtObjectRef::cast_from(r)->name().c_str()));
 
887
  else
 
888
    _wb->show_status_text(_("Failed placing db object."));
 
889
  
 
890
  return model_FigureRef::cast_from(r);
 
891
}
 
892
 
 
893
 
 
894
std::vector<std::string> WBComponentPhysical::get_accepted_drop_types() const
 
895
{
 
896
  std::vector<std::string> types;
 
897
  
 
898
  types.push_back(WB_DBOBJECT_DRAG_TYPE);
 
899
 
 
900
  return types;
 
901
}
 
902
 
 
903
 
 
904
bool WBComponentPhysical::accepts_drop(ModelDiagramForm *view, int x, int y, const std::string &type, const std::list<GrtObjectRef> &objects)
 
905
{
 
906
  if (objects.empty())
 
907
    return false;
 
908
 
 
909
  if (type == WB_DBOBJECT_DRAG_TYPE)
 
910
  {
 
911
    for (std::list<GrtObjectRef>::const_iterator iter= objects.begin();
 
912
      iter != objects.end(); ++iter)
 
913
    {
 
914
      if (!(*iter).is_instance(db_DatabaseObject::static_class_name()))
 
915
        return false;
 
916
    }
 
917
    return true;
 
918
  }
 
919
  return false;
 
920
}
 
921
 
 
922
 
 
923
bool WBComponentPhysical::perform_drop(ModelDiagramForm *view, int x, int y, const std::string &type, const std::list<GrtObjectRef> &objects)
 
924
{
 
925
  if (objects.empty())
 
926
    return false;
 
927
 
 
928
  if (type == WB_DBOBJECT_DRAG_TYPE)
 
929
  {
 
930
    std::list<db_DatabaseObjectRef> dbobjects;
 
931
 
 
932
    for (std::list<GrtObjectRef>::const_iterator iter= objects.begin();
 
933
      iter != objects.end(); ++iter)
 
934
      dbobjects.push_back(db_DatabaseObjectRef::cast_from((*iter)));
 
935
 
 
936
    interactive_place_db_objects(view, x, y, dbobjects);
 
937
    return true;
 
938
  }
 
939
 
 
940
  return false;
 
941
}
 
942
 
 
943
 
 
944
bool WBComponentPhysical::perform_drop(ModelDiagramForm *view, int x, int y, const std::string &type, const std::string &data)
 
945
{
 
946
  if (data.empty())
 
947
    return false;
 
948
  
 
949
  if (type == WB_DBOBJECT_DRAG_TYPE)
 
950
  {
 
951
    std::list<db_DatabaseObjectRef> dbobjects;
 
952
    db_CatalogRef catalog= workbench_physical_ModelRef::cast_from(view->get_model_diagram()->owner())->catalog();
 
953
    
 
954
    dbobjects= bec::CatalogHelper::dragdata_to_dbobject_list(catalog, data);
 
955
    
 
956
    interactive_place_db_objects(view, x, y, dbobjects);
 
957
    
 
958
    return true;
 
959
  }
 
960
  
 
961
  return false;
 
962
}
 
963
 
 
964
 
 
965
void WBComponentPhysical::interactive_place_db_objects(ModelDiagramForm *vform, int x, int y, 
 
966
      const std::list<db_DatabaseObjectRef> &objects)
 
967
{
 
968
  size_t dupes= 0;
 
969
  std::vector<db_TableRef> tables;
 
970
 
 
971
  if (objects.empty())
 
972
  {
 
973
    mforms::Utilities::show_message(_("Cannot Place Object"), _("The dragged object cannot be placed in the diagram."), _("Close"));
 
974
    return;
 
975
  }
 
976
 
 
977
  grt::AutoUndo undo(get_grt());
 
978
 
 
979
  Point op, p= vform->get_view()->window_to_canvas(x, y);
 
980
  op= p;
 
981
  Size view_size(vform->get_view()->get_total_view_size());
 
982
 
 
983
  vform->get_model_diagram()->unselectAll();
 
984
  
 
985
  for (std::list<db_DatabaseObjectRef>::const_iterator iter= objects.begin(); iter != objects.end(); ++iter)
 
986
  {
 
987
    if (has_figure_for_object_in_active_view(*iter, vform))
 
988
      dupes++;
 
989
    else
 
990
    {
 
991
      model_FigureRef figure= place_db_object(vform, p, *iter, false);
 
992
 
 
993
      if (figure.is_valid())
 
994
        vform->get_model_diagram()->selectObject(figure);
 
995
      
 
996
      p.x+= 20;
 
997
      p.y+= 20;
 
998
      if (p.x + 100 > view_size.width)
 
999
      {
 
1000
        op.y+= 20;
 
1001
        p= op;
 
1002
      }
 
1003
      else if (p.y + 100 > view_size.height)
 
1004
      {
 
1005
        op.y+= 20;
 
1006
        p= op;
 
1007
      }
 
1008
 
 
1009
      if (p.x + 100 > view_size.width || p.y+100 > view_size.height)
 
1010
        p= op;
 
1011
 
 
1012
      if (iter->is_instance(db_Table::static_class_name()))
 
1013
        tables.push_back(db_TableRef::cast_from(*iter));
 
1014
    }
 
1015
  }
 
1016
  
 
1017
  undo.end(_("Place object(s) on canvas"));
 
1018
 
 
1019
  if (dupes == objects.size())
 
1020
  {
 
1021
    if (dupes == 1)
 
1022
      mforms::Utilities::show_message(_("Cannot Place Object"), _("The object cannot be placed because it's already present in this diagram."), _("Close"));
 
1023
    else
 
1024
      mforms::Utilities::show_message(_("Cannot Place Objects"), _("The objects cannot be placed because they're already present in this diagram."), _("Close"));
 
1025
  }
 
1026
  else if (dupes > 0)
 
1027
    mforms::Utilities::show_message(_("Cannot Place Object(s)"), _("Some of the objects could not be placed because they're already present in this diagram."), _("Close"));
 
1028
 
 
1029
  // manually force a refresh since adding a figure doesn't trigger a catalog tree refresh
 
1030
#ifdef _WIN32
 
1031
  // catalog tree doesn't need a full refresh, only a redisplay (structure doesn't change,
 
1032
  // only the text), so we can use the RefreshLayer msg to perform a redisplay only
 
1033
  _wb->request_refresh(RefreshSchema, "");
 
1034
#else
 
1035
  _wb->request_refresh(RefreshSchemaNoReload, "");
 
1036
#endif
 
1037
  
 
1038
}
 
1039
 
 
1040
 
 
1041
grt::ValueRef WBComponentPhysical::place_new_db_object_grt(grt::GRT *grt, ModelDiagramForm *vform, 
 
1042
                                                             const Point &pos,
 
1043
                                                             wb::ObjectType type)
 
1044
{
 
1045
  std::string object_struct_name;
 
1046
  db_SchemaRef target_schema;
 
1047
  std::string schema_name;
 
1048
 
 
1049
  grt::AutoUndo undo(get_grt());
 
1050
 
 
1051
  model_DiagramRef view(vform->get_model_diagram());
 
1052
  workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(view));
 
1053
 
 
1054
  switch (type)
 
1055
  {
 
1056
  case ObjectTable:
 
1057
    object_struct_name= workbench_physical_TableFigure::static_class_name();
 
1058
    break;
 
1059
  case ObjectView:
 
1060
    object_struct_name= workbench_physical_ViewFigure::static_class_name();
 
1061
    break;
 
1062
  case ObjectRoutineGroup:
 
1063
    object_struct_name= workbench_physical_RoutineGroupFigure::static_class_name();
 
1064
    break;
 
1065
  default:
 
1066
    throw std::logic_error("place_db_object() called with invalid tool");
 
1067
  }
 
1068
  schema_name= vform->get_tool_argument(object_struct_name+std::string(":Schema"));
 
1069
 
 
1070
  if (!schema_name.empty())
 
1071
  {
 
1072
    db_SchemaRef schema(grt::find_named_object_in_list(model->catalog()->schemata(), schema_name));
 
1073
    if (schema.is_valid())
 
1074
      target_schema= schema;
 
1075
  }
 
1076
 
 
1077
  // pick a default schema..
 
1078
  if (!target_schema.is_valid())
 
1079
  {
 
1080
    if (model->catalog()->schemata().count() == 0)
 
1081
    {
 
1082
      // if there are no schemas, create a default one
 
1083
      add_new_db_schema_grt(grt, model);
 
1084
    }
 
1085
    target_schema= model->catalog()->schemata().get(0);
 
1086
  }
 
1087
 
 
1088
  db_DatabaseObjectRef object;
 
1089
 
 
1090
  switch (type)
 
1091
  {
 
1092
  case ObjectTable:
 
1093
    object= db_DatabaseObjectRef::cast_from(add_new_db_table_grt(grt, target_schema));
 
1094
    break;
 
1095
  case ObjectView:
 
1096
    object= db_DatabaseObjectRef::cast_from(add_new_db_view_grt(grt, target_schema));
 
1097
    break;
 
1098
  case ObjectRoutineGroup:
 
1099
    object= db_DatabaseObjectRef::cast_from(add_new_db_routine_group_grt(grt, target_schema));
 
1100
    break;
 
1101
  default:
 
1102
    throw std::logic_error("place_db_object() called with invalid tool");
 
1103
  }
 
1104
 
 
1105
  std::string collation= vform->get_tool_argument(object_struct_name+":Collation");
 
1106
 
 
1107
  if (collation!="" && collation[0] != '*')
 
1108
  {
 
1109
    if (object.has_member("defaultCollationName"))
 
1110
      object.set_member("defaultCollationName", grt::StringRef(collation));
 
1111
 
 
1112
    std::string charset= base::split(collation, "_", 1)[0];
 
1113
    if (object.has_member("defaultCharacterSetName"))
 
1114
      object.set_member("defaultCharacterSetName", grt::StringRef(charset));
 
1115
  }
 
1116
 
 
1117
  std::string engine= vform->get_tool_argument(object_struct_name+":Engine");
 
1118
  if (!engine.empty() && engine[0] != '*')
 
1119
  {
 
1120
    if (object.has_member("tableEngine"))
 
1121
      object.set_member("tableEngine", grt::StringRef(engine));
 
1122
  }
 
1123
 
 
1124
  grt::ValueRef result= place_db_object_grt(grt, vform, pos, object, true);
 
1125
 
 
1126
  undo.end(strfmt(_("Place '%s'"), object->name().c_str()));
 
1127
 
 
1128
  return result;
 
1129
}
 
1130
 
 
1131
 
 
1132
void WBComponentPhysical::place_new_db_object(ModelDiagramForm *view, const Point &pos,
 
1133
                                              wb::ObjectType type)
 
1134
{
 
1135
  grt::ValueRef r;
 
1136
  
 
1137
  r= _wb->execute_in_grt_thread("Place object in model",
 
1138
                boost::bind(&WBComponentPhysical::place_new_db_object_grt, this, _1, view,  pos, type));
 
1139
  if (r.is_valid())
 
1140
    _wb->show_status_text(strfmt(_("Placed new %s"), model_FigureRef::cast_from(r)->name().c_str()));
 
1141
  else
 
1142
    _wb->show_status_text(_("Failed placing db object."));
 
1143
}
 
1144
 
 
1145
 
 
1146
bool WBComponentPhysical::create_nm_relationship_grt(grt::GRT *grt, ModelDiagramForm *view,
 
1147
                                                   workbench_physical_TableFigureRef table1, 
 
1148
                                                   workbench_physical_TableFigureRef table2,
 
1149
                                                   bool imandatory, bool fmandatory)
 
1150
{
 
1151
  grt::AutoUndo undo(grt);
 
1152
  // create the associative table for a n:m relationship
 
1153
  db_TableRef atable=
 
1154
    bec::TableHelper::create_associative_table(db_SchemaRef::cast_from(table1->table()->owner()),
 
1155
                                              table1->table(), table2->table(),
 
1156
                                              imandatory, fmandatory, 
 
1157
                                               workbench_physical_ModelRef::cast_from(view->get_model_diagram()->owner())->rdbms(),
 
1158
                                              _wb->get_wb_options(),
 
1159
                                              view->get_model_diagram()->owner()->options());
 
1160
 
 
1161
  if (!atable.is_valid())
 
1162
    return false;
 
1163
 
 
1164
  // place the assoc table in the view
 
1165
  Point pos;
 
1166
 
 
1167
  pos.x= (table1->left() + table2->left()) / 2;
 
1168
  pos.y= (table1->top() + table2->top()) / 2;
 
1169
 
 
1170
  place_db_object_grt(grt, view, pos, atable, true);
 
1171
 
 
1172
  undo.end(_("Create n:m Relationship"));
 
1173
 
 
1174
  return true;
 
1175
}
 
1176
 
 
1177
 
 
1178
WBComponentPhysical::RelationshipToolContext *
 
1179
WBComponentPhysical::start_relationship(ModelDiagramForm *view, const Point &pos,
 
1180
                                           RelationshipType type)
 
1181
{
 
1182
  RelationshipToolContext *rctx= new RelationshipToolContext(this, view, type);
 
1183
  
 
1184
  return rctx;
 
1185
}
 
1186
 
 
1187
 
 
1188
void WBComponentPhysical::cancel_relationship(ModelDiagramForm *view, RelationshipToolContext *rctx)
 
1189
{
 
1190
  if (rctx)
 
1191
  {
 
1192
    rctx->cancel();
 
1193
 
 
1194
    delete rctx;
 
1195
  }  
 
1196
}
 
1197
 
 
1198
 
 
1199
void WBComponentPhysical::delete_db_object(const db_DatabaseObjectRef &object)
 
1200
{
 
1201
  db_SchemaRef schema(db_SchemaRef::cast_from(object->owner()));
 
1202
  std::map<std::string, bool> options;
 
1203
  workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(schema));
 
1204
 
 
1205
  // do not delete db object from model object deleter, since that would
 
1206
  // mean deleting it twice and adding 2 entries in the undo stack
 
1207
  options["deletedbobjects"]= false;
 
1208
 
 
1209
  //XXX need to look for refs by other objects and show them to user
 
1210
  // and confirm that they should be removed or cancel
 
1211
 
 
1212
  if (object.is_instance(db_Table::static_class_name()))
 
1213
  {
 
1214
    grt::AutoUndo undo(get_grt());
 
1215
 
 
1216
    schema->tables().remove_value(db_TableRef::cast_from(object));
 
1217
 
 
1218
    if (model.is_valid())
 
1219
    {
 
1220
      for (grt::ListRef<workbench_physical_Diagram>::const_iterator view= model->diagrams().begin();
 
1221
           view != model->diagrams().end(); ++view)
 
1222
      {
 
1223
        grt::ListRef<model_Figure> figures((*view)->figures());
 
1224
        for (size_t f= figures.count(); f > 0; --f)
 
1225
        {
 
1226
          model_FigureRef figure= figures[f-1];
 
1227
          if (figure.is_instance(workbench_physical_TableFigure::static_class_name())
 
1228
            && workbench_physical_TableFigureRef::cast_from(figure)->table() == object)
 
1229
          {
 
1230
            delete_model_object(figure, options);
 
1231
          }
 
1232
        }
 
1233
      }
 
1234
    }
 
1235
 
 
1236
    // remove referencing foreign keys
 
1237
    {
 
1238
      db_TableRef table= db_TableRef::cast_from(object);
 
1239
      grt::ListRef<db_ForeignKey> foreignKeys(db_SchemaRef::cast_from(table->owner())->getForeignKeysReferencingTable(table));
 
1240
      if (0 < foreignKeys.count())
 
1241
      {
 
1242
        for (grt::ListRef<db_ForeignKey>::const_iterator iter= foreignKeys.begin(); 
 
1243
          iter != foreignKeys.end(); ++iter)
 
1244
        {
 
1245
          db_ForeignKeyRef fk(*iter);
 
1246
          db_TableRef ref_table= db_TableRef::cast_from(fk->owner());
 
1247
 
 
1248
          // remove corresponding index
 
1249
          /*
 
1250
          grt::ListRef<db_Index> indices= ref_table->indices();
 
1251
          for (size_t count= indices.count(), i= 0; i < count; ++i)
 
1252
          {
 
1253
            db_IndexRef index= indices.get(i);
 
1254
            if (0 == strcmp(index->indexType().c_str(), "FOREIGN"))
 
1255
            {
 
1256
              grt::ListRef<db_IndexColumn> index_columns= index->columns();
 
1257
              grt::ListRef<db_Column> fk_columns= fk->columns();
 
1258
              if (index_columns.count() == fk_columns.count())
 
1259
              {
 
1260
                bool equal= true;
 
1261
                for (size_t count= index_columns.count(), c= 0; c < count; ++c)
 
1262
                {
 
1263
                  db_ColumnRef index_column= index_columns.get(c)->referencedColumn();
 
1264
                  if (index_column.is_valid())
 
1265
                  {
 
1266
                  db_ColumnRef fk_column= find_object_in_list(fk_columns, index_column.id());
 
1267
                  if (!fk_column.is_valid())
 
1268
                  {
 
1269
                    equal= false;
 
1270
                    break;
 
1271
                  }
 
1272
                }
 
1273
                }
 
1274
                if (equal)
 
1275
                {
 
1276
                  ref_table->indices().remove_value(index);
 
1277
                  break;
 
1278
                }
 
1279
              }
 
1280
            }
 
1281
          }
 
1282
           */
 
1283
          if (fk->index().is_valid())
 
1284
            ref_table->indices().remove_value(fk->index());
 
1285
          ref_table->foreignKeys().remove_value(fk);
 
1286
        }
 
1287
      }
 
1288
    }
 
1289
 
 
1290
    remove_references_to_object(object);
 
1291
 
 
1292
    undo.end(_("Delete Table"));
 
1293
  }
 
1294
  else if (object.is_instance(db_View::static_class_name()))
 
1295
  {
 
1296
    grt::AutoUndo undo(get_grt());
 
1297
 
 
1298
    schema->views().remove_value(db_ViewRef::cast_from(object));
 
1299
 
 
1300
    if (model.is_valid())
 
1301
    {
 
1302
      for (grt::ListRef<workbench_physical_Diagram>::const_iterator view= model->diagrams().begin(); 
 
1303
           view != model->diagrams().end(); ++view)
 
1304
      {
 
1305
        for (grt::ListRef<model_Figure>::const_reverse_iterator figure= (*view)->figures().rbegin(); 
 
1306
             figure != (*view)->figures().rend(); ++figure)
 
1307
        {
 
1308
          if ((*figure).is_instance(workbench_physical_ViewFigure::static_class_name())
 
1309
            && workbench_physical_ViewFigureRef::cast_from(*figure)->view() == object)
 
1310
          {
 
1311
            delete_model_object(*figure, options);
 
1312
            break;//We have deleted figure, figure is invalid from now and may not be incremented
 
1313
          }
 
1314
        }
 
1315
      }
 
1316
    }
 
1317
    
 
1318
    remove_references_to_object(object);
 
1319
 
 
1320
    undo.end(_("Delete View"));
 
1321
  }
 
1322
  else if (object.is_instance(db_RoutineGroup::static_class_name()))
 
1323
  {
 
1324
    std::set<db_RoutineRef> ungrouped_routines;
 
1325
    db_RoutineGroupRef routine_group(db_RoutineGroupRef::cast_from(object));
 
1326
    
 
1327
    // first check if the routines in the rg are in any other routine groups
 
1328
    // if they are in none, check if they should be totally deleted
 
1329
 
 
1330
    GRTLIST_FOREACH(db_Routine, routine_group->routines(), routine)
 
1331
    {
 
1332
      ungrouped_routines.insert(*routine);
 
1333
    }
 
1334
    
 
1335
    if (model.is_valid())
 
1336
    {
 
1337
      GRTLIST_FOREACH(db_RoutineGroup, schema->routineGroups(), rgroup)
 
1338
      {
 
1339
        if (*rgroup != routine_group)
 
1340
        {
 
1341
          GRTLIST_FOREACH(db_Routine, (*rgroup)->routines(), routine)
 
1342
          {
 
1343
            std::set<db_RoutineRef>::iterator iter;
 
1344
            
 
1345
            // remove the routines that are in other groups
 
1346
            if ((iter = ungrouped_routines.find(*routine)) != ungrouped_routines.end())
 
1347
              ungrouped_routines.erase(iter);
 
1348
            
 
1349
            if (ungrouped_routines.empty()) break;
 
1350
          }
 
1351
        }
 
1352
        if (ungrouped_routines.empty()) break;
 
1353
      }
 
1354
    }
 
1355
    
 
1356
    grt::AutoUndo undo(get_grt());
 
1357
    
 
1358
    if (!ungrouped_routines.empty())
 
1359
    {
 
1360
      int result;
 
1361
      if (routine_group->routines().count() == ungrouped_routines.size())
 
1362
        result= mforms::Utilities::show_message(_("Delete Routines"),
 
1363
                                                strfmt(_("Would you like to delete the routines contained in group '%s'?"),
 
1364
                                                       routine_group->name().c_str()),
 
1365
                                                _("Delete"), _("Cancel"), _("Keep"));
 
1366
      else
 
1367
        result= mforms::Utilities::show_message(_("Delete Routines"),
 
1368
                                                strfmt(_("There are %zu routines in '%s' that are not in any other group, would you like to delete them?"),
 
1369
                                                       ungrouped_routines.size(), routine_group->name().c_str()),
 
1370
                                                _("Delete"), _("Cancel"), _("Keep"));
 
1371
      
 
1372
      if (result == mforms::ResultCancel)
 
1373
      {
 
1374
        undo.cancel();
 
1375
        return;
 
1376
      }
 
1377
      else if (result == mforms::ResultOk)
 
1378
      {
 
1379
        // delete all routines
 
1380
        for (base::const_range<std::set<db_RoutineRef> > r(ungrouped_routines); r; ++r)
 
1381
        {
 
1382
          size_t i = schema->routines().get_index(*r);
 
1383
          if (i != grt::BaseListRef::npos)
 
1384
            schema->routines().remove(i);
 
1385
        }
 
1386
      }
 
1387
    }
 
1388
    
 
1389
    schema->routineGroups().remove_value(routine_group);
 
1390
 
 
1391
    if (model.is_valid())
 
1392
    {
 
1393
      for (grt::ListRef<workbench_physical_Diagram>::const_iterator view= model->diagrams().begin(); 
 
1394
           view != model->diagrams().end(); ++view)
 
1395
      {
 
1396
        for (grt::ListRef<model_Figure>::const_reverse_iterator figure= (*view)->figures().rbegin(); 
 
1397
             figure != (*view)->figures().rend(); ++figure)
 
1398
        {
 
1399
          if ((*figure).is_instance(workbench_physical_RoutineGroupFigure::static_class_name())
 
1400
            && workbench_physical_RoutineGroupFigureRef::cast_from(*figure)->routineGroup() == object)
 
1401
          {
 
1402
            delete_model_object(*figure, options);
 
1403
            break;//We have deleted figure, figure is invalid from now and may not be incremented
 
1404
          }
 
1405
        }
 
1406
      }
 
1407
    }
 
1408
 
 
1409
    remove_references_to_object(object);
 
1410
 
 
1411
    undo.end(_("Delete Routine Group"));
 
1412
  }
 
1413
  else if (object.is_instance(db_Routine::static_class_name()))
 
1414
  {
 
1415
    grt::AutoUndo undo(get_grt());
 
1416
    db_RoutineRef routine(db_RoutineRef::cast_from(object));
 
1417
    
 
1418
    schema->routines().remove_value(routine);
 
1419
    // remove from routine groups
 
1420
    GRTLIST_FOREACH(db_RoutineGroup, schema->routineGroups(), rg)
 
1421
    {
 
1422
      size_t i;
 
1423
      while ((i = (*rg)->routines().get_index(routine)) != grt::BaseListRef::npos)
 
1424
      {
 
1425
        (*rg)->routines().remove(i);
 
1426
      }
 
1427
    }
 
1428
 
 
1429
    remove_references_to_object(object);
 
1430
 
 
1431
    undo.end(_("Delete Routine"));
 
1432
  }
 
1433
}
 
1434
 
 
1435
 
 
1436
 
 
1437
bool WBComponentPhysical::delete_model_object(const model_ObjectRef &object, std::map<std::string,bool> &options)
 
1438
{
 
1439
  if (object.is_instance(workbench_physical_Connection::static_class_name()))
 
1440
  {
 
1441
    workbench_physical_ConnectionRef conn(workbench_physical_ConnectionRef::cast_from(object));
 
1442
    db_ForeignKeyRef fk(conn->foreignKey());
 
1443
    db_TableRef table(db_TableRef::cast_from(fk->owner()));
 
1444
    int result;
 
1445
 
 
1446
    // Check if the fk still belongs to the table.
 
1447
    // If the connection is being deleted together with the table that it points to,
 
1448
    // it will be auto-removed. Depending on the order things get executed and by the
 
1449
    // way this place is reached, the FK might already be gone.
 
1450
    if (table->foreignKeys().get_index(fk) == grt::BaseListRef::npos)
 
1451
      return false;
 
1452
 
 
1453
    result= mforms::Utilities::show_message(_("Delete Foreign Key Columns"),
 
1454
      _("Please confirm whether columns used by the foreign key should be deleted too.\nColumns used by other foreign keys will be left untouched."),
 
1455
      _("Delete"), _("Cancel"), _("Keep"));
 
1456
 
 
1457
    if (result == mforms::ResultCancel)
 
1458
      return false;
 
1459
 
 
1460
    grt::AutoUndo undo(get_grt());
 
1461
/*
 
1462
    model_DiagramRef view(conn->owner());
 
1463
    // remove connection
 
1464
    view->removeConnection(conn);
 
1465
*/
 
1466
    table->removeForeignKey(fk, result == mforms::ResultOk ? true : false);
 
1467
 
 
1468
    undo.end(_("Delete Relationship"));
 
1469
  }
 
1470
  else if (object.is_instance(model_Figure::static_class_name()))
 
1471
  {
 
1472
    if (options.find("deletedbobjects-canceled") != options.end())
 
1473
      return false;
 
1474
 
 
1475
    model_FigureRef figure(model_FigureRef::cast_from(object));
 
1476
    bool del_db_object;
 
1477
 
 
1478
    if (options.find("deletedbobjects") == options.end())
 
1479
    {
 
1480
      int ok= mforms::ResultOther;
 
1481
      std::map<std::string, bool>::const_iterator it= options.find("silent-mode");
 
1482
      if((it == options.end()) || (it->second == false))
 
1483
      {
 
1484
        ok= _wb->execute_in_main_thread<int>("ask delete", boost::bind(&mforms::Utilities::show_message,
 
1485
          _("Delete Object"), 
 
1486
          _("Should corresponding database objects be deleted with the figures?"),
 
1487
          _("Delete"), _("Skip"), _("Keep")
 
1488
        ));
 
1489
      }
 
1490
      else
 
1491
      {
 
1492
        ok= mforms::ResultOk;
 
1493
      }
 
1494
 
 
1495
      if (ok == mforms::ResultCancel)
 
1496
      {
 
1497
        options["deletedbobjects-canceled"]= true;
 
1498
        return false;
 
1499
      }
 
1500
      if (ok == mforms::ResultOk)
 
1501
        del_db_object= true;
 
1502
      else
 
1503
        del_db_object= false;
 
1504
 
 
1505
      options["deletedbobjects"]= del_db_object;
 
1506
    }
 
1507
    else
 
1508
    {
 
1509
      del_db_object= options["deletedbobjects"];
 
1510
    }
 
1511
 
 
1512
    grt::AutoUndo undo(get_grt());
 
1513
    // if the figure is a DB object, the DB object is also deleted
 
1514
    if (figure.is_instance(workbench_physical_TableFigure::static_class_name()))
 
1515
    {
 
1516
      db_TableRef dbtable(workbench_physical_TableFigureRef::cast_from(figure)->table());
 
1517
 
 
1518
      workbench_physical_DiagramRef::cast_from(figure->owner())->deleteConnectionsForTable(dbtable);
 
1519
 
 
1520
      workbench_physical_TableFigureRef::cast_from(figure)->table(db_TableRef());
 
1521
 
 
1522
      // this must be called after the figure->table field is invalidated, otherwise
 
1523
      // delete_db_object() will try to delete the figure again and we get into a loop
 
1524
      if (del_db_object)
 
1525
        delete_db_object(dbtable);
 
1526
    }
 
1527
    else if (figure.is_instance(workbench_physical_ViewFigure::static_class_name()))
 
1528
    {      
 
1529
      db_ViewRef view(workbench_physical_ViewFigureRef::cast_from(figure)->view());
 
1530
 
 
1531
      workbench_physical_ViewFigureRef::cast_from(figure)->view(db_ViewRef());
 
1532
 
 
1533
      if (del_db_object)
 
1534
        delete_db_object(view);
 
1535
    }
 
1536
    else if (figure.is_instance(workbench_physical_RoutineGroupFigure::static_class_name()))
 
1537
    {
 
1538
      db_RoutineGroupRef rg(workbench_physical_RoutineGroupFigureRef::cast_from(figure)->routineGroup());
 
1539
 
 
1540
      workbench_physical_RoutineGroupFigureRef::cast_from(figure)->routineGroup(db_RoutineGroupRef());
 
1541
 
 
1542
      if (del_db_object)
 
1543
        delete_db_object(rg);
 
1544
    }
 
1545
    else
 
1546
      return false;
 
1547
 
 
1548
    // removeFigure() will remove anything that depends on the figure automatically, ie connections
 
1549
    workbench_physical_DiagramRef::cast_from(figure->owner())->removeFigure(figure);
 
1550
 
 
1551
    undo.end(strfmt(_("Delete '%s' Figure"), figure.get_metaclass()->get_attribute("caption").c_str()));
 
1552
  }
 
1553
  return true;
 
1554
}
 
1555
 
 
1556
 
 
1557
 
 
1558
 
 
1559
 
 
1560
 
 
1561
bool WBComponentPhysical::handles_figure(const model_ObjectRef &figure)
 
1562
{
 
1563
  if (figure.is_instance(workbench_physical_TableFigure::static_class_name()) ||
 
1564
    figure.is_instance(workbench_physical_ViewFigure::static_class_name()) ||
 
1565
    figure.is_instance(workbench_physical_RoutineGroupFigure::static_class_name()) ||
 
1566
    figure.is_instance(workbench_physical_Connection::static_class_name()))
 
1567
    return true;
 
1568
  return false;
 
1569
}
 
1570
 
 
1571
 
 
1572
model_ObjectRef WBComponentPhysical::clone_object(const model_ObjectRef &object, const model_LayerRef &destlayer, 
 
1573
                                               grt::CopyContext &copy_context, bool copy_only)
 
1574
{
 
1575
  std::set<std::string> skip;
 
1576
  skip.insert("oldName");
 
1577
 
 
1578
  if (object.is_instance(workbench_physical_TableFigure::static_class_name()))
 
1579
  {
 
1580
    workbench_physical_TableFigureRef table(workbench_physical_TableFigureRef::cast_from(object));
 
1581
 
 
1582
    // copy table
 
1583
    db_TableRef dbtable(db_TableRef::cast_from(copy_context.copy(table->table(),skip)));
 
1584
 
 
1585
    copy_context.update_references();
 
1586
 
 
1587
    // post-processing
 
1588
    // - uniquefy foreign key names 
 
1589
    int max_fk_len = workbench_physical_ModelRef::cast_from(dbtable->owner()->owner()->owner())->rdbms()->maximumIdentifierLength();
 
1590
    grt::ListRef<db_ForeignKey> fks(dbtable->foreignKeys());
 
1591
    std::set<std::string> used_fk_names = bec::SchemaHelper::get_foreign_key_names(db_SchemaRef::cast_from(dbtable->owner()));
 
1592
    for (size_t c= fks.count(), i = 0; i < c; i++)
 
1593
    {
 
1594
      db_ForeignKeyRef fk(fks[i]);
 
1595
      
 
1596
      fk->name(bec::SchemaHelper::get_unique_foreign_key_name(used_fk_names, fk->name(), max_fk_len));
 
1597
    }
 
1598
    
 
1599
    // copy figure
 
1600
    skip.insert("table");
 
1601
    workbench_physical_TableFigureRef copy(workbench_physical_TableFigureRef::cast_from(copy_context.copy(table,skip)));
 
1602
    copy->table(dbtable);
 
1603
 
 
1604
    copy_context.update_references();
 
1605
 
 
1606
    if (destlayer.is_valid())
 
1607
    {
 
1608
      copy->owner(destlayer->owner());
 
1609
      copy->layer(destlayer);
 
1610
 
 
1611
      if (!copy_only)
 
1612
      {
 
1613
        if (grt::find_named_object_in_list(db_SchemaRef::cast_from(dbtable->owner())->tables(), dbtable->name()).is_valid())
 
1614
          dbtable->name(grt::get_name_suggestion_for_list_object(db_SchemaRef::cast_from(dbtable->owner())->tables(),
 
1615
            *dbtable->name()+"_copy"));
 
1616
        copy->name(dbtable->name());
 
1617
 
 
1618
        grt::AutoUndo undo(get_grt());
 
1619
 
 
1620
        db_SchemaRef::cast_from(dbtable->owner())->tables().insert(dbtable);
 
1621
 
 
1622
        destlayer->owner()->addFigure(copy);
 
1623
        workbench_physical_DiagramRef::cast_from(destlayer->owner())->createConnectionsForTable(copy->table());
 
1624
 
 
1625
        undo.end(strfmt(_("Duplicate Table '%s'"), copy->name().c_str()));
 
1626
      }
 
1627
    }
 
1628
    else
 
1629
    {
 
1630
      copy->owner(model_DiagramRef());
 
1631
      copy->layer(model_LayerRef());
 
1632
    }
 
1633
 
 
1634
    return copy;
 
1635
  }
 
1636
  else if (object.is_instance(workbench_physical_ViewFigure::static_class_name()))
 
1637
  {
 
1638
    workbench_physical_ViewFigureRef view(workbench_physical_ViewFigureRef::cast_from(object));
 
1639
    
 
1640
    // copy view
 
1641
    db_ViewRef dbview(db_ViewRef::cast_from(copy_context.copy(view->view())));
 
1642
 
 
1643
    // copy figure
 
1644
    skip.insert("view");
 
1645
    workbench_physical_ViewFigureRef copy(workbench_physical_ViewFigureRef::cast_from(copy_context.copy(view)));
 
1646
    copy->view(dbview);
 
1647
 
 
1648
    if (destlayer.is_valid())
 
1649
    {
 
1650
      copy->owner(destlayer->owner());
 
1651
      copy->layer(destlayer);
 
1652
 
 
1653
      if (!copy_only)
 
1654
      {
 
1655
        if (grt::find_named_object_in_list(db_SchemaRef::cast_from(dbview->owner())->views(), dbview->name()).is_valid())
 
1656
          dbview->name(grt::get_name_suggestion_for_list_object(db_SchemaRef::cast_from(dbview->owner())->views(),
 
1657
            *dbview->name()+"_copy"));
 
1658
        copy->name(dbview->name());
 
1659
 
 
1660
        grt::AutoUndo undo(get_grt());
 
1661
 
 
1662
        db_SchemaRef::cast_from(dbview->owner())->views().insert(dbview);
 
1663
 
 
1664
        destlayer->owner()->addFigure(copy);
 
1665
 
 
1666
        undo.end(strfmt(_("Duplicate View '%s'"), copy->name().c_str()));
 
1667
      }
 
1668
    }
 
1669
    else
 
1670
    {
 
1671
      copy->owner(model_DiagramRef());
 
1672
      copy->layer(model_LayerRef());
 
1673
    }
 
1674
    return copy;
 
1675
  }
 
1676
  else if (object.is_instance(workbench_physical_RoutineGroupFigure::static_class_name()))
 
1677
  {
 
1678
    workbench_physical_RoutineGroupFigureRef routineGroup(workbench_physical_RoutineGroupFigureRef::cast_from(object));
 
1679
    
 
1680
    // copy routineGroup
 
1681
    db_RoutineGroupRef dbroutineGroup(db_RoutineGroupRef::cast_from(copy_context.copy(routineGroup->routineGroup())));
 
1682
 
 
1683
    // copy figure
 
1684
    skip.insert("routineGroup");
 
1685
    workbench_physical_RoutineGroupFigureRef copy(workbench_physical_RoutineGroupFigureRef::cast_from(copy_context.copy(routineGroup)));
 
1686
    copy->routineGroup(dbroutineGroup);
 
1687
 
 
1688
    if (destlayer.is_valid())
 
1689
    {
 
1690
      copy->owner(destlayer->owner());
 
1691
      copy->layer(destlayer);
 
1692
 
 
1693
      if (!copy_only)
 
1694
      {
 
1695
        if (grt::find_named_object_in_list(db_SchemaRef::cast_from(dbroutineGroup->owner())->routineGroups(), dbroutineGroup->name()).is_valid())
 
1696
          dbroutineGroup->name(grt::get_name_suggestion_for_list_object(db_SchemaRef::cast_from(dbroutineGroup->owner())->routineGroups(),
 
1697
            *dbroutineGroup->name()+"_copy"));
 
1698
        copy->name(dbroutineGroup->name());
 
1699
 
 
1700
        grt::AutoUndo undo(get_grt());
 
1701
 
 
1702
        db_SchemaRef::cast_from(dbroutineGroup->owner())->routineGroups().insert(dbroutineGroup);
 
1703
 
 
1704
        destlayer->owner()->addFigure(copy);
 
1705
 
 
1706
        undo.end(strfmt(_("Duplicate Routine Group '%s'"), copy->name().c_str()));
 
1707
      }
 
1708
    }
 
1709
    else
 
1710
    {
 
1711
      copy->owner(model_DiagramRef());
 
1712
      copy->layer(model_LayerRef());
 
1713
    }
 
1714
    return copy;
 
1715
  }
 
1716
 
 
1717
  return model_ObjectRef();
 
1718
}
 
1719
 
 
1720
 
 
1721
bool WBComponentPhysical::can_paste_non_model_object(const grt::ObjectRef &object)
 
1722
{
 
1723
  if (db_DatabaseObjectRef::can_wrap(object) && 
 
1724
    !has_figure_for_object_in_active_view(GrtObjectRef::cast_from(object)) &&
 
1725
    (object.is_instance(db_Table::static_class_name()) ||
 
1726
     object.is_instance(db_View::static_class_name()) ||
 
1727
     object.is_instance(db_RoutineGroup::static_class_name())))
 
1728
    return true;
 
1729
  return false;
 
1730
}
 
1731
 
 
1732
 
 
1733
void WBComponentPhysical::paste_non_model_object(ModelDiagramForm *view, const grt::ObjectRef &object)
 
1734
{
 
1735
  std::list<db_DatabaseObjectRef> objects;
 
1736
 
 
1737
  // find the original object
 
1738
  db_DatabaseObjectRef obj(db_DatabaseObjectRef::cast_from(object));
 
1739
  db_SchemaRef schema(db_SchemaRef::cast_from(obj->owner()));
 
1740
 
 
1741
  if (obj.is_instance(db_Table::static_class_name()))
 
1742
    objects.push_back(grt::find_named_object_in_list(schema->tables(), *obj->name()));
 
1743
  else if (obj.is_instance(db_View::static_class_name()))
 
1744
    objects.push_back(grt::find_named_object_in_list(schema->views(), *obj->name()));
 
1745
  else if (obj.is_instance(db_RoutineGroup::static_class_name()))
 
1746
    objects.push_back(grt::find_named_object_in_list(schema->routineGroups(), *obj->name()));
 
1747
  else
 
1748
    return;
 
1749
  
 
1750
  if (objects.front().is_valid())
 
1751
    interactive_place_db_objects(view, 10, 10, objects);
 
1752
}
 
1753
 
 
1754
 
 
1755
std::string WBComponentPhysical::get_object_tooltip(const model_ObjectRef &object, mdc::CanvasItem *item)
 
1756
{
 
1757
  if (workbench_physical_TableFigureRef::can_wrap(object))
 
1758
  {
 
1759
    workbench_physical_TableFigureRef table_figure(workbench_physical_TableFigureRef::cast_from(object));
 
1760
    db_TableRef table(table_figure->table());
 
1761
    
 
1762
    if (table.is_valid())
 
1763
    {
 
1764
      workbench_physical_TableFigure::ImplData *tfig= table_figure->get_data();
 
1765
      if (tfig)
 
1766
      {
 
1767
        db_ColumnRef column(tfig->get_column_at(item));
 
1768
        db_IndexRef index;
 
1769
        
 
1770
        if (!column.is_valid())
 
1771
          index= tfig->get_index_at(item);
 
1772
        
 
1773
        if (column.is_valid())
 
1774
        {
 
1775
          std::string text;
 
1776
          bool isfk= false;
 
1777
          
 
1778
          text.append(*column->name());
 
1779
          if (table->isPrimaryKeyColumn(column))
 
1780
            text.append(" (PK)");
 
1781
          else if (table->isForeignKeyColumn(column))
 
1782
          {
 
1783
            isfk= true;
 
1784
            text.append(" (FK)");
 
1785
          }
 
1786
          text.append("\n");
 
1787
          
 
1788
          if (isfk)
 
1789
          {
 
1790
            text.append("References: ");
 
1791
            
 
1792
            for (size_t c= table->foreignKeys().count(), i= 0; i < c; i++)
 
1793
            {
 
1794
              db_ForeignKeyRef fk(table->foreignKeys()[i]);
 
1795
              //ssize_t idx; // get_index returns size_t, so comparing it by >= 0 is always true!!!
 
1796
              
 
1797
              const size_t idx= fk->columns().get_index(column);
 
1798
              if (idx != BaseListRef::npos)
 
1799
              {
 
1800
                if (fk->referencedTable().is_valid() && fk->referencedColumns().get(idx).is_valid())
 
1801
                {
 
1802
                  text.append(fk->referencedTable()->name());
 
1803
                  text.append(".");
 
1804
                  text.append(fk->referencedColumns().get(idx)->name());
 
1805
                }
 
1806
                else
 
1807
                  text.append("INVALID");
 
1808
                break;
 
1809
              }
 
1810
            }
 
1811
            text.append("\n");
 
1812
          }
 
1813
          
 
1814
          text.append(column->formattedRawType());
 
1815
          text.append("\n");
 
1816
          {
 
1817
            std::string flags;
 
1818
            if (*column->isNotNull())
 
1819
              flags.append("NOT NULL"); //XXX add a method to db_Column to return a formatted string of all flags
 
1820
            for (size_t c= column->flags().count(), i= 0; i < c; i++)
 
1821
            {
 
1822
              if (i > 0 || *column->isNotNull())
 
1823
                flags.append(", ");
 
1824
              flags.append(column->flags().get(i).c_str());
 
1825
            }
 
1826
            if (!flags.empty())
 
1827
              text.append("Flags: ").append(flags);
 
1828
          }
 
1829
          if (*column->defaultValue() != "")
 
1830
            text.append("\nDEFAULT ").append(column->defaultValue().c_str());
 
1831
          
 
1832
          /* comments can be too large
 
1833
           if (*column->comment().c_str())
 
1834
           {
 
1835
           text.append("\n");
 
1836
           text.append(column->comment());
 
1837
           }
 
1838
           */
 
1839
          
 
1840
          return text;
 
1841
        }
 
1842
        else if (index.is_valid())
 
1843
        {
 
1844
          std::string text;
 
1845
          
 
1846
          text.append(*index->name()).append("  (").append(index->indexType().c_str()).append(")\n");
 
1847
          
 
1848
          for (size_t c= index->columns().count(), i= 0; i < c; i++)
 
1849
          {
 
1850
            db_IndexColumnRef column(index->columns()[i]);
 
1851
            
 
1852
            text.append("  - ").append(column->referencedColumn()->name().c_str()).append("\n");
 
1853
          }
 
1854
          
 
1855
          return text;
 
1856
        }
 
1857
        else if (table.is_valid()) // table
 
1858
        {
 
1859
          std::string text;
 
1860
          
 
1861
          text.append(table->owner()->name());
 
1862
          text.append(".");
 
1863
          text.append(table->name());
 
1864
          text.append("\n");
 
1865
          
 
1866
          if (table->foreignKeys().count() > 0)
 
1867
          {
 
1868
            text.append("References:\n");
 
1869
            for (size_t c= table->foreignKeys().count(), i= 0; i < c; i++)
 
1870
            {
 
1871
              db_ForeignKeyRef fk(table->foreignKeys()[i]);
 
1872
              if (fk->referencedTable().is_valid())
 
1873
              {
 
1874
                text.append("  (");
 
1875
                for (size_t d= fk->columns().count(), j= 0; j < d; j++)
 
1876
                {
 
1877
                  if (j > 0)
 
1878
                    text.append(",");
 
1879
                  text.append(fk->columns()[j]->name());
 
1880
                }
 
1881
                text.append(") TO ");
 
1882
                if (fk->referencedTable()->owner() != table->owner())
 
1883
                {
 
1884
                  text.append(fk->referencedTable()->owner()->name());
 
1885
                  text.append(".");
 
1886
                }
 
1887
                text.append(fk->referencedTable()->name());
 
1888
                text.append("(");
 
1889
                for (size_t d= fk->referencedColumns().count(), j= 0; j < d; j++)
 
1890
                {
 
1891
                  if (j > 0)
 
1892
                    text.append(",");
 
1893
                  if (!fk->referencedColumns()[j].is_valid())
 
1894
                    text.append("INVALID");
 
1895
                  else
 
1896
                    text.append(fk->referencedColumns()[j]->name());
 
1897
                }
 
1898
                text.append(")\n");
 
1899
              }
 
1900
              else
 
1901
                text.append("  INVALID\n");
 
1902
            }
 
1903
          }
 
1904
          
 
1905
          grt::ListRef<db_ForeignKey> foreignKeys(db_SchemaRef::cast_from(table->owner())->getForeignKeysReferencingTable(table));
 
1906
          if (foreignKeys.is_valid() && foreignKeys.count() > 0)
 
1907
          {
 
1908
            text.append("Referenced By:\n");
 
1909
            for (grt::ListRef<db_ForeignKey>::const_iterator iter= foreignKeys.begin(); 
 
1910
                 iter != foreignKeys.end(); ++iter)
 
1911
            {
 
1912
              db_ForeignKeyRef fk(*iter);
 
1913
              text.append("  ");
 
1914
              if (fk->owner()->owner() != table->owner())
 
1915
              {
 
1916
                text.append(fk->owner()->owner()->name());
 
1917
                text.append(".");
 
1918
              }
 
1919
              text.append(fk->owner()->name());
 
1920
              text.append(" (");
 
1921
              for (size_t d= fk->columns().count(), j= 0; j < d; j++)
 
1922
              {
 
1923
                if (j > 0)
 
1924
                  text.append(",");
 
1925
                if (fk->columns()[j].is_valid())
 
1926
                  text.append(fk->columns()[j]->name());
 
1927
                else
 
1928
                  text.append("INVALiD");
 
1929
              }
 
1930
              text.append(") TO ");
 
1931
              
 
1932
              text.append("(");
 
1933
              for (size_t d= fk->referencedColumns().count(), j= 0; j < d; j++)
 
1934
              {
 
1935
                if (j > 0)
 
1936
                  text.append(",");
 
1937
                if (fk->referencedColumns()[j].is_valid())
 
1938
                  text.append(fk->referencedColumns()[j]->name());
 
1939
                else
 
1940
                  text.append("INVALID");
 
1941
              }
 
1942
              text.append(")\n");
 
1943
            }
 
1944
          }
 
1945
          
 
1946
          /* comments can be too large
 
1947
           if (*table->comment().c_str())
 
1948
           {
 
1949
           text.append("\n");
 
1950
           text.append(table->comment());
 
1951
           }
 
1952
           */
 
1953
          return text;
 
1954
        }
 
1955
      }
 
1956
    }
 
1957
    return "";
 
1958
  }
 
1959
  else if (workbench_physical_ViewFigureRef::can_wrap(object))
 
1960
  {
 
1961
    workbench_physical_ViewFigureRef figure(workbench_physical_ViewFigureRef::cast_from(object));
 
1962
    if (figure->view().is_valid())
 
1963
      return figure->view()->comment();
 
1964
  }
 
1965
  else if (workbench_physical_RoutineGroupFigureRef::can_wrap(object))
 
1966
  {
 
1967
    workbench_physical_RoutineGroupFigureRef figure(workbench_physical_RoutineGroupFigureRef::cast_from(object));
 
1968
    if (figure->routineGroup().is_valid())
 
1969
      return figure->routineGroup()->comment();
 
1970
  }
 
1971
  else if (workbench_physical_ConnectionRef::can_wrap(object))
 
1972
  {
 
1973
    workbench_physical_ConnectionRef connection(workbench_physical_ConnectionRef::cast_from(object));
 
1974
    std::string text;
 
1975
    db_ForeignKeyRef fk(connection->foreignKey());
 
1976
    if (fk.is_valid())
 
1977
    {
 
1978
      if (fk->owner().is_valid())
 
1979
      {
 
1980
        text.append(fk->owner()->name()).append("\n");
 
1981
        for (size_t c = fk->columns().count(), i= 0; i < c; i++)
 
1982
        {
 
1983
          if (fk->columns()[i].is_valid())
 
1984
            text.append("    ").append(fk->columns()[i]->name()).append("\n");
 
1985
          else
 
1986
            text.append("???\n");
 
1987
        }
 
1988
      }
 
1989
 
 
1990
      text.append("<references>\n");
 
1991
 
 
1992
      if (fk->referencedTable().is_valid())
 
1993
      {
 
1994
        text.append(fk->referencedTable()->name()).append("\n");
 
1995
        for (size_t c = fk->referencedColumns().count(), i= 0; i < c; i++)
 
1996
        {
 
1997
          if (fk->referencedColumns()[i].is_valid())
 
1998
            text.append("    ").append(fk->referencedColumns()[i]->name()).append("\n");
 
1999
          else
 
2000
            text.append("???\n");
 
2001
        }
 
2002
      }
 
2003
    }
 
2004
    return text;
 
2005
  }
 
2006
  
 
2007
  return "";
 
2008
}
 
2009
 
 
2010
 
 
2011
GrtObjectRef WBComponentPhysical::get_object_for_figure(const model_ObjectRef &object)
 
2012
{
 
2013
  if (workbench_physical_TableFigureRef::can_wrap(object))
 
2014
    return workbench_physical_TableFigureRef::cast_from(object)->table();
 
2015
 
 
2016
  else if (workbench_physical_ViewFigureRef::can_wrap(object))
 
2017
    return workbench_physical_ViewFigureRef::cast_from(object)->view();
 
2018
 
 
2019
  else if (workbench_physical_RoutineGroupFigureRef::can_wrap(object))
 
2020
    return workbench_physical_RoutineGroupFigureRef::cast_from(object)->routineGroup();
 
2021
 
 
2022
  return GrtObjectRef();
 
2023
}
 
2024
 
 
2025
 
 
2026
void WBComponentPhysical::activate_canvas_object(const model_ObjectRef &figure, bool newwindow)
 
2027
{
 
2028
  GrtObjectRef object(get_object_for_figure(figure));
 
2029
 
 
2030
  if (object.is_valid())
 
2031
    _wb->open_object_editor(object, newwindow ? bec::ForceNewWindowFlag : bec::NoFlags);
 
2032
 
 
2033
  else if (workbench_physical_ConnectionRef::can_wrap(figure))
 
2034
    _wb->open_object_editor(figure, newwindow ? bec::ForceNewWindowFlag : bec::NoFlags);
 
2035
}
 
2036
 
 
2037
 
 
2038
//TODO sigc _blockable_listeners seened never being filled and thus there is no sence to iterate there
 
2039
void WBComponentPhysical::block_model_notifications()
 
2040
{
 
2041
  /*
 
2042
  //for (std::list<sigc::connection>::iterator iter= _blockable_listeners.begin();
 
2043
       iter != _blockable_listeners.end(); ++iter)
 
2044
    iter->block();
 
2045
    */
 
2046
}
 
2047
 
 
2048
 
 
2049
void WBComponentPhysical::unblock_model_notifications() 
 
2050
{
 
2051
  /*
 
2052
  //for (std::list<sigc::connection>::iterator iter= _blockable_listeners.begin();
 
2053
       iter != _blockable_listeners.end(); ++iter)
 
2054
    iter->unblock();
 
2055
    */
 
2056
}
 
2057
 
 
2058
//--------------------------------------------------------------------------------
 
2059
 
 
2060
 
 
2061
app_ToolbarRef WBComponentPhysical::get_tools_toolbar()
 
2062
{
 
2063
  return app_ToolbarRef::cast_from(_wb->get_grt()->unserialize(make_path(_wb->get_datadir(),"data/tools_toolbar_physical.xml")));  
 
2064
}
 
2065
 
 
2066
 
 
2067
app_ToolbarRef WBComponentPhysical::get_tool_options(const std::string &tool)
 
2068
{
 
2069
  if (_toolbars.find("options/"+tool) != _toolbars.end())
 
2070
    return _toolbars["options/"+tool];
 
2071
  return app_ToolbarRef();
 
2072
}
 
2073
 
 
2074
 
 
2075
grt::ListRef<app_ShortcutItem> WBComponentPhysical::get_shortcut_items()
 
2076
{
 
2077
  return _shortcuts;
 
2078
}
 
2079
 
 
2080
 
 
2081
std::vector<std::string> WBComponentPhysical::get_command_dropdown_items(const std::string &option)
 
2082
{
 
2083
  std::vector<std::string> items;
 
2084
  ModelDiagramForm *form= dynamic_cast<ModelDiagramForm*>(_wb->get_active_main_form());
 
2085
 
 
2086
  if (has_prefix(option, "workbench.physical."))
 
2087
  {
 
2088
    if (has_suffix(option, ":Color"))
 
2089
    {
 
2090
      std::string colors= _wb->get_wb_options().get_string("workbench.model.ObjectFigure:ColorList");
 
2091
      std::vector<std::string> colorList;
 
2092
 
 
2093
      colorList= base::split(colors, "\n");
 
2094
 
 
2095
      if (!colorList.empty())
 
2096
      {
 
2097
        for (size_t c= colorList.size(), i= 0; i < c; i++)
 
2098
        {
 
2099
          if (!colorList[i].empty() && colorList[i][0]=='#')
 
2100
            items.push_back(colorList[i]);
 
2101
        }
 
2102
      }
 
2103
      else
 
2104
      {
 
2105
        items.push_back("#98BFDA");
 
2106
        items.push_back("#FEDE58");
 
2107
        items.push_back("#98D8A5");
 
2108
 
 
2109
        items.push_back("#FE9898");
 
2110
        items.push_back("#FE98FE");
 
2111
 
 
2112
        items.push_back("#FFFFFF");
 
2113
      }
 
2114
 
 
2115
      std::string selected= form->get_tool_argument(option);
 
2116
      if (selected.empty())
 
2117
        selected= _wb->get_wb_options().get_string(option);
 
2118
      if (selected.empty())
 
2119
        selected= items[0];
 
2120
      if (!selected.empty() && std::find(items.begin(), items.end(), selected) == items.end())
 
2121
        items.push_back(selected);
 
2122
 
 
2123
      form->set_tool_argument(option, selected);
 
2124
    }
 
2125
    else if (has_suffix(option, ":Schema"))
 
2126
    {
 
2127
      workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(form->get_model_diagram()));
 
2128
 
 
2129
      if (model.is_valid())
 
2130
      {
 
2131
        for (size_t c= model->catalog()->schemata().count(), i= 0; i < c; i++)
 
2132
          items.push_back(*model->catalog()->schemata().get(i)->name());
 
2133
        std::sort(items.begin(), items.end());
 
2134
      }
 
2135
 
 
2136
      std::string selected= form->get_tool_argument(option);
 
2137
      if (!items.empty() && (selected.empty() || std::find(items.begin(), items.end(), selected) == items.end()))
 
2138
        selected= items[0];
 
2139
 
 
2140
      form->set_tool_argument(option, selected);
 
2141
    }
 
2142
    else if (has_suffix(option, ":Engine"))
 
2143
    {
 
2144
      items.push_back("*Default Engine*");
 
2145
 
 
2146
      grt::Module *module= get_grt()->get_module("DbMySQL");
 
2147
      if (module)
 
2148
      {
 
2149
        grt::ListRef<db_mysql_StorageEngine> engines_ret(grt::ListRef<db_mysql_StorageEngine>::cast_from(module->call_function("getKnownEngines", grt::BaseListRef(get_grt()))));
 
2150
 
 
2151
        for (size_t c= engines_ret.count(), i= 0; i < c; i++)
 
2152
          items.push_back(engines_ret[i]->name());
 
2153
      }
 
2154
      
 
2155
      // Table engine might be model specific.
 
2156
      workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(form->get_model_diagram()));
 
2157
      std::string selected;
 
2158
 
 
2159
      _wb->get_ui()->get_wb_options_value(model.id(), "db.mysql.Table:tableEngine", selected);
 
2160
      if (selected.empty())
 
2161
        selected= "*Default Engine*";
 
2162
 
 
2163
      form->set_tool_argument(option, selected);
 
2164
    }
 
2165
    else if (has_suffix(option, ":Collation"))
 
2166
    {
 
2167
      workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(form->get_model_diagram()));
 
2168
 
 
2169
      if (_collation_list.empty())
 
2170
      {
 
2171
        items.push_back("*Default Collation*");
 
2172
        if (model.is_valid())
 
2173
        {
 
2174
          for (size_t c= model->catalog()->characterSets().count(), i= 0; i < c; i++)
 
2175
          {
 
2176
            db_CharacterSetRef charset(model->catalog()->characterSets().get(i));
 
2177
 
 
2178
            for (size_t d= charset->collations().count(), j= 0; j < d; j++)
 
2179
              items.push_back(*charset->collations().get(j));
 
2180
          }
 
2181
          std::sort(items.begin(), items.end());
 
2182
        }
 
2183
        _collation_list= items;
 
2184
      }
 
2185
      else
 
2186
        items= _collation_list;
 
2187
 
 
2188
      std::string selected= form->get_tool_argument(option);
 
2189
      if (selected.empty())
 
2190
        selected= _wb->get_wb_options().get_string(option);
 
2191
      if (selected.empty())
 
2192
        selected= "*Default Collation*";
 
2193
 
 
2194
      form->set_tool_argument(option, selected);
 
2195
    }
 
2196
  }
 
2197
  else
 
2198
    throw std::logic_error("Unknown option "+option);
 
2199
 
 
2200
  return items;
 
2201
}
 
2202
 
 
2203
 
 
2204
 
 
2205
//--------------------------------------------------------------------------------
 
2206
// Object Listeners
 
2207
 
 
2208
 
 
2209
void WBComponentPhysical::add_schema_listeners(const db_SchemaRef &schema)
 
2210
{
 
2211
  // listener for changes in schema itself
 
2212
  _object_listeners[schema.id()]=
 
2213
      schema->signal_changed()->connect(boost::bind(&WBComponentPhysical::schema_member_changed, this, _1, _2, schema));
 
2214
 
 
2215
  _schema_content_listeners[schema.id()]= schema->signal_refreshDisplay()->connect
 
2216
      (boost::bind(&WBComponentPhysical::schema_content_object_changed, this, _1));
 
2217
  
 
2218
  // for changes in table, view, SP/function, routine (and other) lists 
 
2219
  _schema_list_listeners[schema.id()]= schema->signal_list_changed()->connect(
 
2220
      boost::bind(&WBComponentPhysical::schema_object_list_changed, this, _1, _2, _3, schema));
 
2221
}
 
2222
 
 
2223
//--------------------------------------------------------------------------------------------------
 
2224
 
 
2225
/**
 
2226
 * Removes all previously set listeners.
 
2227
 */
 
2228
void WBComponentPhysical::close_document()
 
2229
{
 
2230
  // Model listeners.
 
2231
  _catalog_object_list_listener.disconnect();
 
2232
  _model_list_listener.disconnect();
 
2233
 
 
2234
  // Object listeners.
 
2235
  for (std::map<std::string, boost::signals2::connection>::iterator iter= _object_listeners.begin();
 
2236
       iter != _object_listeners.end(); ++iter)
 
2237
    iter->second.disconnect();
 
2238
  _object_listeners.clear();
 
2239
 
 
2240
  // Schema listeners.
 
2241
  for (std::map<std::string, boost::signals2::connection>::iterator iter= _schema_list_listeners.begin();
 
2242
       iter != _schema_list_listeners.end(); ++iter)
 
2243
    iter->second.disconnect();
 
2244
  _schema_list_listeners.clear();
 
2245
 
 
2246
  // Figure list listeners.
 
2247
  for (std::map<std::string, boost::signals2::connection>::iterator iter= _figure_list_listeners.begin();
 
2248
    iter != _figure_list_listeners.end(); ++iter)
 
2249
    iter->second.disconnect();
 
2250
  _figure_list_listeners.clear();
 
2251
 
 
2252
}
 
2253
 
 
2254
//--------------------------------------------------------------------------------------------------
 
2255
 
 
2256
/** 
 
2257
 * Refreshes internal state for a document change.
 
2258
 * This will add listeners for a newly created or opened document.
 
2259
 * 
 
2260
 */ 
 
2261
void WBComponentPhysical::reset_document()
 
2262
{
 
2263
  workbench_DocumentRef doc(_wb->get_document());
 
2264
 
 
2265
  // add listener to all schemas, views etc
 
2266
  for (size_t c= doc->physicalModels().count(), i= 0; i < c; i++)
 
2267
  {
 
2268
    workbench_physical_ModelRef model(doc->physicalModels()[i]);
 
2269
    if (model.is_valid())
 
2270
    {
 
2271
      db_CatalogRef catalog(model->catalog());
 
2272
 
 
2273
      if (catalog.is_valid())
 
2274
        _catalog_object_list_listener= 
 
2275
        catalog->signal_list_changed()->connect(boost::bind(&WBComponentPhysical::catalog_object_list_changed, this, _1, _2, _3, catalog));
 
2276
 
 
2277
      for (size_t sc= catalog->schemata().count(), si= 0; si < sc; si++)
 
2278
      {
 
2279
        db_SchemaRef schema(catalog->schemata().get(si));
 
2280
 
 
2281
        add_schema_listeners(schema);
 
2282
 
 
2283
        // currently there are only listeners for tables
 
2284
        grt::ListRef<db_Table> tables(schema->tables());
 
2285
        for (size_t tc= tables.count(), ti= 0; ti < tc; ti++)
 
2286
        {
 
2287
          add_schema_object_listeners(tables[ti]);
 
2288
        }
 
2289
      }
 
2290
 
 
2291
      for (size_t vi= 0, vc= model->diagrams().count(); vi < vc; vi++)
 
2292
      {
 
2293
        model_DiagramRef view(model->diagrams().get(i));
 
2294
        _figure_list_listeners[view.id()]=
 
2295
          view->signal_list_changed()->connect(
 
2296
              boost::bind(&WBComponentPhysical::view_object_list_changed, this, _1, _2, _3, view));
 
2297
      }
 
2298
 
 
2299
      _model_list_listener= model->signal_list_changed()->
 
2300
        connect(boost::bind(&WBComponentPhysical::model_object_list_changed, this, _1, _2, _3));
 
2301
    }
 
2302
  }
 
2303
 
 
2304
 
 
2305
  // make sure frontend is refreshed
 
2306
  _wb->request_refresh(RefreshSchemaList, "");
 
2307
 
 
2308
  ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_scripts();
 
2309
  ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_notes();
 
2310
}
 
2311
 
 
2312
 
 
2313
/** Called when a document is loaded
 
2314
 
 
2315
 - Update the userDatatypes list in the document with what we have now
 
2316
 */
 
2317
void WBComponentPhysical::document_loaded()
 
2318
{
 
2319
  grt::ListRef<workbench_physical_Model> models(_wb->get_document()->physicalModels());
 
2320
  
 
2321
  for (grt::ListRef<workbench_physical_Model>::const_iterator pmodel= models.begin();
 
2322
       pmodel != models.end(); ++pmodel)
 
2323
  {
 
2324
    grt::ListRef<db_UserDatatype> userTypes(create_builtin_user_datatypes((*pmodel)->catalog(), (*pmodel)->rdbms()));
 
2325
    
 
2326
    // merge in built-in UDTs with the one from the model, replacing stuff from the model with ours
 
2327
    grt::merge_contents_by_id((*pmodel)->catalog()->userDatatypes(), userTypes, true);
 
2328
  }
 
2329
}
 
2330
 
 
2331
 
 
2332
/** Listener for changes in the list of schemas
 
2333
 *
 
2334
 * Used for attaching listeners to new schemas and content lists.
 
2335
 */
 
2336
void WBComponentPhysical::catalog_object_list_changed(grt::internal::OwnedList *list, bool added, const grt::ValueRef &value,
 
2337
                                                      const db_CatalogRef &catalog)
 
2338
{
 
2339
  if (grt::BaseListRef(list) == catalog->schemata())
 
2340
  {
 
2341
    // we're called in the GRT thread, so just mark the refresh request
 
2342
    // as pending. This has the bonus that multiple requests will be
 
2343
    // collapsed into 1.
 
2344
    // The requests are actually sent in flush_idle_tasks()
 
2345
 
 
2346
    _wb->request_refresh(RefreshSchemaList, "", 0);
 
2347
 
 
2348
    ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_schema_list();
 
2349
    
 
2350
    if (added)
 
2351
    {
 
2352
      // added new schema
 
2353
      add_schema_listeners(db_SchemaRef::cast_from(value));
 
2354
    }
 
2355
    else
 
2356
    {
 
2357
      db_SchemaRef schema(db_SchemaRef::cast_from(value));
 
2358
      
 
2359
      _wb->request_refresh(RefreshCloseEditor, schema.id());
 
2360
      
 
2361
      // remove listeners for the schema
 
2362
      _object_listeners[schema.id()].disconnect();
 
2363
      _schema_list_listeners[schema.id()].disconnect();
 
2364
      
 
2365
      _object_listeners.erase(schema.id());
 
2366
      _schema_list_listeners.erase(schema.id());
 
2367
    }
 
2368
  }
 
2369
  else
 
2370
    privilege_list_changed(list, added, value, catalog);
 
2371
}
 
2372
 
 
2373
 
 
2374
 
 
2375
void WBComponentPhysical::schema_member_changed(const std::string &member, const grt::ValueRef &ovalue,
 
2376
                                                const db_SchemaRef &schema)
 
2377
{
 
2378
  _wb->request_refresh(RefreshSchema, "", 0);
 
2379
 
 
2380
  if (_wb->get_ui()->get_physical_overview())
 
2381
    ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_for_schema(schema, true);
 
2382
}
 
2383
 
 
2384
 
 
2385
void WBComponentPhysical::add_schema_object_listeners(const grt::ObjectRef &object)
 
2386
{
 
2387
  if (object.is_instance(db_Table::static_class_name()))
 
2388
  {
 
2389
    if (_object_listeners.find(object.id()) != _object_listeners.end())
 
2390
      _object_listeners[object.id()].disconnect();
 
2391
    _object_listeners[object.id()]= db_TableRef::cast_from(object)->signal_foreignKeyChanged()->connect(
 
2392
        boost::bind(&WBComponentPhysical::foreign_key_changed, this, _1));
 
2393
  }
 
2394
}
 
2395
 
 
2396
 
 
2397
void WBComponentPhysical::schema_object_list_changed(grt::internal::OwnedList *list, bool added, const grt::ValueRef &value, const db_SchemaRef &schema)
 
2398
{
 
2399
  grt::ObjectRef object(grt::ObjectRef::cast_from(value));
 
2400
 
 
2401
  if (added)
 
2402
  {
 
2403
    add_schema_object_listeners(object);
 
2404
  }
 
2405
  else
 
2406
  {
 
2407
    // remove old listeners
 
2408
    if (object.is_instance(db_Table::static_class_name()))
 
2409
    {
 
2410
      _object_listeners[object.id()].disconnect();
 
2411
      _object_listeners.erase(object.id());
 
2412
    }
 
2413
    _wb->request_refresh(RefreshCloseEditor, object.id());
 
2414
  }
 
2415
 
 
2416
  if (_wb->get_ui()->get_physical_overview())
 
2417
    ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_for_schema_object(GrtObjectRef::cast_from(value), false);
 
2418
 
 
2419
  _wb->request_refresh(RefreshSchema, "", 0);
 
2420
}
 
2421
 
 
2422
 
 
2423
void WBComponentPhysical::view_object_list_changed(grt::internal::OwnedList *list, bool added, const grt::ValueRef &value, const model_DiagramRef &view)
 
2424
{
 
2425
  if (list == view->figures().valueptr())
 
2426
  {
 
2427
    if (handles_figure(model_ObjectRef::cast_from(value)))
 
2428
    {
 
2429
      if (added)
 
2430
      {
 
2431
#if 0
 
2432
        // if not undoing/redoing, then auto-create the connection for the table
 
2433
        if (!get_grt()->get_undo_manager()->is_undoing() && !get_grt()->get_undo_manager()->is_redoing())
 
2434
        {
 
2435
          if (value.is_instance(workbench_physical_TableFigure::static_class_name()))
 
2436
          {
 
2437
            workbench_physical_TableFigureRef table(workbench_physical_TableFigureRef::cast_from(value));
 
2438
            
 
2439
            if (table.table().is_valid())
 
2440
            {
 
2441
              std::vector<db_TableRef> tbls;
 
2442
              tbls.push_back(table.table());
 
2443
              
 
2444
              update_connections_for_new_tables(view, tbls);
 
2445
            }
 
2446
            else
 
2447
              get_grt()->send_warning("Table figure added to view has no table db object bound to it.");
 
2448
          }
 
2449
        }
 
2450
#endif
 
2451
      }
 
2452
      else
 
2453
      {
 
2454
      }
 
2455
      
 
2456
      // ask for a refresh to update the "present in this view" status in Catalog tree
 
2457
      if (_catalog_tree != NULL)
 
2458
        _catalog_tree->refresh_for_diagram(workbench_physical_DiagramRef::cast_from(view));
 
2459
    }
 
2460
    else
 
2461
    {
 
2462
      // make sure editor for notes and images are closed
 
2463
      // this should be in wb_component_basic.cpp, but since there's no need for anything
 
2464
      // else over there, just put here
 
2465
      if (!added)
 
2466
        _wb->request_refresh(RefreshCloseEditor, grt::ObjectRef::cast_from(value).id());
 
2467
    }
 
2468
  }
 
2469
  else if (list == view->layers().valueptr() ||
 
2470
           list == view->connections().valueptr())
 
2471
  {
 
2472
    if (!added)
 
2473
      _wb->request_refresh(RefreshCloseEditor, grt::ObjectRef::cast_from(value).id());
 
2474
  }
 
2475
}
 
2476
 
 
2477
 
 
2478
static void convert_utf16_to_utf8_if_needed(char *&data, size_t &size)
 
2479
{
 
2480
  gchar *output;
 
2481
  glong iread, iwritten;
 
2482
 
 
2483
  // check if utf16
 
2484
  if (size >= 2 && (guchar)data[0] == 0xff && (guchar)data[1] == 0xfe)
 
2485
  {
 
2486
    output= g_utf16_to_utf8((const gunichar2*)data, (glong) size, &iread, &iwritten, NULL);
 
2487
    if (output)
 
2488
    {
 
2489
      g_free(data);
 
2490
      data= output;
 
2491
      size= iwritten;
 
2492
    }
 
2493
  }
 
2494
}
 
2495
 
 
2496
 
 
2497
 
 
2498
void WBComponentPhysical::model_object_list_changed(grt::internal::OwnedList *list, bool added, const grt::ValueRef &avalue)
 
2499
{
 
2500
  if (avalue.type() == grt::ObjectType)
 
2501
  {
 
2502
    if (added)
 
2503
    {
 
2504
      grt::ObjectRef value(grt::ObjectRef::cast_from(avalue));
 
2505
      std::string group, tmpl;
 
2506
      
 
2507
      if (value.is_instance(db_Script::static_class_name()))
 
2508
      {
 
2509
        group= "@sqlscripts";
 
2510
        tmpl= "script$.sql";
 
2511
      }
 
2512
      else if (value.is_instance(GrtStoredNote::static_class_name()))
 
2513
      {
 
2514
        group= "@notes";
 
2515
        tmpl= "note$.txt";
 
2516
      }
 
2517
      else if (value.is_instance(model_Diagram::static_class_name()))
 
2518
      {
 
2519
        model_DiagramRef view(model_DiagramRef::cast_from(value));
 
2520
        
 
2521
        _figure_list_listeners[view.id()]=
 
2522
        view->signal_list_changed()->connect(
 
2523
                  boost::bind(&WBComponentPhysical::view_object_list_changed, this, _1, _2, _3, view));
 
2524
        
 
2525
        _wb->get_ui()->get_physical_overview()->send_refresh_diagram(model_DiagramRef());
 
2526
        return;
 
2527
      }
 
2528
      else
 
2529
        return;
 
2530
      
 
2531
      // check if the filename is in the temp dir, if so, just readd it with old contents
 
2532
      GrtStoredNoteRef object(GrtStoredNoteRef::cast_from(value));
 
2533
      
 
2534
      
 
2535
#if 0
 
2536
      if (object->filename() != "")
 
2537
      {
 
2538
        if (object->filename().c_str()[0] == '@')
 
2539
        {
 
2540
          gchar *data;
 
2541
          gsize length;
 
2542
          std::string path= make_path(_wb->get_grt_manager()->get_tmp_dir(), object->filename());
 
2543
          
 
2544
          if (g_file_get_contents(path.c_str(), &data, &length, NULL))
 
2545
          {
 
2546
            // we're undoing, load the file and add it back to the model file
 
2547
            object->filename(_wb->recreate_attached_file(object->filename(), data));
 
2548
            g_free(data);
 
2549
          }
 
2550
          else
 
2551
            get_grt()->send_error(strfmt(_("Error undoing file delete: can't read contents of temporary file '%s'"), path.c_str()));
 
2552
        }
 
2553
        else
 
2554
        {
 
2555
          // load file from scratch
 
2556
          gchar *data;
 
2557
          gsize length;
 
2558
          GError *error= NULL;
 
2559
          
 
2560
          if (g_file_get_contents(object->filename().c_str(), &data, &length, &error))
 
2561
          {
 
2562
            convert_utf16_to_utf8_if_needed(data, length);
 
2563
            
 
2564
            object->filename(_wb->create_attached_file(group, object->filename()));
 
2565
            _wb->save_attached_file_contents(object->filename(), data, length);
 
2566
            g_free(data);
 
2567
          }
 
2568
          else
 
2569
          {
 
2570
            get_grt()->send_error(strfmt(_("Error adding file: can't read contents of file '%s': %s"), 
 
2571
                                      object->filename().c_str(), error->message));
 
2572
            g_error_free(error);
 
2573
          }
 
2574
        }
 
2575
      }
 
2576
      else
 
2577
        object->filename(_wb->create_attached_file(group, tmpl));
 
2578
#endif
 
2579
      // request refresh of overview
 
2580
      if (value.is_instance(db_Script::static_class_name()))
 
2581
        ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_scripts();
 
2582
      else if (value.is_instance(GrtStoredNote::static_class_name()))
 
2583
        ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_notes();
 
2584
    }
 
2585
    else // !added
 
2586
    {
 
2587
      grt::ObjectRef value(grt::ObjectRef::cast_from(avalue));
 
2588
      
 
2589
      _wb->request_refresh(RefreshCloseEditor, value.id());
 
2590
      
 
2591
      if (value.is_instance(GrtStoredNote::static_class_name()))
 
2592
      {
 
2593
        GrtStoredNoteRef object(GrtStoredNoteRef::cast_from(value));
 
2594
#if 0
 
2595
        if (object->filename() != "")
 
2596
        {
 
2597
          std::string path= make_path(_wb->get_grt_manager()->get_tmp_dir(), object->filename());
 
2598
          gchar *tmp= g_dirname(path.c_str());
 
2599
          g_mkdir_with_parents(tmp, 0700);
 
2600
          g_free(tmp);
 
2601
          
 
2602
          // save the file in the temp dir in case an undo delete is requested
 
2603
          std::string data= _wb->get_attached_file_contents(object->filename());
 
2604
          
 
2605
          if (!g_file_set_contents(path.c_str(), data.data(), (gssize) data.length(), NULL))
 
2606
          {
 
2607
            get_grt()->send_error(strfmt(_("Could not save temporary file '%s'"), path.c_str()));
 
2608
          }
 
2609
          
 
2610
          _wb->delete_attached_file(object->filename());
 
2611
        }
 
2612
#endif
 
2613
        // request refresh of overview
 
2614
        if (value.is_instance(db_Script::static_class_name()))
 
2615
          ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_scripts();
 
2616
        else
 
2617
          ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_notes();
 
2618
      }
 
2619
      else if (value.is_instance(model_Diagram::static_class_name()))
 
2620
      {
 
2621
        std::string id= grt::ObjectRef::cast_from(value).id();
 
2622
        
 
2623
        _figure_list_listeners[id].disconnect();
 
2624
        _figure_list_listeners.erase(id);
 
2625
        
 
2626
        _wb->get_ui()->get_physical_overview()->send_refresh_diagram(model_DiagramRef());
 
2627
      }
 
2628
    }
 
2629
  }
 
2630
}
 
2631
 
 
2632
 
 
2633
void WBComponentPhysical::foreign_key_changed(const db_ForeignKeyRef &fk)
 
2634
{
 
2635
  // don't auto-create/remove stuff when undoing/redoing
 
2636
  if (get_grt()->get_undo_manager()->is_undoing() || get_grt()->get_undo_manager()->is_redoing())
 
2637
    return;
 
2638
  
 
2639
  bool valid= fk->checkCompleteness() != 0;
 
2640
  grt::ListRef<workbench_physical_Diagram> views(_wb->get_document()->physicalModels()[0]->diagrams());
 
2641
  
 
2642
  // go through all views and create/destroy connections if needed
 
2643
  for (grt::ListRef<workbench_physical_Diagram>::const_iterator iter= views.begin();
 
2644
       iter != views.end(); ++iter)
 
2645
  {
 
2646
    workbench_physical_DiagramRef view(*iter);
 
2647
    workbench_physical_ConnectionRef conn(view->getConnectionForForeignKey(fk));
 
2648
 
 
2649
    if (conn.is_valid() != valid)
 
2650
    {
 
2651
      if (!conn.is_valid())
 
2652
        view->createConnectionForForeignKey(fk);
 
2653
      else
 
2654
        view->removeConnection(conn);
 
2655
    }
 
2656
  }
 
2657
}
 
2658
 
 
2659
 
 
2660
void WBComponentPhysical::schema_content_object_changed(const db_DatabaseObjectRef &object)
 
2661
{
 
2662
  refresh_ui_for_object(object);
 
2663
}
 
2664
 
 
2665
 
 
2666
void WBComponentPhysical::refresh_ui_for_object(const GrtObjectRef &object)
 
2667
{
 
2668
  if (object.is_valid() && object->owner().is_valid())
 
2669
  {
 
2670
    workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(object));
 
2671
    PhysicalOverviewBE *overview= (PhysicalOverviewBE*)((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview());
 
2672
 
 
2673
    if (overview->get_model() != model)
 
2674
      throw std::logic_error("code is outdated");
 
2675
 
 
2676
    overview->send_refresh_for_schema_object(object, true);
 
2677
 
 
2678
    _wb->request_refresh(RefreshSchema, "" /*object.owner().id() not supported yet in fe*/, 0);
 
2679
  }
 
2680
}
 
2681
 
 
2682
 
 
2683
/** 
 
2684
 ****************************************************************************
 
2685
 * @brief Add/remove connections for added/removed table foreign keys
 
2686
 *
 
2687
 * Updates the connections from a table figure corresponding to the given
 
2688
 * foreign key. This can be called when the list of FKs for a table is 
 
2689
 * changed or when a pre-existing table with a fk is added to a view.
 
2690
 * It will also update existing connections in case the referenced table
 
2691
 * of a fk changes.
 
2692
 * 
 
2693
 * @param object the db object
 
2694
 * @param figure the model figure that was assigned to the object
 
2695
 * @param attach whether the figure was attached or detached to the object 
 
2696
 *
 
2697
 * @return true if a change has happened (conn added/remove), false otherwise
 
2698
 ****************************************************************************
 
2699
 */
 
2700
bool WBComponentPhysical::update_table_fk_connection(const db_TableRef &table, const db_ForeignKeyRef &fk, bool added)
 
2701
{
 
2702
  workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(table));
 
2703
 
 
2704
  if (!model.is_valid() || !model->diagrams().is_valid())
 
2705
    return false;
 
2706
 
 
2707
  if (!fk.is_valid())
 
2708
  {
 
2709
    if (!added)
 
2710
    {
 
2711
      // all FKs from table removed
 
2712
    }
 
2713
  }
 
2714
  else
 
2715
  {
 
2716
    if (!fk->referencedTable().is_valid() || fk->owner() != table)
 
2717
      return false;
 
2718
 
 
2719
    // kind of a hack, this is needed because copy_object() will generate
 
2720
    // spurious notifications. eg: in a sync of a model with a relationship,
 
2721
    // the rel will be recreated (because of the copy)
 
2722
    if (added && table->foreignKeys().get_index(fk) == BaseListRef::npos)
 
2723
      return false;
 
2724
    
 
2725
    grt::ListRef<workbench_physical_Diagram> views(model->diagrams());
 
2726
    grt::GRT *grt= get_grt();
 
2727
 
 
2728
    if (added)
 
2729
    {
 
2730
      // we have to go through all views in the model and find all table figures
 
2731
      // that correspond to the FK for creating the relationship in all these views
 
2732
 
 
2733
      for (size_t c= views.count(), i= 0; i < c; i++)
 
2734
      {
 
2735
        workbench_physical_DiagramRef view(views[i]);
 
2736
 
 
2737
        workbench_physical_TableFigureRef table1(workbench_physical_TableFigureRef::cast_from(view->getFigureForDBObject(table)));
 
2738
        workbench_physical_TableFigureRef table2(workbench_physical_TableFigureRef::cast_from(view->getFigureForDBObject(fk->referencedTable())));
 
2739
 
 
2740
        if (table1.is_valid() && table2.is_valid())
 
2741
        { // both tables in the relationship are in this view, so create the connection
 
2742
           
 
2743
          // but 1st check if it already exists
 
2744
 
 
2745
          grt::ListRef<model_Connection> connections(view->connections());
 
2746
          workbench_physical_ConnectionRef found;
 
2747
 
 
2748
          for (size_t c= connections.count(), i= 0; i < c; i++)
 
2749
          {
 
2750
            model_ConnectionRef conn(connections[i]);
 
2751
            if (conn.is_instance(workbench_physical_Connection::static_class_name()))
 
2752
            {
 
2753
              workbench_physical_ConnectionRef pconn(workbench_physical_ConnectionRef::cast_from(conn));
 
2754
 
 
2755
              if (pconn->foreignKey() == fk)
 
2756
              {
 
2757
                found= pconn;
 
2758
                break;
 
2759
              }
 
2760
            }
 
2761
          }
 
2762
 
 
2763
          // connection doesnt exist yet, create it
 
2764
          if (!found.is_valid())
 
2765
          {
 
2766
            workbench_physical_ConnectionRef conn(grt);
 
2767
            
 
2768
            conn->owner(view);
 
2769
            conn->startFigure(table1);
 
2770
            conn->endFigure(table2);
 
2771
            conn->caption(fk->name());
 
2772
            conn->foreignKey(fk);
 
2773
 
 
2774
            conn->name(grt::get_name_suggestion_for_list_object(view->connections(),
 
2775
                      "connection"));
 
2776
 
 
2777
            grt::AutoUndo undo(get_grt());
 
2778
            view->connections().insert(conn);
 
2779
            undo.end(_("Create Relationship"));
 
2780
 
 
2781
            return true;
 
2782
          }
 
2783
          else
 
2784
          {
 
2785
            // connection exists, check if its correct
 
2786
            if (workbench_physical_TableFigureRef::cast_from(found->endFigure())->table() !=
 
2787
              found->foreignKey()->referencedTable())
 
2788
            {
 
2789
              if (!found->foreignKey()->referencedTable().is_valid())
 
2790
              {
 
2791
                // referencedTable was unset, so we need to remove the connection
 
2792
                
 
2793
              }
 
2794
              else
 
2795
              {
 
2796
                // update the connection with the new end figure
 
2797
                grt::AutoUndo undo(get_grt());
 
2798
                found->endFigure(view->getFigureForDBObject(fk->referencedTable()));
 
2799
                undo.end(_("Update Relationship"));
 
2800
              }
 
2801
              return true;
 
2802
            }
 
2803
          }
 
2804
        }
 
2805
      }
 
2806
    }
 
2807
    else
 
2808
    {
 
2809
      // remove all connections that correspond to the FK in all views
 
2810
 
 
2811
      for (grt::ListRef<workbench_physical_Diagram>::const_iterator view= views.begin(); 
 
2812
           view != views.end(); ++view)
 
2813
      {
 
2814
        workbench_physical_TableFigureRef table1(workbench_physical_TableFigureRef::cast_from((*view)->getFigureForDBObject(table)));
 
2815
        grt::ListRef<model_Connection>::const_reverse_iterator end= (*view)->connections().rend();
 
2816
        
 
2817
        for (grt::ListRef<model_Connection>::const_reverse_iterator conn= (*view)->connections().rbegin(); 
 
2818
             conn != end; ++conn)
 
2819
        {
 
2820
          if ((*conn).is_instance(workbench_physical_Connection::static_class_name()))
 
2821
          {
 
2822
            workbench_physical_ConnectionRef pconn(workbench_physical_ConnectionRef::cast_from(*conn));
 
2823
 
 
2824
            if (pconn->foreignKey() == fk)
 
2825
            {
 
2826
              grt::AutoUndo undo(get_grt());
 
2827
              (*view)->connections().remove_value(*conn);
 
2828
              undo.end(_("Remove Relationship"));
 
2829
 
 
2830
              return true;
 
2831
            }
 
2832
          }
 
2833
        }
 
2834
      }
 
2835
    }
 
2836
  }
 
2837
  return false;
 
2838
}
 
2839
 
 
2840
 
 
2841
void WBComponentPhysical::activate_catalog_tree_item(const grt::ValueRef &value)
 
2842
{
 
2843
  if (value.is_valid() && db_DatabaseObjectRef::can_wrap(value))
 
2844
  {
 
2845
    db_DatabaseObjectRef object(db_DatabaseObjectRef::cast_from(value));
 
2846
 
 
2847
    _wb->open_object_editor(object);
 
2848
  }
 
2849
}
 
2850
 
 
2851
 
 
2852
bool WBComponentPhysical::has_figure_for_object_in_active_view(const GrtObjectRef &object, ModelDiagramForm *vform)
 
2853
{
 
2854
  if (!vform)
 
2855
    vform= dynamic_cast<ModelDiagramForm*>(_wb->get_active_main_form());
 
2856
 
 
2857
  if (vform)
 
2858
  {
 
2859
    workbench_physical_DiagramRef view(workbench_physical_DiagramRef::cast_from(vform->get_model_diagram()));
 
2860
 
 
2861
    if (view->getFigureForDBObject(db_DatabaseObjectRef::cast_from(object)).is_valid())
 
2862
      return true;
 
2863
  }
 
2864
  return false;
 
2865
}
 
2866
 
 
2867
 
 
2868
void WBComponentPhysical::update_catalog_tree()
 
2869
{  
 
2870
  if (!_catalog_tree) return;
 
2871
 
 
2872
  UIForm *form= _wb->get_active_main_form();
 
2873
  model_ModelRef model;
 
2874
  workbench_physical_DiagramRef view;
 
2875
 
 
2876
  if (form)
 
2877
  {
 
2878
    ModelDiagramForm *vform= dynamic_cast<ModelDiagramForm*>(form);
 
2879
    if (vform)
 
2880
    {
 
2881
      view= workbench_physical_DiagramRef::cast_from(vform->get_model_diagram());
 
2882
      model= view->owner();
 
2883
    }
 
2884
    else
 
2885
    {
 
2886
      OverviewBE *over= dynamic_cast<OverviewBE*>(form);
 
2887
      if (over)
 
2888
        model= over->get_model();
 
2889
      else
 
2890
        return;
 
2891
    }
 
2892
  }
 
2893
 
 
2894
  _catalog_tree->refresh_for_diagram(view);
 
2895
 
 
2896
  if (model.is_valid())
 
2897
    _catalog_tree->set_displayed_value(workbench_physical_ModelRef::cast_from(model)->catalog()->schemata(), "");
 
2898
  else
 
2899
    _catalog_tree->set_displayed_global_value("", true);
 
2900
  
 
2901
  _wb->request_refresh(RefreshSchemaList, "", 0);
 
2902
}
 
2903
 
 
2904
 
 
2905
 
 
2906
bec::ValueTreeBE *WBComponentPhysical::get_catalog_tree()
 
2907
{
 
2908
  if (!_catalog_tree)
 
2909
  {
 
2910
    _catalog_tree= new CatalogTreeBE(get_grt(), this);
 
2911
    _catalog_tree->set_activate_callback(boost::bind(&WBComponentPhysical::activate_catalog_tree_item, this, _1));
 
2912
 
 
2913
    update_catalog_tree();
 
2914
  }
 
2915
 
 
2916
  return _catalog_tree;
 
2917
}
 
2918
 
 
2919
 
 
2920
void WBComponentPhysical::handle_notification(const std::string &name, void *sender, base::NotificationInfo &info)
 
2921
{
 
2922
  if (name == "GNMainFormChanged")
 
2923
  {
 
2924
    update_catalog_tree();
 
2925
  }
 
2926
}
 
2927
 
 
2928
 
 
2929
void WBComponentPhysical::setup_canvas_tool(ModelDiagramForm *view, const std::string &tool)
 
2930
{
 
2931
  void *data= 0;
 
2932
  bool relationship= false;
 
2933
 
 
2934
  if (tool == WB_TOOL_PTABLE)
 
2935
  {
 
2936
    view->set_cursor("table");
 
2937
    _wb->show_status_text(_("Select location for new table."));
 
2938
  }
 
2939
  else if (tool == WB_TOOL_PVIEW)
 
2940
  {
 
2941
    view->set_cursor("view");
 
2942
    _wb->show_status_text(_("Select location for new view."));
 
2943
  }
 
2944
  else if (tool == WB_TOOL_PROUTINEGROUP)
 
2945
  {
 
2946
    view->set_cursor("routine");
 
2947
    _wb->show_status_text(_("Select location for new routine group."));
 
2948
  }
 
2949
  else if (tool == WB_TOOL_PREL11)
 
2950
  {
 
2951
    view->set_cursor("rel11");
 
2952
    data= start_relationship(view, Point(), Relationship11Id);
 
2953
    relationship= true;
 
2954
  }
 
2955
  else if (tool == WB_TOOL_PREL1n)
 
2956
  {
 
2957
    view->set_cursor("rel1n");
 
2958
    data= start_relationship(view, Point(), Relationship1nId);
 
2959
    relationship= true;
 
2960
  }
 
2961
  else if (tool == WB_TOOL_PRELnm)
 
2962
  {
 
2963
    view->set_cursor("relnm");
 
2964
    data= start_relationship(view, Point(), RelationshipnmId);
 
2965
    relationship= true;
 
2966
  }
 
2967
  else if (tool == WB_TOOL_PREL11_NOID)
 
2968
  {
 
2969
    view->set_cursor("rel11");
 
2970
    data= start_relationship(view, Point(), Relationship11NonId);
 
2971
    relationship= true;
 
2972
  }
 
2973
  else if (tool == WB_TOOL_PREL1n_NOID)
 
2974
  {
 
2975
    view->set_cursor("rel1n");
 
2976
    data= start_relationship(view, Point(), Relationship1nNonId);
 
2977
    relationship= true;
 
2978
  }
 
2979
  else if (tool == WB_TOOL_PREL_PICK)
 
2980
  {
 
2981
    view->set_cursor("rel1n");
 
2982
    data= start_relationship(view, Point(), RelationshipPick);
 
2983
    relationship= true;
 
2984
  }
 
2985
  else
 
2986
  {
 
2987
    _wb->show_status_text("Invalid tool "+tool);
 
2988
    return;
 
2989
  }
 
2990
  view->set_button_callback(boost::bind(&WBComponentPhysical::handle_button_event, this, _1, _2, _3, _4, _5, data));
 
2991
  if (relationship)
 
2992
    view->set_reset_tool_callback(
 
2993
      boost::bind(&WBComponentPhysical::cancel_relationship, this, _1,
 
2994
        reinterpret_cast<RelationshipToolContext*>(data)));
 
2995
}
 
2996
 
 
2997
 
 
2998
 
 
2999
bool WBComponentPhysical::handle_button_event(ModelDiagramForm *view, mdc::MouseButton button, bool press, 
 
3000
                                      Point pos, mdc::EventState, void *data)
 
3001
{
 
3002
  std::string tool= view->get_tool();
 
3003
 
 
3004
  if (button != mdc::ButtonLeft)
 
3005
    return false;
 
3006
 
 
3007
  mdc::CanvasItem *item;
 
3008
  item= view->get_view()->get_item_at(pos);
 
3009
  if (item && item->get_layer() != view->get_view()->get_current_layer())
 
3010
    return false;
 
3011
 
 
3012
  if (tool == WB_TOOL_PTABLE)
 
3013
  {
 
3014
    if (press)
 
3015
    {
 
3016
      place_new_db_object(view, pos, ObjectTable);
 
3017
      view->reset_tool(true);
 
3018
      return true;
 
3019
    }
 
3020
  }
 
3021
  else if (tool == WB_TOOL_PROUTINEGROUP)
 
3022
  {
 
3023
    if (press)
 
3024
    {
 
3025
      place_new_db_object(view, pos, ObjectRoutineGroup);
 
3026
      view->reset_tool(true);
 
3027
      return true;
 
3028
    }
 
3029
  }
 
3030
  else if (tool == WB_TOOL_PVIEW)
 
3031
  {
 
3032
    if (press)
 
3033
    {
 
3034
      place_new_db_object(view, pos, ObjectView);
 
3035
      view->reset_tool(true);
 
3036
      return true;
 
3037
    }
 
3038
  }
 
3039
  else if (tool == WB_TOOL_PREL11 || tool == WB_TOOL_PREL1n || tool == WB_TOOL_PRELnm ||
 
3040
    tool == WB_TOOL_PREL11_NOID || tool == WB_TOOL_PREL1n_NOID || tool == WB_TOOL_PREL_PICK)
 
3041
  {
 
3042
    if (press)
 
3043
    {
 
3044
      RelationshipToolContext *rctx= reinterpret_cast<RelationshipToolContext*>(data);
 
3045
 
 
3046
      if (rctx->button_press(view, pos))
 
3047
        view->reset_tool(true);
 
3048
      return true;
 
3049
    }
 
3050
  }
 
3051
 
 
3052
  return false;
 
3053
}
 
3054
 
 
3055
 
 
3056
//===================================================================================================
 
3057
// Privilege Stuff
 
3058
//===================================================================================================
 
3059
 
 
3060
static void refresh_privileges(PhysicalOverviewBE *overview)
 
3061
{
 
3062
  overview->send_refresh_users();
 
3063
  overview->send_refresh_roles();
 
3064
}
 
3065
 
 
3066
void WBComponentPhysical::privilege_list_changed(grt::internal::OwnedList *list, bool added, const grt::ValueRef &value,
 
3067
                                                 const db_CatalogRef &catalog)
 
3068
{
 
3069
  if (grt::BaseListRef(list) == catalog->users())
 
3070
    ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_users();
 
3071
  else if (grt::BaseListRef(list) == catalog->roles())
 
3072
    ((PhysicalOverviewBE*)_wb->get_ui()->get_physical_overview())->send_refresh_roles();
 
3073
  if (!added)
 
3074
  {
 
3075
    grt::ObjectRef object(grt::ObjectRef::cast_from(value));
 
3076
    _wb->request_refresh(RefreshCloseEditor, object.id());
 
3077
  }
 
3078
}
 
3079
 
 
3080
//--------------------------------------------------------------------------------
 
3081
// Privilege Management
 
3082
 
 
3083
grt::ValueRef WBComponentPhysical::add_new_user_grt(grt::GRT *grt, const workbench_physical_ModelRef &model)
 
3084
{
 
3085
  db_CatalogRef catalog;
 
3086
  db_UserRef user;
 
3087
 
 
3088
  catalog= model->catalog();
 
3089
 
 
3090
  std::string name= grt::get_name_suggestion_for_list_object(grt::ObjectListRef::cast_from(catalog->users()), "user");
 
3091
 
 
3092
  user= db_UserRef(grt);
 
3093
  user->owner(catalog);
 
3094
  user->name(name);
 
3095
 
 
3096
  grt::AutoUndo undo(grt);
 
3097
  catalog->users().insert(user);
 
3098
 
 
3099
  undo.end(strfmt(_("Create User '%s'"), user->name().c_str()));
 
3100
 
 
3101
  return user;
 
3102
}
 
3103
 
 
3104
 
 
3105
void WBComponentPhysical::add_new_user(const workbench_physical_ModelRef &model)
 
3106
{
 
3107
  grt::ValueRef res;
 
3108
 
 
3109
  res= _wb->execute_in_grt_thread("Create new user",
 
3110
                        boost::bind(&WBComponentPhysical::add_new_user_grt, this, _1, model));
 
3111
  if (res.is_valid())
 
3112
  {
 
3113
    db_UserRef user(db_UserRef::cast_from(res));
 
3114
 
 
3115
    _wb->show_status_text(strfmt(_("User '%s' created"), user->name().c_str()));
 
3116
 
 
3117
    _wb->open_object_editor(GrtObjectRef::cast_from(user));
 
3118
  }
 
3119
  else
 
3120
    _wb->show_status_text(_("Could not create new user"));
 
3121
}
 
3122
 
 
3123
 
 
3124
void WBComponentPhysical::remove_user(const db_UserRef &user)
 
3125
{
 
3126
  db_CatalogRef catalog(db_CatalogRef::cast_from(user->owner()));
 
3127
 
 
3128
  grt::AutoUndo undo(get_grt());
 
3129
  catalog->users().remove_value(user);
 
3130
  undo.end(strfmt(_("Remove User '%s'"), user->name().c_str()));
 
3131
 
 
3132
  _wb->show_status_text(strfmt(_("Removed user '%s'"), user->name().c_str()));
 
3133
}
 
3134
 
 
3135
 
 
3136
grt::ValueRef WBComponentPhysical::add_new_role_grt(grt::GRT *grt, const workbench_physical_ModelRef &model)
 
3137
{
 
3138
  db_CatalogRef catalog;
 
3139
  db_RoleRef role;
 
3140
 
 
3141
  catalog= model->catalog();
 
3142
 
 
3143
  std::string name= grt::get_name_suggestion_for_list_object(grt::ObjectListRef::cast_from(catalog->roles()), "role");
 
3144
 
 
3145
  role= db_RoleRef(grt);
 
3146
  role->owner(catalog);
 
3147
  role->name(name);
 
3148
 
 
3149
  grt::AutoUndo undo(get_grt());
 
3150
  catalog->roles().insert(role);
 
3151
  undo.end(strfmt(_("Create Role '%s'"), role->name().c_str()));
 
3152
 
 
3153
  return role;
 
3154
}
 
3155
 
 
3156
 
 
3157
void WBComponentPhysical::add_new_role(const workbench_physical_ModelRef &model)
 
3158
{
 
3159
  grt::ValueRef res;
 
3160
 
 
3161
  res= _wb->execute_in_grt_thread("Create new role",
 
3162
                        boost::bind(&WBComponentPhysical::add_new_role_grt, this, _1, model));
 
3163
  if (res.is_valid())
 
3164
  {
 
3165
    db_RoleRef role(db_RoleRef::cast_from(res));
 
3166
 
 
3167
    _wb->show_status_text(strfmt(_("Role '%s' created"), role->name().c_str()));
 
3168
 
 
3169
    _wb->open_object_editor(role);
 
3170
  }
 
3171
  else
 
3172
    _wb->show_status_text(_("Could not create new role"));
 
3173
}
 
3174
 
 
3175
 
 
3176
void WBComponentPhysical::remove_role(const db_RoleRef &role)
 
3177
{
 
3178
  db_CatalogRef catalog(db_CatalogRef::cast_from(role->owner()));
 
3179
 
 
3180
  grt::AutoUndo undo(get_grt());
 
3181
  catalog->roles().remove_value(role);
 
3182
  undo.end(strfmt(_("Remove Role '%s'"), role->name().c_str()));
 
3183
 
 
3184
  _wb->show_status_text(strfmt(_("Removed role '%s'"), role->name().c_str()));
 
3185
}
 
3186
 
 
3187
 
 
3188
void WBComponentPhysical::remove_references_to_object(const db_DatabaseObjectRef &object)
 
3189
{
 
3190
  // this is called when a object is removed from the schema.
 
3191
 
 
3192
  // remove all role privileges assigned to the object
 
3193
  db_CatalogRef catalog(_wb->get_parent_for_object<db_Catalog>(object));
 
3194
  
 
3195
  grt::ListRef<db_Role> roles(catalog->roles());
 
3196
  {
 
3197
    grt::AutoUndo undo(get_grt());
 
3198
    
 
3199
    for (size_t c= roles.count(), i= 0; i < c; i++)
 
3200
    {
 
3201
      db_RoleRef role(roles[i]);
 
3202
      
 
3203
      grt::ListRef<db_RolePrivilege> privs(role->privileges());
 
3204
      std::list<db_RolePrivilegeRef> privs_to_remove;
 
3205
      for (grt::ListRef<db_RolePrivilege>::const_reverse_iterator priv= privs.rbegin(); 
 
3206
           priv != privs.rend(); ++priv)
 
3207
      {
 
3208
        if ((*priv)->databaseObject() == object)
 
3209
        {
 
3210
          privs_to_remove.push_back(*priv);
 
3211
        }
 
3212
      }
 
3213
      for(std::list<db_RolePrivilegeRef>::const_iterator It = privs_to_remove.begin(); It != privs_to_remove.end(); ++It)
 
3214
        privs.remove_value(*It);
 
3215
    }
 
3216
    undo.end_or_cancel_if_empty(_("Remove Object Privileges"));
 
3217
  }
 
3218
  
 
3219
  workbench_physical_ModelRef model(_wb->get_parent_for_object<workbench_physical_Model>(object));
 
3220
  // remove any tags that reference this object
 
3221
  if (model.is_valid())
 
3222
  {
 
3223
    grt::AutoUndo undo(get_grt());
 
3224
    
 
3225
    for (grt::ListRef<meta_Tag>::const_iterator end= model->tags().end(), tag= model->tags().begin();
 
3226
         tag != end; ++tag)
 
3227
    {
 
3228
      std::list<meta_TaggedObjectRef> tags_to_remove;
 
3229
      for (grt::ListRef<meta_TaggedObject>::const_reverse_iterator rend= (*tag)->objects().rend(), to= (*tag)->objects().rbegin();
 
3230
        to != rend; ++to)
 
3231
      {
 
3232
        if ((*to)->object() == object)
 
3233
        {
 
3234
          tags_to_remove.push_back(*to);
 
3235
        }
 
3236
      }
 
3237
      for(std::list<meta_TaggedObjectRef>::const_iterator It = tags_to_remove.begin(); It != tags_to_remove.end(); ++It)
 
3238
            (*tag)->objects().remove_value(*It);
 
3239
 
 
3240
 
 
3241
    }
 
3242
  
 
3243
    undo.end_or_cancel_if_empty(_("Remove Tags for Object"));
 
3244
  }
 
3245
}
 
3246