summaryrefslogtreecommitdiffstats
path: root/umbrello/umbrello/codeimport/import_utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'umbrello/umbrello/codeimport/import_utils.cpp')
-rw-r--r--umbrello/umbrello/codeimport/import_utils.cpp464
1 files changed, 464 insertions, 0 deletions
diff --git a/umbrello/umbrello/codeimport/import_utils.cpp b/umbrello/umbrello/codeimport/import_utils.cpp
new file mode 100644
index 00000000..92a87867
--- /dev/null
+++ b/umbrello/umbrello/codeimport/import_utils.cpp
@@ -0,0 +1,464 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "import_utils.h"
+// qt/kde includes
+#include <qmap.h>
+#include <qregexp.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+// app includes
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umllistview.h"
+#include "../umllistviewitem.h"
+#include "../umlobject.h"
+#include "../package.h"
+#include "../folder.h"
+#include "../enum.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../template.h"
+#include "../association.h"
+#include "../object_factory.h"
+
+#include <stdlib.h>
+
+namespace Import_Utils {
+
+/**
+ * Flag manipulated by createUMLObject().
+ * Global state is generally bad, I know.
+ * It would be cleaner to make this into a return value from
+ * createUMLObject().
+ */
+bool bNewUMLObjectWasCreated = false;
+
+/**
+ * Related classifier for creation of dependencies on template
+ * parameters in createUMLObject().
+ */
+UMLClassifier * gRelatedClassifier = NULL;
+
+/**
+ * On encountering a scoped typename string where the scopes
+ * have not yet been seen, we synthesize UML objects for the
+ * unknown scopes (using a question dialog to the user to decide
+ * whether to treat a scope as a class or as a package.)
+ * However, such an unknown scope is put at the global level.
+ * I.e. before calling createUMLObject() we set this flag to true.
+ */
+bool bPutAtGlobalScope = false;
+
+/**
+ * The include path list (see addIncludePath() and includePathList())
+ */
+QStringList incPathList;
+
+void putAtGlobalScope(bool yesno) {
+ bPutAtGlobalScope = yesno;
+}
+
+void setRelatedClassifier(UMLClassifier *c) {
+ gRelatedClassifier = c;
+}
+
+void assignUniqueIdOnCreation(bool yesno) {
+ Object_Factory::assignUniqueIdOnCreation(yesno);
+}
+
+bool newUMLObjectWasCreated() {
+ return bNewUMLObjectWasCreated;
+}
+
+QString formatComment(const QString &comment) {
+ if (comment.isEmpty())
+ return comment;
+
+ QStringList lines = QStringList::split("\n", comment);
+ QString& first = lines.first();
+ QRegExp wordex("\\w");
+ if (first.startsWith("/*")) {
+ int wordpos = wordex.search(first);
+ if (wordpos != -1)
+ first = first.mid(wordpos); // remove comment start
+ else
+ lines.pop_front(); // nothing interesting on this line
+ }
+ QString& last = lines.last();
+ int endpos = last.find("*/");
+ if (endpos != -1) {
+ if (last.contains(wordex))
+ last = last.mid(0, endpos - 1); // remove comment end
+ else
+ lines.pop_back(); // nothing interesting on this line
+ }
+ if (! lines.count())
+ return "";
+
+ QStringList::Iterator end(lines.end());
+ for (QStringList::Iterator lit(lines.begin()); lit != end; ++lit) {
+ (*lit).remove(QRegExp("^\\s+"));
+ (*lit).remove(QRegExp("^\\*+\\s?"));
+ }
+ return lines.join("\n");
+}
+
+/*
+UMLObject* findUMLObject(QString name,
+ Uml::Object_Type type) {
+ // Why an extra wrapper? See comment at addMethodParameter()
+ UMLObject * o = umldoc->findUMLObject(name, type);
+ return o;
+}
+ */
+
+UMLObject *createUMLObject(Uml::Object_Type type,
+ const QString& inName,
+ UMLPackage *parentPkg,
+ const QString& comment,
+ const QString& stereotype) {
+ QString name = inName;
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical);
+ const Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ if (parentPkg == NULL) {
+ // kDebug() << "Import_Utils::createUMLObject(" << name
+ // << "): parentPkg is NULL, assuming Logical View" << endl;
+ parentPkg = logicalView;
+ }
+ UMLObject * o = umldoc->findUMLObject(name, type, parentPkg);
+ bNewUMLObjectWasCreated = false;
+ if (o == NULL) {
+ // Strip possible adornments and look again.
+ int isConst = name.contains(QRegExp("^const "));
+ name.remove(QRegExp("^const\\s+"));
+ QString typeName(name);
+ const int isAdorned = typeName.contains( QRegExp("[^\\w:\\. ]") );
+ const int isPointer = typeName.contains('*');
+ const int isRef = typeName.contains('&');
+ typeName.remove(QRegExp("[^\\w:\\. ].*$"));
+ typeName = typeName.simplifyWhiteSpace();
+ UMLObject *origType = umldoc->findUMLObject(typeName, Uml::ot_UMLObject, parentPkg);
+ if (origType == NULL) {
+ // Still not found. Create the stripped down type.
+ if (bPutAtGlobalScope)
+ parentPkg = logicalView;
+ // Find, or create, the scopes.
+ QStringList components;
+ if (typeName.contains("::")) {
+ components = QStringList::split("::", typeName);
+ } else if (typeName.contains(".")) {
+ components = QStringList::split(".", typeName);
+ }
+ if (components.count() > 1) {
+ typeName = components.back();
+ components.pop_back();
+ while ( components.count() ) {
+ QString scopeName = components.front();
+ components.pop_front();
+ o = umldoc->findUMLObject(scopeName, Uml::ot_UMLObject, parentPkg);
+ if (o) {
+ parentPkg = static_cast<UMLPackage*>(o);
+ continue;
+ }
+ int wantNamespace = KMessageBox::Yes;
+ if (pl == Uml::pl_Cpp) {
+ /* We know std and Qt are namespaces */
+ if (scopeName != "std" && scopeName != "Qt") {
+ wantNamespace = KMessageBox::questionYesNo(NULL,
+ i18n("Is the scope %1 a namespace or a class?").arg(scopeName),
+ i18n("C++ Import Requests Your Help"),
+ i18n("Namespace"), i18n("Class"));
+ }
+ }
+ Uml::Object_Type ot = (wantNamespace == KMessageBox::Yes ? Uml::ot_Package : Uml::ot_Class);
+ o = Object_Factory::createUMLObject(ot, scopeName, parentPkg);
+ parentPkg = static_cast<UMLPackage*>(o);
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *lvitem = listView->findUMLObject(o);
+ listView->setCurrentItem(lvitem);
+ }
+ // All scope qualified datatypes live in the global scope.
+ bPutAtGlobalScope = true;
+ }
+ Uml::Object_Type t = type;
+ if (type == Uml::ot_UMLObject || isAdorned)
+ t = Uml::ot_Class;
+ origType = Object_Factory::createUMLObject(t, typeName, parentPkg, false);
+ bNewUMLObjectWasCreated = true;
+ bPutAtGlobalScope = false;
+ }
+ if (isConst || isAdorned) {
+ // Create the full given type (including adornments.)
+ if (isConst)
+ name.prepend("const ");
+ o = Object_Factory::createUMLObject(Uml::ot_Datatype, name,
+ umldoc->getDatatypeFolder(),
+ false); //solicitNewName
+ UMLClassifier *dt = static_cast<UMLClassifier*>(o);
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(origType);
+ if (c)
+ dt->setOriginType(c);
+ else
+ kError() << "createUMLObject(" << name << "): "
+ << "origType " << typeName << " is not a UMLClassifier"
+ << endl;
+ if (isRef || isPointer)
+ dt->setIsReference();
+ /*
+ if (isPointer) {
+ UMLObject *pointerDecl = Object_Factory::createUMLObject(Uml::ot_Datatype, type);
+ UMLClassifier *dt = static_cast<UMLClassifier*>(pointerDecl);
+ dt->setOriginType(classifier);
+ dt->setIsReference();
+ classifier = dt;
+ } */
+ } else {
+ o = origType;
+ }
+ } else if (parentPkg && !bPutAtGlobalScope) {
+ UMLPackage *existingPkg = o->getUMLPackage();
+ if (existingPkg != umldoc->getDatatypeFolder()) {
+ if (existingPkg)
+ existingPkg->removeObject(o);
+ else
+ kError() << "createUMLObject(" << name << "): "
+ << "o->getUMLPackage() was NULL" << endl;
+ o->setUMLPackage(parentPkg);
+ parentPkg->addObject(o);
+ }
+ }
+ QString strippedComment = formatComment(comment);
+ if (! strippedComment.isEmpty()) {
+ o->setDoc(strippedComment);
+ }
+ if (!stereotype.isEmpty()) {
+ o->setStereotype(stereotype);
+ }
+ if (gRelatedClassifier == NULL || gRelatedClassifier == o)
+ return o;
+ QRegExp templateInstantiation("^[\\w:\\.]+\\s*<(.*)>");
+ int pos = templateInstantiation.search(name);
+ if (pos == -1)
+ return o;
+ // Create dependencies on template parameters.
+ QString caption = templateInstantiation.cap(1);
+ QStringList params = QStringList::split(QRegExp("[^\\w:\\.]+"), caption);
+ if (!params.count())
+ return o;
+ QStringList::Iterator end(params.end());
+ for (QStringList::Iterator it(params.begin()); it != end; ++it) {
+ UMLObject *p = umldoc->findUMLObject(*it, Uml::ot_UMLObject, parentPkg);
+ if (p == NULL || p->getBaseType() == Uml::ot_Datatype)
+ continue;
+ const Uml::Association_Type at = Uml::at_Dependency;
+ UMLAssociation *assoc = umldoc->findAssociation(at, gRelatedClassifier, p);
+ if (assoc)
+ continue;
+ assoc = new UMLAssociation(at, gRelatedClassifier, p);
+ assoc->setUMLPackage(umldoc->getRootFolder(Uml::mt_Logical));
+ umldoc->addAssociation(assoc);
+ }
+ return o;
+}
+
+UMLOperation* makeOperation(UMLClassifier *parent, const QString &name) {
+ UMLOperation *op = Object_Factory::createOperation(parent, name);
+ return op;
+}
+
+UMLObject* insertAttribute(UMLClassifier *owner,
+ Uml::Visibility scope,
+ const QString& name,
+ UMLClassifier *attrType,
+ const QString& comment /* ="" */,
+ bool isStatic /* =false */) {
+ Uml::Object_Type ot = owner->getBaseType();
+ Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ if (! (ot == Uml::ot_Class || ot == Uml::ot_Interface && pl == Uml::pl_Java)) {
+ kDebug() << "insertAttribute: Don't know what to do with "
+ << owner->getName() << " (object type " << ot << ")" << endl;
+ return NULL;
+ }
+ UMLObject *o = owner->findChildObject(name, Uml::ot_Attribute);
+ if (o) {
+ return o;
+ }
+
+ UMLAttribute *attr = owner->addAttribute(name, attrType, scope);
+ attr->setStatic(isStatic);
+ QString strippedComment = formatComment(comment);
+ if (! strippedComment.isEmpty()) {
+ attr->setDoc(strippedComment);
+ }
+
+ UMLApp::app()->getDocument()->setModified(true);
+ return attr;
+}
+
+UMLObject* insertAttribute(UMLClassifier *owner, Uml::Visibility scope,
+ const QString& name,
+ const QString& type,
+ const QString& comment /* ="" */,
+ bool isStatic /* =false */) {
+ UMLObject *attrType = owner->findTemplate(type);
+ if (attrType == NULL) {
+ bPutAtGlobalScope = true;
+ gRelatedClassifier = owner;
+ attrType = createUMLObject(Uml::ot_UMLObject, type, owner);
+ gRelatedClassifier = NULL;
+ bPutAtGlobalScope = false;
+ }
+ return insertAttribute (owner, scope, name,
+ static_cast<UMLClassifier*>(attrType),
+ comment, isStatic);
+}
+
+void insertMethod(UMLClassifier *klass, UMLOperation* &op,
+ Uml::Visibility scope, const QString& type,
+ bool isStatic, bool isAbstract,
+ bool isFriend, bool isConstructor,
+ const QString& comment) {
+ op->setVisibility(scope);
+ if (!type.isEmpty() // return type may be missing (constructor/destructor)
+ && type != "void") {
+ if (type == klass->getName()) {
+ op->setType(klass);
+ } else {
+ UMLObject *typeObj = klass->findTemplate(type);
+ if (typeObj == NULL) {
+ bPutAtGlobalScope = true;
+ gRelatedClassifier = klass;
+ typeObj = createUMLObject(Uml::ot_UMLObject, type, klass);
+ gRelatedClassifier = NULL;
+ bPutAtGlobalScope = false;
+ op->setType(typeObj);
+ }
+ }
+ }
+
+ op->setStatic(isStatic);
+ op->setAbstract(isAbstract);
+
+ // if the operation is friend, add it as a stereotype
+ if (isFriend)
+ op->setStereotype("friend");
+ // if the operation is a constructor, add it as a stereotype
+ if (isConstructor)
+ op->setStereotype("constructor");
+
+ QString strippedComment = formatComment(comment);
+ if (! strippedComment.isEmpty()) {
+ op->setDoc(strippedComment);
+ }
+
+ UMLAttributeList params = op->getParmList();
+ UMLOperation *exist = klass->checkOperationSignature(op->getName(), params);
+ if (exist) {
+ // copy contents to existing operation
+ exist->setVisibility(scope);
+ exist->setStatic(isStatic);
+ exist->setAbstract(isAbstract);
+ if (! strippedComment.isEmpty())
+ exist->setDoc(strippedComment);
+ UMLAttributeList exParams = exist->getParmList();
+ UMLAttribute *param, *exParam = exParams.first();
+ for (UMLAttributeListIt it(params); (param = it.current()) != NULL;
+ ++it, exParam = exParams.next()) {
+ exParam->setName(param->getName());
+ exParam->setVisibility(param->getVisibility());
+ exParam->setStatic(param->getStatic());
+ exParam->setAbstract(param->getAbstract());
+ exParam->setDoc(param->getDoc());
+ exParam->setInitialValue(param->getInitialValue());
+ exParam->setParmKind(param->getParmKind());
+ }
+ // delete incoming UMLOperation and pass out the existing one
+ delete op;
+ op = exist;
+ } else {
+ klass->addOperation(op);
+ }
+}
+
+UMLAttribute* addMethodParameter(UMLOperation *method,
+ const QString& type,
+ const QString& name) {
+ UMLClassifier *owner = static_cast<UMLClassifier*>(method->parent());
+ UMLObject *typeObj = owner->findTemplate(type);
+ if (typeObj == NULL) {
+ bPutAtGlobalScope = true;
+ gRelatedClassifier = owner;
+ typeObj = createUMLObject(Uml::ot_UMLObject, type, owner);
+ gRelatedClassifier = NULL;
+ bPutAtGlobalScope = false;
+ }
+ UMLAttribute *attr = Object_Factory::createAttribute(method, name, typeObj);
+ method->addParm(attr);
+ return attr;
+}
+
+void addEnumLiteral(UMLEnum *enumType, const QString &literal, const QString &comment) {
+ UMLObject *el = enumType->addEnumLiteral(literal);
+ el->setDoc(comment);
+}
+
+void createGeneralization(UMLClassifier *child, UMLClassifier *parent) {
+ // if the child is an interface, so is the parent.
+ if (child->isInterface())
+ parent->setBaseType(Uml::ot_Interface);
+ Uml::Association_Type association = Uml::at_Generalization;
+
+ if (parent->isInterface() && !child->isInterface()) {
+ // if the parent is an interface, but the child is not, then
+ // this is really realization.
+ //
+ association = Uml::at_Realization;
+ }
+ UMLAssociation *assoc = new UMLAssociation(association, child, parent);
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ assoc->setUMLPackage(umldoc->getRootFolder(Uml::mt_Logical));
+ umldoc->addAssociation(assoc);
+}
+
+void createGeneralization(UMLClassifier *child, const QString &parentName) {
+ UMLObject *parentObj = createUMLObject( Uml::ot_Class, parentName );
+ UMLClassifier *parent = static_cast<UMLClassifier*>(parentObj);
+ createGeneralization(child, parent);
+}
+
+QStringList includePathList() {
+ QStringList includePathList(incPathList);
+ char *umbrello_incpath = getenv( "UMBRELLO_INCPATH" );
+ if (umbrello_incpath) {
+ includePathList += QStringList::split( ':', umbrello_incpath );
+ }
+ return includePathList;
+}
+
+void addIncludePath(const QString& path) {
+ if (! incPathList.contains(path))
+ incPathList.append(path);
+}
+
+
+bool isDatatype(const QString& name, UMLPackage *parentPkg) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLObject * o = umldoc->findUMLObject(name, Uml::ot_Datatype, parentPkg);
+ return (o!=NULL);
+}
+
+} // end namespace Import_Utils
+