Exemplo n.º 1
0
void UmlClass::extend(WrapperStr mcl)
{
    if (parent()->parent()->kind() != aPackage)
        return;

    int index = mcl.find('#');

    if (index == -1)
        return;

    WrapperStr path = mcl.left(index);
    const char * defltpath0 = "http://schema.omg.org/spec/UML/2.0/uml.xml";
    const char * defltpath1 = "http://schema.omg.org/spec/UML/2.1/uml.xml";
    bool dflt = ((path == defltpath0) || (path == defltpath1));

    mcl = mcl.mid(index + 1);

    static Q3PtrList<UmlClass> metaclasses;

    Q3PtrListIterator<UmlClass> it(metaclasses);
    UmlClass * metacl = UmlClass::get(mcl, 0);
    WrapperStr s;

    if ((metacl == 0) ||
        (metacl->stereotype() != "metaclass") ||
        !((dflt) ? (!metacl->propertyValue("metaclassPath", s) ||
                    (s == defltpath0) ||
                    (s == defltpath1))
          : (metacl->propertyValue("metaclassPath", s) &&
             (path == s)))) {
        metacl = 0;

        if (dflt) {
            for (; (metacl = it.current()) != 0; ++it) {
                if (!strcmp(mcl, metacl->name()) &&
                    (!metacl->propertyValue("metaclassPath", s) ||
                     (s == defltpath0) ||
                     (s == defltpath1)))
                    break;
            }
        }
        else {
            for (; (metacl = it.current()) != 0; ++it) {
                if (!strcmp(mcl, metacl->name()) &&
                    metacl->propertyValue("metaclassPath", s) &&
                    (path == s))
                    break;
            }
        }

        if (metacl == 0) {
            metacl = addMetaclass(mcl, (dflt) ? 0 : (const char *)path); //[rageek] different types for ? :
            metaclasses.append(metacl);
        }
    }

    UmlRelation::create(aDirectionalAssociation, this, metacl);
}
Exemplo n.º 2
0
void UmlJunctionPseudoState::generate(UmlClass * machine, UmlClass * anystate, UmlState * state) {
  // create an operation because a priori shared
  if (_oper.isEmpty())
    _oper.sprintf("_junction%d", ++_rank);

  UmlClass * cl = state->assocClass();
  UmlOperation * junction;
  
  if (((junction = (UmlOperation *) cl->getChild(anOperation, _oper)) == 0) &&
      ((junction = UmlBaseOperation::create(cl, _oper)) == 0)) {
    UmlCom::trace("Error : cannot create operation '" + _oper 
		  + "' in class '" + cl->name() + "'<br>");
    throw 0;
  }

  junction->defaultDef();
  junction->setComment("implement a junction, through an operation because shared, internal");
  junction->setType("void", "${type}");
  junction->addParam(0, InputOutputDirection, "stm", machine);
  junction->setParams("${t0} & ${p0}");
  
  Q3CString body;
  const Q3PtrVector<UmlItem> ch = children();
  Q3PtrList<UmlTransition> trs;
  unsigned index;
  
  for (index = 0; index != ch.count(); index += 1)
    if (ch[index]->kind() == aTransition)
      // theo mandatory
      trs.append((UmlTransition *) ch[index]);
    
  UmlTransition::generate(trs, machine, anystate, state, body, "  ", FALSE);
  
  junction->set_CppBody(body);
}
Exemplo n.º 3
0
bool UmlClass::replaceType(UmlTypeSpec & t, Q3CString & target_id, const Q3CString & ts)
{
  UmlClass * cl = (UmlClass *) findItem(target_id, aClass);
  bool result = FALSE;
  
  if (cl != 0) {
    int index = 0;
    const Q3CString & s = cl->name();
    unsigned ln1 = s.length();
    unsigned ln2 = ts.length();
    
    while ((index = t.explicit_type.find(s, index)) != -1) {
      if (((index == 0) || isSep(((const char *) t.explicit_type)[index - 1])) &&
	  isSep(((const char *) t.explicit_type)[index + (int) ln1])) {
	t.explicit_type.replace((unsigned) index, ln1, ts);
	index += ln2;
	result = TRUE;
      }
      else
	index += 1;
    }
  }

  if (result) {
    target_id = t.explicit_type;
    t.explicit_type = 0;
    t.type = cl;
  }

  return result;
}
Exemplo n.º 4
0
bool UmlAttribute::new_one(Class * container, Q3CString name,
			   aVisibility visibility, bool constp,
			   bool staticp, const Q3CString & value,
			   Q3CString comment, Q3CString description)
{
#ifdef TRACE
  cout << "ATTRIBUTE '" << name << "'\n";
#endif
  
#ifndef REVERSE
  if (visibility == PrivateVisibility)
    return TRUE;
#endif
  
  if (((const char *) name)[0] == '$')
    name = name.mid(1);
  
  UmlClass * cl = container->get_uml();
  UmlAttribute * at = UmlBaseAttribute::create(cl, name);
  
  if (at == 0) {
    PhpCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add attribute <i>")
			 + name + "</i> in <i>" + cl->name() 
			 + "</i></b></font><br>");  
    return FALSE;
  }
#ifdef REVERSE
  Statistic::one_attribute_more();
