~ubuntu-branches/ubuntu/utopic/tcm/utopic

« back to all changes in this revision

Viewing changes to src/sd/fv/dfdiagram.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2003-07-03 20:08:21 UTC
  • Revision ID: james.westby@ubuntu.com-20030703200821-se4xtqx25e5miczi
Tags: upstream-2.20
ImportĀ upstreamĀ versionĀ 2.20

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
////////////////////////////////////////////////////////////////////////////////
 
2
//
 
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).
 
6
//
 
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.
 
11
//
 
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.
 
16
//
 
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
 
20
// 02111-1307, USA.
 
21
////////////////////////////////////////////////////////////////////////////////
 
22
#include "dfgraph.h"
 
23
#include "dfviewer.h"
 
24
#include "dfwindow.h"
 
25
#include "dfstubs.h"
 
26
#include "dfchecks.h"
 
27
#include "line.h"
 
28
#include "messagedialog.h"
 
29
#include "replacedialog.h"
 
30
#include "texteditdialog.h"
 
31
#include "externalentity.h"
 
32
#include "dataprocess.h"
 
33
#include "datastore.h"
 
34
#include "splitmergenode.h"
 
35
#include "bidirectionaldataflow.h"
 
36
#include "dfdiagram.h"
 
37
#include "textbox.h"
 
38
#include "square.h"
 
39
#include "circle.h"
 
40
#include "horizontalbar.h"
 
41
#include "blackdot.h"
 
42
#include "comment.h"
 
43
#include <ctype.h>
 
44
#include <stdlib.h>
 
45
 
 
46
DFDiagram::DFDiagram(Config *c, DFWindow *d, DFViewer *v, DFGraph *g): 
 
47
                Diagram(c,d,v,g) {
 
48
        UpdateNodeType(1);
 
49
        UpdateEdgeType(1);
 
50
        GetReplaceDialog()->ManageNameOnlyToggle(True);
 
51
        editProcess = 0;
 
52
        dfChecks = new DFChecks(this,g);
 
53
        minispecDialog = new TextEditDialog(GetMainWindow()->GetWidget());
 
54
        minispecDialog->Initialize();
 
55
        minispecDialog->SetTitle("Minispec Editor");
 
56
        minispecDialog->SetCancelCallback(0, 0);
 
57
        minispecDialog->SetOKCallback(DFStubs::MinispecOKCB, this);
 
58
        minispecDialog->SetTextSize(12, 60);
 
59
}
 
60
 
 
61
DFDiagram::~DFDiagram() {
 
62
        delete minispecDialog;
 
63
        delete dfChecks;
 
64
}
 
65
 
 
66
Thing *DFDiagram::CreateThing(int classNr) {
 
67
        Grafport *g = GetDiagramViewer()->GetGrafport();
 
68
        ShapeView *v = GetDiagramViewer()->GetCurView();
 
69
        DFGraph *dg = (DFGraph *)GetGraph();
 
70
        Thing *thing = 0;
 
71
        // view
 
72
        if (classNr == Code::VIEW)
 
73
                thing = new ShapeView(GetDiagramViewer());
 
74
        // node shapes
 
75
        else if (classNr == Code::SQUARE)
 
76
                thing = new Square(v, g, 0, 0);
 
77
        else if (classNr == Code::HORIZONTAL_BAR)
 
78
                thing = new HorizontalBar(v, g, 0, 0);
 
79
        else if (classNr == Code::CIRCLE) {
 
80
                Circle *c = new Circle(v, g, 0, 0);
 
81
                c->SetFixedIndexLabel(False);
 
82
                thing = c;
 
83
        }
 
84
        else if (classNr == Code::BLACK_DOT)
 
85
                thing = new BlackDot(v, g, 0, 0);
 
86
        else if (classNr == Code::TEXT_BOX)
 
87
                thing = new TextBox(v, g, 0, 0);
 
88
        // lines
 
89
        else if (classNr == Code::LINE)
 
90
                thing = new Line(v, g, 0, 0, 0);
 
91
        else if (classNr == Code::ARROW) {
 
92
                Line *line = new Line(v, g, 0, 0, 0);
 
93
                line->SetEnd1(LineEnd::EMPTY);
 
94
                line->SetEnd2(LineEnd::FILLED_ARROW);
 
95
                thing = line;
 
96
        }
 
97
        else if (classNr == Code::DOUBLE_ARROW) {
 
98
                Line *line = new Line(v, g, 0, 0, 0);
 
99
                line->SetEnd1(LineEnd::FILLED_ARROW);
 
100
                line->SetEnd2(LineEnd::FILLED_ARROW);
 
101
                thing = line;
 
102
        }
 
103
        // nodes
 
104
        else if (classNr == Code::EXTERNAL_ENTITY)
 
105
                thing = new ExternalEntity(dg);
 
106
        else if (classNr == Code::DATA_STORE)
 
107
                thing = new DataStore(dg);
 
108
        else if (classNr == Code::DATA_PROCESS)
 
109
                thing = new DataProcess(dg);
 
110
        else if (classNr == Code::SPLIT_MERGE_NODE)
 
111
                thing = new SplitMergeNode(dg);
 
112
        else if (classNr == Code::COMMENT)
 
113
                thing = new Comment(dg);
 
114
        // edges
 
115
        else if (classNr == Code::DATA_FLOW)
 
116
                thing = new DataFlow(dg, 0, 0);
 
117
        else if (classNr == Code::BIDIRECTIONAL_DATA_FLOW)
 
118
                thing = new BidirectionalDataFlow(dg, 0, 0);
 
119
        else
 
120
                error("%s, line %d: impl error: "
 
121
                        "wrong class number %d\n", __FILE__, __LINE__, classNr);
 
122
        return thing;
 
123
}
 
