#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("\n"); } fw.write("\n"); } } if (previous != 0) { fw.write("
NameKindDescription
"); x->write("projectFrame"); fw.write(""); fw.write(x->sKind()); fw.write(""); writeq(x->description()); 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("<H2>"); fw.write("Frame Alert</H2>"); fw.write("<P>"); 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("<BR>"); fw.write("Link to <A HREF=\"index.html\">Non-frame version.</A>"); 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("\n"); } fw.write("
"); x->write("projectFrame"); fw.write(""); writeq(x->stereotype()); fw.write(""); writeq(x->description()); 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;