///////////////////////////////////////////////////////////////////////////// // 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 #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 #endif #include #include #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()); }