124
 
 
125
Node *DFDiagram::CreateNode(){
 
126
        Node *node = 0;
 
127
        DFGraph *dg = (DFGraph *)GetGraph();
 
128
        if (GetNodeType() == Code::EXTERNAL_ENTITY)
 
129
                node = new ExternalEntity(dg);
 
130
        else if (GetNodeType() == Code::DATA_PROCESS)
 
131
                node = new DataProcess(dg);
 
132
        else if (GetNodeType() == Code::DATA_STORE)
 
133
                node = new DataStore(dg);
 
134
        else if (GetNodeType() == Code::SPLIT_MERGE_NODE)
 
135
                node = new SplitMergeNode(dg);
 
136
        else if (GetNodeType() == Code::COMMENT)
 
137
                node = new Comment(dg);
 
138
        else {
 
139
                error("%s, line %d: unknown node type\n", 
 
140
                                __FILE__, __LINE__);
 
141
        }
 
142
        return node;
 
143
}
 
144
 
 
145
Edge *DFDiagram::CreateEdge(Subject *subj1, Subject *subj2){
 
146
        if (!CheckEdgeConstraints(subj1, subj2))
 
147
                return 0;
 
148
        Edge *edge = 0;
 
149
        DFGraph *dg = (DFGraph *)GetGraph();
 
150
        if (GetEdgeType() == Code::DATA_FLOW)
 
151
                edge = new DataFlow(dg, subj1, subj2);
 
152
        else if (GetEdgeType() == Code::BIDIRECTIONAL_DATA_FLOW)
 
153
                edge = new BidirectionalDataFlow(dg, subj1, subj2);
 
154
        else
 
155
                error("%s, line %d: unknown edge type\n", __FILE__, __LINE__);
 
156
        return edge;
 
157
}
 
158
 
 
159
NodeShape *DFDiagram::CreateNodeShape(Node *node, int x, int y) {
 
160
        NodeShape *shape = 0;
 
161
        Grafport *g = GetDiagramViewer()->GetGrafport();
 
162
        ShapeView *v = GetDiagramViewer()->GetCurView();
 
163
        if (GetNodeShapeType() == Code::HORIZONTAL_BAR)
 
164
                shape = new HorizontalBar(v, g, x, y);
 
165
        else if (GetNodeShapeType() == Code::CIRCLE) {
 
166
                Circle *c = new Circle(v, g, x, y);
 
167
                c->SetFixedIndexLabel(False);
 
168
                shape = c;
 
169
        }
 
170
        else if (GetNodeShapeType() == Code::SQUARE)
 
171
                shape = new Square(v, g, x, y);
 
172
        else if (GetNodeShapeType() == Code::BLACK_DOT)
 
173
                shape = new BlackDot(v, g, x, y);
 
174
        else if (GetNodeShapeType() == Code::TEXT_BOX)
 
175
                shape = new TextBox(v, g, x, y);
 
176
        else 
 
177
                error("%s, line %d: impl error: "
 
178
                        "node shape type does not exist\n", __FILE__, __LINE__);
 
179
        if (check(shape)) {
 
180
                shape->SetSubject(node);
 
181
                shape->SetTextShape();
 
182
        }
 
183
        return shape;
 
184
}
 
