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
////////////////////////////////////////////////////////////////////////////////
26
#include "messagedialog.h"
28
#include "tripleclassbox.h"
29
#include "doubleclassbox.h"
32
#include "binaryrelationship.h"
33
#include "componentfunction.h"
34
#include "isarelationship.h"
35
#include "modejunction.h"
36
#include "emptyedge.h"
37
#include "miniellipse.h"
40
#include "crdiagram.h"
43
CRDiagram::CRDiagram(Config *c, CRWindow *d, CRViewer *v, CRGraph *g):
44
ERDiagram(c, d, v, g) {
47
crChecks = new CRChecks(this, g);
50
CRDiagram::~CRDiagram() {
54
Thing *CRDiagram::CreateThing(int classNr) {
55
Grafport *g = GetDiagramViewer()->GetGrafport();
56
ShapeView *v = GetDiagramViewer()->GetCurView();
57
CRGraph *cg = (CRGraph *)GetGraph();
60
if (classNr == Code::VIEW)
61
thing = new ShapeView(GetDiagramViewer());
64
else if (classNr==Code::TRIPLE_BOX)
65
thing = new TripleClassBox(v, g, 0, 0);
66
else if (classNr==Code::DOUBLE_BOX)
67
thing = new DoubleClassBox(v, g, 0, 0);
68
else if (classNr==Code::BOX)
69
thing = new Box(v, g, 0, 0);
70
else if (classNr == Code::MINI_ELLIPSE) {
71
MiniEllipse *ellipse = new MiniEllipse(v, g, 0, 0);
72
// extra for older diagram versions.
73
ellipse->SetFixedName(False);
76
else if (classNr==Code::TEXT_BOX)
77
thing = new TextBox(v, g, 0, 0);
80
else if (classNr==Code::T1_LINE)
81
thing = new C1Arrow(v, g, 0, 0, 0);
82
else if (classNr==Code::T4_LINE || classNr==Code::C2R2_LINE)
83
thing = new C2R2Line(v, g, 0, 0, 0);
84
else if (classNr==Code::LINE)
85
thing = new Line(v, g, 0, 0, 0);
87
// (T1_)ARROW and DOUBLE_ARROW from old file formats.
88
else if (classNr==Code::T1_ARROW)
89
thing = new C1Arrow(v, g, 0, 0, 0);
90
else if (classNr==Code::ARROW) {
91
Line *line = new Line(v, g, 0, 0, 0);
92
line->SetEnd2(LineEnd::FILLED_ARROW);
93
line->SetFixedName(True);
96
else if (classNr==Code::DOUBLE_ARROW) {
97
Line *line = new Line(v, g, 0, 0, 0);
98
line->SetEnd1(LineEnd::FILLED_ARROW);
99
line->SetEnd2(LineEnd::FILLED_ARROW);
104
else if (classNr==Code::CLASS_NODE)
105
thing = new ClassNode(cg);
106
else if (classNr==Code::TAXONOMY_JUNCTION)
107
thing = new TaxonomyJunction(cg);
108
else if (classNr==Code::MODE_JUNCTION)
109
thing = new ModeJunction(cg);
110
else if (classNr==Code::COMMENT)
111
thing = new Comment(cg);
114
else if (classNr==Code::BINARY_RELATIONSHIP)
115
thing = new BinaryRelationship(cg, 0, 0);
116
else if (classNr==Code::FUNCTION)
117
thing = new Function(cg, 0, 0);
118
else if (classNr==Code::COMPONENT_FUNCTION)
119
thing = new ComponentFunction(cg, 0, 0);
120
else if (classNr==Code::EMPTY_EDGE)
121
thing = new EmptyEdge(cg, 0, 0);
122
else if (classNr==Code::ISA_RELATIONSHIP)
123
thing = new IsaRelationship(cg, 0, 0);
125
error("%s, line %d: impl error: wrong class number %d\n",
126
__FILE__, __LINE__, classNr);
130
Node *CRDiagram::CreateNode(){
132
CRGraph *g = (CRGraph *)GetGraph();
133
if (GetNodeType()==Code::MODE_JUNCTION)
134
node = new ModeJunction(g);
135
else if (GetNodeType()==Code::TAXONOMY_JUNCTION)
136
node = new TaxonomyJunction(g);
137
else if (GetNodeType()==Code::CLASS_NODE)
138
node = new ClassNode(g);
139
else if (GetNodeType()==Code::COMMENT)
140
node = new Comment(g);
142
error( "%s, line %d: impl error: unknown node type\n",
147
Edge *CRDiagram::CreateEdge(Subject *subj1, Subject *subj2){
148
if (!CheckEdgeConstraints(subj1, subj2))
151
CRGraph *g = (CRGraph *)GetGraph();
152
if (GetEdgeType() == Code::EMPTY_EDGE)
153
edge = new EmptyEdge(g, subj1, subj2);
154
else if (GetEdgeType() == Code::FUNCTION)
155
edge = new Function(g, subj1, subj2);
156
else if (GetEdgeType() == Code::BINARY_RELATIONSHIP)
157
edge = new BinaryRelationship(g, subj1, subj2);
158
else if (GetEdgeType() == Code::COMPONENT_FUNCTION)
159
edge = new ComponentFunction(g, subj1, subj2);
160
else if (GetEdgeType() == Code::ISA_RELATIONSHIP)
161
edge = new IsaRelationship(g, subj1, subj2);
163
error( "%s, line %d: impl error: unknown edge type\n",
166
if (GetEdgeType() == Code::EMPTY_EDGE ||
167
GetEdgeType() == Code::ISA_RELATIONSHIP) {
168
if (!CheckIsaLoop(edge) || !CheckTaxonomyCombination(edge)) {
176
NodeShape *CRDiagram::CreateNodeShape(Node *node, int x, int y) {
177
NodeShape *shape = 0;
178
Grafport *g = GetDiagramViewer()->GetGrafport();
179
ShapeView *v = GetDiagramViewer()->GetCurView();
180
if (GetNodeShapeType() == Code::BOX)
181
shape = new Box(v, g, x, y);
182
else if (GetNodeShapeType() == Code::MINI_ELLIPSE) {
183
shape = new MiniEllipse(v, g, x, y);
184
shape->SetFixedName(False);
186
else if (GetNodeShapeType() == Code::DOUBLE_BOX)
187
shape = new DoubleClassBox(v, g, x, y);
188
else if (GetNodeShapeType() == Code::TEXT_BOX)
189
shape = new TextBox(v, g, x, y);
190
else if (GetNodeShapeType() == Code::TRIPLE_BOX)
191
shape = new TripleClassBox(v, g, x, y);
193
error( "%s, line %d: impl error: "
194
"node shape type doesn't exist\n", __FILE__, __LINE__);
197
shape->SetSubject(node);
198
shape->SetTextShape();
203
Line *CRDiagram::CreateLine(
204
Edge *edge, GShape *from, GShape *to, List<Point *> *l) {
205
Grafport *g = GetDiagramViewer()->GetGrafport();
206
ShapeView *v = GetDiagramViewer()->GetCurView();
208
if (GetLineType()== Code::T1_LINE)
209
line = new C1Arrow(v, g, from, to, l, IsCurve());
210
else if (GetLineType()== Code::C2R2_LINE)
211
line = new C2R2Line(v, g, from, to, l, IsCurve());
212
else if (GetLineType()== Code::LINE)
213
line = new Line(v, g, from, to, l, IsCurve());
215
error( "%s, line %d: impl error: "
216
"line type does not exist\n", __FILE__, __LINE__);
219
line->SetSubject(edge);
220
line->SetTextShape();
221
line->SetEnd1(GetLineEnd1());
222
line->SetEnd2(GetLineEnd2());
223
if (GetEdgeType()==Code::EMPTY_EDGE ||
224
GetEdgeType()==Code::ISA_RELATIONSHIP)
225
line->SetFixedName(True);
226
if (GetLineEnd1()==LineEnd::FILLED_ARROW) {
227
if (edge->GetClassType()==Code::FUNCTION) {
229
((Function *)edge)->SetConstraint(&constr);
236
void CRDiagram::UpdateNodeType(int num) {
237
((DiagramWindow *)GetMainWindow())->SetNodeName(num);
239
case 1: SetNodeType(Code::CLASS_NODE);
240
SetNodeShapeType(Code::BOX);
241
SetNodeLineStyle(LineStyle::SOLID);
243
case 2: SetNodeType(Code::CLASS_NODE);
244
SetNodeShapeType(Code::DOUBLE_BOX);
245
SetNodeLineStyle(LineStyle::SOLID);
247
case 3: SetNodeType(Code::CLASS_NODE);
248
SetNodeShapeType(Code::TRIPLE_BOX);
249
SetNodeLineStyle(LineStyle::SOLID);
251
case 4: SetNodeType(Code::TAXONOMY_JUNCTION);
252
SetNodeShapeType(Code::MINI_ELLIPSE);
253
SetNodeLineStyle(LineStyle::SOLID);
255
case 5: SetNodeType(Code::MODE_JUNCTION);
256
SetNodeShapeType(Code::MINI_ELLIPSE);
257
SetNodeLineStyle(LineStyle::DASHED);
259
case 6: SetNodeType(Code::COMMENT);
260
SetNodeShapeType(Code::TEXT_BOX);
261
SetNodeLineStyle(LineStyle::INVISIBLE);
264
error("%s, line %d: impl error: "
265
"unknown node type selected\n", __FILE__,__LINE__);
269
void CRDiagram::UpdateEdgeType(int num) {
270
((DiagramWindow *)GetMainWindow())->SetEdgeName(num);
272
case 1: SetEdgeType(Code::BINARY_RELATIONSHIP);
273
SetLineType(Code::C2R2_LINE);
274
SetEdgeLineStyle(LineStyle::SOLID);
275
SetLineEnd1(LineEnd::EMPTY);
276
SetLineEnd2(LineEnd::EMPTY);
278
case 2: SetEdgeType(Code::FUNCTION);
279
SetLineType(Code::T1_LINE);
280
SetEdgeLineStyle(LineStyle::SOLID);
281
SetLineEnd1(LineEnd::EMPTY);
282
SetLineEnd2(LineEnd::FILLED_ARROW);
284
case 3: SetEdgeType(Code::COMPONENT_FUNCTION);
285
SetLineType(Code::T1_LINE);
286
SetEdgeLineStyle(LineStyle::DASHED);
287
SetLineEnd1(LineEnd::EMPTY);
288
SetLineEnd2(LineEnd::FILLED_ARROW);
290
case 4: SetEdgeType(Code::ISA_RELATIONSHIP);
291
SetLineType(Code::LINE);
292
SetEdgeLineStyle(LineStyle::SOLID);
293
SetLineEnd1(LineEnd::EMPTY);
294
SetLineEnd2(LineEnd::FILLED_ARROW);
296
case 5: SetEdgeType(Code::EMPTY_EDGE);
297
SetLineType(Code::LINE);
298
SetEdgeLineStyle(LineStyle::SOLID);
299
SetLineEnd1(LineEnd::EMPTY);
300
SetLineEnd2(LineEnd::EMPTY);
302
case 6: SetEdgeType(Code::FUNCTION);
303
SetLineType(Code::LINE);
304
SetEdgeLineStyle(LineStyle::SOLID);
305
SetLineEnd1(LineEnd::FILLED_ARROW);
306
SetLineEnd2(LineEnd::FILLED_ARROW);
309
error("%s, line %d: impl error: "
310
"unknown edge type selected\n", __FILE__,__LINE__);
314
bool CRDiagram::SetText(TextShape *t, const string *s) {
315
const string *d = t->GetDescription();
316
Subject *subj = t->GetParent()->GetSubject();
317
if (*d == "Attribute" && subj->GetClassType()==Code::CLASS_NODE)
318
return SetAttribute((ClassNode *)subj, s, t->GetSequence());
319
else if (*d == "Operation" && subj->GetClassType()==Code::CLASS_NODE)
320
return SetOperation((ClassNode *)subj, s, t->GetSequence());
322
return ERDiagram::SetText(t, s);
325
void CRDiagram::MakeErrorMessage(ClassNode *cl,
326
ClassNode::TextErrType result,
327
const string *s, string *txt) {
328
*txt = "class '" + *cl->GetName() + "' ";
329
if (result == ClassNode::ATTRIBUTE_EXISTS)
330
*txt += "already has an attribute '" + *s + "'";
331
else if (result == ClassNode::OPERATION_EXISTS)
332
*txt += "already has an operation '" + *s + "'";
333
else if (result == ClassNode::FUNCTION_EXISTS)
334
*txt += "already has a function '" + *s + "'";
335
else if (result == ClassNode::COMPONENT_EXISTS)
336
*txt += "already has a component function '" + *s + "'";
337
else if (result == ClassNode::RELATION_EXISTS)
338
*txt += "is already engaged in binary relationship '" + *s + "'";
339
else if (result == ClassNode::IMPOSSIBLE_ATTRIBUTE)
340
*txt = "'" + *s + "' wrong syntax\nfor an attribute declaration";
341
else if (result == ClassNode::IMPOSSIBLE_OPERATION)
342
*txt = "'" + *s + "' wrong syntax\nfor an operation declaration";
345
bool CRDiagram::SetAttribute(ClassNode *cl, const string *s, unsigned nr) {
346
List<GShape *> shapes;
347
GetDiagramViewer()->GetShapes(cl, &shapes);
349
// split string in different strings (separated by newline).
350
// each string becomes a new attribute.
352
char *str = (char *)ss.getstr();
353
char *x = strtok(str, "\r");
358
string *ns = new string(x);
360
ClassNode::TextErrType result;
362
result = cl->SetAttribute(ns, m, True);
364
result = cl->SetAttribute(ns, m, False);
368
MakeErrorMessage(cl, result, ns, &txt);
369
if (result != ClassNode::MEMBER_OK) {
370
ShowDialog(MessageDialog::ERROR, "Error", &txt);
371
// delete the newly created attributes.
373
for (shapes.first(); !shapes.done(); shapes.next()) {
374
if (shapes.cur()->GetClassType() != Code::BOX) {
376
(DoubleBox *)(shapes.cur());
377
if (db->NrLabels()-1 == m)
378
db->UpdateLabel(ns, m, update);
384
// update the double box shapes.
385
for (shapes.first(); !shapes.done(); shapes.next()) {
386
if (shapes.cur()->GetClassType() != Code::BOX)
387
((DoubleBox *)shapes.cur())->
388
UpdateLabel(ns, m, update);
390
if (!shapes.first()) {
391
error( "%s, line %d: impl error: "
392
"shape does not exist!\n", __FILE__, __LINE__);
402
bool CRDiagram::SetOperation(ClassNode *cl, const string *s, unsigned nr) {
403
List<GShape *> shapes;
404
GetDiagramViewer()->GetShapes(cl, &shapes);
406
char *str = (char *)ss.getstr();
409
char *x = strtok(str, "\r");
413
string *ns = new string(x);
415
ClassNode::TextErrType result;
417
result = cl->SetOperation(ns, m, True);
420
result = cl->SetOperation(ns, m, False);
424
MakeErrorMessage(cl, result, ns, &txt);
425
if (result != ClassNode::MEMBER_OK) {
426
ShowDialog(MessageDialog::ERROR, "Error", &txt);
427
// delete the newly created operations.
429
for (shapes.first(); !shapes.done(); shapes.next()) {
430
if (shapes.cur()->GetClassType() ==
433
(TripleBox *)(shapes.cur());
434
if (tb->NrLabels2()-1 == m)
435
tb->UpdateLabel2(ns, m, update);
441
// update the triple box shapes.
442
for (shapes.first(); !shapes.done(); shapes.next()) {
443
if (shapes.cur()->GetClassType() == Code::TRIPLE_BOX)
444
((TripleBox *)shapes.cur())->
445
UpdateLabel2(ns, m, update);
447
if (!shapes.first()) {
448
error( "%s, line %d: impl error: "
449
"shape does not exist!\n", __FILE__, __LINE__);
459
void CRDiagram::CheckDocument() {
462
// Check that binary relationships are named.
463
total += crChecks->CheckNamelessBinaryRelationships(chkbuf);
465
total += crChecks->CheckDoubleNamelessEdges(
466
Code::BINARY_RELATIONSHIP, Code::CLASS_NODE,
467
Code::CLASS_NODE, chkbuf);
468
// Check that classes are named.
469
total += crChecks->CheckNamelessNodes(Code::CLASS_NODE, chkbuf);
470
// double nodes can occur after cut-copy-paste
471
total += crChecks->CheckDoubleNodes(Code::CLASS_NODE, chkbuf);
472
// Check that functions and component functions are identifiable.
473
total += crChecks->CheckDoubleNamelessFunctions(
474
Code::CLASS_NODE, Code::CLASS_NODE, chkbuf);
475
// Check that tax. and mode junctions are connected correctly.
476
total += crChecks->CheckJunctionCoherence(
477
Code::TAXONOMY_JUNCTION, Code::ISA_RELATIONSHIP,
478
Code::EMPTY_EDGE, 2, chkbuf);
479
total += crChecks->CheckJunctionCoherence(
480
Code::MODE_JUNCTION, Code::ISA_RELATIONSHIP,
481
Code::EMPTY_EDGE, 2, chkbuf);
482
// Check that classes have not 1 comp. function.
483
total += crChecks->CheckCountEdgesFrom(
484
Code::CLASS_NODE, Code::COMPONENT_FUNCTION, 2, INT_MAX,
485
True, False, chkbuf);
486
// Check that rel. classes are not spec. of classes.
487
total += crChecks->CheckRelationshipIsaClassNode(chkbuf);
488
ReportCheck(total, &chkbuf);
491
bool CRDiagram::CheckTaxonomyCombination(Edge *edge) {
492
// checks if adding the edge does not make a static partition
493
// (with tax.junction) part of a dynamic partition (with modejunction).
494
int eType = edge->GetClassType();
495
Subject *n1 = edge->GetSubject1();
496
Subject *n2 = edge->GetSubject2();
497
int n1Type = n1->GetClassType();
498
int n2Type = n2->GetClassType();
500
if (eType == Code::EMPTY_EDGE) {
502
if (n1Type == Code::CLASS_NODE &&
503
n2Type == Code::MODE_JUNCTION)
505
else if (n1Type == Code::MODE_JUNCTION &&
506
n2Type == Code::CLASS_NODE)
509
List<Subject *> edges;
510
GetGraph()->GetEdges(&edges, Code::ISA_RELATIONSHIP);
511
for (edges.first(); !edges.done(); edges.next()) {
512
Edge *e = (Edge *)edges.cur();
513
if (nX == e->GetSubject2()) {
514
int t=e->GetSubject1()->GetClassType();
515
if (t == Code::CLASS_NODE ||
516
t == Code::TAXONOMY_JUNCTION)
522
else if (eType == Code::ISA_RELATIONSHIP) {
523
if (n1Type == Code::CLASS_NODE ||
524
n1Type == Code::TAXONOMY_JUNCTION) {
525
List<Subject *> edges;
526
GetGraph()->GetEdges(&edges, Code::EMPTY_EDGE);
527
for (edges.first(); !edges.done(); edges.next()) {
528
Edge *e = (Edge *)edges.cur();
529
if (n2==e->GetSubject1()) {
530
if (e->GetSubject2()->GetClassType() ==
534
else if (n2==e->GetSubject2()) {
535
if (e->GetSubject1()->GetClassType() ==
543
string txt = "Dynamic specialization (with ModeJunction) cannot "
544
"be specialized\n into a static specialization "
545
"(with TaxonomyJunction)";
546
ShowDialog(MessageDialog::ERROR, "Error", &txt);