1
////////////////////////////////////////////////////////////////////////////////
3
// This file is part of Toolkit for Conceptual Modeling (TCM).
4
// (c) copyright 1997, 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 "diagramchecks.h"
28
DiagramChecks::DiagramChecks(Diagram *d, Graph *g) {
33
unsigned DiagramChecks::CheckCount(unsigned min, unsigned max,
34
int type, string &chkbuf, bool node) {
38
total = graph->GetNodes(&s, type);
40
total = graph->GetEdges(&s, type);
41
if (total < min || total > max) {
42
chkbuf += "* Error: diagram has ";
45
chkbuf += Code::GetName(type);
49
diagram->SelectSubjects(&s);
55
unsigned DiagramChecks::CheckNodeCount(unsigned count, int nodeType,
57
return CheckNodeCount(count, count, nodeType, chkbuf);
60
unsigned DiagramChecks::CheckNodeCount(unsigned min, unsigned max,
61
int nodeType, string &chkbuf) {
62
return CheckCount(min, max, nodeType, chkbuf, True);
65
unsigned DiagramChecks::CheckEdgeCount(unsigned count, int edgeType,
67
return CheckEdgeCount(count, count, edgeType, chkbuf);
70
unsigned DiagramChecks::CheckEdgeCount(unsigned min, unsigned max,
71
int edgeType, string &chkbuf) {
72
return CheckCount(min, max, edgeType, chkbuf, False);
76
unsigned DiagramChecks::CheckNamelessNodes(int nodeType, string &chkbuf) {
78
return CheckIllegalNodeNames(nodeType, &empty, chkbuf);
81
unsigned DiagramChecks::CheckNamelessEdges(int nodeType, string &chkbuf) {
83
return CheckIllegalEdgeNames(nodeType, &empty, chkbuf);
86
unsigned DiagramChecks::CheckIllegalNodeNames(int nodeType,
87
const string *name, string &chkbuf) {
88
return CheckIllegalNames(nodeType, name, chkbuf, True);
91
unsigned DiagramChecks::CheckIllegalEdgeNames(int edgeType,
92
const string *name, string &chkbuf) {
93
return CheckIllegalNames(edgeType, name, chkbuf, False);
96
unsigned DiagramChecks::CheckIllegalNames(int type, const string *name,
97
string &chkbuf, bool node) {
101
total = graph->GetNodes(&s, name, type);
103
total = graph->GetEdges(&s, name, type);
105
chkbuf += "* Error: there ";
106
if (total == 1) chkbuf += "is "; else chkbuf += "are ";
109
chkbuf += Code::GetName(type);
117
chkbuf += " without name";
119
chkbuf += " named '";
124
diagram->SelectSubjects(&s);
130
unsigned DiagramChecks::CheckNamelessEdges(int edgeType,
131
int subjectType1, int subjectType2, string &chkbuf) {
132
List<Subject *> edges;
135
graph->GetEdges(&edges, &empty, edgeType);
136
for (edges.first(); !edges.done(); edges.next()){
137
Edge *edge = (Edge *)edges.cur();
138
Subject *subject1 = edge->GetSubject1();
139
Subject *subject2 = edge->GetSubject2();
140
if (subject1->GetClassType() == subjectType1 &&
141
subject2->GetClassType() == subjectType2) {
142
chkbuf += "* Error: there is an unnamed ";
143
chkbuf += Code::GetName(edgeType);
144
chkbuf += " between ";
145
chkbuf += Code::GetName(subjectType1);
147
chkbuf += *subject1->GetName();
150
chkbuf += Code::GetName(subjectType2);
152
chkbuf += *subject2->GetName();
155
diagram->SelectSubject(edge);
161
unsigned DiagramChecks::CheckDoubleNamelessEdges(
162
int edgeType, int subjType1, int subjType2, string &chkbuf) {
165
List<Subject *> subjs_from;
166
List<Subject *> subjs_to;
167
List<Subject *> edges;
168
graph->GetNodes(&subjs_from, subjType1);
169
if (subjs_from.count() == 0)
170
graph->GetEdges(&subjs_from, subjType1);
171
graph->GetNodes(&subjs_to, subjType2);
172
if (subjs_to.count() == 0)
173
graph->GetEdges(&subjs_to, subjType2);
175
for (subjs_from.first(); !subjs_from.done(); subjs_from.next()) {
176
Subject *subj1 = subjs_from.cur();
177
for (subjs_to.first(); !subjs_to.done(); subjs_to.next()) {
178
Subject *subj2 = subjs_to.cur();
179
graph->GetEdges(&edges, subj1, subj2, &empty,
181
unsigned count = edges.count();
183
chkbuf += "* Error: there are ";
185
chkbuf += " unnamed ";
186
chkbuf += Code::GetName(edgeType);
188
chkbuf += " between ";
189
chkbuf += Code::GetName(subjType1);
191
chkbuf += *subj1->GetName();
194
chkbuf += Code::GetName(subjType2);
196
chkbuf += *subj2->GetName();
199
diagram->SelectSubjects(&edges);
207
unsigned DiagramChecks::CheckDoubleNodes(int nodeType, string &chkbuf) {
209
List<Subject *> nodes;
210
List<string> strings_got;
211
graph->GetNodes(&nodes, nodeType);
212
for (nodes.first(); !nodes.done(); nodes.next()) {
213
Subject *node = nodes.cur();
214
string name = *node->GetName();
215
if (name != "" && strings_got.find(name) == -1) {
217
unsigned card = graph->GetNodes(&s, &name, nodeType);
219
chkbuf += "* Error: there are ";
222
chkbuf += Code::GetName(nodeType);
224
chkbuf += " named '";
228
diagram->SelectSubjects(&s);
230
strings_got.add(name);
236
unsigned DiagramChecks::CheckConnected(int nodeType, bool index, string &chkbuf) {
238
List<Subject *> nodes;
239
List<Subject *> edges;
240
graph->GetNodes(&nodes, nodeType);
241
for (nodes.first(); !nodes.done(); nodes.next()) {
242
Subject *node = nodes.cur();
243
graph->CompleteSubject(&edges, node);
244
if (edges.count() < 1) {
245
chkbuf += "* Error: ";
246
chkbuf += Code::GetName(nodeType);
248
if (index && !node->IsEdge())
249
chkbuf += *((Node *)node)->GetIndex();
252
chkbuf += *node->GetName();
255
chkbuf += " is not connected\n";
257
diagram->SelectSubject(node);
264
unsigned DiagramChecks::CheckConnected(int fromType, int toType, int min, int max,
265
bool index, string &chkbuf) {
267
List<Subject *> subjects;
268
List<Subject *> edges;
269
List<Subject *> subjects2;
270
graph->GetNodes(&subjects, fromType);
271
for (subjects.first(); !subjects.done(); subjects.next()) {
272
Subject *subject = subjects.cur();
273
graph->CompleteSubject(&edges, subject);
275
for (edges.first(); !edges.done(); edges.next()) {
276
Edge *edge = (Edge *)edges.cur();
278
if (edge->GetSubject1()==subject)
279
s2 = edge->GetSubject2();
281
s2 = edge->GetSubject1();
282
if (s2->GetClassType()==toType)
286
if (n<min || n>max) {
287
chkbuf += "* Error: ";
288
chkbuf += Code::GetName(fromType);
290
if (index && !subject->IsEdge())
291
chkbuf += *((Node *)subject)->GetIndex();
294
chkbuf += *subject->GetName();
299
chkbuf += " times connected to some ";
300
chkbuf += Code::GetName(toType);
303
chkbuf += " (it should be ";
305
chkbuf += "at least ";
309
chkbuf += "at most ";
312
chkbuf += " times)\n";
313
diagram->SelectSubject(subject);
314
diagram->SelectSubjects(&subjects2);
323
unsigned DiagramChecks::CheckJunctionCoherence(int nodeType, int parenttype,
324
int childtype, unsigned minChildren, string &chkbuf) {
326
unsigned unconnected = 0;
327
unsigned no_parent = 0;
328
unsigned no_child = 0;
329
unsigned few_child = 0;
330
unsigned double_parent = 0;
331
// Check for not properly connected junctions.
332
List<Subject *> nodes;
333
List<Subject *> edges;
334
List<Subject *> errorNodes;
335
graph->GetNodes(&nodes, nodeType);
336
for (nodes.first(); !nodes.done(); nodes.next()) {
337
Subject *node = nodes.cur();
338
graph->CompleteSubject(&edges, node);
339
// count nr. of parent and child edges.
343
for (edges.first(); !edges.done(); edges.next()) {
344
Edge *e = (Edge *)edges.cur();
345
if (parenttype != childtype) {
346
if (e->GetClassType() == parenttype)
348
else if (e->GetClassType() == childtype)
352
if (e->GetClassType() == parenttype) {
353
if (e->GetSubject1()==node)
355
else if (e->GetSubject2()==node)
360
if (parent == 0 && child == 0) {
364
else if (parent == 0) {
368
else if (child == 0) {
372
else if (child < minChildren) {
376
else if (parent > 1) {
382
errorNodes.add(node);
386
if (unconnected != 0) {
387
chkbuf += "* Error: there ";
388
if (unconnected == 1) chkbuf += "is "; else chkbuf += "are ";
389
chkbuf += unconnected;
390
chkbuf += " unconnected ";
391
chkbuf += Code::GetName(nodeType);
392
if (unconnected != 1)
397
chkbuf += "* Error: there ";
398
if (no_child == 1) chkbuf += "is "; else chkbuf += "are ";
401
chkbuf += Code::GetName(nodeType);
404
chkbuf += " not connected by some ";
405
chkbuf += Code::GetName(childtype);
408
if (no_parent != 0) {
409
chkbuf += "* Error: there ";
410
if (no_parent == 1) chkbuf += "is "; else chkbuf += "are ";
413
chkbuf += Code::GetName(nodeType);
416
chkbuf += " not connected by a single ";
417
chkbuf += Code::GetName(parenttype);
420
if (few_child != 0) {
421
chkbuf += "* Error: there ";
422
if (few_child == 1) chkbuf += "is "; else chkbuf += "are ";
425
chkbuf += Code::GetName(nodeType);
428
chkbuf += " connected by too few ";
429
chkbuf += Code::GetName(childtype);
433
if (double_parent != 0) {
434
chkbuf += "* Error: there ";
435
if (double_parent == 1) chkbuf += "is "; else chkbuf += "are ";
436
chkbuf += double_parent;
438
chkbuf += Code::GetName(nodeType);
439
if (double_parent != 1)
441
chkbuf += " connected by more than one ";
442
chkbuf += Code::GetName(parenttype);
445
diagram->SelectSubjects(&errorNodes);
449
unsigned DiagramChecks::CheckCountEdgesFrom(int nType, int eType, unsigned min,
450
unsigned max, bool zero_allowed, bool index, string &chkbuf) {
452
List<Subject *> nodes;
453
List<Subject *> edges;
454
graph->GetNodes(&nodes, nType);
455
graph->GetEdges(&edges, eType);
456
for (nodes.first(); !nodes.done(); nodes.next()) {
458
Subject *subject = (Subject *)(nodes.cur());
459
for (edges.first(); !edges.done(); edges.next()) {
460
Edge *e = (Edge *)edges.cur();
461
if (e->GetSubject1() == subject)
464
if ((n > max || n < min) && (!zero_allowed || n > 0)) {
465
chkbuf += "* Error: ";
466
chkbuf += Code::GetName(nType);
468
if (index && !subject->IsEdge())
469
chkbuf += *((Node *)subject)->GetIndex();
472
chkbuf += *subject->GetName();
477
chkbuf += " departing ";
478
chkbuf += Code::GetName(eType);
481
chkbuf += " (it should be ";
483
chkbuf += "at least ";
487
chkbuf += "at most ";
491
diagram->SelectSubject(subject);
498
unsigned DiagramChecks::CheckReachability(
499
int rootType, int nodeType, bool index, string &chkbuf) {
501
unsigned unnamed = 0;
502
List<Subject *> roots, nodes;
503
graph->GetNodes(&roots, rootType);
504
graph->GetNodes(&nodes, nodeType);
505
// look for each node if there is a path from one of the
507
for (nodes.first(); !nodes.done(); nodes.next()) {
508
bool pathFound = False;
509
Node *node = (Node *)nodes.cur();
510
for (roots.first(); !roots.done(); roots.next()) {
511
Node *root = (Node *)roots.cur();
512
if (graph->PathExists(root, node))
516
// do not report unnamed nodes individually.
517
diagram->SelectSubject(node);
518
if (!index && *node->GetName() == "") {
523
chkbuf += "* Error: ";
524
chkbuf += Code::GetName(nodeType);
527
chkbuf += *node->GetIndex();
530
chkbuf += *node->GetName();
533
chkbuf += " is not reachable from some ";
534
chkbuf += Code::GetName(rootType);
539
// report about the number of unnamed unreachable nodes found.
541
chkbuf += "* Error: there ";
542
if (total == 1) chkbuf += "is "; else chkbuf += "are ";
544
chkbuf += " unnamed ";
545
chkbuf += Code::GetName(nodeType);
548
chkbuf += " unreachable from some ";
549
chkbuf += Code::GetName(rootType);
555
unsigned DiagramChecks::CheckDoubleIndexes(string &chkbuf) {
557
List<Subject *> nodes;
558
List<Subject *> nodes2;
559
List<string> strings_got;
560
graph->GetNodes(&nodes);
561
for (nodes.first(); !nodes.done(); nodes.next()) {
562
Node *node = (Node *)nodes.cur();
563
const string *s = node->GetIndex();
564
if (*s != "" && strings_got.find(*s) == -1) {
566
graph->GetNodes(&nodes2);
567
List<Subject *> errorNodes;
568
for (nodes2.first(); !nodes2.done(); nodes2.next()) {
569
Node *n = (Node *) nodes2.cur();
570
if (*n->GetIndex() == *s) {
578
chkbuf += "* Error: there are ";
580
chkbuf += " nodes having index ";
583
diagram->SelectSubjects(&errorNodes);