/////////////////////////////////////////////////////////////////////////////
// Name: dbentity.cpp
// Purpose: Database Objects
// Author: Daniel Horak
// Modified by:
// RCS-ID: $Id: dbentity.cc,v 1.7 2004/01/04 18:32:16 horakdan Exp $
// Copyright: (c) Daniel Horak
// Licence: GPL
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWindows headers
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/notebook.h>
#include <wx/ogl/ogl.h>
#include "config.h"
#include "xml.h"
#include "dbobject.h"
#include "dbentity.h"
#include "dbattribute.h"
#include "dbindex.h"
#include "dbtrigger.h"
#include "dbconstraint.h"
#include "dbsimpleattr.h"
#include "dbmodelentity.h"
#include "dbrelation.h"
#include "schema.h"
#include "project.h"
DBEntity::DBEntity(DataDesignerProject *project, DataDesignerContainer *container)
:DBObject(DBEntityType, "entity", project, container),
m_attrs(NULL), m_indexes(NULL), m_triggers(NULL), m_constraints(NULL),
m_placed(FALSE), m_xpos(100), m_ypos(100)
{
}
DBEntity::~DBEntity()
{
if (m_attrs) {
m_project->DeleteChildren(m_attrs->GetTreeItemId());
delete m_attrs;
}
if (m_indexes) {
m_project->DeleteChildren(m_indexes->GetTreeItemId());
delete m_indexes;
}
if (m_triggers) {
m_project->DeleteChildren(m_triggers->GetTreeItemId());
delete m_triggers;
}
if (m_constraints) {
m_project->DeleteChildren(m_constraints->GetTreeItemId());
delete m_constraints;
}
wxDBObjectListNode *node;
// must delete all modelentities derived from this real entity
node = m_modelentities.GetFirst();
while (node) {
delete node->GetData();
node = node->GetNext();
}
}
void DBEntity::LoadXmlNode(wxXmlNode *node)
{
wxXmlNode *child;
wxString number;
if (node->GetName() == m_typestr) {
DBObject::LoadXmlNode(node);
number = node->GetPropVal("xpos", "100");
m_xpos = wxAtoi(number);
number = node->GetPropVal("ypos", "100");
m_ypos = wxAtoi(number);
child = node->GetChildren();
while (child) {
if (child->GetName() == "attributes") {
m_attrs->LoadXmlNode(child);
} else if (child->GetName() == "indexes") {
m_indexes->LoadXmlNode(child);
} else if (child->GetName() == "triggers") {
m_triggers->LoadXmlNode(child);
} else if (child->GetName() == "constraints") {
m_constraints->LoadXmlNode(child);
}
child = child->GetNext();
}
} else {
wxLogMessage("wrong type '%s'", node->GetName().c_str());
}
}
wxTreeItemId DBEntity::AppendItem()
{
DataDesignerSchema *schema;
if (! m_appended) {
m_treeitemid = m_project->AppendItem(m_container->GetTreeItemId(), m_name, -1, -1, new DataDesignerItemData(this));
m_attrs = new DBAttributeContainer(m_project, m_project->AppendItem(m_treeitemid, _("Attributes")));
m_indexes = new DBIndexContainer(m_project, m_project->AppendItem(m_treeitemid, _("Indexes")));
m_triggers = new DBTriggerContainer(m_project, m_project->AppendItem(m_treeitemid, _("Triggers")));
m_constraints = new DBConstraintContainer(m_project, m_project->AppendItem(m_treeitemid, _("Constraints")));
if ((schema = m_project->GetSchema()) != NULL) {
schema->AddObject(this);
schema->Refresh();
}
m_appended = TRUE;
}
return m_treeitemid;
}
wxDialog *DBEntity::Editor(bool edit)
{
return new DBEntityEditor(this, edit);
}
wxXmlNode *DBEntity::GetXmlNode()
{
wxXmlNode *node = DBObject::GetXmlNode();
wxString number;
number.Printf("%d", m_xpos);
node->AddProperty("xpos", number);
number.Printf("%d", m_ypos);
node->AddProperty("ypos", number);
node->AddChild(m_attrs->GetXmlNode());
node->AddChild(m_indexes->GetXmlNode());
node->AddChild(m_triggers->GetXmlNode());
node->AddChild(m_constraints->GetXmlNode());
return node;
}
void DBEntity::CreateShape()
{
m_shape = new DBEntityShape(this);
m_shape->Show(TRUE);
}
int DBEntity::GetAttributeCount()
{
return GetProject()->GetChildrenCount(m_attrs->GetTreeItemId(), FALSE);
}
DBAttribute *DBEntity::GetAttributeByName(const wxString& name)
{
wxLogMessage("DBEntity::GetAttributeByName - not implemented");
return NULL;
}
DBAttribute *DBEntity::AddAttribute(DBAttribute *attr)
{
DBAttribute *nattr;
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddAttribute");
#endif
if (attr == NULL) {
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddAttribute - attr == NULL");
#endif
return NULL;
}
nattr = (DBAttribute *)m_attrs->CreateObject();
nattr->Copy(attr);
nattr->AppendItem();
return nattr;
}
void DBEntity::AddAttributeToPrimaryKey(DBAttribute *attr)
{
DBConstraint *pk;
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddAttributeToPrimaryKey");
#endif
if (attr == NULL)
return;
attr->m_primarykey = TRUE;
pk = GetPrimaryKeyConstraint();
if (pk == NULL) {
// create a PK constraint
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddAttributeToPrimaryKey - creating PK constraint");
#endif
pk = (DBConstraint *)m_constraints->CreateObject();
pk->m_type = DBO_CONSTRAINT_TYPE_PRIMARY_KEY;
pk->m_name = m_name + "_pk";
pk->CreatePName();
pk->AppendItem();
}
pk->AddAttribute(attr);
}
void DBEntity::DeleteAttributeFromPrimaryKey(DBAttribute *attr)
{
DBConstraint *pk;
pk = GetPrimaryKeyConstraint();
if (pk != NULL) {
pk->DeleteAttribute(attr->GetName());
if (pk->m_attrs->GetChildrenCount() == 0) {
// if there is no attribute in PK then destroy whole PK constraint
delete pk;
}
}
}
DBConstraint *DBEntity::GetPrimaryKeyConstraint()
{
DBConstraint *pk = NULL, *constr;
long cookie;
wxTreeItemId child;
if (m_constraints == NULL) {
wxLogMessage("DBEntity::GetPrimaryKeyConstraint - m_constraints == NULL");
return NULL;
}
child = GetProject()->GetFirstChild(m_constraints->GetTreeItemId(), cookie);
while (child.IsOk()) {
constr = (DBConstraint *)(((DataDesignerItemData *)m_project->GetItemData(child))->GetObject());
if (constr->m_type == DBO_CONSTRAINT_TYPE_PRIMARY_KEY) {
pk = constr;
break;
}
child = GetProject()->GetNextChild(m_constraints->GetTreeItemId(), cookie);
}
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::GetPrimaryKeyConstraint - PK was %sfound", pk ? "" : "not ");
#endif
return pk;
}
void DBEntity::AddForeignKeyConstraint(DBRelation *relation, bool identifying)
{
DBEntity *parent_ent;
long cookie;
wxTreeItemId child;
DBConstraint *parent_pk;
DBConstraint *fk;
DBSimpleAttribute *simpleattr;
DBAttribute *attr;
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddForeignKeyConstraint - this entity '%s'", m_name.c_str());
#endif
parent_ent = (DBEntity *)(GetProject()->m_top_entities->GetObjectByName(relation->m_parent));
if (parent_ent == NULL) {
wxLogMessage("DBEntity::AddForeignKeyConstraint - cannot find parent entity '%s'", relation->m_parent.c_str());
return;
}
parent_pk = parent_ent->GetPrimaryKeyConstraint();
if (parent_pk == NULL) {
wxLogMessage("DBEntity::AddForeignKeyConstraint - parent entity '%s' has no primary key", parent_ent->GetName().c_str());
return;
}
fk = (DBConstraint *)m_constraints->CreateObject();
fk->m_type = DBO_CONSTRAINT_TYPE_FOREIGN_KEY;
fk->m_name = parent_ent->GetName() + "_fk";
fk->m_relation = relation->GetName();
fk->CreatePName();
fk->AppendItem();
// iterate through attributes in parent's PK
child = GetProject()->GetFirstChild(parent_pk->GetAttributes()->GetTreeItemId(), cookie);
while (child.IsOk()) {
simpleattr = (DBSimpleAttribute *)(((DataDesignerItemData *)GetProject()->GetItemData(child))->GetObject());
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddForeignKeyConstraint - processing attr '%s'", simpleattr->GetName().c_str());
#endif
attr = AddAttribute(simpleattr->GetRealAttribute());
if (attr == NULL) {
wxLogFatalError("attr == NULL");
break;
}
attr->m_imported = TRUE;
attr->m_foreignkey = TRUE;
attr->m_relation = relation->GetName();
fk->AddAttribute(attr);
if ((identifying == TRUE))
AddAttributeToPrimaryKey(attr);
child = GetProject()->GetNextChild(parent_pk->GetTreeItemId(), cookie);
}
}
void DBEntity::AddParentsPrimaryKey(DBRelation *relation)
{
DBEntity *parent_ent;
long cookie;
wxTreeItemId child;
DBConstraint *parent_pk;
DBSimpleAttribute *simpleattr;
DBAttribute *attr;
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddParentKey - this entity '%s'", m_name.c_str());
#endif
parent_ent = (DBEntity *)(GetProject()->m_top_entities->GetObjectByName(relation->m_parent));
if (parent_ent == NULL) {
wxLogMessage("DBEntity::AddParentKey - cannot find parent entity '%s'", relation->m_parent.c_str());
return;
}
parent_pk = parent_ent->GetPrimaryKeyConstraint();
if (parent_pk == NULL) {
wxLogMessage("DBEntity::AddParentKey - parent entity '%s' has no primary key", parent_ent->GetName().c_str());
return;
}
// iterate through attributes in parent's PK
child = GetProject()->GetFirstChild(parent_pk->GetAttributes()->GetTreeItemId(), cookie);
while (child.IsOk()) {
simpleattr = (DBSimpleAttribute *)(((DataDesignerItemData *)GetProject()->GetItemData(child))->GetObject());
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntity::AddParentKey - processing attr '%s'", simpleattr->GetName().c_str());
#endif
attr = AddAttribute(simpleattr->GetRealAttribute());
attr->m_imported = TRUE;
attr->m_foreignkey = TRUE;
attr->m_relation = relation->GetName();
child = GetProject()->GetNextChild(parent_pk->GetTreeItemId(), cookie);
}
}
void DBEntity::AddModelEntity(DBModelEntity *ent)
{
m_modelentities.Append(ent);
}
void DBEntity::DeleteModelEntity(DBModelEntity *ent)
{
if (m_modelentities.IndexOf(ent) != wxNOT_FOUND) {
m_modelentities.DeleteObject(ent);
}
}
/*
* Editor
*/
BEGIN_EVENT_TABLE(DBEntityEditor, DBObjectEditor)
EVT_BUTTON(wxID_APPLY, DBEntityEditor::OnApply)
END_EVENT_TABLE()
DBEntityEditor::DBEntityEditor(DBObject *object, bool edit)
: DBObjectEditor(_("Entity"), wxSize(500,400), object, edit)
{
m_page_attributes = new wxPanel(m_notebook);
m_page_constraints = new wxPanel(m_notebook);
m_page_indexes = new wxPanel(m_notebook);
m_page_triggers = new wxPanel(m_notebook);
m_list_attrs = new DBAttributeListCtrl (m_page_attributes, ((DBEntity *)GetObject())->m_attrs);
m_list_constraints = new DBConstraintListCtrl (m_page_constraints, ((DBEntity *)GetObject())->m_constraints);
m_list_indexes = new DBIndexListCtrl (m_page_indexes, ((DBEntity *)GetObject())->m_indexes);
m_list_triggers = new DBTriggerListCtrl (m_page_triggers, ((DBEntity *)GetObject())->m_triggers);
if (m_edit) {
((DBEntity *)GetObject())->m_attrs->SetList(m_list_attrs);
((DBEntity *)GetObject())->m_attrs->AddObjectsToList();
((DBEntity *)GetObject())->m_constraints->SetList(m_list_constraints);
((DBEntity *)GetObject())->m_constraints->AddObjectsToList();
((DBEntity *)GetObject())->m_indexes->SetList(m_list_indexes);
((DBEntity *)GetObject())->m_indexes->AddObjectsToList();
((DBEntity *)GetObject())->m_triggers->SetList(m_list_triggers);
((DBEntity *)GetObject())->m_triggers->AddObjectsToList();
}
wxLayoutConstraints *c = new wxLayoutConstraints;
c->top.SameAs (m_page_attributes, wxTop);
c->left.SameAs (m_page_attributes, wxLeft);
c->right.SameAs (m_page_attributes, wxRight);
c->bottom.SameAs(m_page_attributes, wxBottom);
m_list_attrs->SetConstraints(c);
c = new wxLayoutConstraints;
c->top.SameAs (m_page_constraints, wxTop);
c->left.SameAs (m_page_constraints, wxLeft);
c->right.SameAs (m_page_constraints, wxRight);
c->bottom.SameAs(m_page_constraints, wxBottom);
m_list_constraints->SetConstraints(c);
c = new wxLayoutConstraints;
c->top.SameAs (m_page_indexes, wxTop);
c->left.SameAs (m_page_indexes, wxLeft);
c->right.SameAs (m_page_indexes, wxRight);
c->bottom.SameAs(m_page_indexes, wxBottom);
m_list_indexes->SetConstraints(c);
c = new wxLayoutConstraints;
c->top.SameAs (m_page_triggers, wxTop);
c->left.SameAs (m_page_triggers, wxLeft);
c->right.SameAs (m_page_triggers, wxRight);
c->bottom.SameAs(m_page_triggers, wxBottom);
m_list_triggers->SetConstraints(c);
m_page_attributes->SetAutoLayout(TRUE);
m_page_constraints->SetAutoLayout(TRUE);
m_page_indexes->SetAutoLayout(TRUE);
m_page_triggers->SetAutoLayout(TRUE);
m_notebook->InsertPage(m_notebook->GetPageCount() - 1, m_page_attributes, _("Attributes"));
m_notebook->InsertPage(m_notebook->GetPageCount() - 1, m_page_constraints, _("Constraints"));
m_notebook->InsertPage(m_notebook->GetPageCount() - 1, m_page_indexes, _("Indexes"));
m_notebook->InsertPage(m_notebook->GetPageCount() - 1, m_page_triggers, _("Triggers"));
m_button_apply = AddButton(wxID_APPLY, _("Apply"), wxSize(60,-1));
if (m_edit) {
m_button_ok->SetDefault();
} else {
m_button_apply->SetDefault();
m_page_attributes->Disable();
m_page_constraints->Disable();
m_page_indexes->Disable();
m_page_triggers->Disable();
}
}
DBEntityEditor::~DBEntityEditor()
{
}
bool DBEntityEditor::TransferDataFromWindow()
{
DBEntity *entity = (DBEntity *)GetObject();
DBObjectEditor::TransferDataFromWindow();
return TRUE;
}
bool DBEntityEditor::TransferDataToWindow()
{
DBEntity *entity = (DBEntity *)GetObject();
DBObjectEditor::TransferDataToWindow();
return TRUE;
}
void DBEntityEditor::OnApply(wxCommandEvent& event)
{
DBObject *object;
if (Validate() == FALSE)
return;
TransferDataFromWindow();
object = GetObject();
object->AppendItem();
m_list_attrs->SetContainer(((DBEntity *)GetObject())->m_attrs);
m_list_constraints->SetContainer(((DBEntity *)GetObject())->m_constraints);
m_list_indexes->SetContainer(((DBEntity *)GetObject())->m_indexes);
m_list_triggers->SetContainer(((DBEntity *)GetObject())->m_triggers);
m_page_attributes->Enable();
m_page_constraints->Enable();
m_page_indexes->Enable();
m_page_triggers->Enable();
m_button_apply->Disable();
m_button_ok->SetDefault();
m_edit = TRUE;
}
/*
* Container
*/
DBEntityContainer::DBEntityContainer(DataDesignerProject *project, const wxTreeItemId& parent)
: DataDesignerContainer(project, parent, "entities")
{
}
DBObject *DBEntityContainer::CreateObject()
{
return new DBEntity(GetProject(), this);
}
void DBEntityContainer::ShowList()
{
SetList(new DBEntityListCtrl(GetProject()->GetSplitter(), this));
DataDesignerContainer::AddObjectsToListAndShow();
}
/*
* ObjectList
*/
DBEntityListCtrl::DBEntityListCtrl(wxWindow *parent, DataDesignerContainer *container)
: DBObjectListCtrl(parent, container)
{
SetColumnWidth(0, 200);
InsertColumn(1, _("Remark"));
SetColumnWidth(1, 400);
}
DBEntityListCtrl::~DBEntityListCtrl()
{
}
void DBEntityListCtrl::SetObject(long item, DBObject *object)
{
DBEntity *entity = (DBEntity *)object;
}
/*
* DBEntityShape
*/
DBEntityShape::DBEntityShape(DBEntity *entity)
: wxRectangleShape(), m_mentity(NULL)
{
Create(entity);
m_xpos = entity->m_xpos;
m_ypos = entity->m_ypos;
}
DBEntityShape::DBEntityShape(DBModelEntity *mentity)
: wxRectangleShape(), m_mentity(mentity)
{
Create(mentity->GetRealEntity());
m_xpos = mentity->m_xpos;
m_ypos = mentity->m_ypos;
}
void DBEntityShape::Create(DBEntity *entity)
{
SetClientData(entity);
m_attrcount = entity->GetAttributeCount();
m_pen = wxBLACK_PEN;
m_brush = wxGREEN_BRUSH;
m_font = g_oglNormalFont;
m_width = 100;
m_height = (m_attrcount + 1) * 20 + 5;
m_fixedWidth = TRUE;
m_fixedHeight = TRUE;
SetDefaultRegionSize();
}
void DBEntityShape::OnDraw(wxDC& dc)
{
DBEntity *entity;
wxCoord left, top;
wxCoord x, y;
int cnt;
wxTreeItemId child, attrsid;
long cookie;
DBAttribute *attr;
DataDesignerProject *project;
wxString attr_txt;
entity = (DBEntity *)GetClientData();
project = entity->GetProject();
attrsid = entity->m_attrs->GetTreeItemId();
cnt = entity->GetAttributeCount();
if (cnt != m_attrcount) {
m_attrcount = cnt;
m_height = (m_attrcount + 1) * 20 + 5;
}
left = (wxCoord)(m_xpos - m_width/2);
top = (wxCoord)(m_ypos - m_height/2);
wxRectangleShape::OnDraw(dc);
dc.SetFont(*m_font);
x = left + 5;
y = top + 5;
dc.DrawText(entity->m_name, x, y);
y = (wxCoord)(top + 20);
dc.DrawLine(left, y, left + (wxCoord)m_width, y);
y += 5;
child = project->GetFirstChild(attrsid, cookie);
while (child.IsOk()) {
attr = (DBAttribute *)(((DataDesignerItemData *)(project->GetItemData(child)))->GetObject());
attr_txt = attr->m_name;
if (attr->m_primarykey || attr->m_foreignkey) {
attr_txt.Append(' ');
if (attr->m_primarykey)
attr_txt.Append('P');
if (attr->m_foreignkey)
attr_txt.Append('F');
attr_txt.Append('K');
}
dc.DrawText(attr_txt, left + 5, y);
y += 20;
child = project->GetNextChild(attrsid, cookie);
}
#if 0
Move(dc, GetX(), GetY()); // redraw ends of relations too
#endif
}
void DBEntityShape::OnEndDragLeft(double x, double y, int keys, int attachment)
{
DBEntity *entity;
wxRectangleShape::OnEndDragLeft(x, y, keys, attachment);
entity = (DBEntity *)GetClientData();
if (m_mentity) {
m_mentity->m_xpos = (wxCoord)m_xpos;
m_mentity->m_ypos = (wxCoord)m_ypos;
} else {
entity->m_xpos = (wxCoord)m_xpos;
entity->m_ypos = (wxCoord)m_ypos;
}
entity->GetProject()->GetSplitter()->GetView()->GetDocument()->Modify(TRUE);
}
void DBEntityShape::OnLeftDoubleClick(double x, double y, int keys, int attachment)
{
DBObject *object;
wxDialog *editor;
wxRectangleShape::OnLeftDoubleClick(x, y, keys, attachment);
object = (DBObject *)GetClientData();
editor = object->Editor(TRUE);
if (editor) {
editor->ShowModal();
editor->Destroy();
}
}
void DBEntityShape::OnLeftClick(double x, double y, int keys, int attachment)
{
DBObject *object;
wxRectangleShape::OnLeftClick(x, y, keys, attachment);
#ifdef NOT_USED_YET
wxClientDC dc(GetCanvas());
GetCanvas()->PrepareDC(dc);
object = (DBObject *)GetClientData();
if (keys == 0) {
bool selected = Selected();
selected = !selected;
Select(selected, &dc);
// object->GetProject()->GetSchema()->SelectAll(FALSE);
} else if (keys & KEY_SHIFT) {
if (Selected()) {
Select(FALSE, &dc);
} else {
Select(TRUE, &dc);
}
}
#endif
}
void DBEntityShape::OnBeginDragRight(double x, double y, int keys, int attachment)
{
wxRectangleShape::OnBeginDragRight(x, y, keys, attachment);
attachment = 0;
wxClientDC dc(GetCanvas());
GetCanvas()->PrepareDC(dc);
wxPen dottedPen(wxColour(0,0,0), 1, wxDOT);
dc.SetLogicalFunction(OGLRBLF);
dc.SetPen(dottedPen);
double xp, yp;
GetAttachmentPosition(attachment, &xp, &yp);
dc.DrawLine((wxCoord) xp, (wxCoord) yp, (wxCoord) x, (wxCoord) y);
GetCanvas()->CaptureMouse();
DBObject *object = (DBObject *)GetClientData();
}
void DBEntityShape::OnDragRight(bool draw, double x, double y, int keys, int attachment)
{
wxRectangleShape::OnDragRight(draw, x, y, keys, attachment);
attachment = 0;
wxClientDC dc(GetCanvas());
GetCanvas()->PrepareDC(dc);
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
dc.SetLogicalFunction(OGLRBLF);
dc.SetPen(dottedPen);
double xp, yp;
GetAttachmentPosition(attachment, &xp, &yp);
dc.DrawLine((wxCoord) xp, (wxCoord) yp, (wxCoord) x, (wxCoord) y);
}
void DBEntityShape::OnEndDragRight(double x, double y, int keys, int attachment)
{
wxRectangleShape::OnEndDragRight(x, y, keys, attachment);
GetCanvas()->ReleaseMouse();
int new_attachment;
wxShape *other = GetCanvas()->FindFirstSensitiveShape(x, y, &new_attachment, OP_DRAG_RIGHT);
if (other == NULL) {
// there is no object on the end, so exit
return;
}
DBObject *object_from = (DBObject *)GetClientData();
DBObject *object_to = (DBObject *)(other->GetClientData());
if (!object_to || (object_to->GetType() != DBEntityType) || (object_to == object_from)) {
#ifdef ENABLE_DEBUG
wxLogMessage("DBEntityShape::OnEndDragRight - no end for relation");
#endif
return;
}
DBRelation *relation = (DBRelation *)(object_from->GetProject()->m_top_relations->CreateObject());
relation->m_parent = object_from->GetName();
relation->m_child = object_to->GetName();
relation->m_name = object_from->m_pname + "_" + object_to->m_pname;
relation->AppendItem();
wxDialog *editor = relation->Editor(TRUE);
if (editor) {
if (editor->ShowModal() != wxID_OK) {
object_from->GetProject()->Delete(relation->GetTreeItemId());
delete relation;
relation = NULL;
}
editor->Destroy();
if (relation) {
// copy PK from parent as FK into child
relation->LinkAttributes();
// attach relation to model iff schema is a model
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1