#endif
  
  if (!comment.isEmpty()) {
    Q3CString s = (at->phpDecl().find("${description}") != -1)
      ? description : comment;
    UmlTypeSpec t;
    int index;
    
    if (! (t.explicit_type = value_of(s, "@var", index)).isEmpty()) {
      at->set_Type(t);
      s.replace(index, t.explicit_type.length(), "${type}");
    }
    
    at->set_Description(s);
    
  }
  
  if (constp)
    at->set_isReadOnly(TRUE);
  
  if (staticp)
    at->set_isClassMember(TRUE);
  
  if (! value.isEmpty())
    at->set_DefaultValue(value);
  
  at->set_Visibility(visibility);
  
  return TRUE;
}
Exemplo n.º 5
0
bool UmlRelation::new_friend(Class * container, UmlClass * to,
			     Q3PtrList<UmlItem> & expected_order)
{
  UmlClass * from = container->get_uml();
  
#ifdef DEBUG_BOUML
  cout << "FRIEND from '" << from->name() << "' to '" << to->name() << "'\n";
#endif
  
  const Q3PtrVector<UmlItem> & ch = from->children();
  UmlItem ** v = ch.data();
  UmlItem ** const vsup = v + ch.size();
  
  for (;v != vsup; v += 1) {
    if (((*v)->kind() == aRelation) &&
	(((UmlRelation *) *v)->relationKind() == aDependency) &&
	(((UmlRelation *) *v)->roleType() == to) &&
	!neq((*v)->stereotype(), "friend")) {
      expected_order.append(*v);
      ((UmlRelation *) *v)->set_usefull();
      return TRUE;
    }
  }

  // relation not found
  
  UmlRelation * rel = UmlBaseRelation::create(aDependency, from, to);
  
  if (rel == 0) {
    UmlCom::trace(Q3CString("<font face=helvetica><b>cannot add friend relation in <i>")
		  + from->name() + "</i> to <i>"
		  + to->name() + "</i></b></font><br><hr><br>");  
    return FALSE;
  }
  
  expected_order.append(rel);
  container->set_updated();
  
  rel->set_CppDecl("Generated");
  
  return rel->set_Stereotype("friend");
}
Exemplo n.º 6
0
bool UmlClass::isAppliedStereotype(Token & tk, WrapperStr & prof_st, Q3ValueList<WrapperStr> & base_v)
{
    static Q3Dict<WrapperStr> stereotypes;
    static Q3Dict<Q3ValueList<WrapperStr> > bases;

    WrapperStr s = tk.what();
    WrapperStr * st = stereotypes[s];

    if (st != 0) {
        prof_st = *st;
        base_v = *bases[s];
        return TRUE;
    }

    base_v.clear();

    if (tk.xmiType().isEmpty() && (getFct(tk) == 0))  {
        int index = s.find(':');

        if ((index != -1) &&
            ((index != 3) || ((s.left(3) != "uml") && (s.left(3) != "xmi")))) {
            UmlClass * cl = findStereotype(s, FALSE);

            if (cl != 0) {
                const Q3PtrVector<UmlItem> ch = cl->children();
                unsigned n = ch.size();

                for (unsigned i = 0; i != n; i += 1) {
                    UmlItem * x = ch[i];

                    if ((x->kind() == aRelation) &&
                        (((UmlRelation *) x)->relationKind() == aDirectionalAssociation) &&
                        (((UmlRelation *) x)->roleType()->stereotype() == "metaclass"))
                        base_v.append("base_" + ((UmlRelation *) x)->roleType()->name().lower());
                }

                if (base_v.isEmpty())
                    base_v.append("base_element");

                prof_st = cl->parent()->parent()->name() + ":" + cl->name();
                stereotypes.insert(s, new WrapperStr(prof_st));
                bases.insert(s, new Q3ValueList<WrapperStr>(base_v));
                return TRUE;
            }
        }
    }

    return FALSE;
}
Exemplo n.º 7
0
bool UmlAttribute::new_one(Class * container, const WrapperStr & name,
                           UmlTypeSpec typespec, aVisibility visibility,
                           bool staticp, bool finalp, bool transientp,
                           bool volatilep, const WrapperStr & array,
                           const WrapperStr & value, WrapperStr comment,
                           WrapperStr description, WrapperStr annotation
#ifdef ROUNDTRIP
                           , bool roundtrip, QList<UmlItem *> & expected_order
#endif
                          )
{
#ifdef TRACE
    QLOG_INFO() << "ATTRIBUTE '" << name << "'\n";
#endif

    if (
#ifdef REVERSE
        container->from_libp() && (
#endif
                                   visibility == PrivateVisibility
#ifdef REVERSE
                                   )
#endif
        )
    {
        Lex::finish_line();
        Lex::clear_comments();
        return TRUE;
    }

    UmlClass * cl = container->get_uml();
    UmlAttribute * at;

#ifdef ROUNDTRIP
    bool created;

    if (!roundtrip ||
        ((at = search_attr(container, name)) == 0)) {
#endif
        at = UmlBaseAttribute::create(cl, name);

        if (at == 0) {
            JavaCatWindow::trace(WrapperStr("<font face=helvetica><b>cannot add attribute <i>")
                                 + name + "</i> in <i>" + cl->name()
                                 + "</i></b></font><br>");
            return FALSE;
        }

#ifdef REVERSE
# ifndef ROUNDTRIP
        Statistic::one_attribute_more();
# else

        if (roundtrip)
            container->set_updated();

        created = TRUE;
    }
    else
        created = FALSE;

# endif
#endif

        Lex::finish_line();

        comment = Lex::get_comments(comment);
        description = Lex::get_description(description);

        WrapperStr decl = JavaSettings::attributeDecl("");
        int index = decl.find("${type}");

        if ((index == -1) || (decl.find("${name}") == -1)) {
            decl = "  ${comment}${@}${visibility}${static}${final}${transient}${volatile}${type} ${name}${value};";
            index = decl.find("${type}");
        }

#ifdef ROUNDTRIP

        if (roundtrip && !created) {
            if (decl.find("${description}") != -1) {
                if (nequal(at->description(), description)) {
                    at->set_Description(description);
                    container->set_updated();
                }
            }
            else if (nequal(at->description(), Lex::simplify_comment(comment))) {
                at->set_Description(comment); // comment was set
                container->set_updated();
            }

            if (at->isReadOnly() != finalp) {
                at->set_isReadOnly(finalp);
                container->set_updated();
            }

            if (at->isJavaTransient() != transientp) {
                at->set_isJavaTransient(transientp);
                container->set_updated();
            }

            if (at->isVolatile() != volatilep) {
                at->set_isVolatile(volatilep);
                container->set_updated();
            }

            if (at->isClassMember() != staticp) {
                at->set_isClassMember(staticp);
                container->set_updated();
            }

            if (!array.isEmpty())
                decl.insert(index + 7, "${multiplicity}");

            if (neq(at->multiplicity(), array)) {
                at->set_Multiplicity(array);
                container->set_updated();
            }

            WrapperStr v = at->defaultValue();

            if (!v.isEmpty() && (((const char *) v)[0] == '='))
                v = v.mid(1);

            if (nequal(v, value)) {
                at->set_DefaultValue(value);
                container->set_updated();
            }

            if (nequal(at->javaAnnotations(), annotation)) {
                at->set_JavaAnnotations(annotation);
                container->set_updated();
            }

            WrapperStr stereotype;
            bool force_ste = FALSE;

            if (cl->stereotype() == "enum") {
                stereotype = "attribute";
                force_ste = TRUE;
            }
            else if (typespec.type == 0) {
                WrapperStr t = typespec.explicit_type;
                int index2;

                if (!t.isEmpty() &&
                    (t.at(t.length() - 1) == ">") &&
                    ((index2 = t.find('<')) > 0)) {
                    stereotype = t.left(index2);
                    typespec.explicit_type =
                        // may be a,b ...
                        t.mid(index2 + 1, t.length() - 2 - index2);
                    decl.replace(index, 7, "${stereotype}<${type}>");
                    force_ste = TRUE;
                }
            }

            if (at->visibility() != visibility) {
                at->set_Visibility(visibility);
                container->set_updated();
            }

            if (neq(at->stereotype(), stereotype)) {
                WrapperStr jst;

                if (! at->stereotype().isEmpty())
                    jst = JavaSettings::relationAttributeStereotype(at->stereotype());

                if ((force_ste) ? (jst != stereotype) : (jst == "attribute")) {
                    at->set_Stereotype(stereotype);
                    container->set_updated();
                }
            }

            if (neq(at->javaDecl(), decl)) {
                at->set_JavaDecl(decl);
                container->set_updated();
            }

            if (!at->type().equal(typespec)) {
                at->set_Type(typespec);
                container->set_updated();
            }

            at->set_usefull();

            expected_order.append(at);
        }
        else {
#endif

            if (!comment.isEmpty())
                at->set_Description((decl.find("${description}") != -1)
                                    ? description : Lex::simplify_comment(comment));

            if (finalp)
                at->set_isReadOnly(TRUE);

            if (transientp)
                at->set_isJavaTransient(TRUE);

            if (volatilep)
                at->set_isVolatile(TRUE);

            if (staticp)
                at->set_isClassMember(TRUE);

            if (!array.isEmpty()) {
                decl.insert(index + 7, "${multiplicity}");
                at->set_Multiplicity(array);
            }

            if (! value.isEmpty())
                at->set_DefaultValue(value);

            if (! annotation.isEmpty())
                at->set_JavaAnnotations(annotation);

            if ((typespec.type == 0) && (cl->stereotype() != "enum")) {
                WrapperStr t = typespec.explicit_type;
                int index2 = 0;

                if (!t.isEmpty() &&
                        (t.at(t.length() - 1) == ">") &&
                    ((index2 = t.find('<')) > 0))
                {
                    at->set_Stereotype(t.left(index2));
                    typespec.explicit_type =
                        // may be a,b ...
                        t.mid(index2 + 1, t.length() - 2 - index2);
                    decl.replace(index, 7, "${stereotype}<${type}>");
                }
            }

            at->set_Visibility(visibility);

            if (cl->stereotype() == "enum") {
                at->set_JavaDecl(decl);
                at->set_Stereotype("attribute");
            }
            else if (decl != JavaSettings::attributeDecl(""))
                at->set_JavaDecl(decl);

            at->set_Type(typespec);

#ifdef ROUNDTRIP

            if (roundtrip)
                expected_order.append(at);
        }

#endif

        return TRUE;
    }
Exemplo n.º 8
0
bool UmlOperation::new_one(Class * container, const Q3CString & name,
                           const Q3ValueList<FormalParameterList> & tmplts,
                           const Q3CString & oper_templ,
                           UmlTypeSpec & type, Q3CString str_actuals,
                           UmlClass * first_actual_class, Q3CString type_def,
                           aVisibility visibility,
                           bool finalp, bool abstractp, bool staticp,
                           bool nativep, bool strictfp, bool synchronizedp,
                           const Q3CString & array, Q3CString comment,
                           Q3CString description, Q3CString annotation
#ifdef ROUNDTRIP
                           , bool roundtrip, Q3PtrList<UmlItem> & expected_order
#endif
                          )
{
    // the "(" was read

#ifdef TRACE
    QLOG_INFO() <<"OPERATION '" << name << "'\n";
#endif

    UmlClass * cl = container->get_uml();
    UmlOperation * op;
#ifdef ROUNDTRIP
    bool may_roundtrip = roundtrip &&
                         (!container->from_libp() ||	(visibility != PrivateVisibility));
    UmlTypeSpec return_type;
    Q3ValueList<UmlParameter> params;
    Q3ValueList<UmlTypeSpec> exceptions;
    Q3CString body;

    if (may_roundtrip)
#else
    if (
# ifdef REVERSE
        container->from_libp() &&
# endif
        (visibility == PrivateVisibility))
#endif
        op = 0;
    else {
        op = UmlBaseOperation::create(cl, name);

        if (op == 0) {
            JavaCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add operation <i>")
                                 + name + "</i> in <i>" + cl->name()
                                 + "</i></b></font><br>");
            return FALSE;
        }

#ifndef ROUNDTRIP
# if defined(REVERSE)
        Statistic::one_operation_more();
# endif
#endif
    }

    Q3CString def;

