1
////////////////////////////////////////////////////////////////////////////////
3
// This file is part of Toolkit for Conceptual Modeling (TCM).
4
// (c) copyright 2001, Universiteit Twente.
5
// Author: Frank Dehne (frank@cs.vu.nl),
6
// David N. Jansen (dnjansen@cs.utwente.nl)
7
// Rik Eshuis (eshuis@cs.utwente.nl)
8
// Jose Canete (canete@lsi.us.es)
10
// TCM is free software; you can redistribute it and/or modify
11
// it under the terms of the GNU General Public License as published by
12
// the Free Software Foundation; either version 2 of the License, or
13
// (at your option) any later version.
15
// TCM is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU General Public License for more details.
20
// You should have received a copy of the GNU General Public License
21
// along with TCM; if not, write to the Free Software
22
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24
////////////////////////////////////////////////////////////////////////////////
29
#include "commentlink.h"
30
#include "scdiagram.h"
31
#include "roundedbox.h"
32
#include "scdandstatebox.h"
33
#include "scdorstate.h"
34
#include "scdandstate.h"
35
#include "scdandedge.h"
36
#include "scdtransitionedge.h"
37
#include "scdandline.h"
40
#include "minidiamond.h"
41
#include "solidhorizontalbar.h"
42
#include "solidverticalbar.h"
45
#include "scddefaultstate.h"
46
#include "scdfinalstate.h"
47
#include "scddecisionstate.h"
48
#include "scdsynchronizationstate.h"
52
#include "modelcheckdialog.h"
57
#include "outputfile.h"
59
#include "adsmcoutputparse.h"
60
#include "adsedgelabelparse.h"
66
SCDiagram::SCDiagram(Config *c, SCWindow *d, SCViewer *v, SCGraph *g):
70
// GetReplaceDialog()->ManageNameOnlyToggle(True);
71
// scChecks = new SCChecks(this,g);
73
promptDialog = new ModelCheckDialog(GetMainWindow()->GetWidget());
74
promptDialog->Initialize();
79
SCDiagram::~SCDiagram() {
87
/* virtual */ void SCDiagram::Initialize() {
88
Diagram::Initialize();
93
Thing *SCDiagram::CreateThing(int classNr) {
94
Grafport *g = GetDiagramViewer()->GetGrafport();
95
ShapeView *v = GetDiagramViewer()->GetCurView();
96
SCGraph *sg = (SCGraph *)GetGraph();
101
thing = new ShapeView(GetDiagramViewer());
105
case Code::ROUNDED_BOX:
106
thing = new RoundedBox(v, g, 0, 0);
108
case Code::SCD_AND_STATE_BOX:
109
thing = new SCDAndStateBox(v, g, 0, 0);
112
thing = new TextBox(v, g, 0, 0);
114
case Code::BLACK_DOT:
115
thing = new BlackDot(v, g, 0, 0);
117
case Code::BULLS_EYE:
118
thing = new BullsEye(v, g, 0, 0);
120
case Code::MINI_DIAMOND:
121
thing = new MiniDiamond(v, g, 0, 0);
123
case Code::SOLID_HORIZONTAL_BAR:
124
thing = new SolidHorizontalBar(v, g, 0, 0);
126
case Code::SOLID_VERTICAL_BAR:
127
thing = new SolidVerticalBar(v, g, 0, 0);
130
thing = new NoteBox(v, g, 0, 0);
135
thing = new Line(v, g, 0, 0, 0);
138
// Line *line = new Line(v, g, 0, 0, 0);
139
// line->SetEnd1(LineEnd::EMPTY);
140
// line->SetEnd2(LineEnd::FILLED_ARROW);
143
case Code::SCD_AND_LINE:
144
thing = new SCDAndLine(v, g, 0, 0);
148
case Code::SCD_AND_STATE:
149
thing = new SCDAndState(sg);
151
case Code::SCD_DECISION_STATE:
152
thing = new SCDDecisionState(sg);
154
case Code::SCD_DEFAULT_STATE:
155
thing = new SCDDefaultState(sg);
157
case Code::SCD_FINAL_STATE:
158
thing = new SCDFinalState(sg);
160
case Code::SCD_OR_STATE:
161
thing = new SCDOrState(sg);
163
case Code::SCD_SYNCHRONIZATION_STATE:
164
thing = new SCDSynchronizationState(sg);
167
thing = new Comment(sg);
170
thing = new Note(sg);
174
case Code::SCD_TRANSITION_EDGE:
175
thing = new SCDTransitionEdge(sg, 0, 0);
177
case Code::SCD_AND_EDGE:
178
thing = new SCDAndEdge(sg, 0, 0);
180
case Code::COMMENT_LINK:
181
thing = new CommentLink(sg, 0, 0);
184
error("%s, line %d: impl error: "
185
"wrong class number %d\n", __FILE__, __LINE__, classNr);
191
Node *SCDiagram::CreateNode() {
193
SCGraph *sg = (SCGraph *)GetGraph();
194
switch ( GetNodeType() ) {
195
case Code::SCD_AND_STATE:
196
node = new SCDAndState(sg);
198
case Code::SCD_DECISION_STATE:
199
node = new SCDDecisionState(sg);
201
case Code::SCD_DEFAULT_STATE:
202
node = new SCDDefaultState(sg);
204
case Code::SCD_FINAL_STATE:
205
node = new SCDFinalState(sg);
207
case Code::SCD_OR_STATE:
208
node = new SCDOrState(sg);
210
case Code::SCD_SYNCHRONIZATION_STATE:
211
node = new SCDSynchronizationState(sg);
214
node = new Comment(sg);
220
error("%s, line %d: impl error: "
221
"unknown node type\n", __FILE__, __LINE__);
227
Edge *SCDiagram::CreateEdge(Subject *subj1, Subject *subj2){
228
if ( ! CheckEdgeConstraints(subj1, subj2) )
231
SCGraph *sg = (SCGraph *)GetGraph();
232
switch ( GetEdgeType() ) {
233
case Code::SCD_TRANSITION_EDGE:
234
edge = new SCDTransitionEdge(sg, subj1, subj2);
236
case Code::SCD_AND_EDGE:
237
if ( ! CheckAndEdgeConstraints(subj1, subj2) )
239
edge = new SCDAndEdge(sg, subj1, subj2);
241
case Code::COMMENT_LINK:
242
edge = new CommentLink(sg, subj1, subj2);
245
error("%s, line %d: impl error: "
246
"unknown edge type\n", __FILE__, __LINE__);
252
NodeShape *SCDiagram::CreateNodeShape(Node *node, int x, int y) {
253
NodeShape *shape = 0;
254
Grafport *g = GetDiagramViewer()->GetGrafport();
255
ShapeView *v = GetDiagramViewer()->GetCurView();
256
switch ( GetNodeShapeType() ) {
257
case Code::ROUNDED_BOX:
258
shape = new RoundedBox(v, g, x, y);
260
case Code::SCD_AND_STATE_BOX:
261
shape = new SCDAndStateBox(v, g, x, y);
264
shape = new TextBox(v, g, x, y);
267
shape = new NoteBox(v, g, x, y);
269
case Code::BLACK_DOT:
270
shape = new BlackDot(v, g, x, y);
272
case Code::BULLS_EYE:
273
shape = new BullsEye(v, g, x, y);
275
case Code::MINI_DIAMOND:
276
shape = new MiniDiamond(v, g, x, y);
278
case Code::SOLID_HORIZONTAL_BAR:
279
shape = new SolidHorizontalBar(v, g, x, y);
281
case Code::SOLID_VERTICAL_BAR:
282
shape = new SolidVerticalBar(v, g, x, y);
285
error("%s, line %d: impl error: "
286
"node shape type does not exist\n", __FILE__, __LINE__);
289
shape->SetSubject(node);
290
shape->SetTextShape();
296
Line *SCDiagram::CreateLine(
297
Edge *edge, GShape *from, GShape *to, List<Point *> *l) {
299
Grafport *g = GetDiagramViewer()->GetGrafport();
300
ShapeView *v = GetDiagramViewer()->GetCurView();
301
// *((*l)[0]) = *(from->GetPosition());
302
// *((*l)[l->count()-1]) = *(to->GetPosition());
303
switch ( GetLineType() ) {
305
line = new Line(v, g, from, to, l, IsCurve());
307
case Code::SCD_AND_LINE:
308
line = new SCDAndLine(v, g, from, l, IsCurve());
311
error("%s, line %d: impl error: "
312
"line type does not exist\n", __FILE__, __LINE__);
316
line->SetSubject(edge);
317
line->SetTextShape();
318
// line->SetEnd1(GetLineEnd1());
319
line->SetEnd2(GetLineEnd2());
325
void SCDiagram::UpdateNodeType(int num) {
326
((DiagramWindow *)GetMainWindow())->SetNodeName(num);
328
case 1: SetNodeType(Code::SCD_OR_STATE);
329
SetNodeShapeType(Code::ROUNDED_BOX);
331
case 2: SetNodeType(Code::SCD_AND_STATE);
332
SetNodeShapeType(Code::SCD_AND_STATE_BOX);
334
case 3: SetNodeType(Code::SCD_DEFAULT_STATE);
335
SetNodeShapeType(Code::BLACK_DOT);
337
case 4: SetNodeType(Code::SCD_FINAL_STATE);
338
SetNodeShapeType(Code::BULLS_EYE);
340
case 5: SetNodeType(Code::COMMENT);
341
SetNodeShapeType(Code::TEXT_BOX);
343
case 6: SetNodeType(Code::SCD_DECISION_STATE);
344
SetNodeShapeType(Code::MINI_DIAMOND);
346
case 7: SetNodeType(Code::SCD_SYNCHRONIZATION_STATE);
347
SetNodeShapeType(Code::SOLID_HORIZONTAL_BAR);
349
case 8: SetNodeType(Code::SCD_SYNCHRONIZATION_STATE);
350
SetNodeShapeType(Code::SOLID_VERTICAL_BAR);
352
case 9: SetNodeType(Code::NOTE);
353
SetNodeShapeType(Code::NOTE_BOX);
357
error("%s, line %d: impl error: "
358
"unknown node type selected\n", __FILE__,__LINE__);
363
void SCDiagram::UpdateEdgeType(int num) {
364
((DiagramWindow *)GetMainWindow())->SetEdgeName(num);
366
case 1: SetEdgeType(Code::SCD_TRANSITION_EDGE);
367
SetLineType(Code::LINE);
368
SetEdgeLineStyle(LineStyle::SOLID);
369
// SetLineEnd1(LineEnd::EMPTY);
370
SetLineEnd2(LineEnd::FILLED_ARROW);
372
case 2: SetEdgeType(Code::COMMENT_LINK);
373
SetLineType(Code::LINE);
374
SetEdgeLineStyle(LineStyle::WIDE_DOTTED);
375
// SetLineEnd1(LineEnd::EMPTY);
376
SetLineEnd2(LineEnd::EMPTY);
378
case 3: SetEdgeType(Code::SCD_AND_EDGE);
379
SetLineType(Code::SCD_AND_LINE);
380
SetEdgeLineStyle(LineStyle::DASHED);
381
// SetLineEnd1(LineEnd::EMPTY);
382
SetLineEnd2(LineEnd::EMPTY);
385
error("%s, line %d: impl error: "
386
"unknown edge type selected\n", __FILE__,__LINE__);
391
bool SCDiagram::CheckAndEdgeConstraints(Subject *subj1, Subject *subj2) {
392
if ( subj1->GetClassType() != Code::SCD_AND_STATE ) {
393
ShowDialog(MessageDialog::ERROR, "Error",
394
"An and-line must begin at an and-state");
397
if ( subj1 != subj2 ) {
398
ShowDialog(MessageDialog::ERROR, "Error",
399
"An and-line must begin and end at the same state");
403
// ----> Hier toevoegen: check that an and-edge lies inside its and-shape.
410
bool SCDiagram::CheckEdgeConstraints(Subject *subj1, Subject *subj2) {
411
// Check possible connections (subj-subj-edge matrix).
412
if (!CheckConnection(subj1, subj2))
418
//bool SCDiagram::SetEvent(Transition *t, const string *s) {
419
// List<GShape *> shapes;
420
// GetDiagramViewer()->GetShapes(t, &shapes);
421
// Subject::NameErrType n = t->SetEvent(s);
422
// if (n == Subject::OK) {
423
// if (shapes.first())
425
// ((TransitionArrow *)shapes.cur())->UpdateEvent(s);
426
// while (shapes.next());
428
// error("%s, line %d: shape does not exist\n",
429
// __FILE__, __LINE__);
434
// else if (n == Subject::IMPOSSIBLE_NAME) {
435
// string msg = "'" + *s + "' wrong syntax\n for an event string";
436
// ShowDialog(MessageDialog::ERROR, "Error", &msg);
439
// else if (n == Subject::DOUBLE_EDGE) {
440
// string msg = "there is already a transition with\n"
441
// "event string '" + *s + "' between this pair of states";
442
// ShowDialog(MessageDialog::ERROR, "Error", &msg);
446
// error("%s, line %d: case not handled\n", __FILE__, __LINE__);
452
//bool SCDiagram::SetAction(Subject *t, const string *s, unsigned nr) {
453
// List<GShape *> shapes;
454
// GetDiagramViewer()->GetShapes(t, &shapes);
456
// // split string in different one line strings.
458
// char *str = (char *)ss.getstr();
459
// char empty[2] = "";
460
// char *x = strtok(str, "\r");
464
// string *ns = new string(x);
465
// bool update = True;
466
// Subject::NameErrType result;
469
// result = ((Transition *)t)->SetAction(ns, m, True);
471
// result = ((InitialState *)t)->SetAction(ns, m, True);
475
// result = ((Transition *)t)->SetAction(ns, m, False);
477
// result = ((InitialState *)t)->SetAction(ns, m, False);
480
// if (result != Subject::OK) {
482
// if (result == Subject::HAS_ACTION)
483
// msg = "transition already has an action '" + *ns + "'";
485
// msg = "'" + *ns + "' wrong syntax\n for an action string";
486
// ShowDialog(MessageDialog::ERROR, "Error", &msg);
487
// // make actions empty.
490
// for (shapes.first(); !shapes.done(); shapes.next()) {
492
// ((TransitionArrow *)shapes.cur())->
493
// UpdateAction(ns, m, update);
495
// ((InitialStateBox *)shapes.cur())->
496
// UpdateAction(ns, m, update);
502
// // update the shapes.
503
// if (shapes.first())
506
// ((TransitionArrow *)shapes.cur())->
507
// UpdateAction(ns, m, update);
509
// ((InitialStateBox *)shapes.cur())->
510
// UpdateAction(ns, m, update);
511
// } while (shapes.next());
513
// error("%s, line %d: shape does not exist\n",
514
// __FILE__, __LINE__);
518
// x = strtok(0, "\r");
525
//InitialState *SCDiagram::FindInitialState(Subject *state) {
526
// if (state->GetClassType() == Code::INITIAL_STATE)
527
// return (InitialState *)state;
528
// List<Subject *> initStates;
529
// GetGraph()->GetNodes(&initStates, Code::INITIAL_STATE);
530
// for (initStates.first(); !initStates.done(); initStates.next()) {
531
// InitialState *init = (InitialState *)initStates.cur();
532
// if (GetGraph()->UndirectedPathExists(init, state))
539
void SCDiagram::CheckDocument() {
542
// total += scChecks->CheckNamelessNodes(Code::INITIAL_STATE, chkbuf);
543
// total += scChecks->CheckNamelessNodes(Code::STATE, chkbuf);
544
// total += scChecks->CheckNamelessNodes(Code::DECISION_POINT, chkbuf);
545
// total += scChecks->CheckDoubleNodes(Code::STATE, chkbuf);
546
// total += scChecks->CheckDoubleNodes(Code::DECISION_POINT, chkbuf);
547
// total += scChecks->CheckDoubleEvents(chkbuf);
548
// total += scChecks->CheckEmptyEvents(chkbuf);
549
// total += scChecks->CheckEmptyActions(chkbuf);
550
// total += scChecks->CheckNoActions(chkbuf);
551
// total += scChecks->CheckCountEdgesFrom(Code::DECISION_POINT,
552
// Code::TRANSITION, 2, INT_MAX, False, False, chkbuf);
553
// int sub = scChecks->CheckNodeCount(1, Code::INITIAL_STATE, chkbuf);
556
// total += scChecks->CheckReachability(
557
// Code::INITIAL_STATE, Code::STATE, False, chkbuf);
558
// total += scChecks->CheckReachability(
559
// Code::INITIAL_STATE, Code::DECISION_POINT, False, chkbuf);
561
ReportCheck(total, &chkbuf);
566
void SCDiagram::ModelCheckProperty() {
567
SetStatus("action: model check document semantics");
568
promptDialog->SetTitle("Model check document semantics");
569
promptDialog->SetOKCallback(ModelCheckDocumentOKCB, this);
570
promptDialog->Popup();
574
/* static */ void SCDiagram::ModelCheckDocumentOKCB(Widget,
575
XtPointer clientData, XtPointer)
577
SCDiagram *scd = (SCDiagram *)clientData;
578
string formula, internal, clock;
579
scd->promptDialog->GetFormulaString(&formula);
580
scd->promptDialog->GetInternString(&internal);
581
scd->promptDialog->GetClockString(&clock);
582
scd->DoModelCheckDocument(&internal, &formula, &clock);
586
//void SCDiagram::DoModelCheckDocument(const string *internal,
587
// const string *formula, const string *clock)
589
// SetStatus("action: model check document semantics");
590
// GetMainWindow()->SetCursor(MouseCursor::WATCH);
592
//tmpModel = "model";
593
//// GetViewer()->GetPrinter()->MakeTmpFile(&tmpModel);
594
// tmpModel += ".smv";
595
//std::cerr << "Temporary model file: " << tmpModel.getstr() << "\n";
597
// SaveForModelChecker(&tmpModel, internal, clock, formula);
598
// bool ok = ExecuteModelChecker(&tmpModel, formula);
599
// GetMainWindow()->SetCursor(MouseCursor::LEFT_PTR);
600
//// unlink(tmpModel.getstr());
602
// SetStatus("model checking aborted");
604
// SetStatus("model checking completed");
609
void SCDiagram::DoModelCheckDocument(const string *internal,
610
const string *formula, const string *clock)
612
SetStatus("action: model check document semantics");
613
GetMainWindow()->SetCursor(MouseCursor::WATCH);
616
// GetViewer()->GetPrinter()->MakeTmpFile(&tmpModel);
618
std::cout << "Temporary model file: " << tmpModel.getstr() << '\n';
620
OutputFile *ofile2= new OutputFile();
621
ofile2->Open(&tmpModel);
622
SCGraph *scg=(SCGraph *)this->GetGraph();
623
scg->WriteNuSMV(ofile2,True);
625
(*ofile2) << "\nSPEC\n" << f<< "\n";
628
// SaveForModelChecker(&tmpModel, internal, clock, formula);
629
// bool ok = ExecuteModelChecker(&tmpModel, formula);
631
GetMainWindow()->SetCursor(MouseCursor::LEFT_PTR);
636
// unlink(tmpModel.getstr());
638
// SetStatus("model checking aborted");
640
// SetStatus("model checking completed");
646
strcpy(output,"XXXXXX");
647
(void)mktemp(output); // replaces the six X's with a string that can be used to create a unique file name
649
string command = "NuSMV model.smv > ";
650
string outputfile= output;
651
outputfile += ".out";
653
command = command + outputfile;
654
std::cout << "Executing command\t" << command;
655
system(command.getstr()); // do the actual model checking
660
// parse the model checker's output
661
::adsmcoutputin=fopen(outputfile.getstr(),"r");
668
for (int i=0; i<2000; i++) ::isStable[i]= 0;
670
bool b=adsmcoutputparse();
672
error("I couldn't parse the model checker's output\n");
678
mctxt="The requirement is satisfied\n";
679
ShowDialog(MessageDialog::MESSAGE, "Notice", &mctxt);
682
mctxt="The requirement is not satisfied; see the counter example\n";
683
ShowDialog(MessageDialog::MESSAGE, "Notice", &mctxt);
684
AbstractSequenceDiagram *asd= GenerateAbstractSequenceDiagram();
685
ConcreteSequenceDiagram *csd= GenerateConcreteSeqDiag(asd);
686
GenerateSeqDiagFile(csd, formula);
689
GetMainWindow()->SetCursor(MouseCursor::LEFT_PTR);
690
unlink(output); // cleanup buf
692
// unlink(buf); // cleanup if wanted
697
void SCDiagram::SaveForModelChecker(const string *path, const string *internal,
698
const string * clock, const string *formula) {
699
/* Split internal into a list of strings */
700
List<string> intevent;
702
const char *cp = internal->getstr();
704
while ( *cp && isspace(*cp) )
716
while ( *++ep && ! isspace(*ep) && '[' != *ep )
719
event.add(cp, ep - cp);
725
// SCDSMV s(GetGraph());
726
// s.WriteSMV(path->getstr(), &intevent, formula);
730
bool SCDiagram::ExecuteModelChecker(const string *path, const string *formula) {
736
List<SCDTransitionEdge *> SCDiagram::ComputeMicroStep (SCGraph *gr, int state)
738
/* This function takes the graph and the number of a state in the NuSMV counterexample trace. It computes the
739
transitions to be fired from state to state+1, i.e., the transitions in the microstep.
740
Please note that the states are numbered from 0 to ::statecounter-1.
744
// state refers to an state of the Kripke structure
748
List<SCDTransitionEdge *> enabledTrans, step;
749
List<Subject *> hedges;
762
if (state >=0 && state < ::statecounter){
770
while ((i<(::enabledindex))&&(enabledstatenumber[i]<state))
772
if (enabledstatenumber[i]>state) // if there is no enabled transition in the specified state of the Kripke Structure (KS)
775
// Now enabledhyperedge[i] (and possibly some of its followers) is an enabled transition in KS state.
776
// We collect all the corresponding SCDTransitionEdge objects in the list "enabledTrans",
777
// using the information contained in enabledhyperedge (which come from the NuSMV output).
779
gr->GetEdges(&hedges);
782
for (int k=i; k<(::enabledindex) && enabledstatenumber[k]==state; k++){
783
for (hedges.first();!hedges.done();hedges.next()){
784
if ((int)hedges.cur()->GetId()==enabledhyperedge[k]){
785
enabledTrans.add((SCDTransitionEdge *)hedges.cur()); // the enabled hyperedges in "state"
786
break; // hyperedge found, so abort loop
791
// Now enabledTrans contains all the enabled transitions in the specified state.
793
ntrans= enabledTrans.count();
796
for (int et=0; et< ntrans; et++){ //for each enabled transition et
798
// We will infer if the transition is taken as in Chan's paper:
799
// - in the next state, its target is set to one
800
// - in the next state, the possible action event is set to one
802
// First we look for the states which are true in the next state.
803
// Remember that in targetname we have all the states which are true in the trace.
806
while (st < targetindex && !found)
807
if (targetstatenumber[st]==nextState)
811
// Now in targetname[st] (and possibly, in some of its followers) we have a state that will been entered in the next state
813
// We check if the target state of et is in the set of states which will been entered in the next state.
815
while (st < targetindex && targetstatenumber[st]==nextState && !found)
816
if (strcmp(targetname[st], enabledTrans[et]->GetSubject2()->GetName()->getstr())==0)
822
if (enabledTrans[et]->GetSendEvent()==NULL) // the transition hasn't send event
824
else { // et has send event
826
// Now we have to check that the possible action event of et is sent in the next state.
829
while (ev < eventIndex && !found)
830
if (occurredEventStates[ev]==nextState)
835
// Now in occurredEvents[ev] (and possibly, in the followers) we have an event which will occur in the next state of the KS.
836
// We check that the send event of et is in the set of occurred events in the next state of the KS.
838
while (ev < eventIndex && occurredEventStates[ev]==nextState && !found)
839
if (strcmp(occurredEvents[ev], enabledTrans[et]->GetSendEvent()->GetName().getstr())==0)
852
if (fired) //then we add the transition to the step
853
step.add (enabledTrans[et]);
863
AbstractSequenceDiagram * SCDiagram::GenerateAbstractSequenceDiagram ()
866
AbstractSequenceDiagram *asd;
867
int currentState; // current state of the Kripke structure
868
int formerState; // state of the Kripke structure where the last processed event was produced
869
int ev; // counter for events
870
InteractionRow * row;
874
List<SCDTransitionEdge *> step;
877
theGraph= (SCGraph *)GetGraph();
880
asd= new AbstractSequenceDiagram;
882
asd->AddParticipant(str);
884
asd->AddParticipant(str);
889
for (ev=0; ev<eventIndex; ev++){
891
// First let's see if ev is really an event (note that it can also be stable (from stable = 1),
892
// events (from events = 1), and so on. If it is an event, it will be in the property list of the graph
893
// and will have an appropiate type.
894
prop= theGraph->EventInPropl(occurredEvents[ev]);
895
if (prop && (prop->GetType()==::EV_FROM_ENV ||
896
prop->GetType()==::EV_TO_ENV ||
897
prop->GetType()==::EV_INT)){ //ok, it is an event!
898
currentState= ::occurredEventStates[ev];
899
if (formerState != currentState) //we need a new row!
900
row= asd->AddRow(currentState); //add a new row with the correct number of columns; it also returns the row
902
// row is the current row in which we have to include the event
903
if (prop->GetType()==::EV_FROM_ENV)
904
row->participants[0].AddPairObjEv(1,prop->GetName());
905
else if (prop->GetType()==::EV_TO_ENV)
906
row->participants[1].AddPairObjEv(0,prop->GetName());
908
row->participants[1].AddPairObjEv(1, prop->GetName());
909
step= ComputeMicroStep (theGraph, currentState-1); //computes the fired transitions from
910
// the KR states currentState-1 to currentState.
911
// With this, we get the transitions that have been fired. The event ev must be in the
912
// action part of some transition in the set. We have to check if it is EV_INT_BC in that
914
if (IsBroadcast (prop->GetName(), step))
915
row->participants[1].AddPairObjEv(0, prop->GetName());
917
formerState= currentState;
927
bool SCDiagram::IsBroadcast (string event, List<SCDTransitionEdge *> step)
933
while (i< step.count() && !found){
934
if (step[i]->GetSendEvent()){ //it has send event
935
prop= step[i]->GetSendEvent();
936
if (prop->GetName()==event && prop->GetType()==::EV_INT_BC)
952
ConcreteSequenceDiagram * SCDiagram::GenerateConcreteSeqDiag (AbstractSequenceDiagram *asd)
954
ConcreteSequenceDiagram *csd;
955
ConcreteParticipant *cp;
957
InteractionParticipant *ip;
963
int formerState, currentState;
965
string microstep= "-----------------microstep-----------------";
966
string stable= "------------------stable-------------------";
972
if (asd==NULL) return NULL;
974
csd= new ConcreteSequenceDiagram;
978
// First we create all the ConcreteParticipants, in the same order as in AbstractSequenceDiagram.
979
// note that this is just the trivial ordering, but it is possible also to have other layouts (different orderings
980
// of the participants).
981
for (i=0; i< asd->numObjs; i++){
982
cp= new ConcreteParticipant();
983
cp->name= asd->objNames[i];
984
cp->logicalId= csd->NextId();
985
cp->shapeId= csd->NextId();
986
cp->y= 50; //we set all the objects to a height of 50
987
cp->x= 120+i*280; //this way every object will be horizontally separated by 280 units from its neighbours.
988
csd->participants.add (cp);
991
// Now we travel across all the happened events.
992
// We create StimulusInfo objects for the list of stimuli, and
993
// we attach those stimuli to the concrete participants created
995
for (i=0; i< asd->rows.count(); i++){
998
// A microstep begins in the diagram. We add the proper comment.
999
// Note that it's simulating a false message from the first participant
1000
// to the last one. This way the comment extends over all the objects.
1001
// Note that we do not add the stimuli in the anchor lists of the objects,
1002
// as it is not an anchor.
1003
sinf= new StimulusInfo();
1004
sinf->sender= csd->participants[0];
1005
sinf->receiver= csd->participants[csd->participants.count()-1];
1006
sinf->label= stable;
1007
sinf->logicalId= csd->NextId();
1008
sinf->shapeId= csd->NextId();
1009
stimY= 110; // initial position in the temporal line
1011
sinf->isComment= True;
1012
csd->stimuli.add (sinf);
1018
formerState= currentState= row->GetCurrentState();
1020
formerState= currentState;
1021
currentState= row->GetCurrentState();
1027
while (k<=currentState && !found){
1035
sinf= new StimulusInfo();
1036
sinf->sender= csd->participants[0];
1037
sinf->receiver= csd->participants[csd->participants.count()-1];
1038
sinf->label= stable;
1039
sinf->logicalId= csd->NextId();
1040
sinf->shapeId= csd->NextId();
1043
sinf->isComment= True;
1044
csd->stimuli.add (sinf);
1048
for (j=0; j< asd->numObjs; j++){
1049
ip= &(row->participants[j]);
1050
for (ev=0; ev< ip->GetNumberOfEvents(); ev++){
1051
pair= ip->GetPairObjEv (ev);
1052
sinf= new StimulusInfo();
1053
sinf->sender= csd->participants[j];
1054
sinf->receiver= csd->participants[pair->GetObj()];
1055
sinf->label= pair->GetEv();
1056
sinf->logicalId= csd->NextId();
1057
sinf->shapeId= csd->NextId();
1060
sinf->isComment= False;
1062
stim1= new Stimulus();
1063
stim2= new Stimulus();
1064
stim1->isSender= True;
1065
stim2->isSender= False;
1069
csd->participants[j]->anchors.add (stim1); //Sender
1070
if (j!=pair->GetObj()) // if it is not an event to self
1071
csd->participants[pair->GetObj()]->anchors.add (stim2); //Receiver
1073
csd->stimuli.add (sinf);
1074
} //end of loop in ev
1075
} //end of loop in j
1077
// We add a new comment to mark the end of the microstep or the stability of the system.
1078
sinf= new StimulusInfo();
1079
sinf->sender= csd->participants[0];
1080
sinf->receiver= csd->participants[csd->participants.count()-1];
1081
sinf->label= microstep;
1082
sinf->logicalId= csd->NextId();
1083
sinf->shapeId= csd->NextId();
1086
sinf->isComment= True;
1087
csd->stimuli.add (sinf);
1088
} //end of loop in i
1090
if (::isStable[::statecounter-1]){ //The system finishes stable
1091
sinf= new StimulusInfo();
1092
sinf->sender= csd->participants[0];
1093
sinf->receiver= csd->participants[csd->participants.count()-1];
1094
sinf->label= stable;
1095
sinf->logicalId= csd->NextId();
1096
sinf->shapeId= csd->NextId();
1099
sinf->isComment= True;
1100
csd->stimuli.add (sinf);
1103
csd->lineLength= stimY+50;
1111
void SCDiagram::GenerateSeqDiagFile (ConcreteSequenceDiagram *csd, const string *formula)
1114
string filen= "cntex.sqd";
1118
if (csd==NULL) return;
1120
fp= new OutputFile();
1123
(*fp) << "Storage\n";
1125
(*fp) << "\t{ Format 1.32 }\n";
1126
(*fp) << "\t{ GeneratedFrom TSCD-version-2.10a }\n";
1127
(*fp) << "\t{ WrittenBy tcm }\n";
1128
(*fp) << "\t{ WrittenOn \"Sat Jul 6 17:16:35 2002\" }\n";
1130
(*fp) << "Document\n";
1132
(*fp) << "\t{ Type \"Sequence Diagram\" }\n";
1133
(*fp) << "\t{ Name cntex.sqd }\n";
1134
(*fp) << "\t{ Author tcm }\n";
1135
(*fp) << "\t{ CreatedOn \"Sat Jul 6 14:14:12 2002\" }\n";
1136
(*fp) << "\t{ Annotation \"\" }\n";
1140
(*fp) << "\t{ PageOrientation Portrait }\n";
1141
(*fp) << "\t{ PageSize A4 }\n";
1142
(*fp) << "\t{ ShowHeaders False }\n";
1143
(*fp) << "\t{ ShowFooters False }\n";
1144
(*fp) << "\t{ ShowNumbers False }\n";
1148
(*fp) << "\t{ ScaleValue 1 }\n";
1150
(*fp) << "# GRAPH NODES\n\n";
1152
GenerateGraphNodes (csd, fp);
1153
GenerateComments (csd, fp);
1154
GenerateNote (csd, fp, formula);
1155
GenerateGraphEdges (csd, fp);
1158
(*fp) << "# VIEWS AND GRAPHICAL SHAPES\n";
1160
(*fp) << "View 1\n";
1162
(*fp) << "\t{ Index \"0\" }\n";
1163
(*fp) << "\t{ Parent 0 }\n";
1166
GenerateObjectBoxes (csd, fp);
1167
GenerateT4Lines (csd, fp);
1168
GenerateTextBoxes (csd, fp);
1169
GenerateNoteBox (csd, fp);
1178
void SCDiagram::GenerateGraphNodes (ConcreteSequenceDiagram *csd, OutputFile *fp)
1181
ConcreteParticipant *cp;
1185
if (csd==NULL || fp==NULL) return;
1188
for (i=0; i< csd->participants.count(); i++){
1189
cp= csd->participants[i];
1190
(*fp) << "CBDObjectNode " << cp->logicalId << "\n";
1192
(*fp) << "\t{ Name \"" << cp->name << "\" }\n";
1193
(*fp) << "\t{ Annotation \"\" }\n";
1194
(*fp) << "\t{ Parent 0 }\n";
1195
(*fp) << "\t{ Index \"\" }\n";
1196
(*fp) << "\t{ Stereotype \"<< - >>\" }\n";
1197
(*fp) << "\t{ Properties \"{ - }\" }\n";
1198
(*fp) << "\t{ Anchors " << cp->anchors.count() << " }\n"; //it's OK also for 0
1199
for (j=0; j< cp->anchors.count(); j++){
1200
(*fp) << "\t{ Anchor " << cp->anchors[j]->info->y << " ";
1201
if (cp->anchors[j]->isSender)
1202
(*fp) << cp->logicalId; // it puts its own number
1204
(*fp) << cp->anchors[j]->info->sender->logicalId;
1215
void SCDiagram::GenerateComments (ConcreteSequenceDiagram *csd, OutputFile *fp)
1220
if (csd==NULL || fp==NULL) return;
1223
// We travel across the stimuli and issue a "Comment" section in the file every
1224
// time we find a stimuli with a True isComment attribute.
1226
for (i=0; i< csd->stimuli.count(); i++){
1227
if (csd->stimuli[i]->isComment){
1228
sinf= csd->stimuli[i];
1229
(*fp) << "Comment " << sinf->logicalId << "\n";
1231
(*fp) << "\t{ Name \"" << sinf->label << "\" }\n";
1232
(*fp) << "\t{ Annotation \"\" }\n";
1233
(*fp) << "\t{ Parent 0 }\n";
1234
(*fp) << "\t{ Index \"\" }\n";
1243
void SCDiagram::GenerateGraphEdges (ConcreteSequenceDiagram *csd, OutputFile *fp)
1250
if (csd==NULL || fp==NULL) return;
1252
(*fp) << "# GRAPH EDGES\n\n";
1255
for (i=0; i< csd->stimuli.count(); i++){
1256
if (!csd->stimuli[i]->isComment){ //then it is a real stimulus
1257
sinf= csd->stimuli[i];
1258
(*fp) << "CBDObjectLinkEdge " << sinf->logicalId << "\n";
1260
(*fp) << "\t{ Name \"" << sinf->label << "\" }\n";
1261
(*fp) << "\t{ Annotation \"\" }\n";
1262
(*fp) << "\t{ Parent 0 }\n";
1263
(*fp) << "\t{ Subject1 " << sinf->sender->logicalId << " }\n";
1264
(*fp) << "\t{ Subject2 " << sinf->receiver->logicalId << " }\n";
1265
(*fp) << "\t{ Anchor1 " << sinf->y << " " << sinf->sender->shapeId << " }\n";
1266
(*fp) << "\t{ Anchor2 " << sinf->y << " " << sinf->receiver->shapeId << " }\n";
1275
void SCDiagram::GenerateObjectBoxes (ConcreteSequenceDiagram *csd, OutputFile *fp)
1278
ConcreteParticipant *cp;
1280
if (csd==NULL || fp==NULL) return;
1282
for (i=0; i< csd->participants.count(); i++){
1283
cp= csd->participants[i];
1284
(*fp) << "SSDSingleObjectBox " << cp->shapeId << "\n";
1286
(*fp) << "\t{ View 1 }\n";
1287
(*fp) << "\t{ Subject " << cp->logicalId << " }\n";
1288
(*fp) << "\t{ Position " << cp->x << " " << cp->y << " }\n";
1289
(*fp) << "\t{ Size 80 40 }\n";
1290
(*fp) << "\t{ Color \"black\" }\n";
1291
(*fp) << "\t{ LineWidth 1 }\n";
1292
(*fp) << "\t{ LineStyle Solid }\n";
1293
(*fp) << "\t{ FillStyle Unfilled }\n";
1294
(*fp) << "\t{ FillColor \"white\" }\n";
1295
(*fp) << "\t{ FixedName False }\n";
1296
(*fp) << "\t{ Font \"-*-helvetica-medium-r-normal--10*\" }\n";
1297
(*fp) << "\t{ TextAlignment Center }\n";
1298
(*fp) << "\t{ TextColor \"black\" }\n";
1299
(*fp) << "\t{ NameUnderlined True }\n";
1301
/* We need to know how long will be the lifeline of each object. We have chosen that
1302
all the objects have the same length.
1304
(*fp) << "\t{ EndPosition " << cp->x << " " << csd->lineLength << " }\n";
1305
(*fp) << "\t{ Destructive 0 }\n";
1314
void SCDiagram::GenerateT4Lines (ConcreteSequenceDiagram *csd, OutputFile *fp)
1321
if (csd==NULL || fp==NULL) return;
1324
for (i=0; i< csd->stimuli.count(); i++){
1325
sinf= csd->stimuli[i];
1326
if (!sinf->isComment){
1327
(*fp) << "T4Line " << sinf->shapeId << "\n";
1329
(*fp) << "\t{ View 1 }\n";
1330
(*fp) << "\t{ Subject " << sinf->logicalId << " }\n";
1331
(*fp) << "\t{ FromShape " << sinf->sender->shapeId << " }\n";
1332
(*fp) << "\t{ ToShape " << sinf->receiver->shapeId << " }\n";
1333
(*fp) << "\t{ Curved False }\n";
1334
(*fp) << "\t{ End1 Empty }\n";
1335
(*fp) << "\t{ End2 FilledArrow }\n";
1336
if (sinf->sender==sinf->receiver){ // event to self
1337
// This kind of arrow consists of 4 points.
1338
(*fp) << "\t{ Points 4 }\n";
1339
(*fp) << "\t{ Point " << sinf->sender->x << " " << sinf->y << " }\n";
1340
(*fp) << "\t{ Point " << (sinf->sender->x+20) << " " << sinf->y << " }\n";
1341
(*fp) << "\t{ Point " << (sinf->sender->x+20) << " " << (sinf->y+10) << " }\n";
1342
(*fp) << "\t{ Point " << sinf->sender->x << " " << (sinf->y+10) << " }\n";
1344
else{ //event between two different participants
1345
(*fp) << "\t{ Points 2 }\n";
1346
(*fp) << "\t{ Point " << sinf->sender->x << " " << sinf->y << " }\n";
1347
(*fp) << "\t{ Point " << sinf->receiver->x << " " << sinf->y << " }\n";
1349
// The position of the name is fixed to 140 units from the smallest X of both objects
1350
// and 10 units from the Y, unless it is an event to self. In that case, the offset is 20.
1351
if (sinf->sender->x < sinf->receiver->x)
1352
min= sinf->sender->x;
1354
min= sinf->receiver->x;
1356
if (sinf->sender==sinf->receiver)
1357
(*fp) << "\t{ NamePosition " << (min+20) << " " << (sinf->y-10) << " }\n";
1359
(*fp) << "\t{ NamePosition " << (min+140) << " " << (sinf->y-10) << " }\n";
1360
(*fp) << "\t{ Color \"black\" }\n";
1361
(*fp) << "\t{ LineWidth 1 }\n";
1362
(*fp) << "\t{ LineStyle Solid }\n";
1363
(*fp) << "\t{ FixedName False }\n";
1364
(*fp) << "\t{ Font \"-*-helvetica-medium-r-normal--10*\" }\n";
1365
(*fp) << "\t{ TextAlignment Center }\n";
1366
(*fp) << "\t{ TextColor \"black\" }\n";
1367
(*fp) << "\t{ NameUnderlined False }\n";
1375
void SCDiagram::GenerateTextBoxes (ConcreteSequenceDiagram *csd, OutputFile *fp)
1380
if (csd==NULL || fp==NULL) return;
1382
for (i=0; i< csd->stimuli.count(); i++){
1383
sinf= csd->stimuli[i];
1384
if (sinf->isComment){
1385
(*fp) << "TextBox " << sinf->shapeId << "\n";
1387
(*fp) << "\t{ View 1 }\n";
1388
(*fp) << "\t{ Subject " << sinf->logicalId << " }\n";
1389
(*fp) << "\t{ Position " << (sinf->sender->x+140) << " " << sinf->y << " }\n";
1390
(*fp) << "\t{ Size 20 20 }";
1391
(*fp) << "\t{ Color \"black\" }\n";
1392
(*fp) << "\t{ LineWidth 1 }\n";
1393
(*fp) << "\t{ LineStyle Invisible }\n";
1394
(*fp) << "\t{ FillStyle Unfilled }\n";
1395
(*fp) << "\t{ FillColor \"white\" }\n";
1396
(*fp) << "\t{ FixedName False }\n";
1397
(*fp) << "\t{ Font \"-*-helvetica-medium-r-normal--10*\" }\n";
1398
(*fp) << "\t{ TextAlignment Center }\n";
1399
(*fp) << "\t{ TextColor \"black\" }\n";
1400
(*fp) << "\t{ NameUnderlined False }\n";
1409
void SCDiagram::GenerateNote (ConcreteSequenceDiagram *csd, OutputFile *fp, const string *formula)
1411
if (csd==NULL || fp==NULL || formula==NULL) return;
1413
(*fp) << "Note " << csd->NextId() << "\n";
1415
(*fp) << "\t{ Name \"Counterexample for\\r" << *formula << "\" }\n";
1416
(*fp) << "\t{ Annotation \"\" }\n";
1417
(*fp) << "\t{ Parent 0 }\n";
1418
(*fp) << "\t{ Index \"\" }\n";
1424
void SCDiagram::GenerateNoteBox (ConcreteSequenceDiagram *csd, OutputFile *fp)
1426
if (csd==NULL || fp==NULL) return;
1428
int id= csd->NextId();
1429
int posx= csd->participants[csd->participants.count()-1]->x;
1430
int posy= csd->participants[csd->participants.count()-1]->y;
1432
(*fp) << "NoteBox " << id << "\n";
1434
(*fp) << "\t{ View 1 }\n";
1435
(*fp) << "\t{ Subject " << (id-1) << " }\n";
1436
(*fp) << "\t{ Position " << (posx+160) << " " << posy << " }\n";
1437
(*fp) << "\t{ Size 170 82 }\n"; //Enhacement: calculate the size based on the characters of the formula.
1438
(*fp) << "\t{ Color \"black\" }\n";
1439
(*fp) << "\t{ LineWidth 1 }\n";
1440
(*fp) << "\t{ LineStyle Solid }\n";
1441
(*fp) << "\t{ FillStyle Unfilled }\n";
1442
(*fp) << "\t{ FillColor \"white\" }\n";
1443
(*fp) << "\t{ FixedName False }\n";
1444
(*fp) << "\t{ Font \"-*-helvetica-medium-r-normal--10*\" }\n";
1445
(*fp) << "\t{ TextAlignment Center }\n";
1446
(*fp) << "\t{ TextColor \"black\" }\n";
1447
(*fp) << "\t{ NameUnderlined False }\n";
1451
void InteractionParticipant::AddPairObjEv (int object, string event)
1453
PairObjEv *newPair= new PairObjEv (object, event);
1454
eventsToSend.add (newPair);
1459
void InteractionParticipant::PrintIt ()
1461
std::cout << "Participant:" << std::endl;
1462
for (int i=0; i< eventsToSend.count(); i++)
1463
eventsToSend[i]->PrintIt();
1464
std::cout << std::endl;
1468
void InteractionRow::PrintIt ()
1470
for (int i=0; i< numObj; i++)
1471
participants[i].PrintIt();
1473
std::cout << std::endl;
1477
void AbstractSequenceDiagram::PrintIt ()
1479
for (int t=0; t< rows.count(); t++){
1480
std::cout << "Time " << std::endl;
1486
InteractionRow * AbstractSequenceDiagram::AddRow (int cs)
1488
InteractionRow *ir= new InteractionRow (numObjs, cs);
1497
//bool SCDiagram::SetText(TextShape *t, const string *s) {
1498
// const string *description = t->GetDescription();
1499
// Subject *subj = t->GetParent()->GetSubject();
1500
// if (*description == "Event")
1501
// return SetEvent((Transition *)subj, s);
1502
// else if (*description == "Action")
1503
// return SetAction(subj, s, t->GetSequence());
1505
// return Diagram::SetText(t, s);