185
 
 
186
Line *DFDiagram::CreateLine(
 
187
                Edge *edge, GShape *from, GShape *to, List<Point *> *l) {
 
188
        Grafport *g = GetDiagramViewer()->GetGrafport();
 
189
        ShapeView *v = GetDiagramViewer()->GetCurView();
 
190
        Line *line = 0;
 
191
        if (GetLineType() == Code::LINE)
 
192
                line = new Line(v, g, from, to, l, IsCurve());
 
193
        else
 
194
                error("%s, line %d: impl error: "
 
195
                        "line type does not exist\n", __FILE__, __LINE__);
 
196
 
 
197
        if (check(line)) {
 
198
                line->SetSubject(edge);
 
199
                line->SetTextShape();
 
200
                line->SetEnd1(GetLineEnd1());
 
201
                line->SetEnd2(GetLineEnd2());
 
202
        }
 
203
        return line;
 
204
}
 
205
 
 
206
void DFDiagram::UpdateNodeType(int num) {
 
207
        ((DiagramWindow *)GetMainWindow())->SetNodeName(num);
 
208
        switch (num) {
 
209
        case 1: SetNodeType(Code::DATA_PROCESS);
 
210
                SetNodeShapeType(Code::CIRCLE);
 
211
                break;
 
212
        case 2: SetNodeType(Code::DATA_STORE);
 
213
                SetNodeShapeType(Code::HORIZONTAL_BAR);
 
214
                break;
 
215
        case 3: SetNodeType(Code::EXTERNAL_ENTITY);
 
216
                SetNodeShapeType(Code::SQUARE);
 
217
                break;
 
218
        case 4: SetNodeType(Code::SPLIT_MERGE_NODE);
 
219
                SetNodeShapeType(Code::BLACK_DOT);
 
220
                break;
 
221
        case 5: SetNodeType(Code::COMMENT);
 
222
                SetNodeShapeType(Code::TEXT_BOX);
 
223
                break;
 
224
        default:
 
225
                error("%s, line %d: impl error: "
 
226
                        "unknown node type selected\n", __FILE__,__LINE__);
 
227
        }
 
228
}
 
229
 
 
230
void DFDiagram::UpdateEdgeType(int num) {
 
231
        ((DiagramWindow *)GetMainWindow())->SetEdgeName(num);
 
232
        SetLineType(Code::LINE);
 
233
        switch(num) {
 
234
        case 1: SetEdgeType(Code::DATA_FLOW);
 
235
                SetLineEnd1(LineEnd::EMPTY);
 
236
                SetLineEnd2(LineEnd::FILLED_ARROW);
 
237
                break;
 
238
        case 2: SetEdgeType(Code::BIDIRECTIONAL_DATA_FLOW);
 
239
                SetLineEnd1(LineEnd::FILLED_ARROW);
 
240
                SetLineEnd2(LineEnd::FILLED_ARROW);
 
241
                break;
 
242
        default:
 
243
                error("%s, line %d: impl error: "
 
244
                        "unknown edge type selected\n", __FILE__,__LINE__);
 
245
        }
 
246
}
 
247
 
 
248
bool DFDiagram::CheckEdgeConstraints(Subject *subj1, Subject *subj2) {
 
249
        // Check possible connections (subj-subj-edge matrix).
 
250
        if (!CheckConnection(subj1, subj2))
 
251
                return False;
 
252
        if (subj1 == subj2) {
 
253
                ShowDialog(MessageDialog::ERROR, "Error",
 
254
                        "Cannot add a flow from and to the same node.");
 
255
                return False;
 
256
        }
 
257
        int subj1Type = subj1->GetClassType();
 
258
        int subj2Type = subj2->GetClassType();
 
259
        // Cannot connect a data process with a splitmerge node
 
260
        // when they are already connected (even in the opposite direction).
 
261
        if ((GetEdgeType()==Code::DATA_FLOW||
 
262
             GetEdgeType()==Code::CONTINUOUS_DATA_FLOW) &&
 
263
                (subj1Type==Code::DATA_PROCESS &&
 
264
                 subj2Type==Code::SPLIT_MERGE_NODE ||
 
265
                 subj1Type==Code::SPLIT_MERGE_NODE &&
 
266
                 subj2Type==Code::DATA_PROCESS) &&
 
267
                (GetGraph()->IsConnected(subj2, subj1) ||
 
268
                 GetGraph()->IsConnected(subj1, subj2))) {
 
269
                ShowDialog(MessageDialog::ERROR, "Error",
 
270
                        "Cannot add another data flow here. ");
 
271
                return False;
 
272
        }
 
273
        return True;
 
274
}
 
275
 
 
276
bool DFDiagram::HasIndexNode(int code) {
 
277
        return (code == Code::DATA_PROCESS || code == Code::CONTROL_PROCESS);
 
278
}
 
279
 
 
280
bool DFDiagram::HasIndexShape(int code) {
 
281
        return (code == Code::CIRCLE);
 
282
}
 
283
 
 
284
void DFDiagram::EditMinispec(Subject *s) {
 
285
        if (s->GetClassType() != Code::DATA_PROCESS) {
 
286
                ShowDialog(MessageDialog::ERROR, "Not a data process",
 
287
                        "Only data processes can have a minispec");
 
288
                return;
 
289
        }
 
290
        if (minispecDialog->IsManaged()) {
 
291
                ShowDialog(MessageDialog::WARNING, "Warning",
 
292
                        "You can only open one minispec editor at a time.");
 
293
                return;
 
294
        }
 
295
        editProcess = (DataProcess *)s;
 
296
        if (editProcess->IsProcessGroup()) {
 
297
                ShowDialog(MessageDialog::ERROR, "A process group",
 
298
                        "This data process is a process group,\n"
 
299
                        "so it cannot have a minispec");
 
300
                editProcess = 0;
 
301
                return;
 
302
        }
 
303
        const string *n = editProcess->GetIndex();
 
304
        const string *spec = editProcess->GetMinispec();
 
305
        string x = "Minispec of process ";
 
306
        string title = x + *n;
 
307
        minispecDialog->SetTitle(&title);
 
308
        minispecDialog->SetTextString(spec);
 
309
        minispecDialog->Popup();
 
310
}
 
311
 
 
312
void DFDiagram::SetMinispec() {
 
313
        SetStatus("action: Update minispec");
 
314
        if (!check(editProcess))
 
315
                return;
 
316
        string t;
 
317
        minispecDialog->GetTextString(&t);
 
318
        editProcess->SetMinispec(&t);
 
319
}
 
320
 
 
321
void DFDiagram::SetDiagram(const string *dfd) {
 
322
        DFGraph *dg = (DFGraph *)GetGraph();
 
323
        string sdfd = *dfd;
 
324
        if (((*dfd == "") || DFProcess::CorrectIndex(&sdfd)) && 
 
325
             (*dfd != "0")) {
 
326
                dg->SetIndexPrefix(&sdfd);
 
327
                ((DFWindow *)GetMainWindow())->SetDiagram(dfd);
 
328
                if (sdfd == "")
 
329
                        sdfd = "0";
 
330
                string txt = "diagram " + sdfd + " is the current diagram";
 
331
                SetStatus(&txt);
 
332
        }
 
333
        else {
 
334
                const string s = *dg->GetIndexPrefix();
 
335
                ((DFWindow *)GetMainWindow())->SetDiagram(&s);
 
336
                string txt = "'";
 
337
                txt += *dfd;
 
338
                txt += "' wrong syntax for \na data flow diagram index";
 
339
                ShowDialog(MessageDialog::ERROR, "Error", &txt);
 
340
        }
 
341
}
 
342
 
 
343
void DFDiagram::CheckDocument() {
 
344
        chkbuf = "";
 
345
        unsigned total = 0;
 
346
        total += dfChecks->CheckNamelessNodes(Code::DATA_PROCESS, chkbuf);
 
347
        total += dfChecks->CheckNamelessNodes(Code::DATA_STORE, chkbuf);
 
348
        total += dfChecks->CheckNamelessNodes(Code::EXTERNAL_ENTITY, chkbuf);
 
349
        total += dfChecks->CheckNamelessFlows(Code::DATA_FLOW, 
 
350
                Code::EXTERNAL_ENTITY, Code::DATA_PROCESS, chkbuf);
 
351
        total += dfChecks->CheckNamelessFlows(Code::DATA_FLOW, 
 
352
                Code::DATA_PROCESS, Code::EXTERNAL_ENTITY, chkbuf);
 
353
        total += dfChecks->CheckNamelessFlows(Code::DATA_FLOW, 
 
354
                Code::DATA_PROCESS, Code::DATA_PROCESS, chkbuf);
 
355
        total += dfChecks->CheckDoubleNodes(Code::DATA_PROCESS, chkbuf);
 
356
        total += dfChecks->CheckDoubleNodes(Code::DATA_STORE, chkbuf);
 
357
        total += dfChecks->CheckDoubleNodes(Code::EXTERNAL_ENTITY, chkbuf);
 
358
        total += dfChecks->CheckDoubleIndexes(chkbuf);
 
359
        total += dfChecks->CheckDataProcessCoherence(chkbuf);
 
360
        total += dfChecks->CheckConnected(Code::DATA_STORE, False, chkbuf);
 
361
        total += dfChecks->CheckConnected(Code::EXTERNAL_ENTITY, False, chkbuf);
 
362
        total += dfChecks->CheckSplitMergeNodeCoherence(chkbuf);
 
363
        total += dfChecks->CheckNamelessSplitMergeEdges(chkbuf);
 
364
        total += dfChecks->CheckMinispecs(chkbuf);
 
365
        ReportCheck(total, &chkbuf);
 
366
}