#ifdef ROUNDTRIP
    if (may_roundtrip || (op != 0)) {
#else
    if (op != 0) {
        op->set_Visibility(visibility);
        if (staticp) op->set_isClassMember(TRUE);
        if (abstractp) op->set_isAbstract(TRUE);
        if (finalp) op->set_isJavaFinal(TRUE);
        if (synchronizedp) op->set_isJavaSynchronized(TRUE);
        if (! annotation.isEmpty()) op->set_JavaAnnotations(annotation);
#endif

        def = JavaSettings::operationDef();

        int index;

        if (((index = def.find("${(}")) == -1) ||
                ((index = def.find("${)}", index + 4)) == -1) ||
                ((index = def.find("${throws}", index + 4)) == -1) ||
                (def.find("${body}", index + 9) == -1) ||
                ((index = def.find("${type}")) == -1)) {
            // use a definition where ${body] is not indented
            def = "  ${comment}${@}${visibility}${final}${static}${abstract}${synchronized}${type} ${name}${(}${)}${throws}${staticnl}{\n${body}}\n";
            index = def.find("${type}");
        }

        if (!array.isEmpty())
            def.insert(index + 7, (const char *)array);

        if (nativep) {
            def.insert(index, "native ");
            index += 7;

            // no body
            int index2 = def.find("${throws}", index+7);

            if (index2 != -1) {
                def.resize(index2 + 12);
                def[index2 + 9] = ';';
                def[index2 + 10] = '\n';
            }
        }

        if (strictfp) {
            def.insert(index, "strictfp ");
            index += 9;
        }

        if (! oper_templ.isEmpty())
            def.insert(index, (const char *)(oper_templ + " "));

        if (name == cl->name()) {
            // constructor, remove useless ${}
            if ((index = def.find("${static}")) != -1)
                def.remove(index, 9);
            if ((index = def.find("${type}")) != -1)
                def.remove(index, (((const char *) def)[index + 7] == ' ') ? 8 : 7);
            if ((index = def.find("${final}")) != -1)
                def.remove(index, 8);
            if ((index = def.find("${abstract}")) != -1)
                def.remove(index, 11);
        }

        if (type.type != 0) {
            UmlClass::manage_generic(def, type, str_actuals, "${type}");
#ifdef ROUNDTRIP
            return_type = type;
#else
            op->set_ReturnType(type);
#endif
        }
        else if (first_actual_class != 0) {
#ifndef ROUNDTRIP
            UmlTypeSpec return_type;
#endif

            return_type.type = first_actual_class;
            def.replace(def.find("${type}"), 7, type_def);
#ifndef ROUNDTRIP
            op->set_ReturnType(return_type);
#endif
        }
        else if (!type.explicit_type.isEmpty()) {
            // not a contructor
#ifdef ROUNDTRIP
            return_type = type;
#else
            op->set_ReturnType(type);
#endif
        }
    }

    // parameters

    unsigned rank = 0;
    UmlParameter param;

#ifdef ROUNDTRIP
    if (may_roundtrip)
        while (read_param(container, rank++, tmplts, param, def, FALSE))
            params.append(param);
    else
#endif
        while (read_param(container, rank, tmplts, param, def, op == 0)) {
            if ((op != 0) && ! op->addParameter(rank, param)) {
                JavaCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add param <i>")
                                     + name + "</i> in <i>" + cl->name()
                                     + "</i></b></font><br>");
# ifdef TRACE
                QLOG_INFO() <<"ERROR cannot add param '" << param.name << "' type '" << param.type.Type() << '\n';
# endif
                return FALSE;
            }
            rank += 1;
        }

    Q3CString s = Lex::read_word();

    if (!s.isEmpty() && (*((const char *) s) == '[')) {
#ifdef ROUNDTRIP
        if (may_roundtrip)
#else
        if (op != 0)
#endif
            // do not place it at the same place
            def.insert(def.find("${type}") + 7, (const char *)s);
        s = Lex::read_word();
    }

    if (s.isEmpty()) {
        Lex::premature_eof();
        return FALSE;
    }

    if (s == "throws") {

        // throws

        rank = 0;

        for (;;) {
            if ((s = Lex::read_word()).isEmpty()) {
                Lex::premature_eof();
                return FALSE;
            }

#ifdef ROUNDTRIP
            if (may_roundtrip) {
                UmlTypeSpec typespec;

                container->compute_type(s, typespec, tmplts);
                exceptions.append(typespec);
            }
            else
#endif
                if (op != 0) {
                    UmlTypeSpec typespec;

                    container->compute_type(s, typespec, tmplts);
                    if (! op->addException(rank++, typespec)) {
# ifdef TRACE
                        QLOG_INFO() <<"cannot add exception " << s << '\n';
# endif
                        return FALSE;
                    }
                }

            if (((s = Lex::read_word()) == "{") || (s == ";"))
                break;

            if (s != ",") {
                Lex::error_near(s, " ',' expected");
                return FALSE;
            }
        }
    }

    // definition

    if (abstractp || nativep ||
            (cl->stereotype() == "interface") ||
            (cl->stereotype() == "@interface")) {
        if ((s == "default") && (cl->stereotype() == "@interface")) {
            int index = def.find("${)}");

            Lex::mark();
            s = Lex::read_word();
            if (s == "{") {
                int level = 1;
                char c;

                for (;;) {
                    if ((c = Lex::read_word_bis()) == 0)
                        return FALSE;
                    else if (c == '{')
                        level += 1;
                    else if ((c == '}') && (--level == 0))
                        break;
                }
                s = Lex::region();
            }

            def.insert(index + 4, (const char *)(" default" + s));
            s = Lex::read_word();
        }
        if (s != ";") {
            Lex::error_near(s, " ';' expected");
            return FALSE;
        }
#ifdef REVERSE
# ifndef ROUNDTRIP
        if ((op != 0) && !container->from_libp())
            op->set_JavaBody(0);
# endif
#endif
    }
    else if (s != "{") {
        Lex::error_near(s, " '{' expected");
        return FALSE;
    }
    else {
        Lex::mark();

        // goto the end of the body

#ifndef ROUNDTRIP
        Q3CString body;
#endif
        int level = 1;	// '{' already read
        char c;

        for (;;) {
            if ((c = Lex::read_word_bis()) == 0)
                return FALSE;
            else if (c == '{')
                level += 1;
            else if ((c == '}') && (--level == 0))
                break;
        }

#ifdef REVERSE
        if (
# ifdef ROUNDTRIP
            may_roundtrip || (op != 0)
# else
            (op != 0) && !container->from_libp()
# endif
        ) {
            body = Lex::region();
            body.truncate(body.length() - 1);	// remove }

            // remove fist \n
            if (*((const char *) body) == '\n')
                body.remove(0, 1);

            // remove last spaces and tabs
            int ln = body.length();

            while (ln && ((body[ln - 1] == ' ') || (body[ln - 1] == '\t')))
                ln -= 1;
            body.truncate(ln);
            if (!body.isEmpty() && (body[ln - 1] != '\n'))
                body += "\n";

# ifndef ROUNDTRIP
            op->set_JavaBody(body);
            op->set_JavaContextualBodyIndent(FALSE);
# endif
        }
#endif
    }

#ifdef ROUNDTRIP
    if (may_roundtrip) {
        if (((op = already_exist_from_id(container, body)) != 0) ||
                ((op = already_exist(container, name, params)) != 0)) {
            // update already existing operation
            op->set_usefull();

            {
                // remove \r in case of preserve body
                Q3CString current_body = op->javaBody();
                int index = 0;

                while ((index = current_body.find('\r', index)) != -1)
                    current_body.remove(index, 1);

                if (nequal(current_body, body)) {
                    container->set_updated();
                    op->set_JavaBody(body);
                    op->set_JavaContextualBodyIndent(FALSE);
                }
            }
            if (op->visibility() != visibility) {
                container->set_updated();
                op->set_Visibility(visibility);
            }
            if (op->isClassMember() != staticp) {
                container->set_updated();
                op->set_isClassMember(staticp);
            }
            if (op->isAbstract() != abstractp) {
                container->set_updated();
                op->set_isAbstract(abstractp);
            }
            if (op->isJavaFinal() != finalp) {
                container->set_updated();
                op->set_isJavaFinal(finalp);
            }
            if (op->isJavaSynchronized() != synchronizedp) {
                container->set_updated();
                op->set_isJavaSynchronized(synchronizedp);
            }
            if (nequal(op->javaAnnotations(), annotation)) {
                container->set_updated();
                op->set_JavaAnnotations(annotation);
            }

            if (!op->returnType().equal(return_type)) {
                container->set_updated();
                op->set_ReturnType(return_type);
            }

            Q3ValueList<UmlParameter>::Iterator itp1;
            const Q3ValueList<UmlParameter> old_params = op->params();
            Q3ValueList<UmlParameter>::ConstIterator itp2;

            for (rank = 0, itp1 = params.begin(), itp2 = old_params.begin();
                    (itp1 != params.end()) && (itp2 != old_params.end());
                    ++itp1, ++itp2, rank += 1) {
                UmlParameter & p1 = *itp1;
                const UmlParameter & p2 = *itp2;

                if ((p1.name != p2.name) ||
                        nequal(p1.default_value, p2.default_value) ||
                        !p1.type.equal(p2.type)) {
                    if (p1.dir != InputDirection)
                        p1.dir = p2.dir;
                    op->replaceParameter(rank, p1);
                    container->set_updated();
                }
                else if ((p1.dir == InputDirection) && (p2.dir != InputDirection)) {
                    op->replaceParameter(rank, p1);
                    container->set_updated();
                }
            }

            if (itp1 != params.end()) {
                // have missing params
                container->set_updated();
                do {
                    op->addParameter(rank, *itp1);
                    itp1++;
                    rank += 1;
                } while (itp1 != params.end());
            }
            else if (itp2 != old_params.end()) {
                // have extra params
                container->set_updated();
                do {
                    op->removeParameter(rank);
                    itp2++;
                } while (itp2 != old_params.end());
            }

            Q3ValueList<UmlTypeSpec>::ConstIterator ite1;
            const Q3ValueList<UmlTypeSpec> old_exceptions = op->exceptions();
            Q3ValueList<UmlTypeSpec>::ConstIterator ite2;

            for (rank = 0, ite1 = exceptions.begin(), ite2 = old_exceptions.begin();
                    (ite1 != exceptions.end()) && (ite2 != old_exceptions.end());
                    ++ite1, ++ite2, rank += 1) {
                const UmlTypeSpec & e1 = *ite1;

                if (!e1.equal(*ite2)) {
                    op->replaceException(rank, e1);
                    container->set_updated();
                }
            }

            if (ite1 != exceptions.end()) {
                // have missing exceptions
                container->set_updated();
                do {
                    op->addException(rank, *ite1);
                    ite1++;
                    rank += 1;
                } while (ite1 != exceptions.end());
            }
            else if (ite2 != old_exceptions.end()) {
                // have extra exceptions
                container->set_updated();
                do {
                    op->removeException(rank);
                    ite2++;
                } while (ite2 != old_exceptions.end());
            }

            if (neq(def, op->javaDecl())) {
                container->set_updated();
                op->set_JavaDecl(def);
            }

            Lex::clear_comments();	// params & body comments
            Lex::finish_line();

            if (def.find("${description}") != -1) {
                if (nequal(op->description(), description)) {
                    container->set_updated();
                    op->set_Description(description);
                }
            }
            else if (nequal(op->description(), Lex::simplify_comment(comment))) {
                op->set_Description(comment); // comment was set
                container->set_updated();
            }

            expected_order.append(op);

            return TRUE;
        }

        // operation doesn't yet exist
        container->set_updated();
        op = UmlBaseOperation::create(cl, name);

        if (op == 0) {
            JavaCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add operation <i>")
                                 + name + "</i> in <i>" + cl->name()
                                 + "</i></b></font><br>");
            throw 0;
        }

        expected_order.append(op);

        Q3ValueList<UmlParameter>::ConstIterator itp;

        for (rank = 0, itp = params.begin(); itp != params.end(); ++itp)
            op->addParameter(rank++, *itp);

        Q3ValueList<UmlTypeSpec>::ConstIterator ite;

        for (rank = 0, ite = exceptions.begin(); ite != exceptions.end(); ++ite)
            op->addException(rank++, *ite);
    }

    if (op != 0) {
        op->set_JavaContextualBodyIndent(FALSE);
        op->set_Visibility(visibility);
        if (staticp) op->set_isClassMember(TRUE);
        if (abstractp) op->set_isAbstract(TRUE);
        if (finalp) op->set_isJavaFinal(TRUE);
        if (synchronizedp) op->set_isJavaSynchronized(TRUE);
        if (! annotation.isEmpty()) op->set_JavaAnnotations(annotation);
        op->set_JavaBody(body);
        op->set_ReturnType(return_type);
        if (def != JavaSettings::operationDef())
            op->set_JavaDecl(def);
    }
