1
////////////////////////////////////////////////////////////////////////////////
3
// This file is part of Toolkit for Conceptual Modeling (TCM).
4
// (c) copyright 1995, Vrije Universiteit Amsterdam.
5
// Author: Frank Dehne (frank@cs.vu.nl).
7
// TCM is free software; you can redistribute it and/or modify
8
// it under the terms of the GNU General Public License as published by
9
// the Free Software Foundation; either version 2 of the License, or
10
// (at your option) any later version.
12
// TCM is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
// GNU General Public License for more details.
17
// You should have received a copy of the GNU General Public License
18
// along with TCM; if not, write to the Free Software
19
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21
////////////////////////////////////////////////////////////////////////////////
30
#include "miniellipse.h"
34
#include "entitytype.h"
35
#include "relationshipnode.h"
36
#include "valuetype.h"
37
#include "taxonomyjunction.h"
38
#include "emptyedge.h"
40
#include "binaryrelationship.h"
41
#include "isarelationship.h"
42
#include "messagedialog.h"
43
#include "replacedialog.h"
44
#include "erdiagram.h"
47
ERDiagram::ERDiagram(Config *c, ERWindow *d, ERViewer *v, ERGraph *g):
51
GetReplaceDialog()->ManageNameOnlyToggle(True);
52
GetFindDialog()->ManageNameOnlyToggle(True);
53
erChecks = new ERChecks(this, g);
56
ERDiagram::~ERDiagram() {
60
Thing *ERDiagram::CreateThing(int classNr) {
61
Grafport *g = GetDiagramViewer()->GetGrafport();
62
ShapeView *v = GetDiagramViewer()->GetCurView();
63
ERGraph *eg = (ERGraph *)GetGraph();
66
if (classNr == Code::VIEW)
67
thing = new ERView((ERViewer *)GetDiagramViewer());
69
else if (classNr == Code::BOX)
70
thing = new Box(v, g, 0, 0);
71
else if (classNr == Code::ELLIPSE)
72
thing = new Ellipse(v, g, 0, 0);
73
else if (classNr == Code::MINI_ELLIPSE) {
74
MiniEllipse *ellipse = new MiniEllipse(v, g, 0, 0);
75
// extra for older diagram versions.
76
ellipse->SetFixedName(False);
79
else if (classNr == Code::DIAMOND)
80
thing = new Diamond(v, g, 0, 0);
81
else if (classNr == Code::TEXT_BOX)
82
thing = new TextBox(v, g, 0, 0);
84
else if (classNr == Code::T1_LINE)
85
thing = new C1Arrow(v, g, 0, 0, 0);
86
else if (classNr == Code::T4_LINE || classNr == Code::C2R2_LINE)
87
thing = new C2R2Line(v, g, 0, 0, 0);
88
else if (classNr == Code::LINE)
89
thing = new Line(v, g, 0, 0, 0);
92
else if (classNr == Code::T1_ARROW)
93
thing = new C1Arrow(v, g, 0, 0, 0);
94
else if (classNr == Code::ARROW) {
95
Line *line = new Line(v, g, 0, 0, 0);
96
line->SetFixedName(True);
97
line->SetEnd2(LineEnd::FILLED_ARROW);
100
else if (classNr == Code::DOUBLE_ARROW) {
101
Line *line = new Line(v, g, 0, 0, 0);
102
line->SetEnd1(LineEnd::FILLED_ARROW);
103
line->SetEnd2(LineEnd::FILLED_ARROW);
107
else if (classNr == Code::ENTITY_TYPE)
108
thing = new EntityType(eg);
109
else if (classNr == Code::VALUE_TYPE)
110
thing = new ValueType(eg);
111
else if (classNr == Code::TAXONOMY_JUNCTION)
112
thing = new TaxonomyJunction(eg);
113
else if (classNr == Code::RELATIONSHIP_NODE)
114
thing = new RelationshipNode(eg);
115
else if (classNr == Code::COMMENT)
116
thing = new Comment(eg);
118
else if (classNr == Code::BINARY_RELATIONSHIP)
119
thing = new BinaryRelationship(eg, 0, 0);
120
else if (classNr == Code::FUNCTION)
121
thing = new Function(eg, 0, 0);
122
else if (classNr == Code::EMPTY_EDGE)
123
thing = new EmptyEdge(eg, 0, 0);
124
else if (classNr == Code::ISA_RELATIONSHIP)
125
thing = new IsaRelationship(eg, 0, 0);
127
error("%s, line %d: impl error: "
128
"wrong class number %d\n", __FILE__, __LINE__, classNr);
132
Node *ERDiagram::CreateNode(){
134
ERGraph *eg = (ERGraph *)GetGraph();
135
if (GetNodeType() == Code::TAXONOMY_JUNCTION)
136
node = new TaxonomyJunction(eg);
137
else if (GetNodeType() == Code::VALUE_TYPE)
138
node = new ValueType(eg);
139
else if (GetNodeType() == Code::ENTITY_TYPE)
140
node = new EntityType(eg);
141
else if (GetNodeType() == Code::RELATIONSHIP_NODE)
142
node = new RelationshipNode(eg);
143
else if (GetNodeType() == Code::COMMENT)
144
node = new Comment(eg);
146
error("%s, line %d: impl error: "
147
"unknown node type\n", __FILE__, __LINE__);
153
bool ERDiagram::CheckEdgeConstraints(Subject *subj1, Subject *subj2) {
154
// Check possible connections (subj-subj-edge matrix).
155
if (!CheckConnection(subj1, subj2))
157
int subj1Type = subj1->GetClassType();
158
int subj2Type = subj2->GetClassType();
159
bool isError = False;
160
// Check for double is_a from tax.junction (or modejunction).
161
// Draw a picture for seeing these different cases.
162
if (GetEdgeType()==Code::ISA_RELATIONSHIP &&
163
(subj1Type==Code::TAXONOMY_JUNCTION ||
164
subj1Type==Code::MODE_JUNCTION) &&
165
((ERGraph *)GetGraph())->IsaLeaves(subj1)) {
168
// Check for double is_a between same ent.types (or object classes).
169
else if (GetEdgeType()==Code::ISA_RELATIONSHIP &&
170
(subj1Type==Code::ENTITY_TYPE||subj1Type==Code::CLASS_NODE) &&
171
(subj2Type==Code::ENTITY_TYPE||subj2Type==Code::CLASS_NODE) &&
172
GetGraph()->IsConnected(subj1, subj2, Code::ISA_RELATIONSHIP)) {
175
// Check for double empty_edge from ent. type (or object class) to a
176
// taxonomyjunction (or modejunction).
177
else if ((GetEdgeType()==Code::EMPTY_EDGE &&
178
(subj1Type==Code::ENTITY_TYPE ||
179
subj1Type==Code::CLASS_NODE) &&
180
(subj2Type==Code::TAXONOMY_JUNCTION ||
181
subj2Type==Code::MODE_JUNCTION) &&
182
GetGraph()->IsConnected(subj1, subj2)) ||
183
(GetEdgeType()==Code::EMPTY_EDGE &&
184
(subj2Type==Code::ENTITY_TYPE ||
185
subj2Type==Code::CLASS_NODE) &&
186
(subj1Type==Code::TAXONOMY_JUNCTION||
187
subj1Type==Code::MODE_JUNCTION) &&
188
GetGraph()->IsConnected(subj2, subj1))) {
192
string txt = "Cannot add another ";
193
txt += Code::GetName(GetEdgeType());
195
ShowDialog(MessageDialog::ERROR, "Error", &txt);
201
bool ERDiagram::CheckIsaLoop(Edge *edge) {
202
if (GetEdgeType() == Code::EMPTY_EDGE ||
203
GetEdgeType() == Code::ISA_RELATIONSHIP) {
204
GetGraph()->AddEdge(edge);
205
Subject *n1 = edge->GetSubject1();
206
if (((ERGraph *)GetGraph())->IsaPathExists(n1, n1)) {
207
string txt = "'is_a loops' are not allowed";
208
ShowDialog(MessageDialog::ERROR, "Error", &txt);
209
GetGraph()->RemoveEdge(edge);
212
GetGraph()->RemoveEdge(edge);
217
Edge *ERDiagram::CreateEdge(Subject *n1, Subject *n2){
218
if (!CheckEdgeConstraints(n1, n2))
221
ERGraph *eg = (ERGraph *)GetGraph();
222
if (GetEdgeType() == Code::EMPTY_EDGE)
223
edge = new EmptyEdge(eg, n1, n2);
224
else if (GetEdgeType() == Code::FUNCTION)
225
edge = new Function(eg, n1, n2);
226
else if (GetEdgeType() == Code::BINARY_RELATIONSHIP)
227
edge = new BinaryRelationship(eg, n1, n2);
228
else if (GetEdgeType() == Code::ISA_RELATIONSHIP)
229
edge = new IsaRelationship(eg, n1, n2);
231
error("%s, line %d: impl error: "
232
"unknown edge type\n", __FILE__, __LINE__);
234
if (!CheckIsaLoop(edge)) {
241
NodeShape *ERDiagram::CreateNodeShape(Node *node, int x, int y) {
242
NodeShape *shape = 0;
243
Grafport *g = GetDiagramViewer()->GetGrafport();
244
ShapeView *v = GetDiagramViewer()->GetCurView();
245
if (GetNodeShapeType() == Code::BOX)
246
shape = new Box(v, g, x, y);
247
else if (GetNodeShapeType() == Code::ELLIPSE)
248
shape = new Ellipse(v, g, x, y);
249
else if (GetNodeShapeType() == Code::MINI_ELLIPSE) {
250
shape = new MiniEllipse(v, g, x, y);
251
shape->SetFixedName(False); // tax.junct. is editable
253
else if (GetNodeShapeType() == Code::DIAMOND)
254
shape = new Diamond(v, g, x, y);
255
else if (GetNodeShapeType() == Code::TEXT_BOX)
256
shape = new TextBox(v, g, x, y);
258
error("%s, line %d: impl error: "
259
"node shape type does not exist\n", __FILE__, __LINE__);
262
shape->SetSubject(node);
263
shape->SetTextShape();
268
Line *ERDiagram::CreateLine(
269
Edge *edge, GShape *from, GShape *to, List<Point *> *l) {
270
Grafport *g = GetDiagramViewer()->GetGrafport();
271
ShapeView *v = GetDiagramViewer()->GetCurView();
273
if (GetLineType() == Code::T1_LINE)
274
line = new C1Arrow(v, g, from, to, l, IsCurve());
275
else if (GetLineType() == Code::C2R2_LINE)
276
line = new C2R2Line(v, g, from, to, l, IsCurve());
277
else if (GetLineType() == Code::LINE)
278
line = new Line(v, g, from, to, l, IsCurve());
280
error("%s, line %d: impl error: "
281
"line type does not exist\n", __FILE__, __LINE__);
284
line->SetSubject(edge);
285
line->SetTextShape();
286
line->SetEnd1(GetLineEnd1());
287
line->SetEnd2(GetLineEnd2());
288
if (GetEdgeType()==Code::EMPTY_EDGE ||
289
GetEdgeType()==Code::ISA_RELATIONSHIP)
290
line->SetFixedName(True);
291
if (GetLineEnd1()==LineEnd::FILLED_ARROW) {
292
if (edge->GetClassType()==Code::FUNCTION) {
294
((Function *)edge)->SetConstraint(&constr);
301
void ERDiagram::UpdateNodeType(int num) {
302
((DiagramWindow *)GetMainWindow())->SetNodeName(num);
304
case 1: SetNodeType(Code::ENTITY_TYPE);
305
SetNodeShapeType(Code::BOX);
307
case 2: SetNodeType(Code::VALUE_TYPE);
308
SetNodeShapeType(Code::ELLIPSE);
310
case 3: SetNodeType(Code::TAXONOMY_JUNCTION);
311
SetNodeShapeType(Code::MINI_ELLIPSE);
313
case 4: SetNodeType(Code::RELATIONSHIP_NODE);
314
SetNodeShapeType(Code::DIAMOND);
316
case 5: SetNodeType(Code::COMMENT);
317
SetNodeShapeType(Code::TEXT_BOX);
320
error("%s, line %d: impl error: "
321
"unknown node type selected\n", __FILE__,__LINE__);
325
void ERDiagram::UpdateEdgeType(int num) {
326
((DiagramWindow *)GetMainWindow())->SetEdgeName(num);
328
case 1: SetEdgeType(Code::BINARY_RELATIONSHIP);
329
SetLineType(Code::C2R2_LINE);
330
SetLineEnd1(LineEnd::EMPTY);
331
SetLineEnd2(LineEnd::EMPTY);
333
case 2: SetEdgeType(Code::FUNCTION);
334
SetLineType(Code::T1_LINE);
335
SetLineEnd1(LineEnd::EMPTY);
336
SetLineEnd2(LineEnd::FILLED_ARROW);
338
case 3: SetEdgeType(Code::ISA_RELATIONSHIP);
339
SetLineType(Code::LINE);
340
SetLineEnd1(LineEnd::EMPTY);
341
SetLineEnd2(LineEnd::FILLED_ARROW);
343
case 4: SetEdgeType(Code::EMPTY_EDGE);
344
SetLineType(Code::LINE);
345
SetLineEnd1(LineEnd::EMPTY);
346
SetLineEnd2(LineEnd::EMPTY);
348
case 5: SetEdgeType(Code::FUNCTION);
349
SetLineType(Code::LINE);
350
SetLineEnd1(LineEnd::FILLED_ARROW);
351
SetLineEnd2(LineEnd::FILLED_ARROW);
354
error("%s, line %d: impl error: "
355
"unknown edge type selected\n", __FILE__,__LINE__);
359
bool ERDiagram::SetText(TextShape *t, const string *s) {
360
const string *description = t->GetDescription();
361
Subject *subj = t->GetParent()->GetSubject();
362
if (*description == "Cardinality Constraint")
363
return SetConstraint(subj, s, t->GetSequence());
364
else if (*description == "Role Name")
365
return SetRoleName(subj, s, t->GetSequence()%2);
367
return Diagram::SetText(t, s);
370
bool ERDiagram::SetConstraint(Subject *subject, const string *s, unsigned nr) {
371
List<GShape *> shapes;
372
GetDiagramViewer()->GetShapes(subject, &shapes);
373
bool wrong_syntax = False;
374
Edge *e = (Edge *)subject;
375
int eType = e->GetClassType();
376
if (eType == Code::FUNCTION || eType == Code::COMPONENT_FUNCTION) {
377
Function *edge = (Function *)subject;
378
if (!edge->SetConstraint(s))
381
else if (eType == Code::SSD_PARTICIPANT_LINK_EDGE) {
382
wrong_syntax = !((C1Edge *)subject)->SetConstraint(s);
384
else if (eType == Code::BINARY_RELATIONSHIP ||
385
eType == Code::SSD_BINARY_ASSOCIATION_EDGE ||
386
eType == Code::UCD_BINARY_ASSOCIATION_EDGE ||
387
eType == Code::SSD_AGGREGATION_EDGE ||
388
eType == Code::SSD_COMPOSITION_EDGE ||
389
eType == Code::CBD_CLASS_LINK_EDGE ||
390
eType == Code::CBD_OBJECT_LINK_EDGE) {
391
BinaryRelationship *edge = (BinaryRelationship *)subject;
393
if (!edge->SetConstraint1(s))
397
if (!edge->SetConstraint2(s))
402
string txt = "'" + *s + "' wrong syntax\n for a "
403
"cardinality constraint";
404
ShowDialog(MessageDialog::ERROR, "Error", &txt);
407
if (check(shapes.first())) {
410
((T1Line *)shapes.cur())->UpdateTextShape1(s);
412
((C2R2Line *)shapes.cur())->UpdateTextShape2(s);
414
while (shapes.next());
421
bool ERDiagram::SetRoleName(Subject *subject, const string *s, unsigned nr) {
422
List<GShape *> shapes;
423
GetDiagramViewer()->GetShapes(subject, &shapes);
424
BinaryRelationship *edge = (BinaryRelationship *)subject;
427
if (!edge->SetRoleName1(s))
431
if (!edge->SetRoleName2(s))
435
string txt = "'" + *s + "' is not a possible role name";
436
ShowDialog(MessageDialog::ERROR, "Error", &txt);
439
if (check(shapes.first())) {
441
Shape *shape = shapes.cur();
443
((C2R2Line *)shape)->UpdateTextShape3(s);
445
((C2R2Line *)shape)->UpdateTextShape4(s);
446
} while (shapes.next());
453
void ERDiagram::CheckDocument() {
456
total += erChecks->CheckNamelessBinaryRelationships(chkbuf);
458
total += erChecks->CheckDoubleNamelessEdges(
459
Code::BINARY_RELATIONSHIP, Code::ENTITY_TYPE,
460
Code::ENTITY_TYPE, chkbuf);
461
// all nodes have a name.
462
total += erChecks->CheckNamelessNodes(Code::ENTITY_TYPE, chkbuf);
463
total += erChecks->CheckNamelessNodes(Code::VALUE_TYPE, chkbuf);
464
total += erChecks->CheckNamelessNodes(Code::RELATIONSHIP_NODE, chkbuf);
465
// all functions and relationships are identifiable.
466
total += erChecks->CheckNamelessEdges(
467
Code::FUNCTION, Code::ENTITY_TYPE, Code::VALUE_TYPE, chkbuf);
468
total += erChecks->CheckNamelessEdges(
469
Code::FUNCTION, Code::RELATIONSHIP_NODE, Code::VALUE_TYPE, chkbuf);
470
total += erChecks->CheckDoubleNamelessEdges(
471
Code::FUNCTION, Code::RELATIONSHIP_NODE, Code::ENTITY_TYPE, chkbuf);
472
total += erChecks->CheckDoubleNamelessEdges(
473
Code::FUNCTION, Code::ENTITY_TYPE, Code::ENTITY_TYPE, chkbuf);
474
// double nodes can still occur after cut-copy-paste
475
total += erChecks->CheckDoubleNodes(Code::ENTITY_TYPE, chkbuf);
476
total += erChecks->CheckConnected(Code::VALUE_TYPE, False, chkbuf);
477
total += erChecks->CheckJunctionCoherence(
478
Code::TAXONOMY_JUNCTION, Code::ISA_RELATIONSHIP,
479
Code::EMPTY_EDGE, 2, chkbuf);
480
total += erChecks->CheckRelationshipCoherence(chkbuf);
481
total += erChecks->CheckDoubleRelationships(chkbuf);
482
ReportCheck(total, &chkbuf);