/////////////////////////////////////////////////////////////////////////////
// Name: dbrelation.cc
// Purpose: Database Objects
// Author: Daniel Horak
// Modified by:
// RCS-ID: $Id: dbrelation.cc,v 1.5 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 "dbrelation.h"
#include "dbrelattr.h"
#include "dbentity.h"
#include "dbmodelrelation.h"
#include "schema.h"
#include "container.h"
DBRelation::DBRelation(DataDesignerProject *project, DataDesignerContainer *container)
:DBObject(DBRelationType, "relation", project, container),
m_type(DBO_RELATION_TYPE_IDENT),
m_parciality_parent(DBO_RELATION_PARCIALITY_MANDATORY), m_parciality_child(DBO_RELATION_PARCIALITY_MANDATORY),
m_refinteg_parent_update(DBO_RELATION_REFINTEG_NONE), m_refinteg_parent_delete(DBO_RELATION_REFINTEG_NONE),
m_refinteg_child_insert(DBO_RELATION_REFINTEG_NONE), m_refinteg_child_update(DBO_RELATION_REFINTEG_NONE),
m_refinteg_match(DBO_RELATION_REFINTEG_MATCH_FULL), m_keys(NULL)
{
}
DBRelation::~DBRelation()
{
if (m_keys) {
m_project->DeleteChildren(m_keys->GetTreeItemId());
delete m_keys;
}
wxDBObjectListNode *node;
// must delete all modelrelations derived from this real relation
node = m_modelrelations.GetFirst();
while (node) {
delete node->GetData();
node = node->GetNext();
}
}
wxDialog *DBRelation::Editor(bool edit)
{
return new DBRelationEditor(this, edit);
}
void DBRelation::LoadXmlNode(wxXmlNode *node)
{
wxXmlNode *child;
if (node->GetName() == m_typestr) {
wxString name;
DBObject::LoadXmlNode(node);
m_parent = node->GetPropVal("parent", wxEmptyString);
m_child = node->GetPropVal("child", wxEmptyString);
child = node->GetChildren();
while (child) {
name = child->GetName();
if (name == "parent") {
LoadTextNode(child, "parent", m_parent);
} else if (name == "child") {
LoadTextNode(child, "child", m_child);
} else if (name == "type") {
wxString type;
LoadTextNode(child, "type", type);
if (type == "ident")
m_type = DBO_RELATION_TYPE_IDENT;
else if (type == "nonident")
m_type = DBO_RELATION_TYPE_NONIDENT;
else if (type == "inform")
m_type = DBO_RELATION_TYPE_INFORM;
else
wxLogMessage("Unknown relation type specification '%s'", type.c_str());
} else if (name == "parciality_parent") {
wxString parc;
LoadTextNode(child, "parciality_parent", parc);
if (ParseParciality(parc, m_parciality_parent) == FALSE)
wxLogMessage("Unknown relation parent parciality specification '%s'", parc.c_str());
} else if (name == "parciality_child") {
wxString parc;
LoadTextNode(child, "parciality_child", parc);
if (ParseParciality(parc, m_parciality_child) == FALSE)
wxLogMessage("Unknown relation child parciality specification '%s'", parc.c_str());
} else if (name == "refinteg_parent_update") {
wxString refinteg;
LoadTextNode(child, "refinteg_parent_update", refinteg);
if (ParseRefIntegParent(refinteg, m_refinteg_parent_update) == FALSE)
wxLogMessage("Unknown relation parent update refinteg specification '%s'", refinteg.c_str());
} else if (name == "refinteg_parent_delete") {
wxString refinteg;
LoadTextNode(child, "refinteg_parent_delete", refinteg);
if (ParseRefIntegParent(refinteg, m_refinteg_parent_delete) == FALSE)
wxLogMessage("Unknown relation parent delete refinteg specification '%s'", refinteg.c_str());
} else if (name == "refinteg_child_insert") {
wxString refinteg;
LoadTextNode(child, "refinteg_child_insert", refinteg);
if (ParseRefIntegChild(refinteg, m_refinteg_child_insert) == FALSE)
wxLogMessage("Unknown relation child insert refinteg specification '%s'", refinteg.c_str());
} else if (name == "refinteg_child_update") {
wxString refinteg;
LoadTextNode(child, "refinteg_child_update", refinteg);
if (ParseRefIntegChild(refinteg, m_refinteg_child_update) == FALSE)
wxLogMessage("Unknown relation child update refinteg specification '%s'", refinteg.c_str());
} else if (name == "refinteg_match") {
wxString match;
LoadTextNode(child, "refinteg_match", match);
if (match == "full")
m_refinteg_match = DBO_RELATION_REFINTEG_MATCH_FULL;
else if (match == "partial")
m_refinteg_match = DBO_RELATION_REFINTEG_MATCH_PARTIAL;
else
wxLogMessage("Unknown relation match refinteg specification '%s'", match.c_str());
} else if ((name == "relationattrs") || (name == "keys")) {
m_keys->LoadXmlNode(child);
}
child = child->GetNext();
}
} else {
wxLogMessage("wrong type '%s'", node->GetName().c_str());
}
}
bool DBRelation::ParseParciality(const wxString& parc, int& var)
{
bool res = TRUE;
if (parc == "mandatory")
var = DBO_RELATION_PARCIALITY_MANDATORY;
else if (parc == "nonmandatory")
var = DBO_RELATION_PARCIALITY_NONMANDATORY;
else
res = FALSE;
return res;
}
bool DBRelation::ParseRefIntegParent(const wxString& refinteg, int& var)
{
bool res = TRUE;
if (refinteg == "none")
var = DBO_RELATION_REFINTEG_NONE;
else if (refinteg == "restrict")
var = DBO_RELATION_REFINTEG_RESTRICT;
else if (refinteg == "cascade")
var = DBO_RELATION_REFINTEG_CASCADE;
else if (refinteg == "setnull")
var = DBO_RELATION_REFINTEG_SETNULL;
else if (refinteg == "setdefault")
var = DBO_RELATION_REFINTEG_SETDEFAULT;
else
res = FALSE;
return res;
}
bool DBRelation::ParseRefIntegChild(const wxString& refinteg, int& var)
{
bool res = TRUE;
if (refinteg == "none")
var = DBO_RELATION_REFINTEG_NONE;
else if (refinteg == "restrict")
var = DBO_RELATION_REFINTEG_RESTRICT;
else
res = FALSE;
return res;
}
void DBRelation::ParcialityToString(int parc, wxString& str)
{
if (parc == DBO_RELATION_PARCIALITY_MANDATORY)
str = "mandatory";
else if (parc == DBO_RELATION_PARCIALITY_NONMANDATORY)
str = "nonmandatory";
else
wxLogMessage("DBRelation::ParcialityToString - unknown parciality type '%d'", parc);
}
void DBRelation::RefIntegToString(int refinteg, wxString& str)
{
if (refinteg == DBO_RELATION_REFINTEG_NONE)
str = "none";
else if (refinteg == DBO_RELATION_REFINTEG_RESTRICT)
str = "restrict";
else if (refinteg == DBO_RELATION_REFINTEG_CASCADE)
str = "cascade";
else if (refinteg == DBO_RELATION_REFINTEG_SETNULL)
str = "setnull";
else if (refinteg == DBO_RELATION_REFINTEG_SETDEFAULT)
str = "setdefault";
else
wxLogMessage("DBRelation::RefIntegToString - unknown referential integrity type '%d'", refinteg);
}
wxTreeItemId DBRelation::AppendItem()
{
DataDesignerSchema *schema;
if (! m_appended) {
m_treeitemid = m_project->AppendItem(m_container->GetTreeItemId(), m_name, -1, -1, new DataDesignerItemData(this));
m_keys = new DBRelationAttributeContainer(m_project, m_project->AppendItem(m_treeitemid, _("Attribute Pairs")));
if ((schema = m_project->GetSchema()) != NULL) {
schema->AddObject(this);
schema->Refresh();
}
m_appended = TRUE;
}
return m_treeitemid;
}
wxXmlNode *DBRelation::GetXmlNode()
{
wxString val;
wxXmlNode *node = DBObject::GetXmlNode();
node->AddChild(GetTextNode("parent", m_parent));
node->AddChild(GetTextNode("child", m_child));
if (m_type == DBO_RELATION_TYPE_IDENT)
val = "ident";
else if (m_type == DBO_RELATION_TYPE_NONIDENT)
val = "nonident";
else if (m_type == DBO_RELATION_TYPE_INFORM)
val = "inform";
else
val = wxEmptyString;
if (! val.IsEmpty())
node->AddChild(GetTextNode("type", val));
ParcialityToString(m_parciality_parent, val);
node->AddChild(GetTextNode("parciality_parent", val));
ParcialityToString(m_parciality_child, val);
node->AddChild(GetTextNode("parciality_child", val));
RefIntegToString(m_refinteg_parent_update, val);
node->AddChild(GetTextNode("refinteg_parent_update", val));
RefIntegToString(m_refinteg_parent_delete, val);
node->AddChild(GetTextNode("refinteg_parent_delete", val));
RefIntegToString(m_refinteg_child_insert, val);
node->AddChild(GetTextNode("refinteg_child_insert", val));
RefIntegToString(m_refinteg_child_update, val);
node->AddChild(GetTextNode("refinteg_child_update", val));
if (m_refinteg_match == DBO_RELATION_REFINTEG_MATCH_FULL)
val = "full";
else if (m_refinteg_match == DBO_RELATION_REFINTEG_MATCH_PARTIAL)
val = "partial";
else
val = wxEmptyString;
if (! val.IsEmpty())
node->AddChild(GetTextNode("refinteg_match", val));
node->AddChild(m_keys->GetXmlNode());
return node;
}
void DBRelation::CreateShape()
{
m_shape = new DBRelationShape(this);
m_shape->Show(TRUE);
}
void DBRelation::LinkAttributes()
{
DBEntity *ent_parent, *ent_child;
ent_parent = (DBEntity *)(GetProject()->m_top_entities->GetObjectByName(m_parent));
ent_child = (DBEntity *)(GetProject()->m_top_entities->GetObjectByName(m_child));
if ((ent_parent == NULL) || (ent_child == NULL)) {
wxLogMessage("DBRelation::LinkAttribute - cannot find parent or child entity");
return;
}
if (m_type == DBO_RELATION_TYPE_IDENT) {
// copy parent's primary key into child's key + make as foreign key
ent_child->AddForeignKeyConstraint(this, TRUE);
} else if (m_type == DBO_RELATION_TYPE_NONIDENT) {
// copy parent's primary key into child + make as foreign key
ent_child->AddForeignKeyConstraint(this, FALSE);
} else if (m_type == DBO_RELATION_TYPE_INFORM ) {
// copy parent's primary key into child
ent_child->AddParentsPrimaryKey(this);
} else {
wxLogMessage("DBRelation::LinkAttribute - unknown relation type '%d'", m_type);
}
}
void DBRelation::AddAttributesToKeys(const wxString& attr_parent, const wxString& attr_child)
{
DBRelationAttribute *relattr;
relattr = (DBRelationAttribute *)m_keys->CreateObject();
if (relattr != NULL) {
relattr->m_parent = attr_parent;
relattr->m_child = attr_child;
relattr->AppendItem();
}
}
void DBRelation::AddModelRelation(DBModelRelation *rel)
{
m_modelrelations.Append(rel);
}
void DBRelation::DeleteModelRelation(DBModelRelation *rel)
{
if (m_modelrelations.IndexOf(rel) != wxNOT_FOUND) {
m_modelrelations.DeleteObject(rel);
}
}
/*
* Editor
*/
BEGIN_EVENT_TABLE(DBRelationEditor, DBObjectEditor)
EVT_BUTTON(wxID_APPLY, DBRelationEditor::OnApply)
END_EVENT_TABLE()
wxString DBRelationEditor::m_type_str[] = { _("Identifying"), _("Non-identifying"), _("Informational") };
wxString DBRelationEditor::m_parciality_str[] = { _("Mandatory"), _("Non-mandatory") };
wxString DBRelationEditor::m_refinteg_parent_str[] = { _("none"), _("restrict"), _("cascade"), _("set NULL"), _("set default") };
wxString DBRelationEditor::m_refinteg_child_str[] = { _("none"), _("restrict") };
wxString DBRelationEditor::m_refinteg_match_str[] = { _("Full"), _("Partial") };
DBRelationEditor::DBRelationEditor(DBObject *object, bool edit)
: DBObjectEditor(_("Relation"), wxSize(500,350), object, edit)
{
wxString **strings;
int idx = 0;
m_page_refinteg = new wxPanel(m_notebook);
new wxStaticBox(m_page_refinteg, -1, _("Parent"), wxPoint(5,5), wxSize(210,80));
new wxStaticText(m_page_refinteg, -1, _("Update"), wxPoint(10,25), wxSize(80,-1), wxALIGN_RIGHT);
c6 = new wxComboBox(m_page_refinteg, -1, wxEmptyString, wxPoint(100,25), wxSize(100,-1), 5, m_refinteg_parent_str, wxCB_READONLY);
new wxStaticText(m_page_refinteg, -1, _("Delete"), wxPoint(10,50), wxSize(80,-1), wxALIGN_RIGHT);
c7 = new wxComboBox(m_page_refinteg, -1, wxEmptyString, wxPoint(100,50), wxSize(100,-1), 5, m_refinteg_parent_str, wxCB_READONLY);
new wxStaticBox(m_page_refinteg, -1, _("Child"), wxPoint(225,5), wxSize(210,80));
new wxStaticText(m_page_refinteg, -1, _("Insert"), wxPoint(230,25), wxSize(80,-1), wxALIGN_RIGHT);
c8 = new wxComboBox(m_page_refinteg, -1, wxEmptyString, wxPoint(320,25), wxSize(100,-1), 2, m_refinteg_child_str, wxCB_READONLY);
new wxStaticText(m_page_refinteg, -1, _("Update"), wxPoint(230,50), wxSize(80,-1), wxALIGN_RIGHT);
c9 = new wxComboBox(m_page_refinteg, -1, wxEmptyString, wxPoint(320,50), wxSize(100,-1), 2, m_refinteg_child_str, wxCB_READONLY);
r10 = new wxRadioBox(m_page_refinteg, -1, _("Match"), wxPoint(10,100), wxSize(-1,-1), 2, m_refinteg_match_str, 1, wxRA_HORIZONTAL);
m_page_keys = new wxPanel(m_notebook);
m_list_keys = new DBRelationAttributeListCtrl(m_page_keys,((DBRelation *)GetObject())->m_keys);
if (m_edit) {
((DBRelation *)GetObject())->m_keys->SetList(m_list_keys);
((DBRelation *)GetObject())->m_keys->AddObjectsToList();
}
wxLayoutConstraints *c = new wxLayoutConstraints;
c->top.SameAs (m_page_keys, wxTop);
c->left.SameAs (m_page_keys, wxLeft);
c->right.SameAs (m_page_keys, wxRight);
c->bottom.SameAs(m_page_keys, wxBottom);
m_list_keys->SetConstraints(c);
m_page_keys->SetAutoLayout(TRUE);
m_notebook->InsertPage(m_notebook->GetPageCount() - 1, m_page_refinteg, _("Referential Integrity"));
m_notebook->InsertPage(m_notebook->GetPageCount() - 1, m_page_keys, _("Keys"));
strings = GetObject()->GetProject()->m_top_entities->ListNames();
new wxStaticText(m_page_general, -1, _("Parent entity"), wxPoint(10,60), wxSize(80,-1), wxALIGN_RIGHT);
c1 = new wxComboBox(m_page_general, -1, wxEmptyString, wxPoint(100,60), wxSize(200,-1), 0, NULL, wxCB_READONLY | wxCB_SORT);
new wxStaticText(m_page_general, -1, _("Child entity"), wxPoint(10,85), wxSize(80,-1), wxALIGN_RIGHT);
c2 = new wxComboBox(m_page_general, -1, wxEmptyString, wxPoint(100,85), wxSize(200,-1), 0, NULL, wxCB_READONLY | wxCB_SORT);
while (strings[idx]) {
c1->Append(*strings[idx]);
c2->Append(*strings[idx]);
idx++;
}
delete [] strings;
r3 = new wxRadioBox(m_page_general, -1, _("Type"), wxPoint(10,110), wxSize(-1,-1), 3, m_type_str, 2, wxRA_HORIZONTAL);
r4 = new wxRadioBox(m_page_general, -1, _("Parent Parciality"), wxPoint(10,190), wxSize(-1,-1), 2, m_parciality_str, 1, wxRA_HORIZONTAL);
r5 = new wxRadioBox(m_page_general, -1, _("Child Parciality"), wxPoint(200,190), wxSize(-1,-1), 2, m_parciality_str, 1, wxRA_HORIZONTAL);
m_button_apply = AddButton(wxID_APPLY, _("Apply"), wxSize(60,-1));
if (m_edit) {
m_button_ok->SetDefault();
} else {
m_button_apply->SetDefault();
m_page_keys->Disable();
}
if (m_edit) {
c1->Disable();
c2->Disable();
}
}
DBRelationEditor::~DBRelationEditor()
{
}
bool DBRelationEditor::TransferDataFromWindow()
{
DBRelation *object = (DBRelation *)GetObject();
DBObjectEditor::TransferDataFromWindow();
if (! m_edit) {
object->m_parent = c1->GetValue();
object->m_child = c2->GetValue();
}
object->m_type = r3->GetSelection();
object->m_parciality_parent = r4->GetSelection();
object->m_parciality_child = r5->GetSelection();
object->m_refinteg_parent_update = c6->FindString(c6->GetValue());
object->m_refinteg_parent_delete = c7->FindString(c7->GetValue());
object->m_refinteg_child_insert = c8->FindString(c8->GetValue());
object->m_refinteg_child_update = c9->FindString(c9->GetValue());
object->m_refinteg_match = r10->GetSelection();
return TRUE;
}
bool DBRelationEditor::TransferDataToWindow()
{
DBRelation *object = (DBRelation *)GetObject();
DBObjectEditor::TransferDataToWindow();
c1->SetValue(object->m_parent);
c2->SetValue(object->m_child);
r3->SetSelection(object->m_type);
r4->SetSelection(object->m_parciality_parent);
r5->SetSelection(object->m_parciality_child);
c6->SetValue(c6->GetString(object->m_refinteg_parent_update));
c7->SetValue(c7->GetString(object->m_refinteg_parent_delete));
c8->SetValue(c8->GetString(object->m_refinteg_child_insert));
c9->SetValue(c9->GetString(object->m_refinteg_child_update));
r10->SetSelection(object->m_refinteg_match);
return TRUE;
}
bool DBRelationEditor::Validate()
{
bool res = DBObjectEditor::Validate();
if (res == FALSE)
return res;
if (c1->GetValue().IsEmpty() || c2->GetValue().IsEmpty()) {
wxMessageBox(_("Missing name(s) of linked table(s)"), _("Error"), wxOK | wxICON_ERROR);
return FALSE;
}
return TRUE;
}
void DBRelationEditor::OnApply(wxCommandEvent& event)
{
DBRelation *object = (DBRelation *)GetObject();
if (Validate() == FALSE)
return;
TransferDataFromWindow();
object->AppendItem();
m_list_keys->SetContainer(object->m_keys);
m_page_keys->Enable();
m_button_apply->Disable();
m_button_ok->SetDefault();
m_edit = TRUE;
}
/*
* Container
*/
DBRelationContainer::DBRelationContainer(DataDesignerProject *project, const wxTreeItemId& parent)
: DataDesignerContainer(project, parent, "relations")
{
}
DBObject *DBRelationContainer::CreateObject()
{
return new DBRelation(GetProject(), this);
}
void DBRelationContainer::ShowList()
{
SetList(new DBRelationListCtrl(GetProject()->GetSplitter(), this));
DataDesignerContainer::AddObjectsToListAndShow();
}
/*
* ObjectList
*/
DBRelationListCtrl::DBRelationListCtrl(wxWindow *parent, DataDesignerContainer *container)
: DBObjectListCtrl(parent, container)
{
SetColumnWidth(0, 200);
InsertColumn(1, _("Parent entity"));
SetColumnWidth(1, 150);
InsertColumn(2, _("Child entity"));
SetColumnWidth(2, 150);
}
DBRelationListCtrl::~DBRelationListCtrl()
{
}
void DBRelationListCtrl::SetObject(long item, DBObject *object)
{
DBRelation *relation = (DBRelation *)object;
SetItem(item, 1, relation->m_parent);
SetItem(item, 2, relation->m_child);
}
/*
* Shape
*/
DBRelationShape::DBRelationShape(DBRelation *relation)
: wxLineShape()
{
DBObject *entity;
SetClientData(relation);
entity = relation->GetProject()->m_top_entities->GetObjectByName(relation->m_parent);
if (entity)
m_shape_from = entity->GetShape();
else {
wxLogMessage("no parent");
return;
}
entity = relation->GetProject()->m_top_entities->GetObjectByName(relation->m_child);
if (entity)
m_shape_to = entity->GetShape();
else {
wxLogMessage("no child");
return;
}
SetPen(wxBLACK_PEN);
SetBrush(wxRED_BRUSH);
AddArrow(ARROW_ARROW, ARROW_POSITION_END, 20);
MakeLineControlPoints(2);
SetDisableLabel(TRUE);
m_shape_from->AddLine(this, m_shape_to);
wxClientDC dc(m_shape_from->GetCanvas());
m_shape_from->Move(dc, m_shape_from->GetX(), m_shape_from->GetY());
m_shape_to->Move(dc, m_shape_to->GetX(), m_shape_to->GetY());
}
syntax highlighted by Code2HTML, v. 0.9.1