#include "UmlItem.h"
#include "UmlDiagram.h"
#include "UmlTypeSpec.h"
#include
#include
#include
#include "UmlClass.h"
#include "UmlOperation.h"
#include "UmlAttribute.h"
#include "UmlClassDiagram.h"
#include "UmlObjectDiagram.h"
#include "UmlActivityDiagram.h"
#include "UmlStateDiagram.h"
#include "UmlUseCaseDiagram.h"
#include "UmlSequenceDiagram.h"
#include "UmlCollaborationDiagram.h"
#include "UmlComponentDiagram.h"
#include "UmlDeploymentDiagram.h"
#include "UmlPackage.h"
#include "UmlUseCase.h"
#include "UmlActivity.h"
#include "UmlState.h"
#include "UmlNcRelation.h"
#include "UmlCom.h"
#include "CppSettings.h"
#include "JavaSettings.h"
UmlItem::~UmlItem() {
}
QCString UmlItem::sKind() {
return "???";
}
void UmlItem::set_dir(int argc, char ** argv) {
QString d;
bool ask;
bool rem;
bool replace_css;
if ((argc != 0) && !strcmp(argv[0], "-flat")) {
flat = TRUE;
argc -= 1;
argv += 1;
}
else
flat = FALSE;
if ((argc != 0) && !strcmp(argv[0], "-svg")) {
svg = TRUE;
argc -= 1;
argv += 1;
}
else
svg = FALSE;
if (argc == 0) {
if (!UmlBasePackage::getProject()->propertyValue("html dir", directory))
directory = "/tmp/" + name() + "_html";
d = directory;
d = QFileDialog::getExistingDirectory(d, 0, "","Directory where the files will be produced", TRUE);
if (d.isEmpty())
throw 0;
ask = TRUE;
rem = FALSE;
replace_css = TRUE;
}
else {
d = argv[0];
ask = FALSE;
if ((argc == 2) && !strcmp(argv[1], "-del_html")) {
rem = TRUE;
argc -= 1;
argv += 1;
}
else
rem = FALSE;
replace_css = ((argc == 2) && !strcmp(argv[1], "-del_css"));
}
if ((d.at(d.length() - 1) != '/') && (d.at(d.length() - 1) != '\\'))
d += '/';
directory = (const char *) d;
QDir dir(d);
unsigned i;
if (dir.exists()) {
if (ask) {
// remove old html files ?
for (i = 0; i != dir.count(); i += 1) {
if (dir[i].right(5).lower() == ".html") {
if (!rem &&
(QMessageBox::critical(0, "Html generator",
"Delete already existing html files ?",
"Yes", "No", QString::null,
1, 1) != 0))
break;
rem = TRUE;
dir.remove(dir[i]);
}
}
// remove old css file ?
for (i = 0; i != dir.count(); i += 1) {
if (dir[i] == "style.css") {
if (QMessageBox::critical(0, "Html generator",
"Replace already existing style.css ?",
"Yes", "No", QString::null,
1, 1) != 0)
replace_css = FALSE;
break;
}
}
}
else {
if (rem) {
for (i = 0; i != dir.count(); i += 1) {
if (dir[i].right(5).lower() == ".html")
dir.remove(dir[i]);
}
}
if (!replace_css) {
replace_css = TRUE; // to create it
for (i = 0; i != dir.count(); i += 1) {
if (dir[i] == "style.css") {
// already exist, don't replace
replace_css = FALSE;
break;
}
}
}
}
}
else if (! dir.mkdir(d)) {
UmlCom::trace("Cannot create directory " + directory);
throw 0;
}
else
replace_css = TRUE; // to create it
if (ask)
UmlBasePackage::getProject()->set_PropertyValue("html dir", directory);
if (replace_css) {
// write css file
FileWriter fw;
if (fw.open(directory + "style.css")) {
fw.write("\
div.title { font-size: 150%; background: #87ceff; text-align: center; font-weight: bold; }\n\
\n\
div.sub { margin-left : 20px; }\n\
div.element { background: #d3d3d3; }\n\
\n\
h1.package { background: #ffe4c4; }\n\
h1.view { background: #98fb98; }\n\
\n\
h2.package { background: #ffe4c4; }\n\
h2.view { background: #98fb98; }\n\
h2.class { background: #87ceff; }\n\
h2.usecase { background: #87ceff; }\n\
h2.state { background: #87ceff; }\n\
h2.activity { background: #87ceff; }\n\
\n\
h3.package { background: #ffe4c4; }\n\
h3.view { background: #98fb98; }\n\
h3.class { background: #87ceff; }\n\
h3.usecase { background: #87ceff; }\n\
h3.state { background: #87ceff; }\n\
h3.stateregion { background: #87ceff; }\n\
h3.activity { background: #87ceff; }\n\
\n\
h4.package { background: #ffe4c4; }\n\
h4.view { background: #98fb98; }\n\
h4.class { background: #87ceff; }\n\
h4.usecase { background: #87ceff; }\n\
h4.state { background: #87ceff; }\n\
h4.stateregion { background: #87ceff; }\n\
h4.activity { background: #87ceff; }\n");
fw.close();
}
}
}
void UmlItem::memo_ref() {
all.addElement(this);
known = TRUE;
const QVector ch = children();
for (unsigned i = 0; i != ch.size(); i += 1)
ch[i]->memo_ref();
}
void UmlItem::define() {
fw.write(" \n");
}
void UmlItem::start_file(QCString f, QCString s, bool withrefs)
{
QCString filename = directory + f;
if (! fw.open(filename + ".html"))
throw 0;
fw.write("\n");
fw.write("\n");
fw.write("\n");
fw.write((svg) ? "\n"
: "\n");
fw.write("\n");
fw.write("\n");
if (s.isEmpty()) {
fw.write("" + filename + " \n");
fw.write(" \n");
fw.write("\n");
if (withrefs) {
fw.write("\n");
ref_indexes();
}
}
else {
fw.write(""); fw.write(s); fw.write(" \n");
fw.write(" \n");
fw.write("\n");
fw.write("\n");
fw.write("\n");
fw.write("\n");
fw.write(""); writeq(s); fw.write("
\n");
fw.write("
\n");
fw.write("\n");
fw.write("\n");
fw.write("\n");
}
}
void UmlItem::end_file()
{
fw.write("\n");
fw.write("\n");
fw.close();
}
void UmlItem::ref_indexes()
{
fw.write("
\n");
fw.write(" -Top- ");
UmlClass::ref_index();
UmlOperation::ref_index();
UmlAttribute::ref_index();
UmlPackage::ref_index();
UmlUseCase::ref_index();
UmlActivity::ref_index();
UmlState::ref_index();
UmlClassDiagram::ref_index();
UmlObjectDiagram::ref_index();
UmlActivityDiagram::ref_index();
UmlStateDiagram::ref_index();
UmlUseCaseDiagram::ref_index();
UmlSequenceDiagram::ref_index();
UmlCollaborationDiagram::ref_index();
UmlComponentDiagram::ref_index();
UmlDeploymentDiagram::ref_index();
fw.write("
\n\n
\n");
for (unsigned i = 0; i != letters.length(); i += 1) {
fw.write(" ");
writeq(letters.at(i));
fw.write(" ");
}
fw.write("
\n");
}
void UmlItem::generate_indexes()
{
UmlClass::generate_index();
UmlOperation::generate_index();
UmlAttribute::generate_index();
UmlPackage::generate_index();
UmlUseCase::generate_index();
UmlActivity::generate_index();
UmlState::generate_index();
UmlClassDiagram::generate_index();
UmlObjectDiagram::generate_index();
UmlActivityDiagram::generate_index();
UmlStateDiagram::generate_index();
UmlUseCaseDiagram::generate_index();
UmlSequenceDiagram::generate_index();
UmlCollaborationDiagram::generate_index();
UmlComponentDiagram::generate_index();
UmlDeploymentDiagram::generate_index();
int n = all.size();
int i;
char previous;
sort(all);
previous = 0;
for (i = 0; i != n; i += 1) {
UmlItem * x = all.elementAt(i);
QCString s = x->pretty_name();
if (! s.isEmpty()) {
char c = *((const char *) s);
if ((c >= 'a') && (c <= 'z'))
c += 'A' - 'a';
if (c != previous) {
previous = c;
letters += c;
}
}
}
previous = 0;
for (i = 0; i != n; i += 1) {
UmlItem * x = all.elementAt(i);
QCString s = x->pretty_name();
if (! s.isEmpty()) {
char c = *((const char *) s);
if ((c >= 'a') && (c <= 'z'))
c += 'A' - 'a';
if (c != previous) {
if (previous != 0) {
fw.write("\n");
end_file();
}
previous = c;
QCString sn;
sn.setNum((int) (c & 255));
start_file(QCString("index_") + sn, QCString("") + c, TRUE);
fw.write("\n");
fw.write("Name Kind Description \n");
}
fw.write("");
x->write("projectFrame");
fw.write(" ");
fw.write(x->sKind());
fw.write(" ");
writeq(x->description());
fw.write(" \n");
}
}
if (previous != 0) {
fw.write("
\n");
end_file();
}
}
void UmlItem::frame()
{
start_file("index-withframe", "", FALSE);
fw.write("\n");
fw.write(" \n");
fw.write(" \n");
fw.write(" \n");
fw.write(" \n");
fw.write(" \n");
fw.write(" \n");
fw.write("\n");
fw.write("");
fw.write("Frame Alert ");
fw.write("");
fw.write("This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.");
fw.write(" ");
fw.write("Link to Non-frame version.
");
end_file();
UmlCom::trace("document with frame produced in "
+ directory + "index-withframe.html");
UmlCom::trace("document without frame produced in "
+ directory + "index.html");
}
bool UmlItem::chapterp() {
return FALSE;
}
void UmlItem::html(QCString pfix, unsigned int rank, QCString what, unsigned int level, QCString kind) {
define();
chapter(what, pfix, rank, kind, level);
if (! description().isEmpty()) {
fw.write(" ");
writeq(description());
fw.write("
\n");
}
write_properties();
const QVector ch = children();
unsigned n = ch.size();
if (n != 0) {
QCString spfix;
if (rank != 0) {
spfix.setNum(rank);
spfix = pfix + spfix + ".";
}
level += 1;
rank = 1;
fw.write("\n");
for (unsigned i = 0; i != n; i += 1) {
ch[i]->html(spfix, rank, level);
if (ch[i]->chapterp())
rank += 1;
}
fw.write("
\n");
}
}
void UmlItem::html(const char * what, UmlDiagram * diagram) {
define();
fw.write("");
fw.write(what);
fw.write(" ");
writeq(name());
fw.write("
\n");
QCString d = description();
if (!d.isEmpty()) {
fw.write("");
writeq(d);
fw.write("
\n");
}
write_dependencies();
if (diagram != 0) {
fw.write("Diagram : ");
diagram->write();
fw.write("
\n");
}
write_properties();
}
void UmlItem::write_children(QCString pfix, unsigned int rank, unsigned int level) {
const QVector ch = children();
unsigned n = ch.size();
if (n != 0) {
QCString spfix;
unsigned srank = 1;
if (rank != 0) {
spfix.setNum(rank);
spfix = pfix + spfix + ".";
fw.write("\n");
}
level += 1;
for (unsigned i = 0; i != n; i += 1) {
ch[i]->html(spfix, srank, level);
if (ch[i]->chapterp())
srank += 1;
}
if (rank != 0)
fw.write("
\n");
}
}
void UmlItem::write_dependencies() {
const QVector ch = children();
unsigned n = ch.size();
for (unsigned i = 0; i != n; i += 1) {
if ((ch[i]->kind() == aNcRelation) &&
(((UmlNcRelation *) ch[i])->relationKind() == aDependency)) {
fw.write("Depends on ");
((UmlNcRelation *) ch[i])->target()->write();
fw.write("
");
}
}
}
void UmlItem::write_properties() {
const QDict d = properties();
if (! d.isEmpty()) {
fw.write("Properties:
\n");
QDictIterator it(d);
while (it.current()) {
fw.write("");
writeq(it.currentKey().latin1());
fw.write(":");
writeq(*(it.current()));
fw.write("
\n");
++it;
}
fw.write(" \n");
}
}
void UmlItem::chapter(QCString k, QCString pfix, unsigned int rank, QCString kind, unsigned int level) {
if (rank != 0) {
if (level > 4)
level = 4;
fw.write("");
}
else
fw.write(">");
fw.write(pfix);
fw.write(rank);
fw.write(' ');
fw.write(k);
fw.write(' ');
writeq(name());
fw.write(" \n");
}
}
const char * UmlItem::bypass_comment(const char * s) {
while (*s) {
if (*s <= ' ')
s += 1;
else if ((*s == '/') && (s[1] != 0)) {
if (s[1] == '/') {
do
s += 1;
while ((*s != 0) &&
(*s != '\n') && (*s != '\r'));
}
else if (s[1] == '*') {
const char * s2 = strstr(s + 2, "*/");
if (s2 != 0)
s = s2 + 2;
else
return s;
}
else
return s;
}
else if (*s == '#') {
do {
if ((*++s == 0) ||
((*s == '\\') && (*++s == 0)))
return s;
} while ((*s != '\n') && (*s != '\r'));
}
else
return s;
}
return s;
}
void UmlItem::manage_alias(const char *& p) {
// p starts by '@'
const char * pclosed;
if ((p[1] == '{') && ((pclosed = strchr(p + 2, '}')) != 0)) {
QCString key(p + 2, pclosed - p - 1);
QCString value;
UmlItem * node = this;
do {
if (node->propertyValue(key, value))
break;
node = node->parent();
} while (node != 0);
if (node != 0)
// find, insert the value
writeq(value);
else {
// not find, insert the key
fw.write("@{");
writeq(key);
fw.write("}");
}
// bypass the key
p += strlen(key) + 3;
}
else {
// bypass '@'
fw.write("@");
p += 1;
}
}
void UmlItem::write() {
if (known) {
fw.write("kind() == aClass)){
fw.write("class");
fw.write((unsigned) parent()->getIdentifier());
}
else
fw.write("index");
fw.write(".html#ref");
fw.write(sKind());
fw.write((unsigned) getIdentifier());
fw.write("\">");
writeq(pretty_name());
fw.write(" ");
}
else
writeq(name());
}
void UmlItem::write(QCString target) {
if (known) {
fw.write("");
writeq(pretty_name());
fw.write(" ");
}
else
writeq(name());
}
void UmlItem::writeq(QCString s)
{
const char * p = s;
while (*p)
writeq(*p++);
}
void UmlItem::writeq(char c)
{
switch (c) {
case '<':
fw.write("<");
break;
case '>':
fw.write(">");
break;
case '&':
fw.write("&");
break;
case '\n':
fw.write(" ");
break;
case '\r':
break;
default:
fw.write(c);
break;
}
}
void UmlItem::write(const UmlTypeSpec & t, aLanguage lang)
{
if (t.type != 0)
t.type->write();
else
switch (lang) {
case cppLanguage:
writeq(CppSettings::type(t.toString()));
break;
case javaLanguage:
writeq(JavaSettings::type(t.toString()));
break;
default:
writeq(t.toString());
}
}
void UmlItem::write(const UmlTypeSpec & t)
{
if (t.type != 0)
t.type->write();
else
writeq(t.toString());
}
void UmlItem::write(aVisibility v, aLanguage lang)
{
switch (v) {
case PublicVisibility:
fw.write("public");
break;
case ProtectedVisibility:
fw.write("protected");
break;
case PrivateVisibility:
fw.write("private");
break;
case PackageVisibility:
switch (lang) {
case cppLanguage:
fw.write("public");
break;
case javaLanguage:
fw.write("package");
default:
break;
}
break;
default:
fw.write("???");
}
}
void UmlItem::write(aVisibility v)
{
switch (v) {
case PublicVisibility:
fw.write("+ ");
break;
case ProtectedVisibility:
fw.write("# ");
break;
case PrivateVisibility:
fw.write("- ");
break;
default:
// PackageVisibility:
fw.write("~ ");
}
}
void UmlItem::write(aDirection d)
{
switch (d) {
case InputOutputDirection:
fw.write("input output");
break;
case InputDirection:
fw.write("input");
break;
case OutputDirection:
fw.write("output");
break;
case ReturnDirection:
fw.write("return");
break;
default:
fw.write("???");
}
}
void UmlItem::write(aParameterEffectKind d)
{
switch (d) {
case noEffect:
fw.write("none");
break;
case createEffect:
fw.write("create");
break;
case readEffect:
fw.write("read");
break;
case updateEffect:
fw.write("update");
break;
case deleteEffect:
fw.write("delete");
break;
default:
fw.write("???");
}
}
void UmlItem::write(anOrdering d)
{
switch (d) {
case unordered:
fw.write("unordered");
break;
case ordered:
fw.write("ordered");
break;
case lifo:
fw.write("lifo");
break;
case fifo:
fw.write("fifo");
break;
default:
fw.write("???");
}
}
void UmlItem::generate_index(Vector & v, QCString k, QCString r)
{
int n = v.size();
if (n != 0) {
sort(v);
start_file(r, k + " Index", TRUE);
fw.write("\n");
for (int i = 0; i != n; i += 1) {
UmlItem * x = v.elementAt(i);
fw.write("");
x->write("projectFrame");
fw.write(" ");
writeq(x->stereotype());
fw.write(" ");
writeq(x->description());
fw.write(" \n");
}
fw.write("
\n");
end_file();
}
}
void UmlItem::sort(Vector & v)
{
sort(v, 0, v.size() - 1);
}
void UmlItem::sort(Vector & v, int low, int high)
{
if (low < high) {
int lo = low;
int hi = high + 1;
UmlItem * e = v.elementAt(low);
for (;;) {
while ((++lo < hi) && !v.elementAt(lo)->gt(e))
;
while (v.elementAt(--hi)->gt(e));
;
if (lo < hi) {
UmlItem * x = v.elementAt(lo);
v.setElementAt(v.elementAt(hi), lo);
v.setElementAt(x, hi);
}
else
break;
}
UmlItem * x = v.elementAt(low);
v.setElementAt(v.elementAt(hi), low);
v.setElementAt(x, hi);
sort(v, low, hi - 1);
sort(v, hi + 1, high);
}
}
bool UmlItem::gt(UmlItem * other) {
QCString s1 = pretty_name();
QCString s2 = other->pretty_name();
int i = qstricmp((const char *) s1, (const char *) s2);
if ((i == 0) && (parent() != 0) && (other->parent() != 0)) {
s1 = parent()->pretty_name();
s2 = other->parent()->pretty_name();
return (qstricmp((const char *) s1, (const char *) s2) > 0);
}
else
return (i > 0);
}
QCString UmlItem::pretty_name() {
return name().isEmpty() ? sKind() : name();
}
Vector UmlItem::all;
FileWriter UmlItem::fw;
QCString UmlItem::directory;
unsigned int UmlItem::nrefs = 0;
QCString UmlItem::letters;
//true => use SVG picture rather than PNG
bool UmlItem::flat;
//true => classes and tables are generated in index.html, else an own files are generated
bool UmlItem::svg;