#else
    if ((op != 0) && (def != JavaSettings::operationDef()))
        op->set_JavaDecl(def);
#endif

    Lex::clear_comments();	// params & body comments
    Lex::finish_line();
    if (!comment.isEmpty())
        if (op != 0)
            op->set_Description((def.find("${description}") != -1)
                                ? description : Lex::simplify_comment(comment));

    return TRUE;
}

bool UmlOperation::read_param(Class * container, unsigned rank,
                              const Q3ValueList<FormalParameterList> & tmplts,
                              UmlParameter & param, Q3CString & def, bool bypass)
{
#ifdef TRACE
    QLOG_INFO() <<"UmlOperation::manage_param " << rank << "\n";
#endif

    bool finalp = FALSE;
    bool in = FALSE;
    bool ellipsis = FALSE;
    Q3CString array;
    bool type_read = FALSE;
    Q3ValueList<UmlTypeSpec> actuals;
    Q3CString str_actuals;
    Q3CString annotation;

    param.name = param.default_value = 0;

    Q3CString s = Lex::read_word();

#ifdef TRACE
    QLOG_INFO() <<"commence par " << s << '\n';
#endif

    if (s == ")")
        return FALSE;

    for (;;) {
        if (s.isEmpty()) {
            Lex::premature_eof();
            return FALSE;
        }
        else if (s == "final")
            finalp = TRUE;
        else if ((s == "void") || (s == "byte") || (s == "char") ||
                 (s == "short") || (s == "int") || (s == "long") ||
                 (s == "float") || (s == "double")) {
            if (type_read) {
                Lex::error_near(s);
                return FALSE;
            }
            param.type.type = 0;
            param.type.explicit_type = s;
            type_read = TRUE;
            in = TRUE;
        }
        else if ((s == ")") || (s == ",")) {
            if (param.name.isEmpty() && !type_read) {
                Lex::error_near(s);
                return FALSE;
            }
            if (s == ")")
                Lex::unread_word(s);

            if (! bypass) {
                param.dir = (finalp || in)
                            ? InputDirection : InputOutputDirection;

                Q3CString s;

                if (rank != 0)
                    s = ", ";
                if (! annotation.isEmpty())
                    s += annotation + " ";
                if (finalp)
                    s += "final ";
                if ((param.type.type != 0) &&
                        !param.type.explicit_type.isEmpty())
                    s += param.type.explicit_type;
                else {
                    s += "${t";
                    s += Q3CString().setNum(rank);
                    s += "}";
                    if (param.type.type != 0)
                        s += str_actuals;
                }
                s += array;
                s += (ellipsis) ? " ... ${p": " ${p";
                s += Q3CString().setNum(rank);
                s += "}";
                def.insert(def.find("${)}"), 	// cannot be -1
                           (const char *)s);
            }
            return TRUE;
        }
        else if (Lex::identifierp(s)) {
            if (!type_read) {
                while (s.at(s.length() - 1) == '.') {
                    // type on several lines, managed in this case
                    Q3CString s2 = Lex::read_word();

                    if (Lex::identifierp(s2))
                        s += s2;
                    else {
                        Lex::error_near(s, " identifier expected");
                        return FALSE;
                    }
                }
#ifdef TRACE
                QLOG_INFO() <<"type = '" << s << "...'\n";
#endif
                if (! bypass) {
                    Q3CString dummy;

                    container->read_type(param.type, 0, tmplts, 0, str_actuals, s,
                                         0, dummy, dummy);

                    if (param.type.explicit_type == "String")
                        // at least for it !
                        in = TRUE;
                }
                else
                    Lex::bypass_type(s);

                type_read = TRUE;
            }
            else if (param.name.isEmpty()) {
                if (s == "...")
                    ellipsis = TRUE;
                else {
                    param.name = s;
#ifdef TRACE
                    QLOG_INFO() <<"name = '" << param.name << "'\n";
#endif
                }
            }
            else {
                Lex::error_near(s);
#ifdef TRACE
                QLOG_INFO() <<"ERROR '" << s << "' alors qu a deja le type et le nom '" << param.name << "'\n";
#endif
                return FALSE;
            }
        }
        else if (*((const char *) s) == '@')
            annotation = s;
        else if (*((const char *) s) == '[') {
            in = FALSE;
            array = s;
        }
        else {
            Lex::error_near(s);
#ifdef TRACE
            QLOG_INFO() <<"ERROR : '" << s << "'\n";
#endif
            return FALSE;
        }

        s = Lex::read_word();
    }
}
Exemplo n.º 9
0
void UmlRelation::write_relation_as_attribute(FileOut & out) {
  UmlRelation * first = side(TRUE);
  Q3CString s;  
  UmlClass * base;

  if ((first->parent()->stereotype() == "stereotype") &&
      (first->roleType()->stereotype() == "metaclass")) {
    if (this != first)
      return;
    
    base = first->roleType();
    s = "base_" + base->name();
  }
  else {
    base = 0;
      
    switch (_lang) {
    case Uml:
      s = roleName();
      break;
    case Cpp:
      if (cppDecl().isEmpty())
	return;
      s = true_name(roleName(), cppDecl());
      break;
    default: // Java
      if (javaDecl().isEmpty())
	return;
      s = true_name(roleName(), javaDecl());
    }
  }
  
  out.indent();
  out << "<ownedAttribute xmi:type=\"uml:Property\" name=\"" << s << '"';
  out.id(this);
  
  if (base != 0)
    out.ref(first, "association", "EXT_");
  else {
    write_visibility(out);
    write_scope(out);
    if (isReadOnly())
      out << " isReadOnly=\"true\"";
    if (isDerived()) {
      out << " isDerived=\"true\"";
      if (isDerivedUnion())
	out << " isDerivedUnion=\"true\"";
    }
    if (isOrdered())
      out << " isOrdered=\"true\"";
    if (isUnique())
      out << " isUnique=\"true\"";
  
    if (first->_assoc_class != 0)
      out.ref(first->_assoc_class, "association");
    else
      out.ref(first, "association", "ASSOC_");
  
    out << " aggregation=\"";
    if (this == first) {
      parent()->memo_relation(this);
      if (_gen_eclipse) {
	switch (relationKind()) {
	case anAggregation:
	case aDirectionalAggregation:
	  out << "shared";
	  break;
	case anAggregationByValue:
	case aDirectionalAggregationByValue:
	  out << "composite";
	  break;
	default:
	  out << "none";
	}
      }
      else
	out << "none";
    }
    else if (_gen_eclipse)
      out << "none";
    else {
      switch (relationKind()) {
      case anAggregation:
      case aDirectionalAggregation:
	out << "shared";
	break;
      case anAggregationByValue:
      case aDirectionalAggregationByValue:
	out << "composite";
	break;
      default:
	out << "none";
      }
    }
    out << '"';
  }
  
  out << ">\n";
  out.indent(+1);
  
  out.indent();
  out << "<type xmi:type=\"uml:Class\"";
  if (base != 0) {
    if (! base->propertyValue("metaclassPath", s))
      s = (_uml_20) ? "http://schema.omg.org/spec/UML/2.0/uml.xml"
		    : "http://schema.omg.org/spec/UML/2.1/uml.xml";
    out << " href=\"" << s << '#' << base->name() << '"';
  }
  else
    out.idref(roleType());
  out << "/>\n";
  write_multiplicity(out, multiplicity(), this);
  write_default_value(out, defaultValue(), this);
  write_constraint(out);
  write_annotation(out);
  write_description_properties(out);
  
  out.indent(-1);
  out.indent();
  out << "</ownedAttribute>\n";

  unload();
}
Exemplo n.º 10
0
bool UmlAttribute::new_one(Class * container, const Q3CString & name,
			   const Q3CString & type, const Q3CString & modifier,
			   const Q3CString & pretype, const Q3CString & array,
			   aVisibility visibility, bool staticp, bool constp,
			   bool typenamep, bool mutablep, bool volatilep,
			   const Q3CString & bitfield, const Q3CString & value,
			   Q3CString comment, Q3CString description
#ifdef ROUNDTRIP
			   , bool roundtrip, Q3PtrList<UmlItem> & expected_order
#endif
			   )
{
#ifdef DEBUG_BOUML
  cout << "ATTRIBUTE '" << name << "' type '" << type << "' modifier '" << modifier << "' array '" << array << "'\n";
#endif
  
  if (
#ifdef REVERSE
      container->from_libp() &&
#endif
      (visibility == PrivateVisibility)) {
    Lex::finish_line();
    Lex::clear_comments();
    return TRUE;
  }
  
  UmlClass * cl = container->get_uml();
  UmlAttribute * at;
  
#ifdef ROUNDTRIP
  bool created;
  
  if (!roundtrip ||
      ((at = search_attr(cl, name)) == 0)) {
#endif
    at = UmlBaseAttribute::create(cl, name);
    
    if (at == 0) {
      UmlCom::trace(Q3CString("<font face=helvetica><b>cannot add attribute <i>")
		    + name + "</i> in <i>" + Q3CString(cl->name())
		    + "</i></b></font><br><hr>");  
      return FALSE;
    }
  
#ifdef REVERSE
# ifndef ROUNDTRIP
    Statistic::one_attribute_more();
# else
    if (roundtrip)
      container->set_updated();
    created = TRUE;
  }
  else
    created = FALSE;
# endif
#endif
  
  Lex::finish_line();
  
  comment = Lex::get_comments(comment);
  description = Lex::get_description(description);
  
  bool pfunc = (type.find('$') != -1);
  UmlTypeSpec typespec;
  Q3CString typeform;
  Q3CString stereotype;
  
  if (! pfunc) {
    typeform = (pretype.isEmpty())
      ? Q3CString("${type}")
      : pretype + " ${type}";
    
    container->compute_type(type, typespec, typeform);
  }
  else {
    typespec.explicit_type = type.simplifyWhiteSpace();
    
    int index = typespec.explicit_type.find("${name}");
    
    if (index != -1)
      typespec.explicit_type.remove(index, 7);
  }
  
  Q3CString decl = CppSettings::attributeDecl("");
  int index = decl.find("${type}");
  
  if ((index == -1) ||
      (decl.find("${const}") == -1) ||
      (decl.find("${name}") == -1) ||
      (decl.find("${mutable}") == -1) ||
      (decl.find("${volatile}") == -1) ||
      (decl.find(';') == -1)) {
    decl = "    ${comment}${static}${mutable}${volatile}${const}${type} ${name}${value};";
    index = decl.find("${type}");
  }
  
  if (pfunc)
    decl.replace(index, decl.find("${name}") + 7 - index, type);
  else {
    if (!modifier.isEmpty())
      decl.insert(index + 7, (const char*)(Q3CString(" ") + modifier));
        
    if (typeform != "${type}")
      decl.replace(index, 7, typeform);
    else if (typespec.type == 0) {
      Q3CString t = typespec.explicit_type;
      int index2;
      
      if (!t.isEmpty() &&
	  (t.at(t.length() - 1) == '>') &&
	  ((index2 = t.find('<')) > 0)) {
	stereotype = t.left(index2);
	typespec.explicit_type =
	  // may be a,b ...
	  t.mid(index2 + 1, t.length() - 2 - index2);
	decl.replace(index, 7, "${stereotype}<${type}>");
      }
    }
    
    if (!array.isEmpty())
      decl.insert(decl.find("${name}") + 7, "${multiplicity}");
    
    if (!bitfield.isEmpty())
      decl.insert(decl.find(';'), (const char *)(Q3CString(" : ") + bitfield));
  }
  
  if (typenamep) {
    int index = decl.find("${const}") + 8; // find cannot return -1
    int index2 = decl.find("${mutable}") + 10; // find cannot return -1
    int index3 = decl.find("${volatile}") + 11; // find cannot return -1
    
    if (index2 > index) index = index2;
    if (index3 > index) index = index3;
    
    decl.insert(index, "typename ");
  }
  
  if (!value.isEmpty() && ((index = decl.find("${value}")) != -1))
    decl.insert(index + 2,  "h_");
  
#ifdef ROUNDTRIP
  if (roundtrip && !created) {
    if (decl.find("${description}") != -1) {
      if (nequal(at->description(), description)) {
	at->set_Description(description);
	container->set_updated();
      }
    }
    else if (nequal(at->description(), Lex::simplify_comment(comment))) {
      at->set_Description(comment); // comment was set
      container->set_updated();
    }
          
    if (at->isReadOnly() != constp) {
      at->set_isReadOnly(constp);
      container->set_updated();
    }
    
    if (at->isCppMutable() != mutablep) {
      at->set_isCppMutable(mutablep);
      container->set_updated();
    }
    
    if (at->isVolatile() != volatilep) {
      at->set_isVolatile(volatilep);
      container->set_updated();
    }
    
    if (at->isClassMember() != staticp) {
      at->set_isClassMember(staticp);
      container->set_updated();
    }
    
    if (neq(at->multiplicity(), array)) {
      at->set_Multiplicity(array);
      container->set_updated();
    }
    
    if (!staticp) {
      Q3CString v = at->defaultValue();
      
      if (!v.isEmpty() && (((const char *) v)[0] == '='))
	v = v.mid(1);
      
      if (nequal(v, value)) {
	at->set_DefaultValue(value);
	container->set_updated();
      }
    }
    
    if (at->visibility() != visibility) {
      at->set_Visibility(visibility);
      container->set_updated();
    }
    
    if (!stereotype.isEmpty()) {
      Q3CString cppst;
      
      if (!at->stereotype().isEmpty())
	cppst = CppSettings::relationAttributeStereotype(at->stereotype());
      
      if (cppst != stereotype) {
	at->set_Stereotype(stereotype);
	container->set_updated();
      }
    }
    
    if (!at->type().equal(typespec)) {
      at->set_Type(typespec);
      container->set_updated();
    }
    
    if (neq(at->cppDecl(), decl)) {
      at->set_CppDecl(decl);
      container->set_updated();
    }
          
    at->set_usefull();
    
    expected_order.append(at);
  }
  else {
#endif
    if (!comment.isEmpty())
      at->set_Description((decl.find("${description}") != -1)
			  ? description : Lex::simplify_comment(comment));
    
    if (constp)
      at->set_isReadOnly(TRUE);
    
    if (mutablep)
      at->set_isCppMutable(TRUE);
    
    if (volatilep)
      at->set_isVolatile(TRUE);
    
    if (staticp)
      at->set_isClassMember(TRUE);
    
    if (!array.isEmpty())
      at->set_Multiplicity(array);
    
    if (! value.isEmpty())
      at->set_DefaultValue(value);
    
    at->set_Visibility(visibility);
    
    if (! stereotype.isEmpty())
      at->set_Stereotype(stereotype);
    
    at->set_Type(typespec);
    
    at->set_CppDecl(decl);
    
#ifdef ROUNDTRIP
    if (roundtrip)
      expected_order.append(at);
  }
#endif
  
  return TRUE;
}
Exemplo n.º 11
0
void UmlAttribute::generate_def(QTextOStream & f, Q3CString indent, bool h,
				Q3CString templates, Q3CString cl_names,
				Q3CString, Q3CString) {
  if (isClassMember() && !cppDecl().isEmpty()) {
    UmlClass * cl = (UmlClass *) parent();

    if ((!templates.isEmpty() || ((cl->name().find('<') != -1))) ? h : !h) {
      const char * p = cppDecl();
      const char * pp = 0;
      
      while ((*p == ' ') || (*p == '\t'))
	p += 1;
      
      bool re_template = !templates.isEmpty() && 
	insert_template(p, f, indent, templates);
      
      if (*p != '#')
	f << indent;
      
      const char * pname = name_spec(p);
      
      for (;;) {
	if (*p == 0) {
	  if (pp == 0)
	    break;
	  
	  // comment management done
	  p = pp;
	  pp = 0;

	  if (re_template)
	    f << templates;

	  if (*p == 0)
	    break;

	  f << indent;
	}

	if (*p == '\n') {
	  f << *p++;
	  if (*p && (*p != '#'))
	    f << indent;
	}
	else if (*p == '@')
	  manage_alias(p, f);
	else if (*p != '$') {
	  if (p == pname)
	    f << cl_names << "::";
	  f << *p++;
	}
	else if (!strncmp(p, "${comment}", 10)) {
	  if (!manage_comment(p, pp, CppSettings::isGenerateJavadocStyleComment())
	      && re_template)
	    f << templates;
	}
	else if (!strncmp(p, "${description}", 14)) {
	  if (!manage_description(p, pp) && re_template)
	    f << templates;
	}
	else if (!strncmp(p, "${name}", 7)) {
	  if (*pname == '$')
	    f << cl_names << "::";
	  p += 7;
	  f << name();
	}
	else if (!strncmp(p, "${multiplicity}", 15)) {
	  p += 15;
      
	  const Q3CString & m = multiplicity();
	  
	  if (!m.isEmpty() && (*((const char *) m) == '['))
	    f << m;
	  else
	    f << '[' << m << ']';
	}
	else if (!strncmp(p, "${stereotype}", 13)) {
	  p += 13;
	  f << CppSettings::relationAttributeStereotype(stereotype());
	}
	else if (!strncmp(p, "${value}", 8)) {
	  if (!defaultValue().isEmpty()) {
	    if (need_equal(p, defaultValue()))
	      f << " = ";
	    f << defaultValue();
	  }
	  p += 8;
	}
	else if (!strncmp(p, "${h_value}", 10))
	  p += 10;
	else if (!strncmp(p, "${static}", 9)) {
	  p += 9;
	}
	else if (!strncmp(p, "${const}", 8)) {
	  p += 8;
	  if (isReadOnly())
	    f << "const ";
	}
	else if (!strncmp(p, "${volatile}", 11)) {
	  p += 11;
	  if (isVolatile())
	    f << "volatile ";
	}
	else if (!strncmp(p, "${mutable}", 10)) {
	  p += 10;
	}
	else if (!strncmp(p, "${type}", 7)) {
	  p += 7;
	  UmlClass::write(f, type());
	  //f << CppSettings::Type(Type().Type());
	}
	else
	  // strange
	  f << *p++;
      }
      
      f << '\n';
    }
  }
}
Exemplo n.º 12
0
// not from a form 'generic<...C...> var' where C is a class
bool UmlRelation::new_one(Class * container, const WrapperStr & name,
                          UmlTypeSpec & dest, WrapperStr str_actuals,
                          aVisibility visibility, bool staticp,
                          bool constp, bool transientp, bool volatilep,
                          const WrapperStr & array, const WrapperStr & value,
                          WrapperStr comment, WrapperStr description,
                          WrapperStr annotation
#ifdef ROUNDTRIP
                          , bool roundtrip, QList<UmlItem *> & expected_order
#endif
                         )
{
#ifdef TRACE
    QLOG_INFO() << "RELATION '" << name << "' from '" << cl->Name() << "' to '" << dest.type->Name()
                << "' array '" << array << "'\n";
#endif

    if (
#ifdef REVERSE
        container->from_libp() &&
#endif
        (visibility == PrivateVisibility)) {
        Lex::finish_line();
        Lex::clear_comments();
        return TRUE;
    }

    UmlClass * cl = container->get_uml();
    UmlRelation * rel;

#ifdef ROUNDTRIP
    bool created;

    if (!roundtrip ||
        ((rel = search_rel(container, name, dest.type, "")) == 0)) {
#endif
        rel = UmlBaseRelation::create(aDirectionalAssociation, cl, dest.type);

        if (rel == 0) {
            JavaCatWindow::trace(WrapperStr("<font face=helvetica><b>cannot add relation <i>")
                                 + name + "</i> in <i>" + cl->name() + "</i> to <i>"
                                 + dest.type->name() + "</i></b></font><br>");
            return FALSE;
        }

#ifdef REVERSE
# ifndef ROUNDTRIP
        Statistic::one_relation_more();
# else

        if (roundtrip)
            container->set_updated();

        created = TRUE;
    }
    else
        created = FALSE;

# endif
#endif

        WrapperStr decl = JavaSettings::relationDecl(array);

        UmlClass::manage_generic(decl, dest, str_actuals, "${type}");

        Lex::finish_line();
        comment = Lex::get_comments(comment);
        description = Lex::get_description(description);

#ifdef ROUNDTRIP

        if (roundtrip && !created) {
            if (rel->visibility() != visibility) {
                rel->set_Visibility(visibility);
                container->set_updated();
            }

            if (decl.find("${description}") != -1) {
                if (nequal(rel->description(), description)) {
                    rel->set_Description(description);
                    container->set_updated();
                }
            }
            else if (nequal(rel->description(), Lex::simplify_comment(comment))) {
                rel->set_Description(comment); // comment was set
                container->set_updated();
            }

            if (rel->isReadOnly() != constp) {
                rel->set_isReadOnly(constp);
                container->set_updated();
            }

            if (rel->isJavaTransient() != transientp) {
                rel->set_isJavaTransient(transientp);
                container->set_updated();
            }

            if (rel->isVolatile() != volatilep) {
                rel->set_isVolatile(volatilep);
                container->set_updated();
            }

            if (rel->isClassMember() != staticp) {
                rel->set_isClassMember(staticp);
                container->set_updated();
            }

            if (neq(rel->multiplicity(), array)) {
                rel->set_Multiplicity(array);
                container->set_updated();
            }

            WrapperStr v = rel->defaultValue();

            if (!v.isEmpty() && (((const char *) v)[0] == '='))
                v = v.mid(1);

            if (nequal(v, value)) {
                rel->set_DefaultValue(value);
                container->set_updated();
            }

            if (nequal(rel->javaAnnotations(), annotation)) {
                rel->set_JavaAnnotations(annotation);
                container->set_updated();
            }

            if (neq(rel->javaDecl(), decl)) {
                rel->set_JavaDecl(decl);
                container->set_updated();
            }

            rel->set_usefull();

            expected_order.append(rel);
        }
        else {
#endif
            rel->set_Visibility(visibility);

            if (!comment.isEmpty())
                rel->set_Description((decl.find("${description}") != -1)
                                     ? description : comment);

            if (constp)
                rel->set_isReadOnly(TRUE);

            if (transientp)
                rel->set_isJavaTransient(TRUE);

            if (volatilep)
                rel->set_isVolatile(TRUE);

            if (staticp)
                rel->set_isClassMember(TRUE);

            if (!array.isEmpty())
                rel->set_Multiplicity(array);

            if (! value.isEmpty())
                rel->set_DefaultValue(value);

            if (! annotation.isEmpty())
                rel->set_JavaAnnotations(annotation);

            rel->set_JavaDecl(decl);

            rel->set_RoleName(name);

#ifdef ROUNDTRIP

            if (roundtrip)
                expected_order.append(rel);
        }

#endif

        return TRUE;
    }
Exemplo n.º 13
0
bool UmlRelation::new_one(Class * container, const Q3CString & name,
			  UmlClass * dest, const Q3CString & modifier, 
			  const Q3CString & pretype, const Q3CString & array, 
			  const Q3CString & typeform, aVisibility visibility,
			  bool staticp, bool constp, bool mutablep, bool volatilep, 
			  const Q3CString & value, Q3CString comment,
			  Q3CString description
#ifdef ROUNDTRIP
			  , bool roundtrip, Q3PtrList<UmlItem> & expected_order
#endif
			  )
{
#ifdef DEBUG_BOUML
  cout << "RELATION '" << name << "' from '" << cl->name() << "' to '" << dest->name()
    << "' modifier '" << modifier << "' array '" << array
      << "' typeform '" << typeform << "'\n";
#endif
  
  if (
#ifdef REVERSE
      container->from_libp() &&
#endif
      (visibility == PrivateVisibility)) {
    Lex::finish_line();
    Lex::clear_comments();
    return TRUE;
  }
  
  UmlClass * cl = container->get_uml();
  UmlRelation * rel;
  
#ifdef ROUNDTRIP
  if (roundtrip &&
      ((rel = search_rel(container, name, dest, "")) != 0)) {
    rel->set_usefull();
    expected_order.append(rel);
  }
  else {
#endif  
    rel = UmlBaseRelation::create((modifier.isEmpty() &&
				   ((typeform == "${type}") ||
				    (typeform[typeform.find("${type}") + 7] != '*')))
				  ? aDirectionalAggregationByValue
				  : aDirectionalAssociation,
				  cl, dest);
  
    if (rel == 0) {
      UmlCom::trace(Q3CString("<font face=helvetica><b>cannot add relation <i>")
		    + name + "</i> in <i>" + cl->name() + "</i> to <i>"
		    + dest->name() + "</i></b></font><br><hr>");  
      return FALSE;
    }
    
#ifdef REVERSE
# ifndef ROUNDTRIP
    Statistic::one_relation_more();
# else
    if (roundtrip) {
      expected_order.append(rel);
      container->set_updated();
      roundtrip = FALSE;
    }
  }
# endif
#endif
  
  Lex::finish_line();
  
  comment = Lex::get_comments(comment);
  description = Lex::get_description(description);
  
#ifdef ROUNDTRIP
  if (roundtrip) {
    if (rel->visibility() != visibility) {
      rel->set_Visibility(visibility);
      container->set_updated();
    }
  
    if (rel->isReadOnly() != constp) {
      rel->set_isReadOnly(constp);
      container->set_updated();
    }
    
    if (rel->isClassMember() != staticp) {
      rel->set_isClassMember(staticp);
      container->set_updated();
    }
    
    if (rel->isCppMutable() != mutablep) {
      rel->set_isCppMutable(mutablep);
      container->set_updated();
    }
    
    if (rel->isVolatile() != volatilep) {
      rel->set_isVolatile(volatilep);
      container->set_updated();
    }
  }
  else {
#endif
    rel->set_Visibility(visibility);
    if (constp) rel->set_isReadOnly(TRUE);
    if (staticp) rel->set_isClassMember(TRUE);
    if (mutablep) rel->set_isCppMutable(TRUE);
    if (volatilep) rel->set_isVolatile(TRUE);
    
#ifdef ROUNDTRIP
  }
#endif
  
  Q3CString decl;
  
  if (typeform != "${type}") {
    // array & modified are empty, pretype is empty ?
    decl = CppSettings::relationDecl(TRUE, "*");
    
    int index = typeform.find("<");	// cannot be -1
    Q3CString st = typeform.left(index);
    Q3CString st_uml = CppSettings::umlType(st);

#ifdef ROUNDTRIP
    if (roundtrip) {
      if (st_uml.isEmpty()) 
	st_uml = st;
      
      if (neq(rel->stereotype(), st_uml)) {
	rel->set_Stereotype(st_uml);
	container->set_updated();
      }
    }
    else
#endif
      rel->set_Stereotype((st_uml.isEmpty()) ? st : st_uml);
    
    int index2;
    
    if ((index2 = decl.find("<${type}>")) == -1) {
      decl = "    ${comment}${static}${mutable}${volatile}${const}${stereotype}<${type}> ${name}${value};";
      index2 = decl.find("<${type}>");
    }
    decl.replace(index2, 9, typeform.mid(index));
  }
  else {
    if (!array.isEmpty()) {
#ifdef ROUNDTRIP
    if (roundtrip) {
      if (neq(rel->multiplicity(), array)) {
	rel->set_Multiplicity(array);
	container->set_updated();
      }
    }
    else
#endif
      rel->set_Multiplicity(array);
    }
    decl = CppSettings::relationDecl(modifier != "*", array);
    
    int index;
    
    if (!pretype.isEmpty() &&
	((index = decl.find("${type}")) != 0))
      decl.insert(index,(const char*)( pretype + " "));
    
    if ((modifier == "&") && ((index = decl.find("${type}")) != 0))
      decl.insert(index + 7, " &");
  }
  
  if (! value.isEmpty()) {
    int index = decl.find("${value}");
    
    if (index != -1)
      decl.insert(index + 2,  "h_");
    
#ifdef ROUNDTRIP
    if (roundtrip) {
      if (!staticp) {
	Q3CString v = rel->defaultValue();
	
	if (!v.isEmpty() && (((const char *) v)[0] == '='))
	  v = v.mid(1);
	
	if (nequal(v, value)) {
	  rel->set_DefaultValue(value);
	  container->set_updated();
	}
      }
    }
    else
#endif
      rel->set_DefaultValue(value);
  }
  
#ifdef ROUNDTRIP
  if (roundtrip) {
    if (neq(rel->cppDecl(), decl)) {
      rel->set_CppDecl(decl);
      container->set_updated();
    }
    
    if (decl.find("${description}") != -1) {
      if (nequal(rel->description(), description)) {
	rel->set_Description(description);
	container->set_updated();
      }
    }
    else if (nequal(rel->description(), Lex::simplify_comment(comment))) {
      rel->set_Description(comment); // comment was set
      container->set_updated();
    }
    
    // role name is the right one
    return TRUE;
  }
#endif

  rel->set_CppDecl(decl);
  
  if (!comment.isEmpty())
    rel->set_Description((decl.find("${description") != -1)
			 ? description : Lex::simplify_comment(comment));
  
  return rel->set_RoleName(name);
}
Exemplo n.º 14
0
void UmlRelation::generate_def(QTextStream & f, WrapperStr indent, bool h,
                               WrapperStr templates, WrapperStr cl_names,
                               WrapperStr, WrapperStr)
{
    if (isClassMember() && !cppDecl().isEmpty()) {
        UmlClass * cl = (UmlClass *) parent();

        if ((!templates.isEmpty() || (cl->name().find('<') != -1))
            ? h : !h) {
            const char * p = cppDecl();
            const char * pp = 0;

            while ((*p == ' ') || (*p == '\t'))
                p += 1;

            bool re_template = !templates.isEmpty() &&
                               insert_template(p, f, indent, templates);

            if (*p != '#')
                f << indent;

            const char * pname = name_spec(p);

            for (;;) {
                if (*p == 0) {
                    if (pp == 0)
                        break;

                    // comment management done
                    p = pp;
                    pp = 0;

                    if (re_template)
                        f << templates;

                    if (*p == 0)
                        break;

                    if (*p != '#')
                        f << indent;
                }

                if (*p == '\n') {
                    f << toLocale(p);

                    if (*p && (*p != '#'))
                        f << indent;
                }
                else if (*p == '@')
                    manage_alias(p, f);
                else if (*p != '$') {
                    if (p == pname)
                        f << cl_names << "::";

                    f << toLocale(p);
                }
                else if (!strncmp(p, "${comment}", 10)) {
                    if (!manage_comment(p, pp, CppSettings::isGenerateJavadocStyleComment())
                        && re_template)
                        f << templates;
                }
                else if (!strncmp(p, "${description}", 14)) {
                    if (!manage_description(p, pp) && re_template)
                        f << templates;
                }
                else if (!strncmp(p, "${static}", 9)) {
                    p += 9;
                }
                else if (!strncmp(p, "${const}", 8)) {
                    p += 8;

                    if (isReadOnly())
                        f << "const ";
                }
                else if (!strncmp(p, "${volatile}", 11)) {
                    p += 11;

                    if (isVolatile())
                        f << "volatile ";
                }
                else if (!strncmp(p, "${mutable}", 10)) {
                    p += 10;
                }
                else if (!strncmp(p, "${type}", 7)) {
                    p += 7;
                    roleType()->write(f);
                }
                else if (!strncmp(p, "${name}", 7)) {
                    p += 7;

                    if (*pname == '$')
                        f << cl_names << "::";

                    f << roleName();
                }
                else if (!strncmp(p, "${inverse_name}", 15)) {
                    p += 15;

                    switch (relationKind()) {
                    case anAssociation:
                    case anAggregation:
                    case anAggregationByValue:
                        f << side(side(TRUE) != this)->roleName();

                    default:
                        break;
                    }
                }
                else if (!strncmp(p, "${multiplicity}", 15)) {
                    p += 15;

                    const WrapperStr & m = multiplicity();

                    if (!m.isEmpty() && (*((const char *) m) == '['))
                        f << m;
                    else
                        f << '[' << m << ']';
                }
                else if (!strncmp(p, "${stereotype}", 13)) {
                    p += 13;
                    f << CppSettings::relationAttributeStereotype(stereotype());
                }
                else if (!strncmp(p, "${value}", 8)) {
                    if (!defaultValue().isEmpty()) {
                        if (need_equal(p, defaultValue()))
                            f << " = ";

                        f << defaultValue();
                    }

                    p += 8;
                }
                else if (!strncmp(p, "${h_value}", 10))
                    p += 10;
                else if (!strncmp(p, "${association}", 14)) {
                    p += 14;
                    UmlClass::write(f, association());
                }
                else
                    // strange
                    f << toLocale(p);
            }

            f << '\n';
        }
    }
}
Exemplo n.º 15
0
// from a form 'generic<...C...> var' where C is a class
bool UmlRelation::new_one(Class * container, const QCString & name,
			  UmlClass * type, QCString type_def,
			  QCString genericname,
			  aVisibility visibility, bool staticp,
			  bool constp, bool transientp, bool volatilep,
			  const QCString & array, const QCString & value,
			  QCString comment, QCString description,
			  QCString annotation
#ifdef ROUNDTRIP
			  , bool roundtrip, QList<UmlItem> & expected_order
#endif
			)
{
#ifdef TRACE
  cout << "RELATION '" << name << "' from '" << cl->Name() << "' to '" << type->Name()
    << "' array '" << array << "'\n";
#endif
  
  if (
#ifdef REVERSE
      container->from_libp() &&
#endif
      (visibility == PrivateVisibility)) {
    Lex::finish_line();
    Lex::clear_comments();
    return TRUE;
  }
  
  QCString st = JavaSettings::umlType(genericname);
  
  if (st.isEmpty())
    st = genericname;
  
  UmlClass * cl = container->get_uml();
  UmlRelation * rel;
  
#ifdef ROUNDTRIP
  bool created;
  
  if (!roundtrip ||
      ((rel = search_rel(container, name, type, st)) == 0)) {
#endif
  rel = UmlBaseRelation::create(aDirectionalAssociation, cl, type);
  
  if (rel == 0) {
    JavaCatWindow::trace(QCString("<font face=helvetica><b>cannot add relation <i>")
			 + name + "</i> in <i>" + cl->name() + "</i> to <i>"
			 + type->name() + "</i></b></font><br>");  
    return FALSE;
  }
    
#ifdef REVERSE
# ifndef ROUNDTRIP
    Statistic::one_relation_more();
# else
    if (roundtrip)
      container->set_updated();
    
    created = TRUE;
  }
  else
    created = FALSE;
# endif
#endif
  
  Lex::finish_line();
  
  comment = Lex::get_comments(comment);
  description = Lex::get_description(description);
  
  QCString decl = JavaSettings::relationDecl(array);
  
  type_def.replace(0, genericname.length(), "${stereotype}");
  decl.replace(decl.find("${type}"), 7, type_def);
    
  
#ifdef ROUNDTRIP
  if (roundtrip && !created) {
    if (rel->visibility() != visibility) {
      rel->set_Visibility(visibility);
      container->set_updated();
    }
  
    if (decl.find("${description}") != -1) {
      if (nequal(rel->description(), description)) {
	rel->set_Description(description);
	container->set_updated();
      }
    }
    else if (nequal(rel->description(), Lex::simplify_comment(comment))) {
      rel->set_Description(comment); // comment was set
      container->set_updated();
    }
  
    if (rel->isReadOnly() != constp) {
      rel->set_isReadOnly(constp);
      container->set_updated();
    }
    
    if (rel->isJavaTransient() != transientp) {
      rel->set_isJavaTransient(transientp);
      container->set_updated();
    }
    
    if (rel->isVolatile() != volatilep) {
      rel->set_isVolatile(volatilep);
      container->set_updated();
    }
    
    if (rel->isClassMember() != staticp) {
      rel->set_isClassMember(staticp);
      container->set_updated();
    }
    
    if (neq(rel->multiplicity(), array)) {
      rel->set_Multiplicity(array);
      container->set_updated();
    }
    
    if (neq(rel->defaultValue(), value)) {
      rel->set_DefaultValue(value);
      container->set_updated();
    }
    
    if (nequal(rel->javaAnnotations(), annotation)) {
      rel->set_JavaAnnotations(annotation);
      container->set_updated();
    }
    
    if (neq(rel->stereotype(), st) &&
	(rel->stereotype().isEmpty() ||
	 (JavaSettings::relationAttributeStereotype(rel->stereotype()) != st))) {
      rel->set_Stereotype(st);
      container->set_updated();
    }
    
    if (neq(rel->javaDecl(), decl)) {
      rel->set_JavaDecl(decl);
      container->set_updated();
    }
    
    // role name is the right one
    
    rel->set_usefull();
    expected_order.append(rel);
  }
  else {
#endif
  rel->set_Visibility(visibility);
  
  if (!comment.isEmpty())
    rel->set_Description((decl.find("${description}") != -1)
			 ? description : Lex::simplify_comment(comment));
  
  if (constp)
    rel->set_isReadOnly(TRUE);
  
  if (transientp)
    rel->set_isJavaTransient(TRUE);
  
  if (volatilep)
    rel->set_isVolatile(TRUE);
  
  if (staticp)
    rel->set_isClassMember(TRUE);
  
  if (!array.isEmpty())
    rel->set_Multiplicity(array);
  
  if (! value.isEmpty())
    rel->set_DefaultValue(value);
  
  if (! annotation.isEmpty())
    rel->set_JavaAnnotations(annotation);
  
  rel->set_Stereotype(st);
  
  rel->set_JavaDecl(decl);

  rel->set_RoleName(name);
  
#ifdef ROUNDTRIP
  if (roundtrip)
    expected_order.append(rel);
  }
#endif
  
  return TRUE;
}
Exemplo n.º 16
0
void CppRefType::compute(Q3PtrList<CppRefType> & dependencies,
                         const WrapperStr & hdef, const WrapperStr & srcdef,
                         WrapperStr & h_incl,  WrapperStr & decl, WrapperStr & src_incl,
                         UmlArtifact * who)
{
    UmlPackage * pack = who->package();
    WrapperStr hdir;
    WrapperStr srcdir;

    if (CppSettings::isRelativePath()) {
        WrapperStr empty;

        hdir = pack->header_path(empty);
        srcdir = pack->source_path(empty);
    }
    else if (CppSettings::isRootRelativePath())
        hdir =  srcdir = UmlPackage::rootDir();

    // aze.cpp includes aze.h
    src_incl += "#include \"";

    if (CppSettings::includeWithPath())
        src_incl += pack->header_path(who->name(), srcdir);
    else {
        src_incl += who->name();
        src_incl += '.';
        src_incl += CppSettings::headerExtension();
    }

    src_incl += "\"\n";
    h_incl = "";	// to not be WrapperStr::null
    decl = "";	// to not be WrapperStr::null

    CppRefType * ref;

    for (ref = dependencies.first(); ref != 0; ref = dependencies.next())
    {
        UmlClass * cl = (ref->type.type)
                        ? ref->type.type
                        : UmlBaseClass::get(ref->type.explicit_type, 0);
        bool included = ref->included;

        WrapperStr hform;	// form in header
        WrapperStr srcform;	// form in source

        if (cl == 0) {
            WrapperStr in = CppSettings::include(ref->type.explicit_type);

            if (!in.isEmpty())
                hform = srcform = in + '\n';
            else
                // doesn't know what it is
                continue;
        }
        else if (cl->isCppExternal())
        {
            QString className = cl->name();
            hform = cl->cppDecl();

            int index;

            if ((index = hform.find('\n')) == -1)
                // wrong form
                continue;

            hform = hform.mid(index + 1) + '\n';

            for (;;) {
                if ((index = hform.find("${name}")) != -1)
                    hform.replace(index, 7, cl->name());
                else if ((index = hform.find("${Name}")) != -1)
                    hform.replace(index, 7, capitalize(cl->name()));
                else if ((index = hform.find("${NAME}")) != -1)
                    hform.replace(index, 7, cl->name().upper());
                else if ((index = hform.find("${nAME}")) != -1)
                    hform.replace(index, 7, cl->name().lower());
                else
                    break;
            }

            srcform = hform;
        }
        else {
            QString className = cl->name();
            WrapperStr st = cl->cpp_stereotype();

            if ((st == "enum") || (st == "typedef"))
                included = TRUE;

            UmlArtifact * art = cl->associatedArtifact();

            if (art != 0) {
                if (art == who)
                    // don't include itself
                    continue;

                if (CppSettings::includeWithPath()) {
                    UmlPackage * p = art->package();

                    hform = "#include \"" + p->header_path(art->name(), hdir) + "\"\n";
                    srcform = "#include \"" + p->header_path(art->name(), srcdir) + "\"\n";
                }
                else
                    srcform = hform = "#include \"" + art->name() + '.' +
                                      CppSettings::headerExtension() + "\"\n";
            }
            else if (cl->parent()->kind() != aClass) {
                write_trace_header();
                UmlCom::trace(WrapperStr("&nbsp;&nbsp;&nbsp;&nbsp;<font color=\"red\"><b> class<i> ") + cl->name() +
                              "</i> referenced but does not have associated <i>artifact</i></b></font><br>");
                incr_warning();
                continue;
            }
        }

        if (included) {
            // #include must be placed in the header file
            if ((h_incl.find(hform) == -1) && (hdef.find(hform) == -1))
                h_incl += hform;
        }
        else if ((cl != 0) &&
                 (cl->parent()->kind() != aClass)) {	// else too complicated
            // #include useless in header file, place it in the source file
            if ((src_incl.find(srcform) == -1) && (h_incl.find(hform) == -1) &&
                (hdef.find(hform) == -1) && (srcdef.find(srcform) == -1))
                src_incl += srcform;

            if (!cl->isCppExternal()) {
                // header file must contains the declaration
                hform = cl->decl();

                if (decl.find(hform) == -1)
                    decl += hform;

                if ((cl->associatedArtifact() == 0) &&
                    (cl->parent()->kind() != aClass)) {
                    write_trace_header();
                    UmlCom::trace(WrapperStr("&nbsp;&nbsp;&nbsp;&nbsp;<font color=\"red\"><b> class<i> ") + cl->name() +
                                  "</i> referenced but does not have associated <i>artifact</i></b></font><br>");
                    incr_warning();
                }
            }
        }
        else if (!hform.isEmpty()) {
            // have the #include form but does not know if it is a class or other,
            // generate the #include in the header file EXCEPT if the #include is
            // already in the header/source file to allow to optimize the generated
            // code
            if ((src_incl.find(srcform) == -1) && (h_incl.find(hform) == -1) &&
                (hdef.find(hform) == -1) && (srcdef.find(srcform) == -1))
                h_incl += hform;
        }
    }
}
Exemplo n.º 17
0
bool UmlOperation::new_one(Class * container, aVisibility visibility,
			   bool finalp, bool abstractp, bool staticp,
			   Q3CString comment, Q3CString description)
{
  // 'function' was read, it is followed by :
  // ['&'] name'(' {'array' | <classname>] ['&'] '$'<varname> ['=' <value>]}* ')' '{' ... '}'
  Q3CString s = Lex::read_word();
  bool refp;
  
  if (s == "&") {
    refp = TRUE;
    s = Lex::read_word();
  }
  else
    refp = FALSE;
  
  if (s.isEmpty()) {
    Lex::premature_eof();
    return FALSE;
  }
    
  Q3CString name = s;
  
#ifdef TRACE
  QLOG_INFO() <<"OPERATION '" << name << "'\n";
#endif
  
  s = Lex::read_word();
  if (s != "(") {
    Lex::syntax_error("'(' expected rather than '" + s + "'");
    return FALSE;
  }
  
  UmlClass * cl = container->get_uml();
  UmlOperation * op;
  
#ifndef REVERSE
  if (visibility == PrivateVisibility)
    op = 0;
  else
#endif
  {
    op = UmlBaseOperation::create(cl, name);
    
    if (op == 0) {
      PhpCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add operation <i>")
			   + name + "</i> in <i>" + cl->name() 
			   + "</i></b></font><br>");  
      return FALSE;
    }
    
#ifdef REVERSE
    Statistic::one_operation_more();
#endif
  }
    
  Q3CString def;
    
  if (op != 0) {
    op->set_Visibility(visibility);
    if (staticp) op->set_isClassMember(TRUE);
    if (finalp) op->set_isPhpFinal(TRUE);
  
    def = PhpSettings::operationDef();
  
    int index;
    
    if (((index = def.find("${(}")) == -1) ||
	(def.find("${)}", index + 4) == -1) ||
	((index = def.find("${name}")) == -1) ||
	(def.find("${body}") == -1)) {
      // use a definition where ${body] is not indented
      def = "  ${comment}${final}${visibility}${abstract}${static}function ${name}${(}${)}\n{\n  ${body}}\n";
      index = def.find("${name}");
    }
    
    if (refp)
      def.insert(index, "&");
    
    if ((name == cl->name()) || (name == "__construct")) {
      // constructor, remove useless ${}
      if ((index = def.find("${static}")) != -1)
	def.remove(index, 9);
      if ((index = def.find("${final}")) != -1)
	def.remove(index, 8);
      if ((index = def.find("${abstract}")) != -1)
	def.remove(index, 11);
    }
    
    if (abstractp) {
      op->set_isAbstract(TRUE);
      
      def = def.left(def.find("${)}") + 4) + ";";
    }
  }
  
  // parameters
  
  unsigned rank = 0;
  UmlParameter param;
  
  while (read_param(container, rank, param, def, op == 0)) {
    if ((op != 0) && ! op->addParameter(rank++, param)) {
      PhpCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add param <i>")
			   + name + "</i> in <i>" + cl->name() 
			   + "</i></b></font><br>");  
#ifdef TRACE
      QLOG_INFO() <<"ERROR cannot add param '" << param.name << '\n';
#endif
      return FALSE;
    }
  }
  
  s = Lex::read_word();
  
  if (s.isEmpty()) {
    Lex::premature_eof();
    return FALSE;
  }
    
  // definition
  
  if (abstractp || (cl->stereotype() == "interface")) {
    if (s != ";") {
      Lex::error_near(s);
      return FALSE;
    }
#ifdef REVERSE
    if (op != 0)
      op->set_PhpBody(0);
#endif
  }
  else if (s != "{") {
    Lex::error_near(s);
    return FALSE;
  }
  else {
    Lex::mark();
    
    // goto the end of the body
    
    char c;
    int level = 1;	// '{' already read
    
    for (;;) {
      if ((c = Lex::read_word_bis()) == 0)
	return FALSE;
      else if (c == '{')
	level += 1;
      else if ((c == '}') && (--level == 0))
	break;
    }
    
#ifdef REVERSE
    if (op != 0) {
      Q3CString e = Lex::region();
      
      e.truncate(e.length() - 1);	// remove }

      // remove fist \n
      if (*((const char *) e) == '\n')
	e.remove(0, 1);
      
      // remove last spaces and tabs
      int ln = e.length();
      
      while (ln && ((e[ln - 1] == ' ') || (e[ln - 1] == '\t')))
	ln -= 1;
      e.truncate(ln);
      
      op->set_PhpBody(e);
      op->set_PhpContextualBodyIndent(FALSE);
    }
#endif
  }
  
  if ((op != 0) && (def != op->phpDecl()))
    op->set_PhpDecl(def);
  
  Lex::clear_comments();	// params & body comments
  Lex::finish_line();
  
  if ((op != 0) && !comment.isEmpty()) {
    s = (def.find("${description}") != -1) ? description : comment;
    
    UmlTypeSpec t;
    int index1;
    
    if (! (t.explicit_type = value_of(s, "@return", index1)).isEmpty()) {
      op->set_ReturnType(t);
      s.replace(index1, t.explicit_type.length(), "${type}");
    }
    
    Q3ValueList<UmlParameter> l = op->params();
    unsigned nparams = l.count();

    if (nparams != 0) {
      Q3CString varname;
      int index2;
      char xn[16];

      index1 = 0;
      rank = 0;
      
      while (!((t.explicit_type = value_of(s, "@param", index1, varname, index2))
	       .isEmpty())) {
	if (varname.isEmpty() || (varname[0] != '$')) {
	  if (rank < nparams) {
	    UmlParameter & p = l[rank];
	    
	    p.type = t;
	    op->replaceParameter(rank, p);
	  }
	}
	else {
	  varname = varname.mid(1);
	  
	  Q3ValueList<UmlParameter>::Iterator it;
	  
	  for (it = l.begin(), rank = 0; it != l.end(); ++it, rank += 1) {
	    if ((*it).name == varname) {
	      (*it).type = t;
	      op->replaceParameter(rank, *it);
	      sprintf(xn, "${p%d}", rank);
	      s.replace(index2, varname.length() + 1, xn);
	      break;
	    }
	  }
	}
	sprintf(xn, "${t%d}", rank++);
	s.replace(index1, t.explicit_type.length(), xn);
      }
    }
    op->set_Description(s);
  }
  
  return TRUE;
}