⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psdiagram.c

📁 这个工具集提供以下结构化分析和UML分析中所用的图形化绘图工具:ER-diagrams, data and event flow diagrams and state-transition diagr
💻 C
字号:
//////////////////////////////////////////////////////////////////////////////////// This file is part of Toolkit for Conceptual Modeling (TCM).// (c) copyright 1995, Vrije Universiteit Amsterdam.// Author: Frank Dehne (frank@cs.vu.nl).//// TCM is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// TCM is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with TCM; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA// 02111-1307, USA.////////////////////////////////////////////////////////////////////////////////#include "psgraph.h"#include "psviewer.h"#include "pswindow.h"#include "pschecks.h"#include "emptyedge.h"#include "psprocess.h"#include "urlabeledbox.h"#include "textbox.h"#include "comment.h"#include "line.h"#include "messagedialog.h"#include "psdiagram.h"PSDiagram::PSDiagram(Config *c, PSWindow *d, PSViewer *v, PSGraph *g): 		Diagram(c,d,v,g) {	UpdateNodeType(1);	UpdateEdgeType(1);	treeSequenceNr = 0;	actionSequenceNr = 0;	psChecks = new PSChecks(this,g);}PSDiagram::~PSDiagram() {	delete psChecks;}Thing *PSDiagram::CreateThing(int classNr) {	Grafport *g = GetDiagramViewer()->GetGrafport();	ShapeView *v = GetDiagramViewer()->GetCurView();	PSGraph *pg = (PSGraph *)GetGraph();	Thing *thing = 0;	// view	if (classNr == Code::VIEW)		thing = new ShapeView(GetDiagramViewer());	// node shapes	else if (classNr == Code::UR_LABELED_BOX)		thing = new URLabeledBox(v, g, 0, 0);	else if (classNr == Code::TEXT_BOX)		thing = new TextBox(v, g, 0, 0);	// lines	else if (classNr == Code::LINE) {		Line *line = new Line(v, g, 0, 0, 0);		line->SetFixedName(True);		thing = line;	}	// nodes	else if (classNr == Code::PS_PROCESS)		thing = new PSProcess(pg);	else if (classNr == Code::COMMENT)		thing = new Comment(pg);	// edges	else if (classNr == Code::EMPTY_EDGE)		thing = new EmptyEdge(pg, 0, 0);	else		error("%s, line %d: impl error: "			"wrong class number %d in file\n", __FILE__, __LINE__, classNr);	return thing;}Node *PSDiagram::CreateNode(){	Node *node = 0;	PSGraph *pg = (PSGraph *)GetGraph();	if (GetNodeType() == Code::PS_PROCESS)		node = new PSProcess(pg);	else if (GetNodeType() == Code::COMMENT)		node = new Comment(pg);	else		error("%s, line %d: impl error: "			"unknown node type\n", __FILE__, __LINE__);	return node;} Edge *PSDiagram::CreateEdge(Subject *n1, Subject *n2){	if (!CheckEdgeConstraints(n1, n2))		return 0;	Edge *edge = 0;	PSGraph *pg = (PSGraph *)GetGraph();	if (GetEdgeType() == Code::EMPTY_EDGE)		edge = new EmptyEdge(pg, n1, n2);	else		error("%s, line %d: impl error: "			"unknown edge type\n", __FILE__, __LINE__);	return edge;}NodeShape *PSDiagram::CreateNodeShape(Node *node, int x, int y) {	NodeShape *shape = 0;	Grafport *g = GetDiagramViewer()->GetGrafport();	ShapeView *v = GetDiagramViewer()->GetCurView();	if (GetNodeShapeType() == Code::TEXT_BOX)		shape = new TextBox(v, g, x, y);	else if (GetNodeShapeType() == Code::UR_LABELED_BOX)		shape = new URLabeledBox(v, g, x, y);	else		error("%s, line %d: impl error: "			"node shape type does not exist\n", __FILE__, __LINE__);	if (check(shape)) {		shape->SetSubject(node);		shape->SetTextShape();	}	return shape;}Line *PSDiagram::CreateLine(		Edge *edge, GShape *from, GShape *to, List<Point *> *l) {	Line *line = 0;	Grafport *g = GetDiagramViewer()->GetGrafport();	ShapeView *v = GetDiagramViewer()->GetCurView();	*((*l)[0]) = *(from->GetPosition());	*((*l)[l->count()-1]) = *(to->GetPosition());	if (GetLineType() == Code::LINE) {		line = new Line(v, g, from, to, l, IsCurve());		line->SetFixedName(True);	}	else {		error("%s, line %d: impl error: "			"line type does not exist\n", __FILE__, __LINE__);	}	if (check(line)) {		line->SetSubject(edge);		line->SetTextShape();	}	return line;}void PSDiagram::UpdateNodeType(int num) {	((DiagramWindow *)GetMainWindow())->SetNodeName(num);	switch (num) {	case 1: SetNodeType(Code::PS_PROCESS);		SetNodeShapeType(Code::UR_LABELED_BOX);		break;	case 2: SetNodeType(Code::COMMENT);		SetNodeShapeType(Code::TEXT_BOX);		break;	default:		error("%s, line %d: impl error: "		"unknown node type selected\n", __FILE__, __LINE__);	}} void PSDiagram::UpdateEdgeType(int num) {	((DiagramWindow *)GetMainWindow())->SetEdgeName(num);	switch(num) {	case 1: SetEdgeType(Code::EMPTY_EDGE);		SetLineType(Code::LINE);		break;	default:		error("%s, line %d: impl error: "		"unknown edge type selected\n", __FILE__, __LINE__);	}}bool PSDiagram::CheckEdgeConstraints(Subject *subj1, Subject *subj2) {	if (!CheckConnection(subj1, subj2))		return False;	if ((subj1 == subj2) || GetGraph()->PathExists(subj1, subj2)) {		ShowDialog(MessageDialog::ERROR, "Error",			"This connection violates the tree constraint");		return False;	}	return True;}void PSDiagram::SaveEntries() {	TraverseTree(False);	Diagram::SaveEntries();	((PSViewer *)GetDiagramViewer())->UpdateShowSequences();} unsigned PSDiagram::TraverseTree(bool chec) {	unsigned errors = 0;	List<Subject *> all_nodes;	treeSequenceNr = 0;	actionSequenceNr = 0;	GetGraph()->GetNodes(&all_nodes, Code::PS_PROCESS);	PSProcess *root;	unsigned nrRoots = FindRoot(&all_nodes, &root);	List<Subject *> tree_nodes;	if (nrRoots == 1) {		root->SetRoot(True);		tree_nodes.add(root);			if (chec)				errors += psChecks->CheckRootOperator(root, chkbuf);		errors += TraverseChildren(root, &tree_nodes, chec);	}	else if (nrRoots == 0 && chec) {		chkbuf +="* Error: there is no root process\n";		errors++;	}	else if (nrRoots > 1 && chec) {		chkbuf +="* Error: there is no unique root process\n";		errors++;	}	// Check if there are remaining nodes not part of the tree:	for (all_nodes.first(); !all_nodes.done(); all_nodes.next()) {		Subject *node = all_nodes.cur();		if (tree_nodes.find(node) == -1) {			// give remaining node unused sequence numbers.			((PSProcess *)node)->SetTreeSequence(0);			((PSProcess *)node)->SetActionSequence(0);			// give error if required.			if (chec && nrRoots == 1 && *node->GetName() != "") {				// empty names are noted elsewhere.				errors++;				chkbuf += "* Error: Process '";				chkbuf += *node->GetName();				chkbuf += "' is not part of the main tree\n";			}		}	}	return errors;}unsigned PSDiagram::FindRoot(List<Subject *> *nodes, PSProcess **root) {	// find the root: the subject that has the shape with	// the smallest y-coordinate.	Point root_pos;	unsigned card = 0;	if (nodes->first()) {		PSProcess *node = (PSProcess *)nodes->cur();		Shape *nshape = GetDiagramViewer()->GetShape(node);		root_pos = *nshape->GetPosition();		*root = node;		card = 1;		while (nodes->next()) {			node = (PSProcess *)nodes->cur();			nshape = GetDiagramViewer()->GetShape(node);			const Point *pt = nshape->GetPosition();			if (root_pos.y > pt->y) {				root_pos = *pt;				*root = node;				card = 1;			}			else if (root_pos.y == pt->y) {				// more than one root ?				card++;			}		}	}	return card;}void PSDiagram::FindChildren(PSProcess *parent, List<Subject *> *nodes, 			List<Subject *> *children) {	List<Subject *> edges;	List<Subject *> child_edges;	// find all edges that connect the parent with its children.	GetGraph()->CompleteSubject(&edges, parent);	for (edges.first(); !edges.done(); edges.next()) {		Edge *edge = (Edge *)edges.cur();		Subject *n1 = edge->GetSubject1();		Subject *n2 = edge->GetSubject2();		if (n1 == parent && nodes->find(n2) == -1) {			child_edges.add(edge);		}		else if (n2 == parent && nodes->find(n1) == -1) {			child_edges.add(edge);		}	}	children->empty();	Edge *leftMost = 0;	// look repeatedly for the 'leftMost' edge: i.e. the	// edge whose line connects to the shape of the parent	// with the smallest x-coordinate.	while ((leftMost = FindLeftMostEdge(parent, &child_edges))) {		if (leftMost->GetSubject2() == parent)			children->add(leftMost->GetSubject1());		else			children->add(leftMost->GetSubject2());		child_edges.remove(leftMost);	}}Edge *PSDiagram::FindLeftMostEdge(PSProcess *parent, List<Subject *> *child_edges) {	Edge *leftMost =0;	int min_x;	if (child_edges->first()) {		Edge *edge = (Edge *)(*child_edges)[0];		Line *line = (Line *)GetDiagramViewer()->GetShape(edge);		Shape *nshape = GetDiagramViewer()->GetShape(parent);		// we have to take care of the two different directions 		// of the line.		if (line->GetFromShape() == nshape)			min_x = (*line->GetLine())[0]->x;		else			min_x = (*line->GetLine())[line->NrPoints()-1]->x;		leftMost = edge;		while (child_edges->next()) {			edge = (Edge *)child_edges->cur();			line = (Line *)GetDiagramViewer()->GetShape(edge);			Point *pt;			if (line->GetFromShape() == nshape)				pt = (*line->GetLine())[0];			else				pt = (*line->GetLine())[line->NrPoints()-1];			if (pt->x < min_x) {				min_x = pt->x; 				leftMost = edge;			}		}	}	return leftMost;}unsigned PSDiagram::TraverseChildren(PSProcess *parent, List<Subject *> *nodes, bool chec) {	unsigned errors = 0;	List<Subject *> children;	FindChildren(parent, nodes, &children);	// list name of parent and of their children.	// Call this function recursively for all the children.	for (children.first(); !children.done(); children.next()) {		PSProcess *child = (PSProcess *)children.cur();		child->SetRoot(False);		nodes->add(children.cur());	}	if (chec) {		errors += psChecks->CheckChildPositions(			GetDiagramViewer(), parent, &children, chkbuf);		errors += psChecks->CheckChildOperators(parent, &children, chkbuf);	}	for (children.first(); !children.done(); children.next())		errors += TraverseChildren((PSProcess *)children.cur(), nodes, chec);	if (children.count() == 0) {		char op = parent->GetOperator();		if (op != '?' && op != '!')			parent->SetAction(True);		else			parent->SetAction(False);	}	else if (children.count() == 1) {		// parent of a '!' process is also considered as a action.		PSProcess *p = (PSProcess *)children[0];		if (p->GetOperator() == '!')			parent->SetAction(True);		else			parent->SetAction(False);	}	else		parent->SetAction(False);	parent->SetTreeSequence(++treeSequenceNr);	if (parent->IsAction())		parent->SetActionSequence(++actionSequenceNr);	else		parent->SetActionSequence(0);	return errors;}void PSDiagram::CheckDocument() {	chkbuf = "";	unsigned errors = 0;	errors += TraverseTree(True);	((PSViewer *)GetDiagramViewer())->UpdateShowSequences();	errors += psChecks->CheckNamelessNodes(Code::PS_PROCESS, chkbuf);	errors += psChecks->CheckDoubleProcessNames(chkbuf);	ReportCheck(errors, &chkbuf);}bool PSDiagram::SetOperator(PSProcess *proc, const string *s) {	List<GShape *> shapes;	GetDiagramViewer()->GetShapes(proc, &shapes);	// empty string means sequence (space).	char op;	if (s->length() == 0)		op = ' ';	else		op = (*s)[0];	if (proc->SetOperator(op)) {		if (check(shapes.first()))			do				((URLabeledBox *)shapes.cur())->UpdateURLabel(s);			while (shapes.next());		else 			return False;	}	else {		string txt = *s + " is not a valid process operator";		ShowDialog(MessageDialog::ERROR, "Error", &txt);		return False;	}	return True;}bool PSDiagram::SetText(TextShape *t, const string *s) {	const string *description = t->GetDescription();	Subject *subj = t->GetParent()->GetSubject();	if (*description == "Process Operator" &&		    (subj->GetClassType()==Code::PS_PROCESS))		return SetOperator((PSProcess *)subj, s);	else		return Diagram::SetText(t, s);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -