diff --git a/umbrello/codegenerators/cpp/cppcodegenerationform.cpp b/umbrello/codegenerators/cpp/cppcodegenerationform.cpp index e37291ff0..9594eefe6 100644 --- a/umbrello/codegenerators/cpp/cppcodegenerationform.cpp +++ b/umbrello/codegenerators/cpp/cppcodegenerationform.cpp @@ -1,420 +1,442 @@ /*************************************************************************** * 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) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "cppcodegenerationform.h" // kde includes #if QT_VERSION < 0x050000 #include #endif #include #include #include // qt includes #if QT_VERSION >= 0x050000 #include #endif #include #include #include /** * Constructor. * @param parent the parent of this widget * @param name the object name */ CPPCodeGenerationForm::CPPCodeGenerationForm(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(QLatin1String(name)); setupUi(this); Qt::ItemFlags flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; m_optionPackageIsANamespace = new QListWidgetItem(i18n("Package is a namespace"), ui_generalOptionsListWidget); m_optionPackageIsANamespace->setFlags(flags); m_optionVirtualDestructors = new QListWidgetItem(i18n("Virtual destructors"), ui_generalOptionsListWidget); m_optionVirtualDestructors->setFlags(flags); m_optionGenerateEmptyConstructors = new QListWidgetItem(i18n("Generate empty constructors"), ui_generalOptionsListWidget); m_optionGenerateEmptyConstructors->setFlags(flags); m_optionGenerateAccessorMethods = new QListWidgetItem(i18n("Generate accessor methods"), ui_generalOptionsListWidget); m_optionGenerateAccessorMethods->setFlags(flags); m_optionOperationsAreInline = new QListWidgetItem(i18n("Operations are inline"), ui_generalOptionsListWidget); m_optionOperationsAreInline->setFlags(flags); m_optionAccessorsAreInline = new QListWidgetItem(i18n("Accessors are inline"), ui_generalOptionsListWidget); m_optionAccessorsAreInline->setFlags(flags); m_optionAccessorsArePublic = new QListWidgetItem(i18n("Accessors are public"), ui_generalOptionsListWidget); m_optionAccessorsArePublic->setFlags(flags); m_optionGetterWithGetPrefix = - new QListWidgetItem(i18n("Create getters with get prefix"), ui_generalOptionsListWidget); + new QListWidgetItem(i18n("Create getters with 'get' prefix"), ui_generalOptionsListWidget); m_optionGetterWithGetPrefix->setFlags(flags); m_optionRemovePrefixFromAccessorMethodName = new QListWidgetItem(i18n("Remove prefix '[a-zA-Z]_' from accessor method names"), ui_generalOptionsListWidget); m_optionRemovePrefixFromAccessorMethodName->setFlags(flags); m_optionAccessorMethodsStartWithUpperCase = new QListWidgetItem(i18n("Accessor methods start with capital letters"), ui_generalOptionsListWidget); m_optionAccessorMethodsStartWithUpperCase->setFlags(flags); m_optionDocToolTag = new QListWidgetItem(i18n("Use '\\' as documentation tag instead of '@'"), ui_generalOptionsListWidget); m_optionDocToolTag->setFlags(flags); connect(ui_generalOptionsListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(generalOptionsListWidgetClicked(QListWidgetItem*))); + + connect(ui_generalOptionsListWidget, + SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, + SLOT(editClassMemberPrefixDoubleClicked(QListWidgetItem*))); } /** * Destructor. */ CPPCodeGenerationForm::~CPPCodeGenerationForm() { } /** * Slot for clicking on the browse buttons. */ void CPPCodeGenerationForm::browseClicked() { QString button = sender()->objectName(); #if QT_VERSION >= 0x050000 QString file = QFileDialog::getOpenFileName(this, QLatin1String("Get Header File"), QString(), QLatin1String("*.h")); #else QString file = KFileDialog::getOpenFileName(KUrl(), QLatin1String("*.h"), this, QLatin1String("Get Header File")); #endif if (file.isEmpty()) { return; } if (button == QLatin1String("m_browseStringButton")) { // search for match in history list, if absent, then add it ui_stringIncludeFileHistoryCombo->setCurrentItem(file, true); } else if (button == QLatin1String("m_browseListButton")) { // search for match in history list, if absent, then add it ui_listIncludeFileHistoryCombo->setCurrentItem(file, true); } } /** * Slot for clicking in the list widget. * @param pSender the sender of the signal, the item in the list */ void CPPCodeGenerationForm::generalOptionsListWidgetClicked(QListWidgetItem *pSender) { // operations are inline and accessors are operations :) if (m_optionOperationsAreInline->checkState() == Qt::Checked && m_optionGenerateAccessorMethods->checkState() == Qt::Checked) { m_optionAccessorsAreInline->setCheckState(Qt::Checked); } if (pSender == m_optionPackageIsANamespace) { #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "sender=m_optionPackageIsANamespace"); #endif return; } if (pSender == m_optionVirtualDestructors) { #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "sender=m_optionVirtualDestructors"); #endif return; } if (pSender == m_optionGenerateEmptyConstructors) { #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "sender=m_optionVirtualDestructors"); #endif return; } if (pSender == m_optionGenerateAccessorMethods) { bool dontGenerateAccessorMethods = (m_optionGenerateAccessorMethods->checkState() == Qt::Unchecked); m_optionAccessorsAreInline->setHidden(dontGenerateAccessorMethods); m_optionAccessorsArePublic->setHidden(dontGenerateAccessorMethods); m_optionGetterWithGetPrefix->setHidden(dontGenerateAccessorMethods); m_optionRemovePrefixFromAccessorMethodName->setHidden(dontGenerateAccessorMethods); m_optionAccessorMethodsStartWithUpperCase->setHidden(dontGenerateAccessorMethods); // reset the value if needed if (dontGenerateAccessorMethods) { m_optionAccessorsAreInline->setCheckState(Qt::Unchecked); m_optionAccessorsArePublic->setCheckState(Qt::Unchecked); m_optionGetterWithGetPrefix->setCheckState(Qt::Unchecked); m_optionRemovePrefixFromAccessorMethodName->setCheckState(Qt::Unchecked); m_optionAccessorMethodsStartWithUpperCase->setHidden(Qt::Unchecked); } #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "sender=m_optionGenerateAccessorMethods"); #endif return; } if (pSender == m_optionOperationsAreInline) { #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "sender=m_optionOperationsAreInline"); #endif return; } if (pSender == m_optionAccessorsAreInline) { #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "sender=m_optionAccessorsAreInline"); #endif return; } #if 0 KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): " "unknown sender"); #endif return; } /** * Set the display state of option "Package Is Namespace". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setPackageIsANamespace(bool bFlag) { m_optionPackageIsANamespace->setCheckState(toCheckState(bFlag)); } /** * Set the display state of option "Virtual Destructors". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setVirtualDestructors(bool bFlag) { m_optionVirtualDestructors->setCheckState(toCheckState(bFlag)); } /** * Set the display state of option "Generate Empty Constructors". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setGenerateEmptyConstructors(bool bFlag) { m_optionGenerateEmptyConstructors->setCheckState(toCheckState(bFlag)); } /** * Set the display state of option "Generate Accessor Methods". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setGenerateAccessorMethods(bool bFlag) { m_optionGenerateAccessorMethods->setCheckState(toCheckState(bFlag)); // initial settings m_optionAccessorsAreInline->setHidden(m_optionGenerateAccessorMethods->checkState() == Qt::Unchecked); m_optionAccessorsArePublic->setHidden(m_optionGenerateAccessorMethods->checkState() == Qt::Unchecked); // reset the value if needed if (m_optionGenerateAccessorMethods->checkState() == Qt::Unchecked) { m_optionAccessorsAreInline->setCheckState(Qt::Unchecked); m_optionAccessorsArePublic->setCheckState(Qt::Unchecked); } } /** * Set the display state of option "Operations Are Inline". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setOperationsAreInline(bool bFlag) { m_optionOperationsAreInline->setCheckState(toCheckState(bFlag)); } /** * Set the display state of option "Accessors Are Inline". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setAccessorsAreInline(bool bFlag) { m_optionAccessorsAreInline->setCheckState(toCheckState(bFlag)); } /** * Set the display state of option "Accessors Are Public". * @param bFlag the flag to set */ void CPPCodeGenerationForm::setAccessorsArePublic(bool bFlag) { m_optionAccessorsArePublic->setCheckState(toCheckState(bFlag)); } /** * Set the display state of the related checkbox * @param flag the flag to set */ void CPPCodeGenerationForm::setGetterWithoutGetPrefix(bool bFlag) { m_optionGetterWithGetPrefix->setCheckState(toCheckState(toCheckState(bFlag))); } /** * Set the display state of the related checkbox * @param flag the flag to set */ void CPPCodeGenerationForm::setRemovePrefixFromAccessorMethodName(bool bFlag) { m_optionRemovePrefixFromAccessorMethodName->setCheckState(toCheckState(toCheckState(bFlag))); } /** * Set the display state of the related checkbox * @param flag the flag to set */ void CPPCodeGenerationForm::setAccessorMethodsStartWithUpperCase(bool bFlag) { m_optionAccessorMethodsStartWithUpperCase->setCheckState(toCheckState(toCheckState(bFlag))); } /** * Set the doc display state of option "Doc Tool Tag". * @param value the value of the tag */ void CPPCodeGenerationForm::setDocToolTag(const QString &value) { m_optionDocToolTag->setCheckState(toCheckState(value == QLatin1String("\\"))); } +/** + * Set the class member prefix + * @param value the value to set + */ +void CPPCodeGenerationForm::setClassMemberPrefix(const QString &value) +{ + ui_classMemberPrefixEdit->setText(value); +} + /** * Get the display state of option "Package Is Namespace". * @return the state of the flag */ bool CPPCodeGenerationForm::getPackageIsANamespace() { return m_optionPackageIsANamespace->checkState() == Qt::Checked; } /** * Get the display state of option "Virtual Destructors". * @return the state of the flag */ bool CPPCodeGenerationForm::getVirtualDestructors() { return m_optionVirtualDestructors->checkState() == Qt::Checked; } /** * Get the display state of option "Generate Empty Constructors". * @return the state of the flag */ bool CPPCodeGenerationForm::getGenerateEmptyConstructors() { return m_optionGenerateEmptyConstructors->checkState() == Qt::Checked; } /** * Get the display state of option "Generate Accessor Methods". * @return the state of the flag */ bool CPPCodeGenerationForm::getGenerateAccessorMethods() { return m_optionGenerateAccessorMethods->checkState() == Qt::Checked; } /** * Get the display state of option "Operations Are Inline". * @return the state of the flag */ bool CPPCodeGenerationForm::getOperationsAreInline() { return m_optionOperationsAreInline->checkState() == Qt::Checked; } /** * Get the display state of option "Accessors Are Inline". * @return the state of the flag */ bool CPPCodeGenerationForm::getAccessorsAreInline() { return m_optionAccessorsAreInline->checkState() == Qt::Checked; } /** * Get the display state of option "Accessors Are Public". * @return the state of the flag */ bool CPPCodeGenerationForm::getAccessorsArePublic() { return m_optionAccessorsArePublic->checkState() == Qt::Checked; } /** * Get the display state of the related option * @return the state of the flag */ bool CPPCodeGenerationForm::getGettersWithGetPrefix() { return m_optionGetterWithGetPrefix->checkState() == Qt::Checked; } /** * Get the display state of the related option * @return the state of the flag */ bool CPPCodeGenerationForm::getRemovePrefixFromAccessorMethodName() { return m_optionRemovePrefixFromAccessorMethodName->checkState() == Qt::Checked; } /** * Get the display state of the related option * @return the state of the flag */ bool CPPCodeGenerationForm::getAccessorMethodsStartWithUpperCase() { return m_optionAccessorMethodsStartWithUpperCase->checkState() == Qt::Checked; } /** * Get the display state of the related option * @return the state of the flag */ QString CPPCodeGenerationForm::getDocToolTag() { return m_optionDocToolTag->checkState() == Qt::Checked ? QLatin1String("\\") : QLatin1String("@"); } +/** + * Get the class member prefix + * @return value + */ +QString CPPCodeGenerationForm::getClassMemberPrefix() +{ + return ui_classMemberPrefixEdit->text(); +} + /** * Conversion utility (static) from bool to Qt::CheckState. * @param value the value to be converted * @return the check state */ Qt::CheckState CPPCodeGenerationForm::toCheckState(bool value) { if (value) { return Qt::Checked; } else { return Qt::Unchecked; } } diff --git a/umbrello/codegenerators/cpp/cppcodegenerationform.h b/umbrello/codegenerators/cpp/cppcodegenerationform.h index f25205080..fc47cac4c 100644 --- a/umbrello/codegenerators/cpp/cppcodegenerationform.h +++ b/umbrello/codegenerators/cpp/cppcodegenerationform.h @@ -1,85 +1,87 @@ /*************************************************************************** * 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) 2003-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ #ifndef CPPCODEGENERATIONFORM_H #define CPPCODEGENERATIONFORM_H #include "ui_cppcodegenerationformbase.h" class QListWidgetItem; /** * @author Brian Thomas */ class CPPCodeGenerationForm : public QWidget, private Ui::CPPCodeGenerationFormBase { Q_OBJECT public: explicit CPPCodeGenerationForm (QWidget *parent = 0, const char *name = 0); virtual ~CPPCodeGenerationForm(); void setPackageIsANamespace(bool bFlag = true); void setVirtualDestructors(bool bFlag = true); void setGenerateEmptyConstructors(bool bFlag = true); void setGenerateAccessorMethods(bool bFlag = true); void setOperationsAreInline(bool bFlag = true); void setAccessorsAreInline(bool bFlag = true); void setAccessorsArePublic(bool bFlag = true); void setGenerateMakefileDocument(bool bFlag = true); void setDocToolTag(const QString &value); void setGetterWithoutGetPrefix(bool bFlag = true); void setRemovePrefixFromAccessorMethodName(bool bFlag = true); void setAccessorMethodsStartWithUpperCase(bool bFlag); + void setClassMemberPrefix(const QString &value); bool getPackageIsANamespace(); bool getVirtualDestructors(); bool getGenerateEmptyConstructors(); bool getGenerateAccessorMethods(); bool getOperationsAreInline(); bool getAccessorsAreInline(); bool getAccessorsArePublic(); bool getGenerateMakefileDocument(); QString getDocToolTag(); bool getGettersWithGetPrefix(); bool getRemovePrefixFromAccessorMethodName(); bool getAccessorMethodsStartWithUpperCase(); + QString getClassMemberPrefix(); public slots: virtual void browseClicked(); private slots: virtual void generalOptionsListWidgetClicked(QListWidgetItem *); private: friend class CPPCodeGenerationPolicyPage; // check boxes for the available options QListWidgetItem *m_optionPackageIsANamespace; QListWidgetItem *m_optionVirtualDestructors; QListWidgetItem *m_optionGenerateEmptyConstructors; QListWidgetItem *m_optionGenerateAccessorMethods; QListWidgetItem *m_optionOperationsAreInline; QListWidgetItem *m_optionAccessorsAreInline; QListWidgetItem *m_optionAccessorsArePublic; QListWidgetItem *m_optionDocToolTag; QListWidgetItem *m_optionGetterWithGetPrefix; QListWidgetItem *m_optionRemovePrefixFromAccessorMethodName; QListWidgetItem *m_optionAccessorMethodsStartWithUpperCase; static Qt::CheckState toCheckState(bool value); }; #endif diff --git a/umbrello/codegenerators/cpp/cppcodegenerationformbase.ui b/umbrello/codegenerators/cpp/cppcodegenerationformbase.ui index e3159174a..abe202c55 100644 --- a/umbrello/codegenerators/cpp/cppcodegenerationformbase.ui +++ b/umbrello/codegenerators/cpp/cppcodegenerationformbase.ui @@ -1,612 +1,636 @@ CPPCodeGenerationFormBase 0 0 463 488 0 0 16777215 40 <p align="center">C++ Code Generation</p> false 0 0 1 General - - - - - + + + + 4 + 4 + 441 + 222 + + + + + + + + + Class member prefix + + + + + + + + + + + + + Method Body Generation Qt::Vertical QSizePolicy::Expanding 410 113 0 0 false false QPtrList vector vector 0 vector <b>Variable</b> false 0 0 32 32767 ... true 0 0 false false QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string QString string 0 string Qt::Horizontal QSizePolicy::Minimum 20 20 Qt::Horizontal QSizePolicy::Minimum 20 20 0 0 <p align="center">String</p> false 0 0 <p align="center">List</p> false true 0 0 32 32767 ... <i>global?</i> false 0 0 qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector qptrlist.h vector 0 vector 0 0 qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string qstring.h string 0 string Class name false <i><p align="center">Include file</p></i> false Use following for classes in generated code: false 0 80 16777215 100 Documentation Style: false Slash-Slash (//) Slash-Star (/** */) KComboBox QComboBox
kcombobox.h
KHistoryComboBox KComboBox
khistorycombobox.h
klineedit.h ui_browseListButton clicked() CPPCodeGenerationFormBase browseClicked() 20 20 20 20 ui_browseStringButton clicked() CPPCodeGenerationFormBase browseClicked() 20 20 20 20
diff --git a/umbrello/codegenerators/cpp/cppcodegenerationpolicy.cpp b/umbrello/codegenerators/cpp/cppcodegenerationpolicy.cpp index 6619b6bd8..db13bed84 100644 --- a/umbrello/codegenerators/cpp/cppcodegenerationpolicy.cpp +++ b/umbrello/codegenerators/cpp/cppcodegenerationpolicy.cpp @@ -1,458 +1,476 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "cppcodegenerationpolicy.h" // app includes #include "cppcodegenerationpolicypage.h" #include "uml.h" #include "umbrellosettings.h" #include "optionstate.h" // kde includes #include // qt includes #include const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_METHOD_APPEND = "%VARNAME%.push_back(value);"; const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_METHOD_REMOVE = "int size = %VARNAME%.size();\nfor (int i = 0; i < size; ++i) {\n\t%ITEMCLASS% item = %VARNAME%.at(i);\n\tif(item == value) {\n\t\tvector<%ITEMCLASS%>::iterator it = %VARNAME%.begin() + i;\n\t\t%VARNAME%.erase(it);\n\t\treturn;\n\t}\n }"; const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_METHOD_INIT = " "; // nothing to do in std::vector krazy:exclude=doublequote_chars const char * CPPCodeGenerationPolicy::DEFAULT_OBJECT_METHOD_INIT = "%VARNAME% = new %ITEMCLASS%();"; /** * Constructor. */ CPPCodeGenerationPolicy::CPPCodeGenerationPolicy() { init(); } /** * Destructor. */ CPPCodeGenerationPolicy::~CPPCodeGenerationPolicy() { } /** * Set the value of publicAccessors * @param var the new value */ void CPPCodeGenerationPolicy::setAccessorsArePublic(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.publicAccessors = var; // @todo we should probably use an own signal for this UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Get the value of m_publicAccessors * @return the boolean value of m_publicAccessors */ bool CPPCodeGenerationPolicy::getAccessorsArePublic() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.publicAccessors; } /** * Set the value of m_inlineAccessors * @param var the new value */ void CPPCodeGenerationPolicy::setAccessorsAreInline(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.inlineAccessors = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Get the value of m_inlineAccessors. * @return the boolean value of m_inlineAccessors */ bool CPPCodeGenerationPolicy::getAccessorsAreInline() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.inlineAccessors; } /** * Set the value of m_inlineOperations. * @param var the new value */ void CPPCodeGenerationPolicy::setOperationsAreInline(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.inlineOps = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Get the value of m_inlineOperations. * @return the boolean value of m_inlineOperations */ bool CPPCodeGenerationPolicy::getOperationsAreInline() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.inlineOps; } /** * Set the value of m_virtualDestructors. * @param var the new value */ void CPPCodeGenerationPolicy::setDestructorsAreVirtual(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.virtualDestructors = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Get the value of m_virtualDestructors. * @return the boolean value of m_virtualDestructors */ bool CPPCodeGenerationPolicy::getDestructorsAreVirtual() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.virtualDestructors; } void CPPCodeGenerationPolicy::setGetterWithGetPrefix(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.getterWithGetPrefix = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } bool CPPCodeGenerationPolicy::getGetterWithGetPrefix() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.getterWithGetPrefix; } void CPPCodeGenerationPolicy::setRemovePrefixFromAccessorMethods(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.removePrefixFromAccessorMethods = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } bool CPPCodeGenerationPolicy::getRemovePrefixFromAccessorMethods() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.removePrefixFromAccessorMethods; } void CPPCodeGenerationPolicy::setAccessorMethodsStartWithUpperCase(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.accessorMethodsStartWithUpperCase = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } bool CPPCodeGenerationPolicy::getAccessorMethodsStartWithUpperCase() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.accessorMethodsStartWithUpperCase; } /** * Set the value of m_packageIsNamespace. * @param var the new value */ void CPPCodeGenerationPolicy::setPackageIsNamespace(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.packageIsNamespace = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Get the value of m_packageIsNamespace. * @return the boolean value of m_packageIsNamespace */ bool CPPCodeGenerationPolicy::getPackageIsNamespace() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.packageIsNamespace; } /** * Set the value of m_autoGenerateAccessors. * @param var the new value */ void CPPCodeGenerationPolicy::setAutoGenerateAccessors(bool var) { Settings::optionState().codeGenerationState.cppCodeGenerationState.autoGenAccessors = var; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Get the value of m_autoGenerateAccessors. * @return the boolean value of m_autoGenerateAccessors */ bool CPPCodeGenerationPolicy::getAutoGenerateAccessors() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.autoGenAccessors; } QString CPPCodeGenerationPolicy::getStringClassName() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.stringClassName; } QString CPPCodeGenerationPolicy::getStringClassNameInclude() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.stringClassNameInclude; } QString CPPCodeGenerationPolicy::getVectorClassName() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassName; } QString CPPCodeGenerationPolicy::getVectorClassNameInclude() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassNameInclude; } void CPPCodeGenerationPolicy::setStringClassName(const QString &value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.stringClassName = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } void CPPCodeGenerationPolicy::setStringClassNameInclude(const QString &value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.stringClassNameInclude = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } void CPPCodeGenerationPolicy::setVectorClassName(const QString &value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassName = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } void CPPCodeGenerationPolicy::setVectorClassNameInclude(const QString &value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassNameInclude = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } +void CPPCodeGenerationPolicy::setClassMemberPrefix(const QString &value) +{ + Settings::optionState().codeGenerationState.cppCodeGenerationState.classMemberPrefix = value; + UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); +} + +QString CPPCodeGenerationPolicy::getClassMemberPrefix() +{ + return Settings::optionState().codeGenerationState.cppCodeGenerationState.classMemberPrefix; +} + void CPPCodeGenerationPolicy::setDocToolTag(const QString &value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.docToolTag = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } QString CPPCodeGenerationPolicy::getDocToolTag() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.docToolTag; } /** * Determine if the string include is global. * @return value of flag */ bool CPPCodeGenerationPolicy::stringIncludeIsGlobal() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.stringIncludeIsGlobal; } /** * Determine if the vector include is global. * @return value of flag */ bool CPPCodeGenerationPolicy::vectorIncludeIsGlobal() { return Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorIncludeIsGlobal; } /** * Set flag whether string include is global. * @param value the value of the flag */ void CPPCodeGenerationPolicy::setStringIncludeIsGlobal(bool value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.stringIncludeIsGlobal = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Set flag whether vector include is global. * @param value the value of the flag */ void CPPCodeGenerationPolicy::setVectorIncludeIsGlobal(bool value) { Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorIncludeIsGlobal = value; UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } QString CPPCodeGenerationPolicy::getVectorMethodAppend(const QString & variableName, const QString & itemClassName) { QString value = m_vectorMethodAppendBase; if(!variableName.isEmpty()) value.replace(QRegExp(QLatin1String("%VARNAME%")), variableName); value.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassName); if(!itemClassName.isEmpty()) value.replace(QRegExp(QLatin1String("%ITEMCLASS%")), itemClassName); return value; } QString CPPCodeGenerationPolicy::getVectorMethodRemove(const QString & variableName, const QString & itemClassName) { QString value = m_vectorMethodRemoveBase; if(!variableName.isEmpty()) value.replace(QRegExp(QLatin1String("%VARNAME%")), variableName); value.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassName); if(!itemClassName.isEmpty()) value.replace(QRegExp(QLatin1String("%ITEMCLASS%")), itemClassName); return value; } QString CPPCodeGenerationPolicy::getVectorMethodInit(const QString & variableName, const QString & itemClassName) { QString value = m_vectorMethodInitBase; if(!variableName.isEmpty()) value.replace(QRegExp(QLatin1String("%VARNAME%")), variableName); value.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassName); if(!itemClassName.isEmpty()) value.replace(QRegExp(QLatin1String("%ITEMCLASS%")), itemClassName); return value; } /** * Be somewhat flexible about how new object classes are initialized. * Not sure if this should be user configureable. For now, it is not. * @param variableName variable name * @param itemClassName item class name * @return object method init string */ QString CPPCodeGenerationPolicy::getObjectMethodInit(const QString & variableName, const QString & itemClassName) { QString value = m_objectMethodInitBase; if(!variableName.isEmpty()) value.replace(QRegExp(QLatin1String("%VARNAME%")), variableName); value.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), Settings::optionState().codeGenerationState.cppCodeGenerationState.vectorClassName); if(!itemClassName.isEmpty()) value.replace(QRegExp(QLatin1String("%ITEMCLASS%")), itemClassName); return value; } /** * Set the defaults for this code generator from the passed generator. * @param cppclone code generation policy object for cloning * @param emitUpdateSignal flag whether to emit update signal */ void CPPCodeGenerationPolicy::setDefaults(CPPCodeGenerationPolicy * cppclone, bool emitUpdateSignal) { blockSignals(true); // we need to do this because otherwise most of these // settors below will each send the modifiedCodeContent() signal // needlessly (we can just make one call at the end). { setAutoGenerateAccessors(cppclone->getAutoGenerateAccessors()); setAccessorsAreInline(cppclone->getAccessorsAreInline()); setOperationsAreInline(cppclone->getOperationsAreInline()); setDestructorsAreVirtual(cppclone->getDestructorsAreVirtual()); setGetterWithGetPrefix(cppclone->getGetterWithGetPrefix()); setRemovePrefixFromAccessorMethods(cppclone->getRemovePrefixFromAccessorMethods()); setAccessorMethodsStartWithUpperCase(cppclone->getAccessorMethodsStartWithUpperCase()); setPackageIsNamespace(cppclone->getPackageIsNamespace()); setStringClassName(cppclone->getStringClassName()); setStringClassNameInclude(cppclone->getStringClassNameInclude()); setStringIncludeIsGlobal(cppclone->stringIncludeIsGlobal()); setVectorClassName(cppclone->getVectorClassName()); setVectorClassNameInclude(cppclone->getVectorClassNameInclude()); setVectorIncludeIsGlobal(cppclone->vectorIncludeIsGlobal()); + setDocToolTag(cppclone->getDocToolTag()); + setClassMemberPrefix(cppclone->getClassMemberPrefix()); } blockSignals(false); // "as you were citizen" if(emitUpdateSignal) UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Set the defaults from a config file for this code generator from the passed KConfig pointer. * @param emitUpdateSignal flag whether to emit update signal */ void CPPCodeGenerationPolicy::setDefaults(bool emitUpdateSignal) { blockSignals(true); // we need to do this because otherwise most of these // settors below will each send the modifiedCodeContent() signal // needlessly (we can just make one call at the end). setAutoGenerateAccessors(UmbrelloSettings::autoGenAccessors()); setAccessorsAreInline(UmbrelloSettings::inlineAccessors()); setAccessorsArePublic(UmbrelloSettings::publicAccessors()); setOperationsAreInline(UmbrelloSettings::inlineOps()); setDestructorsAreVirtual(UmbrelloSettings::virtualDestructors()); setGetterWithGetPrefix(UmbrelloSettings::getterWithGetPrefix()); setRemovePrefixFromAccessorMethods(UmbrelloSettings::removePrefixFromAccessorMethods()); setAccessorMethodsStartWithUpperCase(UmbrelloSettings::accessorMethodsStartWithUpperCase()); setPackageIsNamespace(UmbrelloSettings::packageIsNamespace()); setStringClassName(UmbrelloSettings::stringClassName()); setStringClassNameInclude(UmbrelloSettings::stringClassNameInclude()); setStringIncludeIsGlobal(UmbrelloSettings::stringIncludeIsGlobal()); setVectorClassName(UmbrelloSettings::vectorClassName()); setVectorClassNameInclude(UmbrelloSettings::vectorClassNameInclude()); setVectorIncludeIsGlobal(UmbrelloSettings::vectorIncludeIsGlobal()); + setDocToolTag(UmbrelloSettings::docToolTag()); + setClassMemberPrefix(UmbrelloSettings::classMemberPrefix()); blockSignals(false); // "as you were citizen" if(emitUpdateSignal) UMLApp::app()->commonPolicy()->emitModifiedCodeContentSig(); } /** * Create a new dialog interface for this object. * @param parent the parent widget * @param name the name of the page * @return dialog object */ CodeGenerationPolicyPage * CPPCodeGenerationPolicy::createPage(QWidget *parent, const char *name) { return new CPPCodeGenerationPolicyPage(parent, name, this); } /** * Initialisation routine. */ void CPPCodeGenerationPolicy::init() { blockSignals(true); m_vectorMethodAppendBase = QLatin1String(DEFAULT_VECTOR_METHOD_APPEND); m_vectorMethodRemoveBase = QLatin1String(DEFAULT_VECTOR_METHOD_REMOVE); m_vectorMethodInitBase = QLatin1String(DEFAULT_VECTOR_METHOD_INIT); m_objectMethodInitBase = QLatin1String(DEFAULT_OBJECT_METHOD_INIT); Settings::OptionState optionState = Settings::optionState(); setAutoGenerateAccessors(optionState.codeGenerationState.cppCodeGenerationState.autoGenAccessors); setAccessorsAreInline(optionState.codeGenerationState.cppCodeGenerationState.inlineAccessors); setAccessorsArePublic(optionState.codeGenerationState.cppCodeGenerationState.publicAccessors); setOperationsAreInline(optionState.codeGenerationState.cppCodeGenerationState.inlineOps); setDestructorsAreVirtual(optionState.codeGenerationState.cppCodeGenerationState.virtualDestructors); setGetterWithGetPrefix(optionState.codeGenerationState.cppCodeGenerationState.getterWithGetPrefix); setRemovePrefixFromAccessorMethods(optionState.codeGenerationState.cppCodeGenerationState.removePrefixFromAccessorMethods); setAccessorMethodsStartWithUpperCase(optionState.codeGenerationState.cppCodeGenerationState.accessorMethodsStartWithUpperCase); setPackageIsNamespace(optionState.codeGenerationState.cppCodeGenerationState.packageIsNamespace); setStringClassName(optionState.codeGenerationState.cppCodeGenerationState.stringClassName); setStringClassNameInclude(optionState.codeGenerationState.cppCodeGenerationState.stringClassNameInclude); setStringIncludeIsGlobal(optionState.codeGenerationState.cppCodeGenerationState.stringIncludeIsGlobal); setVectorClassName(optionState.codeGenerationState.cppCodeGenerationState.vectorClassName); setVectorClassNameInclude(optionState.codeGenerationState.cppCodeGenerationState.vectorClassNameInclude); setVectorIncludeIsGlobal(optionState.codeGenerationState.cppCodeGenerationState.vectorIncludeIsGlobal); + setDocToolTag(optionState.codeGenerationState.cppCodeGenerationState.docToolTag); + setClassMemberPrefix(optionState.codeGenerationState.cppCodeGenerationState.classMemberPrefix); + blockSignals(false); } diff --git a/umbrello/codegenerators/cpp/cppcodegenerationpolicy.h b/umbrello/codegenerators/cpp/cppcodegenerationpolicy.h index f25a08ff3..4e8d4c736 100644 --- a/umbrello/codegenerators/cpp/cppcodegenerationpolicy.h +++ b/umbrello/codegenerators/cpp/cppcodegenerationpolicy.h @@ -1,111 +1,114 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ #ifndef CPPCODEGENERATIONPOLICY_H #define CPPCODEGENERATIONPOLICY_H #include "codegenpolicyext.h" #include "codegenerationpolicy.h" #include class CodeGenerationPolicyPage; class CPPCodeGenerationPolicy : public CodeGenPolicyExt { Q_OBJECT public: static const char * DEFAULT_VECTOR_METHOD_APPEND; static const char * DEFAULT_VECTOR_METHOD_REMOVE; static const char * DEFAULT_VECTOR_METHOD_INIT; static const char * DEFAULT_OBJECT_METHOD_INIT; CPPCodeGenerationPolicy(); virtual ~CPPCodeGenerationPolicy(); void setAccessorsAreInline(bool var); bool getAccessorsAreInline(); void setOperationsAreInline(bool var); bool getOperationsAreInline(); void setDestructorsAreVirtual(bool var); bool getDestructorsAreVirtual(); void setPackageIsNamespace(bool var); bool getPackageIsNamespace(); void setAutoGenerateAccessors(bool var); bool getAutoGenerateAccessors(); void setAccessorsArePublic(bool var); bool getAccessorsArePublic(); void setGetterWithGetPrefix(bool var); bool getGetterWithGetPrefix(); void setRemovePrefixFromAccessorMethods(bool var); bool getRemovePrefixFromAccessorMethods(); bool getAccessorMethodsStartWithUpperCase(); void setAccessorMethodsStartWithUpperCase(bool var); /** * We want to be flexible about which classes are allowed for generation * of the CPP code. In the next 4 method pairs, we give accessors that allow setting and getting * the names of the classes, and their include files for string and vectors. */ void setStringClassName(const QString &value); QString getStringClassName(); void setStringClassNameInclude(const QString &value); QString getStringClassNameInclude(); void setVectorClassName(const QString &value); QString getVectorClassName(); void setVectorClassNameInclude(const QString &value); QString getVectorClassNameInclude(); + void setClassMemberPrefix(const QString &value); + QString getClassMemberPrefix(); + void setDocToolTag(const QString &value); QString getDocToolTag(); void setStringIncludeIsGlobal (bool value); bool stringIncludeIsGlobal (); void setVectorIncludeIsGlobal (bool value); bool vectorIncludeIsGlobal (); /** More flexible generation. We want to allow the user to specify how the * bodies of the vector methods should be auto-generated. */ QString getVectorMethodAppend(const QString & variableName = QString(), const QString & itemClassName = QString()); QString getVectorMethodRemove(const QString & variableName = QString(), const QString & itemClassName = QString()); QString getVectorMethodInit(const QString & variableName = QString(), const QString & itemClassName = QString()); QString getObjectMethodInit(const QString & variableName = QString(), const QString & itemClassName = QString()); virtual void setDefaults (CPPCodeGenerationPolicy * cppclone, bool emitUpdateSignal = true); virtual void setDefaults(bool emitUpdateSignal = true); CodeGenerationPolicyPage * createPage (QWidget *parent = 0, const char * name = 0); protected: void init(); private: QString m_vectorMethodAppendBase; QString m_vectorMethodRemoveBase; QString m_vectorMethodInitBase; QString m_objectMethodInitBase; }; #endif // CPPCODEGENERATIONPOLICY_H diff --git a/umbrello/codegenerators/cpp/cppcodegenerationpolicypage.cpp b/umbrello/codegenerators/cpp/cppcodegenerationpolicypage.cpp index 8e4e0e215..9cfc88a92 100644 --- a/umbrello/codegenerators/cpp/cppcodegenerationpolicypage.cpp +++ b/umbrello/codegenerators/cpp/cppcodegenerationpolicypage.cpp @@ -1,104 +1,107 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "cppcodegenerationpolicypage.h" // app includes #include "debug_utils.h" #include "uml.h" // kde includes #include #include // qt includes #include #include CPPCodeGenerationPolicyPage::CPPCodeGenerationPolicyPage(QWidget *parent, const char *name, CPPCodeGenerationPolicy * policy) : CodeGenerationPolicyPage(parent, name, policy) { CodeGenerationPolicy *common = UMLApp::app()->commonPolicy(); QVBoxLayout* vboxLayout = new QVBoxLayout(this); form = new CPPCodeGenerationForm(this); form->ui_selectCommentStyle->setCurrentIndex((int)(common->getCommentStyle())); form->setPackageIsANamespace(policy->getPackageIsNamespace()); form->setVirtualDestructors(policy->getDestructorsAreVirtual()); form->setGenerateAccessorMethods(policy->getAutoGenerateAccessors()); form->setGenerateEmptyConstructors(common->getAutoGenerateConstructors()); form->setOperationsAreInline(policy->getOperationsAreInline()); form->setAccessorsAreInline(policy->getAccessorsAreInline()); form->setAccessorsArePublic(policy->getAccessorsArePublic()); form->setGetterWithoutGetPrefix(policy->getGetterWithGetPrefix()); form->setRemovePrefixFromAccessorMethodName(policy->getRemovePrefixFromAccessorMethods()); form->setAccessorMethodsStartWithUpperCase(policy->getAccessorMethodsStartWithUpperCase()); form->setDocToolTag(policy->getDocToolTag()); + form->setClassMemberPrefix(policy->getClassMemberPrefix()); form->ui_stringClassHCombo->setCurrentItem(policy->getStringClassName(), true); form->ui_listClassHCombo->setCurrentItem(policy->getVectorClassName(), true); form->ui_stringIncludeFileHistoryCombo->setCurrentItem(policy->getStringClassNameInclude(), true); form->ui_listIncludeFileHistoryCombo->setCurrentItem(policy->getVectorClassNameInclude(), true); form->ui_globalStringCheckBox->setChecked(policy->stringIncludeIsGlobal()); form->ui_globalListCheckBox->setChecked(policy->vectorIncludeIsGlobal()); vboxLayout->addWidget(form); } CPPCodeGenerationPolicyPage::~CPPCodeGenerationPolicyPage() { } void CPPCodeGenerationPolicyPage::apply() { CodeGenerationPolicy *common = UMLApp::app()->commonPolicy(); // now do our cpp-specific configs CPPCodeGenerationPolicy * parent = (CPPCodeGenerationPolicy*) m_parentPolicy; // block signals so that we don't generate too many sync signals for child code // documents parent->blockSignals(true); common->setCommentStyle((CodeGenerationPolicy::CommentStyle) form->ui_selectCommentStyle->currentIndex()); common->setAutoGenerateConstructors(form->getGenerateEmptyConstructors()); parent->setAutoGenerateAccessors(form->getGenerateAccessorMethods()); uDebug() << form->getGenerateAccessorMethods(); parent->setDestructorsAreVirtual(form->getVirtualDestructors()); parent->setPackageIsNamespace(form->getPackageIsANamespace()); parent->setAccessorsAreInline(form->getAccessorsAreInline()); parent->setOperationsAreInline(form->getOperationsAreInline()); parent->setAccessorsArePublic(form->getAccessorsArePublic()); parent->setGetterWithGetPrefix(form->getGettersWithGetPrefix()); parent->setRemovePrefixFromAccessorMethods(form->getRemovePrefixFromAccessorMethodName()); parent->setAccessorMethodsStartWithUpperCase(form->getAccessorMethodsStartWithUpperCase()); - parent->setDocToolTag(form->getDocToolTag()); parent->setStringClassName(form->ui_stringClassHCombo->currentText()); parent->setStringClassNameInclude(form->ui_stringIncludeFileHistoryCombo->currentText()); parent->setStringIncludeIsGlobal(form->ui_globalStringCheckBox->isChecked()); parent->setVectorClassName(form->ui_listClassHCombo->currentText()); parent->setVectorClassNameInclude(form->ui_listIncludeFileHistoryCombo->currentText()); parent->setVectorIncludeIsGlobal(form->ui_globalListCheckBox->isChecked()); + parent->setDocToolTag(form->getDocToolTag()); + parent->setClassMemberPrefix(form->getClassMemberPrefix()); + parent->blockSignals(false); // now send out modified code content signal common->emitModifiedCodeContentSig(); } diff --git a/umbrello/codegenerators/cpp/cppheadercodeaccessormethod.cpp b/umbrello/codegenerators/cpp/cppheadercodeaccessormethod.cpp index 5cde1ab41..4190982e6 100644 --- a/umbrello/codegenerators/cpp/cppheadercodeaccessormethod.cpp +++ b/umbrello/codegenerators/cpp/cppheadercodeaccessormethod.cpp @@ -1,171 +1,172 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "cppheadercodeaccessormethod.h" // local includes #include "attribute.h" #include "classifiercodedocument.h" #include "cppcodegenerator.h" #include "cppsourcecodedocument.h" #include "cppcodegenerationpolicy.h" #include "cppcodeclassfield.h" #include "cppcodedocumentation.h" #include "debug_utils.h" #include "umlobject.h" #include "umlrole.h" #include "uml.h" CPPHeaderCodeAccessorMethod::CPPHeaderCodeAccessorMethod(CodeClassField * field, CodeAccessorMethod::AccessorType type) : CodeAccessorMethod(field) { setType(type); } void CPPHeaderCodeAccessorMethod::update() { updateMethodDeclaration(); updateContent(); } CPPHeaderCodeAccessorMethod::~CPPHeaderCodeAccessorMethod() { } // we basically want to update the body of this method void CPPHeaderCodeAccessorMethod::updateContent() { CodeClassField * parentField = getParentClassField(); CPPCodeClassField * cppfield = dynamic_cast(parentField); // Check for dynamic casting failure! if (cppfield == 0) { uError() << "cppfield: invalid dynamic cast"; return; } CodeGenPolicyExt *pe = UMLApp::app()->policyExt(); CPPCodeGenerationPolicy * policy = dynamic_cast(pe); // Check for dynamic casting failure! if (policy == 0) { uError() << "policy: invalid dynamic cast"; return; } bool isInlineMethod = policy->getAccessorsAreInline(); // Uml::Visibility scope = parentField->getVisibility(); QString variableName = cppfield->getFieldName(); QString itemClassName = cppfield->getTypeName(); QString text; if(isInlineMethod) { switch(getType()) { case CodeAccessorMethod::ADD: text = policy->getVectorMethodAppend(variableName, itemClassName); break; case CodeAccessorMethod::REMOVE: text = policy->getVectorMethodRemove(variableName, itemClassName); break; case CodeAccessorMethod::SET: text = variableName + QLatin1String(" = value;"); break; case CodeAccessorMethod::LIST: case CodeAccessorMethod::GET: default: text = QLatin1String("return ") + variableName + QLatin1Char(';'); break; } } setText(text); } // we basically want to update the start text of this method void CPPHeaderCodeAccessorMethod::updateMethodDeclaration() { CodeClassField * parentField = getParentClassField(); ClassifierCodeDocument * doc = parentField->getParentDocument(); CodeGenPolicyExt *pe = UMLApp::app()->policyExt(); CPPCodeGenerationPolicy * policy = dynamic_cast(pe); CPPCodeClassField * cppfield = dynamic_cast(parentField); bool isInlineMethod = policy->getAccessorsAreInline(); QString tag = policy->getDocToolTag(); + QString classMemberPrefix = policy->getClassMemberPrefix(); QString vectorClassName = policy->getVectorClassName(); - QString fieldName = cppfield->getFieldName(); + QString fieldName = classMemberPrefix + cppfield->getFieldName(); QString fieldType = cppfield->getTypeName(); QString objectType = cppfield->getListObjectType(); if(objectType.isEmpty()) objectType = fieldName; QString methodReturnType = QLatin1String("void"); QString methodName; // QLatin1String("get") + cppdoc->capitalizeFirstLetter(fieldName); QString methodParams = QChar(QLatin1Char(' ')); // QLatin1String("get") + cppdoc->capitalizeFirstLetter(fieldName); QString headerText; QString endLine = UMLApp::app()->commonPolicy()->getNewLineEndingChars(); switch(getType()) { case CodeAccessorMethod::ADD: methodName = QLatin1String("add_") + fieldType; methodReturnType = QLatin1String("void"); methodParams = objectType + QLatin1String(" value "); headerText = QLatin1String("Add a ") + fieldName + QLatin1String(" object to the ") + fieldName + QLatin1String("List") + endLine + getParentObject()->doc() + endLine + tag + QLatin1String("return void"); break; case CodeAccessorMethod::REMOVE: methodName = QLatin1String("remove_") + fieldType; methodParams = objectType + QLatin1String(" value "); methodReturnType = QLatin1String("void"); headerText = QLatin1String("Remove a ") + fieldName + QLatin1String(" object from the ") + fieldName + QLatin1String("List") + endLine + getParentObject()->doc() + endLine + tag + QLatin1String("return void"); break; case CodeAccessorMethod::LIST: methodName = QLatin1String("get_") + fieldType + QLatin1String("_list"); methodReturnType = vectorClassName; headerText = QLatin1String("Get the ") + fieldName + QLatin1String("List") + endLine + getParentObject()->doc() + endLine + tag + QLatin1String("return ") + vectorClassName + QLatin1String("with list of objects"); break; case CodeAccessorMethod::SET: methodName = QLatin1String("set_") + fieldName; methodParams = fieldType + QLatin1String(" value "); methodReturnType = QLatin1String("void"); headerText = QLatin1String("Set the value of ") + fieldName + endLine + getParentObject()->doc() + endLine + tag + QLatin1String("param value the value of ") + fieldName; break; case CodeAccessorMethod::GET: default: methodName = QLatin1String("get_") + fieldName; methodReturnType = fieldType; headerText = QLatin1String("Get the value of ") + fieldName + endLine + getParentObject()->doc() + endLine + tag + QLatin1String("return the value of ") + fieldName; break; } // set header CPPCodeDocumentation * header = new CPPCodeDocumentation(doc); if(!getParentObject()->doc().isEmpty()) header->setText(headerText); setComment(header); // set start/end method text QString startText = methodReturnType + QLatin1Char(' ') + methodName + QLatin1String(" (") + methodParams + QLatin1Char(')'); if (isInlineMethod) startText += QLatin1String(" {"); else startText += QLatin1Char(';'); QString endText = (isInlineMethod ? QLatin1String("}") : QString()); setStartMethodText(startText); setEndMethodText(endText); setOverallIndentationLevel(1); } diff --git a/umbrello/codegenerators/cpp/cppwriter.cpp b/umbrello/codegenerators/cpp/cppwriter.cpp index 46e1dec2a..c2fee157d 100644 --- a/umbrello/codegenerators/cpp/cppwriter.cpp +++ b/umbrello/codegenerators/cpp/cppwriter.cpp @@ -1,1410 +1,1422 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * * * copyright (C) 2004-2014 Umbrello UML Modeller Authors * * * ***************************************************************************/ // own header #include "cppwriter.h" // app includes #include "association.h" #include "classifier.h" #include "codegen_utils.h" #include "datatype.h" #include "debug_utils.h" #include "model_utils.h" #include "uml.h" #include "umldoc.h" #include "operation.h" #include "template.h" #include "umltemplatelist.h" #include "umlclassifierlistitemlist.h" #include "classifierlistitem.h" #include "codegenerationpolicy.h" #include "enumliteral.h" // qt includes #include #include #include // 3-14-2003: this code developed from the javawriter with parts of the // original cppwriter by Luis De la Parra Blum /** * Constructor, initialises a couple of variables. */ CppWriter::CppWriter() { // Probably we could resolve this better through the use of templates, // but it is a quick n dirty fix for the timebeing.. until codegeneration // template system is in place. // You can insert code here. 3 general variables exist: "%VARNAME%" // allows you to specify where the vector variable should be in your code, // and "%ITEMCLASS%", if needed, where the class of the item is declared. VECTOR_METHOD_APPEND = QLatin1String("%VARNAME%.push_back(add_object);"); // for std::vector VECTOR_METHOD_REMOVE = QString(QLatin1String("int i, size = %VARNAME%.size();\nfor (i = 0; i < size; ++i) {\n\t%ITEMCLASS% item = %VARNAME%.at(i);\n\tif(item == remove_object) {\n\t\t%1<%ITEMCLASS%>::iterator it = %VARNAME%.begin() + i;\n\t\t%VARNAME%.erase(it);\n\t\treturn;\n\t}\n }")).arg(policyExt()->getVectorClassName()); // for std::vector VECTOR_METHOD_INIT.clear(); // nothing to be done /* VECTOR_METHOD_APPEND = QLatin1String("%VARNAME%.append(&add_object);"); // Qt lib implementation VECTOR_METHOD_REMOVE = QLatin1String("%VARNAME%.removeRef(&remove_object);"); // Qt lib implementation VECTOR_METHOD_INIT = QLatin1String("%VARNAME%.setAutoDelete(false);"); // Qt library */ OBJECT_METHOD_INIT = QLatin1String("%VARNAME% = new %ITEMCLASS%();"); // Qt library // boolean config params INLINE_ASSOCIATION_METHODS = false; } /** * Destructor, empty. */ CppWriter::~CppWriter() { } /** * Returns "C++". * @return the programming language identifier */ Uml::ProgrammingLanguage::Enum CppWriter::language() const { return Uml::ProgrammingLanguage::Cpp; } /** * Return the policy object. */ CPPCodeGenerationPolicy *CppWriter::policyExt() { return static_cast(UMLApp::app()->policyExt()); } /** * Call this method to generate cpp code for a UMLClassifier. * @param c the class to generate code for */ void CppWriter::writeClass(UMLClassifier *c) { if (!c) { uDebug() << "Cannot write class of NULL concept!"; return; } QFile fileh, filecpp; // find an appropriate name for our file fileName_ = findFileName(c, QLatin1String(".h")); if (fileName_.isEmpty()) { emit codeGenerated(c, false); return; } className_ = cleanName(c->name()); if (c->visibility() != Uml::Visibility::Implementation) { if (!openFile(fileh, fileName_)) { emit codeGenerated(c, false); return; } // write Header file writeHeaderFile(c, fileh); fileh.close(); } // Determine whether the implementation file is required. // (It is not required if the class is an enumeration.) bool need_impl = true; if (c->baseType() == UMLObject::ot_Enum || c->isInterface()) { need_impl = false; } if (need_impl) { fileName_.replace(QRegExp(QLatin1String(".h$")), QLatin1String(".cpp")); if (!openFile(filecpp, fileName_)) { emit codeGenerated(c, false); return; } // write Source file writeSourceFile(c, filecpp); filecpp.close(); } emit codeGenerated(c, true); } /** * Write the header file for this classifier. */ void CppWriter::writeHeaderFile (UMLClassifier *c, QFile &file) { // open stream for writing QTextStream h (&file); // up the indent level to one m_indentLevel = 1; // write header blurb QString str = getHeadingFile(QLatin1String(".h")); if (!str.isEmpty()) { str.replace(QRegExp(QLatin1String("%filename%")), fileName_ + QLatin1String(".h")); str.replace(QRegExp(QLatin1String("%filepath%")), file.fileName()); h << str<< m_endl; } // Write the hash define stuff to prevent multiple parsing/inclusion of header QString hashDefine = className_.toUpper().simplified().replace(QRegExp(QLatin1String(" ")), QLatin1String("_")); writeBlankLine(h); h << "#ifndef "<< hashDefine << "_H" << m_endl; h << "#define "<< hashDefine << "_H" << m_endl; writeClassDecl(c, h); // last thing..close our hashdefine h << m_endl << "#endif // " << hashDefine << "_H" << m_endl; } void CppWriter::writeHeaderAccessorMethodDecl(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream) { // attributes writeHeaderAttributeAccessorMethods(c, permitScope, true, stream); // write static attributes first writeHeaderAttributeAccessorMethods(c, permitScope, false, stream); // associations writeAssociationMethods(c->getSpecificAssocs(Uml::AssociationType::Association), permitScope, true, INLINE_ASSOCIATION_METHODS, true, c->id(), stream); writeAssociationMethods(c->getUniAssociationToBeImplemented(), permitScope, true, INLINE_ASSOCIATION_METHODS, true, c->id(), stream); writeAssociationMethods(c->getAggregations(), permitScope, true, INLINE_ASSOCIATION_METHODS, true, c->id(), stream); writeAssociationMethods(c->getCompositions(), permitScope, true, INLINE_ASSOCIATION_METHODS, false, c->id(), stream); writeBlankLine(stream); } /** * Write out fields and operations for this class selected on a particular * visibility. */ void CppWriter::writeHeaderFieldDecl(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream) { // attributes writeAttributeDecls(c, permitScope, true, stream); // write static attributes first writeAttributeDecls(c, permitScope, false, stream); // associations writeAssociationDecls(c->getSpecificAssocs(Uml::AssociationType::Association), permitScope, c->id(), stream); writeAssociationDecls(c->getUniAssociationToBeImplemented(), permitScope, c->id(), stream); writeAssociationDecls(c->getAggregations(), permitScope, c->id(), stream); writeAssociationDecls(c->getCompositions(), permitScope, c->id(), stream); } /** * Write the source code body file for this classifier. */ void CppWriter::writeSourceFile(UMLClassifier *c, QFile &file) { // open stream for writing QTextStream cpp (&file); // set the starting indentation at zero m_indentLevel = 0; //try to find a heading file (license, coments, etc) QString str; str = getHeadingFile(QLatin1String(".cpp")); if (!str.isEmpty()) { str.replace(QRegExp(QLatin1String("%filename%")), fileName_ + QLatin1String(".cpp")); str.replace(QRegExp(QLatin1String("%filepath%")), file.fileName()); cpp << str << m_endl; } // IMPORT statements // Q: Why all utils? Isnt just List and Vector the only classes we are using? // Our import *should* also look at operations, and check that objects being // used arent in another package (and thus need to be explicitly imported here). cpp << "#include \"" << className_ << ".h\"" << m_endl; writeBlankLine(cpp); if (c->visibility() == Uml::Visibility::Implementation) { writeClassDecl(c, cpp); } // Start body of class // Constructors: anything we more we need to do here ? // if (!c->isInterface()) writeConstructorMethods(c, cpp); // METHODS // // write comment for section IF needed QString indnt = indent(); if (forceDoc() || c->hasAccessorMethods() || c->hasOperationMethods()) { writeComment(QLatin1String(" "), indnt, cpp); writeComment(QLatin1String("Methods"), indnt, cpp); writeComment(QLatin1String(" "), indnt, cpp); writeBlankLine(cpp); writeBlankLine(cpp); } // write comment for sub-section IF needed if (forceDoc() || c->hasAccessorMethods()) { writeComment(QLatin1String("Accessor methods"), indnt, cpp); writeComment(QLatin1String(" "), indnt, cpp); writeBlankLine(cpp); } // Accessor methods for attributes const bool bInlineAccessors = policyExt()->getAccessorsAreInline(); if (!bInlineAccessors && c->hasAttributes()) { writeAttributeMethods(c->getAttributeListStatic(Uml::Visibility::Public), Uml::Visibility::Public, false, true, !bInlineAccessors, cpp); writeAttributeMethods(c->getAttributeList(Uml::Visibility::Public), Uml::Visibility::Public, false, false, !bInlineAccessors, cpp); writeAttributeMethods(c->getAttributeListStatic(Uml::Visibility::Protected), Uml::Visibility::Protected, false, true, !bInlineAccessors, cpp); writeAttributeMethods(c->getAttributeList(Uml::Visibility::Protected), Uml::Visibility::Protected, false, false, !bInlineAccessors, cpp); writeAttributeMethods(c->getAttributeListStatic(Uml::Visibility::Private), Uml::Visibility::Private, false, true, !bInlineAccessors, cpp); writeAttributeMethods(c->getAttributeList(Uml::Visibility::Private), Uml::Visibility::Private, false, false, !bInlineAccessors, cpp); } // accessor methods for associations // public writeAssociationMethods(c->getSpecificAssocs(Uml::AssociationType::Association), Uml::Visibility::Public, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getUniAssociationToBeImplemented(), Uml::Visibility::Public, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getAggregations(), Uml::Visibility::Public, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getCompositions(), Uml::Visibility::Public, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); // protected writeAssociationMethods(c->getSpecificAssocs(Uml::AssociationType::Association), Uml::Visibility::Protected, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getUniAssociationToBeImplemented(), Uml::Visibility::Protected, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getAggregations(), Uml::Visibility::Protected, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getCompositions(), Uml::Visibility::Protected, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); // private writeAssociationMethods(c->getSpecificAssocs(Uml::AssociationType::Association), Uml::Visibility::Private, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getUniAssociationToBeImplemented(), Uml::Visibility::Private, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getAggregations(), Uml::Visibility::Private, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeAssociationMethods(c->getCompositions(), Uml::Visibility::Private, false, !INLINE_ASSOCIATION_METHODS, true, c->id(), cpp); writeBlankLine(cpp); // Other operation methods -- all other operations are now written // // write comment for sub-section IF needed if (forceDoc() || c->hasOperationMethods()) { writeComment(QLatin1String("Other methods"), indnt, cpp); writeComment(QLatin1String(" "), indnt, cpp); writeBlankLine(cpp); } if (!policyExt()->getOperationsAreInline()) { writeOperations(c, false, Uml::Visibility::Public, cpp); writeOperations(c, false, Uml::Visibility::Protected, cpp); writeOperations(c, false, Uml::Visibility::Private, cpp); } // Yep, bringing up the back of the bus, our initialization method for attributes writeInitAttributeMethod(c, cpp); writeBlankLine(cpp); } /** * Writes class's documentation to the class header * "public abstract class Foo extents {". */ void CppWriter::writeClassDecl(UMLClassifier *c, QTextStream &cpp) { UMLClassifierList superclasses = c->getSuperClasses(); foreach (UMLClassifier* classifier, superclasses) { QString headerName = findFileName(classifier, QLatin1String(".h")); if (!headerName.isEmpty()) { cpp << "#include \"" << headerName << "\"" << m_endl; } } writeBlankLine(cpp); cpp << "#include " << policyExt()->getStringClassNameInclude() << m_endl; if (c->hasVectorFields()) { cpp << "#include " << policyExt()->getVectorClassNameInclude() << m_endl; writeBlankLine(cpp); } if (c->hasAssociations()) { // write all includes we need to include other classes, that arent us. printAssociationIncludeDecl (c->getSpecificAssocs(Uml::AssociationType::Association), c->id(), cpp); printAssociationIncludeDecl (c->getUniAssociationToBeImplemented(), c->id(), cpp); printAssociationIncludeDecl (c->getAggregations(), c->id(), cpp); printAssociationIncludeDecl (c->getCompositions(), c->id(), cpp); writeBlankLine(cpp); } foreach (UMLClassifier* classifier, superclasses) { if (classifier->package()!=c->package() && !classifier->package().isEmpty()) { cpp << "using " << cleanName(classifier->package()) << "::" << cleanName(classifier->name()) << ";" << m_endl; } } if (!c->package().isEmpty() && policyExt()->getPackageIsNamespace()) cpp << m_endl << "namespace " << cleanName(c->package()) << " {" << m_endl << m_endl; //Write class Documentation if there is somthing or if force option if (forceDoc() || !c->doc().isEmpty()) { cpp << m_endl << "/**" << m_endl; cpp << " * class " << className_ << m_endl; cpp << formatDoc(c->doc(), QLatin1String(" * ")); cpp << " */"; writeBlankLine(cpp); writeBlankLine(cpp); } //check if class is abstract and / or has abstract methods if ((c->isAbstract() || c->isInterface()) && !hasAbstractOps(c)) cpp << "/******************************* Abstract Class ****************************" << m_endl << className_ << " does not have any pure virtual methods, but its author" << m_endl << " defined it as an abstract class, so you should not use it directly." << m_endl << " Inherit from it instead and create only objects from the derived classes" << m_endl << "*****************************************************************************/" << m_endl << m_endl; if (c->baseType() == UMLObject::ot_Enum) { UMLClassifierListItemList litList = c->getFilteredList(UMLObject::ot_EnumLiteral); uint i = 0; cpp << "enum " << className_ << " {" << m_endl; foreach (UMLClassifierListItem* lit, litList) { UMLEnumLiteral *el = static_cast(lit); QString enumLiteral = cleanName(lit->name()); cpp << indent() << enumLiteral; if (!el->value().isEmpty()) cpp << " = " << el->value(); if (++i < (uint)litList.count()) cpp << ","; cpp << m_endl; } cpp << m_endl << "};" << m_endl; // end of class header if (!c->package().isEmpty() && policyExt()->getPackageIsNamespace()) cpp << "} // end of package namespace" << m_endl; return; } // Generate template parameters. UMLTemplateList template_params = c->getTemplateList(); if (template_params.count()) { cpp << "template<"; for (UMLTemplateListIt tlit(template_params); tlit.hasNext();) { UMLTemplate* t = tlit.next(); QString formalName = t->name(); QString typeName = t->getTypeName(); cpp << typeName << " " << formalName; if (tlit.hasNext()) { tlit.next(); cpp << ", "; } } cpp << ">" << m_endl; } cpp << "class " << className_; uint numOfSuperClasses = c->getSuperClasses().count(); if (numOfSuperClasses > 0) cpp << " : "; uint i = 0; foreach (UMLClassifier* superClass, c->getSuperClasses()) { i++; if (superClass->isAbstract() || superClass->isInterface()) cpp << "virtual "; cpp << "public " << cleanName(superClass->name()); if (i < numOfSuperClasses) cpp << ", "; } cpp << m_endl << "{" << m_endl; // begin the body of the class // // write out field and operations decl grouped by visibility // QString s; QTextStream tmp(&s); // PUBLIC attribs/methods writeDataTypes(c, Uml::Visibility::Public, tmp); // for public: constructors are first ops we print out if (!c->isInterface()) writeConstructorDecls(tmp); writeHeaderFieldDecl(c, Uml::Visibility::Public, tmp); writeHeaderAccessorMethodDecl(c, Uml::Visibility::Public, tmp); writeOperations(c, true, Uml::Visibility::Public, tmp); s = s.trimmed(); if (!s.isEmpty()) { cpp << "public:" << m_endl << indent() << s << m_endl << m_endl; } s.clear(); // PROTECTED attribs/methods writeDataTypes(c, Uml::Visibility::Protected, tmp); writeHeaderFieldDecl(c, Uml::Visibility::Protected, tmp); writeHeaderAccessorMethodDecl(c, Uml::Visibility::Protected, tmp); writeOperations(c, true, Uml::Visibility::Protected, tmp); s = s.trimmed(); if (!s.isEmpty()) { cpp << "protected:" << m_endl << indent() << s << m_endl << m_endl; } s.clear(); // PRIVATE attribs/methods writeDataTypes(c, Uml::Visibility::Private, tmp); writeHeaderFieldDecl(c, Uml::Visibility::Private, tmp); writeHeaderAccessorMethodDecl(c, Uml::Visibility::Private, tmp); writeOperations(c, true, Uml::Visibility::Private, tmp); writeInitAttributeDecl(c, tmp); // this is always private, used by constructors to initialize class s = s.trimmed(); if (!s.isEmpty()) { cpp << "private:" << m_endl << indent() << s << m_endl; } // end of class header cpp << m_endl << "};" << m_endl; // end of class namespace, if any if (!c->package().isEmpty() && policyExt()->getPackageIsNamespace()) cpp << "} // end of package namespace" << m_endl; } /** * Writes the attribute declarations. * @param c the classifier * @param visibility the visibility of the attribs to print out * @param writeStatic whether to write static or non-static attributes out * @param stream text stream */ void CppWriter::writeAttributeDecls (UMLClassifier *c, Uml::Visibility::Enum visibility, bool writeStatic, QTextStream &stream) { if (c->isInterface()) return; UMLAttributeList list; if (writeStatic) list = c->getAttributeListStatic(visibility); else list = c->getAttributeList(visibility); //write documentation if (forceDoc() || list.count() > 0) { QString strVis = Codegen_Utils::capitalizeFirstLetter(Uml::Visibility::toString(visibility)); QString strStatic = writeStatic ? QLatin1String("Static ") : QString(); writeComment(strStatic + strVis + QLatin1String(" attributes"), indent(), stream); writeComment(QLatin1String(" "), indent(), stream); writeBlankLine(stream); } if (list.count() > 0) { // write attrib declarations now // bool isFirstAttrib = true; QString documentation; foreach (UMLAttribute* at, list) { // bool noPriorDocExists = documentation.isEmpty(); documentation = at->doc(); // add a line for code clarity IF PRIOR attrib has comment on it // OR this line has documentation // if (!isFirstAttrib && (!documentation.isEmpty()||!noPriorDocExists)) // writeBlankLine(stream); // isFirstAttrib = false; QString varName = getAttributeVariableName(at); QString staticValue = at->isStatic() ? QLatin1String("static ") : QString(); QString typeName = fixTypeName(at->getTypeName()); int i = typeName.indexOf(QLatin1Char('[')); if (i > -1) { varName += typeName.mid(i); typeName = typeName.left(i); } if (!documentation.isEmpty()) writeComment(documentation, indent(), stream); stream << indent() << staticValue << typeName << " " << varName << ";" << m_endl; } /* if (list.count() > 0) writeBlankLine(stream); */ } } void CppWriter::writeHeaderAttributeAccessorMethods (UMLClassifier *c, Uml::Visibility::Enum visibility, bool writeStatic, QTextStream &stream) { // check the current policy about generate accessors as public UMLAttributeList list; if (writeStatic) list = c->getAttributeListStatic(visibility); else list = c->getAttributeList(visibility); // write accessor methods for attribs we found writeAttributeMethods(list, visibility, true, false, policyExt()->getAccessorsAreInline(), stream); } /** * This is for writing *source* or *header* file attribute methods. * Calls @ref writeSingleAttributeAccessorMethods() on each of the attributes in attribs list. */ void CppWriter::writeAttributeMethods(UMLAttributeList attribs, Uml::Visibility::Enum visibility, bool isHeaderMethod, bool isStatic, bool writeMethodBody, QTextStream &stream) { if (!policyExt()->getAutoGenerateAccessors()) return; if (forceDoc() || attribs.count() > 0) { QString strVis = Codegen_Utils::capitalizeFirstLetter(Uml::Visibility::toString(visibility)); QString strStatic = (isStatic ? QLatin1String(" static") : QString()); writeBlankLine(stream); writeComment(strVis + strStatic + QLatin1String(" attribute accessor methods"), indent(), stream); writeComment(QLatin1String(" "), indent(), stream); writeBlankLine(stream); } // return now if NO attributes to work on if (attribs.count() == 0) return; foreach (UMLAttribute* at, attribs) { QString varName = getAttributeVariableName(at); - QString methodBaseName = cleanName(at->name()); + QString methodBaseName = getAttributeMethodBaseName(cleanName(at->name())); methodBaseName = methodBaseName.trimmed(); writeSingleAttributeAccessorMethods(at->getTypeName(), varName, methodBaseName, at->doc(), Uml::Changeability::Changeable, isHeaderMethod, at->isStatic(), writeMethodBody, stream); } } /** * Writes a // style comment. */ void CppWriter::writeComment(const QString &comment, const QString &myIndent, QTextStream &cpp) { // in the case we have several line comment.. // NOTE: this part of the method has the problem of adopting UNIX newline, // need to resolve for using with MAC/WinDoze eventually I assume if (comment.contains(QRegExp(QLatin1String("\n")))) { QStringList lines = comment.split(QLatin1Char('\n')); for (int i= 0; i < lines.count(); ++i) { cpp << myIndent << QLatin1String("// ") << lines[i] << m_endl; } } else { // this should be more fancy in the future, breaking it up into 80 char // lines so that it doesn't look too bad cpp << myIndent << QLatin1String("// ")<< comment << m_endl; } } /** * Writes a documentation comment. */ void CppWriter::writeDocumentation(QString header, QString body, QString end, QTextStream &cpp) { writeBlankLine(cpp); QString indnt = indent(); cpp << indnt << QLatin1String("/**") << m_endl; if (!header.isEmpty()) cpp << formatDoc(header, indnt + QLatin1String(" * ")); if (!body.isEmpty()) cpp << formatDoc(body, indnt + QLatin1String(" * ")); if (!end.isEmpty()) { QStringList lines = end.split(QLatin1Char('\n')); for (int i = 0; i < lines.count(); ++i) { cpp << formatDoc(lines[i], indnt + QLatin1String(" * ")); } } cpp << indnt << QLatin1String(" */") << m_endl; } /** * Searches a list of associations for appropriate ones to write out as attributes. */ void CppWriter::writeAssociationDecls(UMLAssociationList associations, Uml::Visibility::Enum permitScope, Uml::ID::Type id, QTextStream &h) { if (forceSections() || !associations.isEmpty()) { bool printRoleA = false, printRoleB = false; foreach (UMLAssociation *a, associations) { // it may seem counter intuitive, but you want to insert the role of the // *other* class into *this* class. if (a->getObjectId(Uml::RoleType::A) == id && !a->getRoleName(Uml::RoleType::B).isEmpty()) printRoleB = true; if (a->getObjectId(Uml::RoleType::B) == id && !a->getRoleName(Uml::RoleType::A).isEmpty()) printRoleA = true; // First: we insert documentaion for association IF it has either role AND some documentation (!) if ((printRoleA || printRoleB) && !(a->doc().isEmpty())) writeComment(a->doc(), indent(), h); // print RoleB decl if (printRoleB && a->visibility(Uml::RoleType::B) == permitScope) { QString fieldClassName = cleanName(umlObjectName(a->getObject(Uml::RoleType::B))); writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::RoleType::B), a->getMultiplicity(Uml::RoleType::B), a->getRoleDoc(Uml::RoleType::B), h); } // print RoleA decl if (printRoleA && a->visibility(Uml::RoleType::A) == permitScope) { QString fieldClassName = cleanName(umlObjectName(a->getObject(Uml::RoleType::A))); writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::RoleType::A), a->getMultiplicity(Uml::RoleType::A), a->getRoleDoc(Uml::RoleType::A), h); } // reset for next association in our loop printRoleA = false; printRoleB = false; } } } /** * Writes out an association as an attribute using Vector. */ void CppWriter::writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi, QString doc, QTextStream &stream) { // ONLY write out IF there is a rolename given // otherwise it is not meant to be declared in the code if (roleName.isEmpty()) return; QString indnt = indent(); // always put space between this and prior decl, if any writeBlankLine(stream); if (!doc.isEmpty()) writeComment(doc, indnt, stream); // declare the association based on whether it is this a single variable // or a List (Vector). One day this will be done correctly with special // multiplicity object that we don't have to figure out what it means via regex. if (multi.isEmpty() || multi.contains(QRegExp(QLatin1String("^[01]$")))) { QString fieldVarName = QLatin1String("m_") + roleName.toLower(); // record this for later consideration of initialization IF the // multi value requires 1 of these objects if (ObjectFieldVariables.indexOf(fieldVarName) == -1 && multi.contains(QRegExp(QLatin1String("^1$")))) { // ugh. UGLY. Storing variable name and its class in pairs. ObjectFieldVariables.append(fieldVarName); ObjectFieldVariables.append(fieldClassName); } stream << indnt << fieldClassName << " * " << fieldVarName << ";" << m_endl; } else { QString fieldVarName = QLatin1String("m_") + roleName.toLower() + QLatin1String("Vector"); // record unique occurrences for later when we want to check // for initialization of this vector if (VectorFieldVariables.indexOf(fieldVarName) == -1) VectorFieldVariables.append(fieldVarName); stream << indnt << policyExt()->getVectorClassName() << "<" << fieldClassName << "*"; stream << "> " << fieldVarName << ";" << m_endl; } } /** * Calls @ref writeAssociationRoleMethod() on each of the associations in the given list * for either source or header files. */ void CppWriter::writeAssociationMethods (UMLAssociationList associations, Uml::Visibility::Enum permitVisib, bool isHeaderMethod, bool writeMethodBody, bool writePointerVar, Uml::ID::Type myID, QTextStream &stream) { if (forceSections() || !associations.isEmpty()) { foreach (UMLAssociation *a, associations) { // insert the methods to access the role of the other // class in the code of this one if (a->getObjectId(Uml::RoleType::A) == myID && a->visibility(Uml::RoleType::B) == permitVisib) { // only write out IF there is a rolename given if (!a->getRoleName(Uml::RoleType::B).isEmpty()) { QString fieldClassName = umlObjectName(a->getObject(Uml::RoleType::B)) + (writePointerVar ? QLatin1String(" *") : QString()); writeAssociationRoleMethod(fieldClassName, isHeaderMethod, writeMethodBody, a->getRoleName(Uml::RoleType::B), a->getMultiplicity(Uml::RoleType::B), a->getRoleDoc(Uml::RoleType::B), a->changeability(Uml::RoleType::B), stream); } } if (a->getObjectId(Uml::RoleType::B) == myID && a->visibility(Uml::RoleType::A) == permitVisib) { // only write out IF there is a rolename given if (!a->getRoleName(Uml::RoleType::A).isEmpty()) { QString fieldClassName = umlObjectName(a->getObject(Uml::RoleType::A)) + (writePointerVar ? QLatin1String(" *") : QString()); writeAssociationRoleMethod(fieldClassName, isHeaderMethod, writeMethodBody, a->getRoleName(Uml::RoleType::A), a->getMultiplicity(Uml::RoleType::A), a->getRoleDoc(Uml::RoleType::A), a->changeability(Uml::RoleType::A), stream); } } } } } /** * Calls @ref writeSingleAttributeAccessorMethods() or @ref * writeVectorAttributeAccessorMethods() on the association * role. */ void CppWriter::writeAssociationRoleMethod (const QString &fieldClassName, bool isHeaderMethod, bool writeMethodBody, const QString &roleName, const QString &multi, const QString &description, Uml::Changeability::Enum change, QTextStream &stream) { if (multi.isEmpty() || multi.contains(QRegExp(QLatin1String("^[01]$")))) { QString fieldVarName = QLatin1String("m_") + roleName.toLower(); writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName, description, change, isHeaderMethod, false, writeMethodBody, stream); } else { QString fieldVarName = QLatin1String("m_") + roleName.toLower() + QLatin1String("Vector"); writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName, description, change, isHeaderMethod, writeMethodBody, stream); } } /** * Writes addFoo() and removeFoo() accessor methods for the Vector attribute. */ void CppWriter::writeVectorAttributeAccessorMethods ( const QString &fieldClassName, const QString &fieldVarName, const QString &fieldName, const QString &description, Uml::Changeability::Enum changeType, bool isHeaderMethod, bool writeMethodBody, QTextStream &stream) { QString className = fixTypeName(fieldClassName); QString fldName = Codegen_Utils::capitalizeFirstLetter(fieldName); QString indnt = indent(); // ONLY IF changeability is NOT Frozen if (changeType != Uml::Changeability::Frozen) { writeDocumentation(QLatin1String("Add a ") + fldName + QLatin1String(" object to the ") + fieldVarName + QLatin1String(" List"), description, QString(), stream); stream << indnt << QLatin1String("void "); if (!isHeaderMethod) stream << className_ << "::"; stream << "add" << fldName << " (" << className << " add_object)"; if (writeMethodBody) { QString method = VECTOR_METHOD_APPEND; method.replace(QRegExp(QLatin1String("%VARNAME%")), fieldVarName); method.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), policyExt()->getVectorClassName()); method.replace(QRegExp(QLatin1String("%ITEMCLASS%")), className); stream << indnt << " {" << m_endl; m_indentLevel++; printTextAsSeparateLinesWithIndent(method, indent(), stream); m_indentLevel--; stream << indnt << "}" << m_endl; } else stream << ";" << m_endl; } // ONLY IF changeability is Changeable if (changeType == Uml::Changeability::Changeable) { writeDocumentation(QLatin1String("Remove a ") + fldName + QLatin1String(" object from ") + fieldVarName + QLatin1String(" List"), description, QString(), stream); stream << indnt << "void "; if (!isHeaderMethod) stream << className_ << "::"; stream << "remove" << fldName << " (" << className << " remove_object)"; if (writeMethodBody) { QString method = VECTOR_METHOD_REMOVE; method.replace(QRegExp(QLatin1String("%VARNAME%")), fieldVarName); method.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), policyExt()->getVectorClassName()); method.replace(QRegExp(QLatin1String("%ITEMCLASS%")), className); stream << indnt << " {" << m_endl; m_indentLevel++; printTextAsSeparateLinesWithIndent(method, indent(), stream); m_indentLevel--; stream << indnt << "}" << m_endl; } else stream << ";" << m_endl; } // always allow getting the list of stuff QString returnVarName = policyExt()->getVectorClassName() + QLatin1Char('<') + className + QLatin1Char('>'); writeDocumentation(QLatin1String("Get the list of ") + fldName + QLatin1String(" objects held by ") + fieldVarName, description, policyExt()->getDocToolTag() + QLatin1String("return ") + returnVarName + QLatin1String(" list of ") + fldName + QLatin1String(" objects held by ") + fieldVarName, stream); stream << indnt << returnVarName << " "; if (!isHeaderMethod) stream << className_ << "::"; stream << "get" << fldName << "List()"; if (writeMethodBody) { stream << indnt << " {" << m_endl; m_indentLevel++; stream << indent() << "return " << fieldVarName << ";" << m_endl; m_indentLevel--; stream << indnt << "}" << m_endl; } else { stream << ";" << m_endl; } } /** * Writes getFoo() and setFoo() accessor methods for the attribute. */ void CppWriter::writeSingleAttributeAccessorMethods( const QString& fieldClassName, const QString& fieldVarName, const QString& fieldName, const QString &description, Uml::Changeability::Enum change, bool isHeaderMethod, bool isStatic, bool writeMethodBody, QTextStream &stream) { // DON'T write this IF it is a source method AND writeMethodBody is "false" if (!isHeaderMethod && !writeMethodBody) return; QString className = fixTypeName(fieldClassName); - QString fldName = fieldName; - if (policyExt()->getRemovePrefixFromAccessorMethods()) - fldName.replace(QRegExp(QLatin1String("^[a-zA-Z]_")), QLatin1String("")); - QString setFldName = Codegen_Utils::capitalizeFirstLetter(fldName); - if (policyExt()->getAccessorMethodsStartWithUpperCase()) - Codegen_Utils::capitalizeFirstLetter(fldName); QString indnt = indent(); QString varName = QLatin1String("new_var"); QString fullVarName = varName; int i = className.indexOf(QLatin1Char('[')); bool isArrayType = false; if (i > -1) { fullVarName += className.mid(i); className = className.left(i); isArrayType = true; } + QString fldName = fieldName; + if (policyExt()->getAccessorMethodsStartWithUpperCase()) + fldName = Codegen_Utils::capitalizeFirstLetter(fieldName); // set method if (change == Uml::Changeability::Changeable) { writeDocumentation(QLatin1String("Set the value of ") + fieldVarName, description, policyExt()->getDocToolTag() + QLatin1String("param new_var the new value of ") + fieldVarName, stream); stream << indnt << "void "; if (!isHeaderMethod) stream << className_ << "::"; stream << "set" << fldName << "(" << className << " " << fullVarName << ")"; if (writeMethodBody) { stream << m_endl << indnt << "{" << m_endl; m_indentLevel++; stream << indent(); m_indentLevel--; if (isStatic) stream << className_ << "::"; if (isArrayType) stream << "*" << fieldVarName << " = *" << varName << ";" << m_endl; else stream << fieldVarName << " = " << fullVarName << ";" << m_endl; stream << indnt << "}" << m_endl; } else stream << ";" << m_endl; } if (i > -1) className += QLatin1String("*"); // get method writeDocumentation(QLatin1String("Get the value of ") + fieldVarName, description, policyExt()->getDocToolTag() + QLatin1String("return the value of ") + fieldVarName, stream); stream << indnt << className << " "; if (!isHeaderMethod) stream << className_ << "::"; - if (!policyExt()->getRemovePrefixFromAccessorMethods()) - stream << "get"; - stream << fldName << "()"; + if (policyExt()->getGetterWithGetPrefix()) + stream << "get" << fldName << "()"; + else + stream << fieldName << "()"; if (writeMethodBody) { stream << m_endl << indnt << "{" << m_endl; m_indentLevel++; stream << indent() << "return "; m_indentLevel--; if (isStatic) stream << className_ << "::"; stream << fieldVarName << ";" << m_endl; stream << indnt << "}"; } else stream << ";" << m_endl; writeBlankLine(stream); } /** * Writes the comment and class constructor declaration or methods. * Note: * One day, this should print out non-empty constructor operations too. */ void CppWriter::writeConstructorDecls(QTextStream &stream) { const bool generateEmptyConstructors = UMLApp::app()->commonPolicy()->getAutoGenerateConstructors(); if (forceDoc() || generateEmptyConstructors) { writeComment(QLatin1String("Constructors/Destructors"), indent(), stream); writeComment(QLatin1String(" "), indent(), stream); writeBlankLine(stream); } if (!generateEmptyConstructors) return; writeDocumentation(QString(), QLatin1String("Empty Constructor"), QString(), stream); stream << indent() << className_ << "();" << m_endl; writeDocumentation(QString(), QLatin1String("Empty Destructor"), QString(), stream); stream << indent(); stream << "virtual ~" << className_ << "();" << m_endl; writeBlankLine(stream); } /** * If needed, write out the declaration for the method to initialize attributes of our class. */ void CppWriter::writeInitAttributeDecl(UMLClassifier * c, QTextStream &stream) { if (UMLApp::app()->commonPolicy()->getAutoGenerateConstructors() && c->hasAttributes()) stream << indent() << "void initAttributes();" << m_endl; } /** * If needed, write out the method to initialize attributes of our class. */ void CppWriter::writeInitAttributeMethod(UMLClassifier * c, QTextStream &stream) { // only need to do this under certain conditions if (!UMLApp::app()->commonPolicy()->getAutoGenerateConstructors() || !c->hasAttributes()) return; QString indnt = indent(); stream << indnt << "void " << className_ << "::" << "initAttributes()" << m_endl << "{" << m_endl; m_indentLevel++; // first, initiation of fields derived from attributes UMLAttributeList atl = c->getAttributeList(); foreach (UMLAttribute* at, atl) { if (!at->getInitialValue().isEmpty()) { QString varName = getAttributeVariableName(at); stream << indent() << varName << " = " << at->getInitialValue() << ";" << m_endl; } } // Now initialize the association related fields (e.g. vectors) if (!VECTOR_METHOD_INIT.isEmpty()) { QStringList::Iterator it; for (it = VectorFieldVariables.begin(); it != VectorFieldVariables.end(); ++it) { QString fieldVarName = *it; QString method = VECTOR_METHOD_INIT; method.replace(QRegExp(QLatin1String("%VARNAME%")), fieldVarName); method.replace(QRegExp(QLatin1String("%VECTORTYPENAME%")), policyExt()->getVectorClassName()); stream << indent() << method << m_endl; } } if (!OBJECT_METHOD_INIT.isEmpty()) { QStringList::Iterator it; for (it = ObjectFieldVariables.begin(); it != ObjectFieldVariables.end(); ++it) { QString fieldVarName = *it; it++; QString fieldClassName = *it; QString method = OBJECT_METHOD_INIT; method.replace(QRegExp(QLatin1String("%VARNAME%")), fieldVarName); method.replace(QRegExp(QLatin1String("%ITEMCLASS%")), fieldClassName); stream << indent() << method << m_endl; } } // clean up ObjectFieldVariables.clear(); // shouldn't be needed? VectorFieldVariables.clear(); // shouldn't be needed? m_indentLevel--; stream << indnt << "}" << m_endl; } // one day, this should print out non-empty constructor operations too. void CppWriter::writeConstructorMethods(UMLClassifier * c, QTextStream &stream) { const bool generateEmptyConstructors = UMLApp::app()->commonPolicy()->getAutoGenerateConstructors(); if (forceDoc() || generateEmptyConstructors) { writeComment(QLatin1String("Constructors/Destructors"), indent(), stream); writeComment(QLatin1String(" "), indent(), stream); writeBlankLine(stream); } if (!generateEmptyConstructors) return; // empty constructor QString indnt = indent(); stream << indent() << className_ << "::" << className_ << "()" << m_endl << indent() << "{" << m_endl; m_indentLevel++; if (c->hasAttributes()) stream << indent() << "initAttributes();" << m_endl; m_indentLevel--; stream << indent() << "}" << m_endl; writeBlankLine(stream); // empty destructor stream << indent() << className_ << "::~" << className_ << "()" << m_endl << indent() << "{" << m_endl << indent() << "}" << m_endl; writeBlankLine(stream); } /** * Write all datatypes for a given class. * @param c the class for which we are generating code * @param permitScope what type of method to write (by Scope) * @param cpp the stream associated with the output file */ void CppWriter::writeDataTypes(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream) { foreach (UMLObject* o, c->containedObjects()) { uIgnoreZeroPointer(o); if (o->visibility() != permitScope) continue; if (!o->isUMLDatatype()) continue; UMLDatatype *d = o->asUMLDatatype(); if (d && d->isReference() && d->originType()) { stream << indent() << "typedef " << d->originType()->name() << " " << d->name() << ";" << m_endl; } } } /** * Replaces `string' with STRING_TYPENAME. */ QString CppWriter::fixTypeName(const QString &string) { if (string.isEmpty()) return QLatin1String("void"); if (string == QLatin1String("string")) return policyExt()->getStringClassName(); return string; } /** * Write all ooperations for a given class. * @param c the class for which we are generating code * @param isHeaderMethod true when writing to a header file, false for body file * @param permitScope what type of method to write (by Scope) * @param cpp the stream associated with the output file */ void CppWriter::writeOperations(UMLClassifier *c, bool isHeaderMethod, Uml::Visibility::Enum permitScope, QTextStream &cpp) { UMLOperationList oplist; //sort operations by scope first and see if there are abstract methods UMLOperationList inputlist = c->getOpList(); foreach (UMLOperation* op, inputlist) { if (op->visibility() == permitScope) { oplist.append(op); } } // do people REALLY want these comments? Hmm. /* if (forceSections() || oppub.count()) { writeComment(QLatin1String("public operations"), indent(), cpp); writeBlankLine(cpp); } */ writeOperations(c, oplist, isHeaderMethod, cpp); } /** * Write a list of operations for a given class. * Writes operation in either header or source file. * @param c the class for which we are generating code * @param oplist the list of operations you want to write * @param isHeaderMethod true when writing to a header file, false for body file * @param cpp the stream associated with the output file */ void CppWriter::writeOperations(UMLClassifier *c, UMLOperationList &oplist, bool isHeaderMethod, QTextStream &cpp) { const bool generateEmptyConstructors = UMLApp::app()->commonPolicy()->getAutoGenerateConstructors(); // generate method decl for each operation given foreach (UMLOperation* op, oplist) { QString doc; // buffer for documentation QString methodReturnType; UMLAttributeList atl = op->getParmList(); // method parameters if (op->isConstructorOperation()) { if (generateEmptyConstructors && atl.count() == 0) continue; // it's already been written, see writeConstructor{Decls, Methods} } else if (op->isDestructorOperation()) { if (generateEmptyConstructors) continue; // it's already been written, see writeConstructor{Decls, Methods} } else { methodReturnType = fixTypeName(op->getTypeName()); if (methodReturnType != QLatin1String("void")) doc += policyExt()->getDocToolTag() + QLatin1String("return ") + methodReturnType + QLatin1Char('\n'); } QString str; if (op->isAbstract() || c->isInterface()) { if (isHeaderMethod) { // declare abstract method as 'virtual' str += QLatin1String("virtual "); } } // static declaration for header file if (isHeaderMethod && op->isStatic()) str += QLatin1String("static "); // returntype of method str += methodReturnType + QLatin1Char(' '); if (!isHeaderMethod) str += className_ + QLatin1String("::"); str += cleanName(op->name()) + QLatin1String("("); // generate parameters uint j = 0; for (UMLAttributeListIt atlIt(atl); atlIt.hasNext() ; ++j) { UMLAttribute* at = atlIt.next(); QString typeName = fixTypeName(at->getTypeName()); QString atName = cleanName(at->name()); QString atNameType = atName; int i = typeName.indexOf(QLatin1Char('[')); if (i > -1) { atNameType += typeName.mid(i); typeName = typeName.left(i); } str += typeName + QLatin1Char(' ') + atName; const QString initVal = at->getInitialValue(); if (! initVal.isEmpty()) str += QLatin1String(" = ") + initVal; if (j < (uint)(atl.count() - 1)) str += QLatin1String(", "); doc += policyExt()->getDocToolTag() + QLatin1String("param ") + atName + QLatin1Char(' ') + at->doc() + m_endl; } doc = doc.remove(doc.size() - 1, 1); // remove last endl of comment str += QLatin1Char(')'); if (op->getConst()) str += QLatin1String(" const"); if (op->getOverride()) str += QLatin1String(" override"); if (isHeaderMethod && op->isAbstract()) { str += QLatin1String(" = 0;"); } // method body : only gets IF it is not in a header else if (isHeaderMethod && !policyExt()->getOperationsAreInline()) { str += QLatin1Char(';'); // terminate now } else { str += m_endl + indent() + QLatin1Char('{') + m_endl; QString sourceCode = op->getSourceCode(); if (sourceCode.isEmpty()) { // empty method body - TODO: throw exception } else { str += formatSourceCode(sourceCode, indent() + indent()); } str += indent() + QLatin1Char('}'); } // write it out writeDocumentation(QString(), op->doc(), doc, cpp); cpp << indent() << str << m_endl; writeBlankLine(cpp); } } /** * Intellegently print out header include/forward decl. for associated classes. * Note: * To prevent circular including when both classifiers on either end * of an association have roles we need to have forward declaration of * the other class...but only IF it is not THIS class (as could happen * in self-association relationship). */ void CppWriter::printAssociationIncludeDecl(UMLAssociationList list, Uml::ID::Type myId, QTextStream &stream) { foreach (UMLAssociation *a, list) { UMLClassifier *current = 0; bool isFirstClass = true; // only use OTHER classes (e.g. we don't need to write includes for ourselves!! // AND only IF the roleName is defined, otherwise, it is not meant to be noticed. if (a->getObjectId(Uml::RoleType::A) == myId && !a->getRoleName(Uml::RoleType::B).isEmpty()) { current = a->getObject(Uml::RoleType::B)->asUMLClassifier(); } else if (a->getObjectId(Uml::RoleType::B) == myId && !a->getRoleName(Uml::RoleType::A).isEmpty()) { current = a->getObject(Uml::RoleType::A)->asUMLClassifier(); isFirstClass = false; } // as header doc for this method indicates, we need to be a bit sophisticated on // how to declare some associations. if (current) { if (!isFirstClass && !a->getRoleName(Uml::RoleType::A).isEmpty() && !a->getRoleName(Uml::RoleType::B).isEmpty()) stream << "class " << current->name() << ";" << m_endl; // special case: use forward declaration else stream << "#include \"" << current->name() << ".h\"" << m_endl; // just the include statement } } } /** * Check that initial values of strings have quotes around them. */ QString CppWriter::fixInitialStringDeclValue(const QString &value, const QString &type) { QString val = value; // check for strings only if (!val.isEmpty() && type == policyExt()->getStringClassName()) { if (!val.startsWith(QLatin1Char('"'))) val.prepend(QLatin1Char('"')); if (!val.endsWith(QLatin1Char('"'))) val.append(QLatin1Char('"')); } return val; } /** * Returns the name of the given object (if it exists). * Note: * Methods like this _shouldn't_ be needed IF we properly did things thruought the code. */ QString CppWriter::umlObjectName(UMLObject *obj) { return (obj ? obj->name() : QLatin1String("NULL")); } /** * Write a blank line. */ void CppWriter::writeBlankLine(QTextStream &stream) { stream << m_endl; } /** * Utility method to break up a block of text, which has embedded newline chars, * and print them to a stream as separate lines of text, indented as directed. */ void CppWriter::printTextAsSeparateLinesWithIndent(const QString &text, const QString &indent, QTextStream &stream) { if (text.isEmpty()) { return; } QStringList lines = text.split(QLatin1Char('\n')); for (int i= 0; i < lines.count(); ++i) { stream << indent << lines[i] << m_endl; } } /** * Determine what the variable name of this attribute should be. */ QString CppWriter::getAttributeVariableName(UMLAttribute *at) { - QString fieldName = cleanName(at->name()); + QString fieldName; + CodeGenPolicyExt *pe = UMLApp::app()->policyExt(); + CPPCodeGenerationPolicy * policy = dynamic_cast(pe); + if (policy && !policy->getClassMemberPrefix().isEmpty()) + fieldName = policy->getClassMemberPrefix() + cleanName(at->name()); + else + fieldName = cleanName(at->name()); return fieldName; } +QString CppWriter::getAttributeMethodBaseName(const QString &fieldName) +{ + QString fldName = fieldName; + if (policyExt()->getRemovePrefixFromAccessorMethods()) + fldName.replace(QRegExp(QLatin1String("^[a-zA-Z]_")), QLatin1String("")); + return fldName; +} + /** * Add C++ primitives as datatypes. * @return the list of default datatypes */ QStringList CppWriter::defaultDatatypes() { return Codegen_Utils::cppDatatypes(); } /** * Get list of reserved keywords. * @return the list of reserved keywords */ QStringList CppWriter::reservedKeywords() const { return Codegen_Utils::reservedCppKeywords(); } diff --git a/umbrello/codegenerators/cpp/cppwriter.h b/umbrello/codegenerators/cpp/cppwriter.h index 0846a88c2..47104faeb 100644 --- a/umbrello/codegenerators/cpp/cppwriter.h +++ b/umbrello/codegenerators/cpp/cppwriter.h @@ -1,161 +1,162 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * * * copyright (C) 2004-2014 Umbrello UML Modeller Authors * * * ***************************************************************************/ #ifndef CPPWRITER_H #define CPPWRITER_H #include "simplecodegenerator.h" #include "cppcodegenerationpolicy.h" #include "umloperationlist.h" #include "umlattributelist.h" #include "umlassociationlist.h" class QFile; /** * Class CppWriter is a code generator for UMLClassifier objects. * Create an instance of this class, and feed it a UMLClassifier when * calling writeClass and it will generate both a header (.h) and * source (.cpp) file for that classifier. * Note: * This is the "old" code generator that does not support code editing * in the Modeller but uses significantly less file space because the * source code is not replicated in the XMI file. */ class CppWriter : public SimpleCodeGenerator { public: CppWriter(); virtual ~CppWriter(); virtual void writeClass(UMLClassifier *c); virtual Uml::ProgrammingLanguage::Enum language() const; QStringList defaultDatatypes(); virtual QStringList reservedKeywords() const; private: void writeClassDecl(UMLClassifier *c, QTextStream &cpp); void writeConstructorDecls(QTextStream &h); void writeConstructorMethods(UMLClassifier * c, QTextStream &cpp); // /** // * Write all field declarations, for both attributes and associations for the // * given permitted scope. // */ // void writeFieldDecl(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream); // /** // * Write all method declarations, for attributes and associations // * for the given permitted scope. // */ // void writeAccessorMethodDecl(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream); void writeOperations(UMLClassifier *c, bool isHeaderMethod, Uml::Visibility::Enum permitScope, QTextStream &cpp); void writeOperations(UMLClassifier *c, UMLOperationList &oplist, bool isHeaderMethod, QTextStream &cpp); // /** // * Write all attributes for a given class. // * @param c the class for which we are generating code // * @param j the stream associated with the output file // */ // void writeAttributes(UMLClassifier *c, QTextStream &j); void writeAttributeDecls(UMLClassifier *c, Uml::Visibility::Enum visibility, bool writeStatic, QTextStream &stream); void writeHeaderFieldDecl(UMLClassifier *c, Uml::Visibility::Enum permitVisibility, QTextStream &stream); void writeHeaderAttributeAccessorMethods(UMLClassifier *c, Uml::Visibility::Enum visibility, bool writeStatic, QTextStream &stream); void writeHeaderAttributeAccessorMethodDecls(UMLClassifier *c, Uml::Visibility::Enum permitVisibility, QTextStream &stream); void writeHeaderAccessorMethodDecl(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream); void writeAssociationDecls(UMLAssociationList associations, Uml::Visibility::Enum permit, Uml::ID::Type id, QTextStream &stream); void writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi, QString doc, QTextStream &stream); void writeAttributeMethods(UMLAttributeList attribs, Uml::Visibility::Enum visib, bool isHeaderMethod, bool isStatic, bool writeMethodBody, QTextStream &stream); void writeAssociationMethods(UMLAssociationList associations, Uml::Visibility::Enum permitVisib, bool isHeaderMethod, bool writeMethodBody, bool writePointerVar, Uml::ID::Type id, QTextStream &stream); void writeAssociationRoleMethod(const QString &fieldClassName, bool isHeaderMethod, bool writeMethodBody, const QString &roleName, const QString &multi, const QString &description, Uml::Changeability::Enum change, QTextStream &stream); void writeSingleAttributeAccessorMethods( const QString &fieldClassName, const QString &Name, const QString &fieldName, const QString &description, Uml::Changeability::Enum change, bool isHeaderMethod, bool isStatic, bool writeMethodBody, QTextStream &cpp); void writeVectorAttributeAccessorMethods( const QString &fieldClassName, const QString &fieldVarName, const QString &fieldName, const QString &description, Uml::Changeability::Enum change, bool isHeaderMethod, bool writeMethodBody, QTextStream &stream); void writeComment(const QString &text, const QString &indent, QTextStream &cpp); void writeDocumentation(QString header, QString body, QString end, QTextStream &cpp); void writeHeaderFile(UMLClassifier *c, QFile &file); void writeSourceFile(UMLClassifier *c, QFile &file); void printTextAsSeparateLinesWithIndent (const QString &text, const QString &indent, QTextStream &stream); void printAssociationIncludeDecl(UMLAssociationList list, Uml::ID::Type this_id, QTextStream &stream); void writeInitAttributeMethod(UMLClassifier * c, QTextStream &stream); void writeInitAttributeDecl(UMLClassifier * c, QTextStream &stream); void writeDataTypes(UMLClassifier *c, Uml::Visibility::Enum permitScope, QTextStream &stream); QString umlObjectName(UMLObject *obj); QString fixTypeName(const QString &string); QString fixInitialStringDeclValue(const QString &value, const QString &type); QString getAttributeVariableName(UMLAttribute *at); + QString getAttributeMethodBaseName(const QString &fieldName); void writeBlankLine(QTextStream &stream); CPPCodeGenerationPolicy *policyExt(); QString VECTOR_METHOD_APPEND; QString VECTOR_METHOD_REMOVE; QString VECTOR_METHOD_INIT; QString OBJECT_METHOD_INIT; /** * Create association methods for class attributes/associations/operations as inline decl in header. */ bool INLINE_ASSOCIATION_METHODS; QStringList ObjectFieldVariables; QStringList VectorFieldVariables; }; #endif // CPPWRITER_H diff --git a/umbrello/codegenerators/java/javawriter.cpp b/umbrello/codegenerators/java/javawriter.cpp index 1a2ed8c8e..9d94a3366 100644 --- a/umbrello/codegenerators/java/javawriter.cpp +++ b/umbrello/codegenerators/java/javawriter.cpp @@ -1,1008 +1,1008 @@ /*************************************************************************** * 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) 2003 Brian Thomas * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "javawriter.h" // app includes #include "codegen_utils.h" #include "classifier.h" #include "debug_utils.h" #include "operation.h" #include "attribute.h" #include "association.h" #include "template.h" #include "umldoc.h" #include "umltemplatelist.h" // qt includes #include #include #include /** * Constructor, initialises a couple of variables. */ JavaWriter::JavaWriter() : m_isInterface(false) { m_startline = m_endl + m_indentation; } /** * Destructor, empty. */ JavaWriter::~JavaWriter() { } /** * Returns "Java". * @return the programming language identifier */ Uml::ProgrammingLanguage::Enum JavaWriter::language() const { return Uml::ProgrammingLanguage::Java; } /** * Call this method to generate java code for a UMLClassifier. * @param c the class to generate code for */ void JavaWriter::writeClass(UMLClassifier *c) { if (!c) { uDebug() << "Cannot write class of NULL concept!\n"; return; } m_isInterface = c->isInterface(); QString fileName = cleanName(c->name().toLower()); //find an appropriate name for our file fileName = findFileName(c, QLatin1String(".java")); if (fileName.isEmpty()) { emit codeGenerated(c, false); return; } // check that we may open that file for writing QFile file; if (!openFile(file, fileName)) { emit codeGenerated(c, false); return; } // Preparations // // sort attributes by Scope UMLAttributeList atl; UMLAttributeList atpub, atprot, atpriv; UMLAttributeList final_atpub, final_atprot, final_atpriv; if (!m_isInterface) { UMLAttributeList atl = c->getAttributeList(); foreach (UMLAttribute *at, atl) { switch(at->visibility()) { case Uml::Visibility::Public: if (at->isStatic()) final_atpub.append(at); else atpub.append(at); break; case Uml::Visibility::Protected: if (at->isStatic()) final_atprot.append(at); else atprot.append(at); break; case Uml::Visibility::Private: if (at->isStatic()) final_atpriv.append(at); else atpriv.append(at); break; default: break; } } } // another preparation, determine what we have UMLAssociationList associations = c->getSpecificAssocs(Uml::AssociationType::Association); // BAD! only way to get "general" associations. UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented(); UMLAssociationList aggregations = c->getAggregations(); UMLAssociationList compositions = c->getCompositions(); bool hasAssociations = aggregations.count() > 0 || associations.count() > 0 || compositions.count() > 0 || uniAssociations.count() > 0; bool hasAttributes = (atl.count() > 0); bool hasAccessorMethods = hasAttributes || hasAssociations; bool hasOperationMethods = (c->getOpList().count() > 0); // this is a bit too simplistic..some associations are for // SINGLE objects, and WONT be declared as Vectors, so this // is a bit overly inclusive bool hasVectorFields = hasAssociations ? true : false; // open text stream to file QTextStream java(&file); //try to find a heading file (license, coments, etc) QString str; str = getHeadingFile(QLatin1String(".java")); if (!str.isEmpty()) { str.replace(QRegExp(QLatin1String("%filename%")), fileName); str.replace(QRegExp(QLatin1String("%filepath%")), file.fileName()); java << str << m_endl; } if (!c->package().isEmpty()) java << "package " << c->package() << ";" << m_endl; // IMPORT statements // Q: Why all utils? Aren't just List and Vector the only classes we are using? // A: doesn't matter at all; it is more readable to just include '*' and java compilers // don't slow down or anything. (TZ) if (hasVectorFields) { writeBlankLine(java); java << "import java.util.*;" << m_endl; } //only import classes in a different package as this class UMLPackageList imports; findObjectsRelated(c, imports); foreach (UMLPackage* con, imports) { if (con->isUMLDatatype()) continue; QString pkg = con->package(); if (!pkg.isEmpty() && pkg != c->package()) java << "import " << pkg << "." << cleanName(con->name()) << ";" << m_endl; } writeBlankLine(java); // write the opening declaration for the class incl any documentation, // interfaces and/or inheritence issues we have writeClassDecl(c, java); // start body of class java << " {" << m_endl; // ATTRIBUTES // // write comment for section IF needed if (forceDoc() || hasAccessorMethods) { writeComment(QString(), m_indentation, java); writeComment(QLatin1String("Fields"), m_indentation, java); writeComment(QString(), m_indentation, java); writeBlankLine(java); } writeAttributeDecls(final_atpub, final_atprot, final_atpriv, java); writeAttributeDecls(atpub, atprot, atpriv, java); writeAssociationDecls(associations, c->id(), java); writeAssociationDecls(uniAssociations, c->id(), java); writeAssociationDecls(aggregations, c->id(), java); writeAssociationDecls(compositions, c->id(), java); // Constructors: anything we more we need to do here ? // if (!m_isInterface) writeConstructor(c, java); // METHODS // // write comment for section IF needed if (forceDoc() || hasAccessorMethods || hasOperationMethods) { java << m_startline; writeComment(QString(), m_indentation, java); writeComment(QLatin1String("Methods"), m_indentation, java); writeComment(QString(), m_indentation, java); writeBlankLine(java); writeBlankLine(java); } // write comment for sub-section IF needed if (forceDoc() || hasAccessorMethods) { writeComment(QString(), m_indentation, java); writeComment(QLatin1String("Accessor methods"), m_indentation, java); writeComment(QString(), m_indentation, java); writeBlankLine(java); } // Accessors for attributes writeAttributeMethods(final_atpub, Uml::Visibility::Public, java); - writeAttributeMethods(final_atprot, Uml::Visibility::Protected, java); - writeAttributeMethods(final_atpriv, Uml::Visibility::Private, java); + writeAttributeMethods(final_atprot, Uml::Visibility::Public, java); + writeAttributeMethods(final_atpriv, Uml::Visibility::Public, java); writeAttributeMethods(atpub, Uml::Visibility::Public, java); - writeAttributeMethods(atprot, Uml::Visibility::Protected, java); - writeAttributeMethods(atpriv, Uml::Visibility::Private, java); + writeAttributeMethods(atprot, Uml::Visibility::Public, java); + writeAttributeMethods(atpriv, Uml::Visibility::Public, java); // accessor methods for associations // first: determine the name of the other class writeAssociationMethods(associations, c, java); writeAssociationMethods(uniAssociations, c, java); writeAssociationMethods(aggregations, c, java); writeAssociationMethods(compositions, c, java); // Other operation methods // all other operations are now written // write comment for sub-section IF needed if (forceDoc() || hasOperationMethods) { writeComment(QString(), m_indentation, java); writeComment(QLatin1String("Other methods"), m_indentation, java); writeComment(QString(), m_indentation, java); writeBlankLine(java); } writeOperations(c, java); writeBlankLine(java); java << "}" << m_endl; // end class file.close(); emit codeGenerated(c, true); } /** * Writes class's documentation then the class header * "public abstract class Foo extents {". */ void JavaWriter::writeClassDecl(UMLClassifier *c, QTextStream &java) { QString classname = cleanName(c->name()); // our class name // write documentation for class, if any, first if (forceDoc() || !c->doc().isEmpty()) { if (m_isInterface) writeDocumentation(QLatin1String("Interface ") + classname, c->doc(), QString(), QString(), java); else writeDocumentation(QLatin1String("Class ") + classname, c->doc(), QString(), QString(), java); writeBlankLine(java); } // Now write the actual class declaration QString scope; // = c->getVisibility().toString(); if (c->visibility() != Uml::Visibility::Public) { // We should emit a warning in here .. java doesn't like to allow // private/protected classes. The best we can do (I believe) // is to let these declarations default to "package visibility" // which is a level between traditional "private" and "protected" // scopes. To get this visibility level we just print nothing.. } else scope = QLatin1String("public "); java << ((c->isAbstract() && !m_isInterface) ? QLatin1String("abstract ") : QString()) << scope; if (m_isInterface) java << "interface "; else java << "class "; java << classname; // Generics UMLTemplateList template_params = c->getTemplateList(); if (template_params.count()) { java << "<"; for (UMLTemplateListIt tlit(template_params); tlit.hasNext();) { UMLTemplate* t = tlit.next(); QString formalName = t->name(); java << formalName; QString typeName = t->getTypeName(); if (typeName != QLatin1String("class")) { java << " extends " << typeName; } if (tlit.hasNext()) { tlit.next(); java << ", "; } } java << ">" << m_endl; } // write inheritances out UMLClassifierList superclasses = c->findSuperClassConcepts(UMLClassifier::CLASS); int i = 0; foreach (UMLClassifier *concept, superclasses) { if (i == 0) { java << " extends "; } else { //The java generated code is wrong ! : No multiple inheritence of class java << ", " ; } java << cleanName(concept->name()); i++; } UMLClassifierList superInterfaces = c->findSuperClassConcepts(UMLClassifier::INTERFACE); i = 0; foreach (UMLClassifier *concept, superInterfaces) { if (i == 0) { if (m_isInterface) java << " extends "; else java << " implements "; } else { //The java generated code is OK ! : multiple inheritence of interface java << ", " ; } java << cleanName(concept->name()); i++; } } /** * Writes the Attribute declarations. * @param atpub list of public attributes * @param atprot list of protected attributes * @param atpriv list of private attributes * @param java text stream */ void JavaWriter::writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot, UMLAttributeList &atpriv, QTextStream &java) { foreach (UMLAttribute *at, atpub) { QString documentation = at->doc(); QString staticValue = at->isStatic() ? QLatin1String("static ") : QString(); QString typeName = fixTypeName(at->getTypeName()); QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName); if (!documentation.isEmpty()) writeComment(documentation, m_indentation, java, true); java << m_startline << staticValue << "public " << typeName << " " << cleanName(at->name()) << (initialValue.isEmpty() ? QString() : QLatin1String(" = ") + initialValue) << ";"; } foreach (UMLAttribute *at, atprot){ QString documentation = at->doc(); QString typeName = fixTypeName(at->getTypeName()); QString staticValue = at->isStatic() ? QLatin1String("static ") : QString(); QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName); if (!documentation.isEmpty()) writeComment(documentation, m_indentation, java, true); java << m_startline << staticValue << "protected " << typeName << " " << cleanName(at->name()) << (initialValue.isEmpty() ? QString() : QLatin1String(" = ") + initialValue) << ";"; } foreach (UMLAttribute *at, atpriv) { QString documentation = at->doc(); QString typeName = fixTypeName(at->getTypeName()); QString staticValue = at->isStatic() ? QLatin1String("static ") : QString(); QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName); if (!documentation.isEmpty()) writeComment(documentation, m_indentation, java, true); java << m_startline << staticValue << "private " << typeName << " " << cleanName(at->name()) << (initialValue.isEmpty() ? QString() : QLatin1String(" = ") + initialValue) << ";"; } } /** * Calls @ref writeSingleAttributeAccessorMethods() on each of the attributes in atpub. */ void JavaWriter::writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility::Enum visibility, QTextStream &java) { foreach (UMLAttribute *at, atpub){ QString fieldName = cleanName(at->name()); // force capitalizing the field name, this is silly, // from what I can tell, this IS the default behavior for // cleanName. I dunno why it is not working -b.t. fieldName.replace(0, 1, fieldName.at(0).toUpper()); writeSingleAttributeAccessorMethods(at->getTypeName(), cleanName(at->name()), fieldName, at->doc(), visibility, Uml::Changeability::Changeable, at->isStatic(), java); } } /** * Writes a // style comment. */ void JavaWriter::writeComment(const QString &comment, const QString &myIndent, QTextStream &java, bool javaDocStyle) { // in the case we have several line comment.. // NOTE: this part of the method has the problem of adopting UNIX newline, // need to resolve for using with MAC/WinDoze eventually I assume if (comment.contains(QRegExp(QLatin1String("\n")))) { if (javaDocStyle) java << myIndent << "/**" << m_endl; QStringList lines = comment.split(QLatin1String("\n")); for (int i= 0; i < lines.count(); i++) { writeBlankLine(java); if (javaDocStyle) java << myIndent << " * "; else java << myIndent << "// "; java << lines[i]; } if (javaDocStyle) java << myIndent << " */" << m_endl; } else { // this should be more fancy in the future, breaking it up into 80 char // lines so that it doesn't look too bad writeBlankLine(java); if (javaDocStyle) java << myIndent << "/**" << m_endl << myIndent << " *"; else java << myIndent << "//"; if (comment.length() > 0) java << " " << comment; if (javaDocStyle) java << m_endl << myIndent << " */"; } } /** * Writes a documentation comment. */ void JavaWriter::writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &java) { writeBlankLine(java); java << indent << "/**" << m_endl; if (!header.isEmpty()) java << formatDoc(header, indent + QLatin1String(" * ")); if (!body.isEmpty()) java << formatDoc(body, indent + QLatin1String(" * ")); if (!end.isEmpty()) { QStringList lines = end.split(QLatin1String("\n")); for (int i= 0; i < lines.count(); i++) java << formatDoc(lines[i], indent + QLatin1String(" * ")); } java << indent << " */"; } /** * Searches a list of associations for appropriate ones to write out as attributes. */ void JavaWriter::writeAssociationDecls(UMLAssociationList associations, Uml::ID::Type id, QTextStream &java) { if (forceSections() || !associations.isEmpty()) { bool printRoleA = false, printRoleB = false; foreach (UMLAssociation *a, associations) { // it may seem counter intuitive, but you want to insert the role of the // *other* class into *this* class. if (a->getObjectId(Uml::RoleType::A) == id) printRoleB = true; if (a->getObjectId(Uml::RoleType::B) == id) printRoleA = true; // First: we insert documentaion for association IF it has either role AND some documentation (!) if ((printRoleA || printRoleB) && !(a->doc().isEmpty())) writeComment(a->doc(), m_indentation, java); // print RoleB decl if (printRoleB) { QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::RoleType::B))); writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::RoleType::B), a->getMultiplicity(Uml::RoleType::B), a->getRoleDoc(Uml::RoleType::B), a->visibility(Uml::RoleType::B), java); } // print RoleA decl if (printRoleA) { QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::RoleType::A))); writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::RoleType::A), a->getMultiplicity(Uml::RoleType::A), a->getRoleDoc(Uml::RoleType::A), a->visibility(Uml::RoleType::A), java); } } } } /** * Writes out an association as an attribute using Vector. */ void JavaWriter::writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi, QString doc, Uml::Visibility::Enum visib, QTextStream &java) { // ONLY write out IF there is a rolename given // otherwise it is not meant to be declared in the code if (roleName.isEmpty()) return; QString scope = Uml::Visibility::toString(visib); // always put space between this and prior decl, if any writeBlankLine(java); if (!doc.isEmpty()) writeComment(doc, m_indentation, java); // declare the association based on whether it is this a single variable // or a List (Vector). One day this will be done correctly with special // multiplicity object that we don't have to figure out what it means via regex. if (multi.isEmpty() || multi.contains(QRegExp(QLatin1String("^[01]$")))) { QString fieldVarName = QLatin1String("m_") + roleName.replace(0, 1, roleName.left(1).toLower()); java << m_startline << scope << " " << fieldClassName << " " << fieldVarName << ";"; } else { QString fieldVarName = roleName.toLower() + QLatin1String("Vector"); java << m_startline << scope << " Vector " << fieldVarName << " = new Vector();"; // from here we could initialize default values, or put in an init() section // of the constructors } } /** * Calls @ref writeAssociationRoleMethod() on each of the associations in the given list. */ void JavaWriter::writeAssociationMethods (UMLAssociationList associations, UMLClassifier *thisClass, QTextStream &java) { if (forceSections() || !associations.isEmpty()) { foreach(UMLAssociation *a, associations) { // insert the methods to access the role of the other // class in the code of this one if (a->getObjectId(Uml::RoleType::A) == thisClass->id()) { // only write out IF there is a rolename given if (!a->getRoleName(Uml::RoleType::B).isEmpty()) { QString fieldClassName = getUMLObjectName(a->getObject(Uml::RoleType::B)); writeAssociationRoleMethod(fieldClassName, a->getRoleName(Uml::RoleType::B), a->getMultiplicity(Uml::RoleType::B), a->getRoleDoc(Uml::RoleType::B), a->visibility(Uml::RoleType::B), a->changeability(Uml::RoleType::B), java); } } if (a->getObjectId(Uml::RoleType::B) == thisClass->id()) { // only write out IF there is a rolename given if (!a->getRoleName(Uml::RoleType::A).isEmpty()) { QString fieldClassName = getUMLObjectName(a->getObject(Uml::RoleType::A)); writeAssociationRoleMethod(fieldClassName, a->getRoleName(Uml::RoleType::A), a->getMultiplicity(Uml::RoleType::A), a->getRoleDoc(Uml::RoleType::A), a->visibility(Uml::RoleType::A), a->changeability(Uml::RoleType::A), java); } } } } } /** * Calls @ref writeSingleAttributeAccessorMethods() or @ref * writeVectorAttributeAccessorMethods() on the assocaition * role. */ void JavaWriter::writeAssociationRoleMethod (QString fieldClassName, QString roleName, QString multi, QString description, Uml::Visibility::Enum visib, Uml::Changeability::Enum change, QTextStream &java) { if (multi.isEmpty() || multi.contains(QRegExp(QLatin1String("^[01]$")))) { QString fieldVarName = QLatin1String("m_") + roleName.replace(0, 1, roleName.left(1).toLower()); writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName, description, visib, change, false, java); } else { QString fieldVarName = roleName.toLower() + QLatin1String("Vector"); writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName, description, visib, change, java); } } /** * Writes addFoo() and removeFoo() accessor methods for the Vector attribute. */ void JavaWriter::writeVectorAttributeAccessorMethods(QString fieldClassName, QString fieldVarName, QString fieldName, QString description, Uml::Visibility::Enum visibility, Uml::Changeability::Enum changeType, QTextStream &java) { fieldClassName = fixTypeName(fieldClassName); fieldName = Codegen_Utils::capitalizeFirstLetter(fieldName); QString strVis = Uml::Visibility::toString(visibility); // ONLY IF changeability is NOT Frozen if (changeType != Uml::Changeability::Frozen) { writeDocumentation(QLatin1String("Add a ") + fieldName + QLatin1String(" object to the ") + fieldVarName + QLatin1String(" List"), description, QString(), m_indentation, java); java << m_startline << strVis << " void add" << fieldName << " (" << fieldClassName << " new_object) {"; java << m_startline << m_indentation << fieldVarName << ".add(new_object);"; java << m_startline << "}" << m_endl; } // ONLY IF changeability is Changeable if (changeType == Uml::Changeability::Changeable) { writeDocumentation(QLatin1String("Remove a ") + fieldName + QLatin1String(" object from ") + fieldVarName + QLatin1String(" List"), description, QString(), m_indentation, java); java << m_startline << strVis << " void remove" << fieldName << " (" << fieldClassName << " new_object)"; java << m_startline << "{"; java << m_startline << m_indentation << fieldVarName << ".remove(new_object);"; java << m_startline << "}" << m_endl; } // always allow getting the list of stuff writeDocumentation(QLatin1String("Get the List of ") + fieldName + QLatin1String(" objects held by ") + fieldVarName, description, QLatin1String("@return List of ") + fieldName + QLatin1String(" objects held by ") + fieldVarName, m_indentation, java); java << m_startline << strVis << " List get" << fieldName << "List () {"; java << m_startline << m_indentation << "return (List) " << fieldVarName << ";"; java << m_startline << "}" << m_endl; writeBlankLine(java); } /** * Writes getFoo() and setFoo() accessor methods for the attribute. */ void JavaWriter::writeSingleAttributeAccessorMethods(QString fieldClassName, QString fieldVarName, QString fieldName, QString description, Uml::Visibility::Enum visibility, Uml::Changeability::Enum change, bool isFinal, QTextStream &java) { QString strVis = Uml::Visibility::toString(visibility); fieldClassName = fixTypeName(fieldClassName); fieldName = Codegen_Utils::capitalizeFirstLetter(fieldName); // set method if (change == Uml::Changeability::Changeable && !isFinal) { writeDocumentation(QLatin1String("Set the value of ") + fieldVarName, description, QLatin1String("@param newVar the new value of ") + fieldVarName, m_indentation, java); java << m_startline << strVis << " void set" << fieldName << " (" << fieldClassName << " newVar) {"; java << m_startline << m_indentation << fieldVarName << " = newVar;"; java << m_startline << "}" << m_endl; } // get method writeDocumentation(QLatin1String("Get the value of ") + fieldVarName, description, QLatin1String("@return the value of ") + fieldVarName, m_indentation, java); java << m_startline << strVis << " " << fieldClassName << " get" << fieldName << " () {"; java << m_startline << m_indentation << "return " << fieldVarName << ";"; java << m_startline << "}"; writeBlankLine(java); } /** * Writes the comment and class constructor. */ void JavaWriter::writeConstructor(UMLClassifier *c, QTextStream &java) { if (forceDoc()) { java << m_startline; writeComment(QString(), m_indentation, java); writeComment(QLatin1String("Constructors"), m_indentation, java); writeComment(QString(), m_indentation, java); writeBlankLine(java); } // write the first constructor QString className = cleanName(c->name()); java << m_indentation << "public " << className << " () { };"; } /** * Replaces `string' with `String' and `bool' with `boolean'. * IF the type is "string" we need to declare it as * the Java Object "String" (there is no string primitive in Java). * Same thing again for "bool" to "boolean". */ QString JavaWriter::fixTypeName(const QString& string) { if (string.isEmpty()) return QLatin1String("void"); if (string == QLatin1String("string")) return QLatin1String("String"); if (string == QLatin1String("bool")) return QLatin1String("boolean"); return string; } /** * Overrides method from class CodeGenerator. * @return the list of default datatypes */ QStringList JavaWriter::defaultDatatypes() { QStringList l; l.append(QLatin1String("int")); l.append(QLatin1String("char")); l.append(QLatin1String("boolean")); l.append(QLatin1String("float")); l.append(QLatin1String("double")); l.append(QLatin1String("byte")); l.append(QLatin1String("short")); l.append(QLatin1String("long")); l.append(QLatin1String("String")); l.append(QLatin1String("Integer")); l.append(QLatin1String("Character")); l.append(QLatin1String("Boolean")); l.append(QLatin1String("Float")); l.append(QLatin1String("Double")); l.append(QLatin1String("Byte")); l.append(QLatin1String("Short")); l.append(QLatin1String("Long")); l.append(QLatin1String("StringBuffer")); l.append(QLatin1String("StringBuilder")); return l; } /** * Return true if the two operations have the same name and the same parameters. * @param op1 first operation to be compared * @param op2 second operation to be compared */ bool JavaWriter::compareJavaMethod(UMLOperation *op1, UMLOperation *op2) { if (op1 == 0 || op2 == 0) return false; if (op1 == op2) return true; if (op1->name() != op2->name()) return false; UMLAttributeList atl1 = op1->getParmList(); UMLAttributeList atl2 = op2->getParmList(); if (atl1.count() != atl2.count()) return false; for (UMLAttributeListIt atl1It(atl1), atl2It(atl2); atl1It.hasNext() && atl2It.hasNext();) { UMLAttribute *at1 = atl1It.next(); UMLAttribute *at2 = atl2It.next(); if (at1->getTypeName() != at2->getTypeName()) return false; } return true; } /** * Return true if the operation is in the list. * @param umlOp operation to be searched * @param opl list of operations */ bool JavaWriter::javaMethodInList(UMLOperation *umlOp, UMLOperationList &opl) { foreach (UMLOperation *op, opl) { if (JavaWriter::compareJavaMethod(op, umlOp)) { return true; } } return false; } /** * Get all operations which a given class inherit from all its super interfaces and get all operations * which this given class inherit from all its super classes. * @param c the class for which we are generating code * @param yetImplementedOpList the list of yet implemented operations * @param toBeImplementedOpList the list of to be implemented operations * @param noClassInPath tells if there is a class between the base class and the current interface */ void JavaWriter::getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList, UMLOperationList &toBeImplementedOpList, bool noClassInPath) { UMLClassifierList superClasses = c->findSuperClassConcepts(); foreach (UMLClassifier *concept, superClasses) { getSuperImplementedOperations(concept, yetImplementedOpList, toBeImplementedOpList, (concept->isInterface() && noClassInPath)); UMLOperationList opl = concept->getOpList(); foreach (UMLOperation *op, opl) { if (concept->isInterface() && noClassInPath) { if (!JavaWriter::javaMethodInList(op, toBeImplementedOpList)) toBeImplementedOpList.append(op); } else { if (!JavaWriter::javaMethodInList(op, yetImplementedOpList)) yetImplementedOpList.append(op); } } } } /** * Get all operations which a given class inherit from all its super interfaces and that should be implemented. * @param c the class for which we are generating code * @param opl the list of operations used to append the operations */ void JavaWriter::getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opList) { UMLOperationList yetImplementedOpList; UMLOperationList toBeImplementedOpList; getSuperImplementedOperations(c, yetImplementedOpList, toBeImplementedOpList); foreach (UMLOperation *op, toBeImplementedOpList) { if (! JavaWriter::javaMethodInList(op, yetImplementedOpList) && ! JavaWriter::javaMethodInList(op, opList)) opList.append(op); } } /** * Write all operations for a given class. * @param c the class for which we are generating code * @param j the stream associated with the output file */ void JavaWriter::writeOperations(UMLClassifier *c, QTextStream &java) { UMLOperationList opl; UMLOperationList oppub, opprot, oppriv; //sort operations by scope first and see if there are abstract methods opl = c->getOpList(); if (! c->isInterface()) { getInterfacesOperationsToBeImplemented(c, opl); } foreach (UMLOperation *op, opl) { switch(op->visibility()) { case Uml::Visibility::Public: oppub.append(op); break; case Uml::Visibility::Protected: opprot.append(op); break; case Uml::Visibility::Private: oppriv.append(op); break; default: break; } } // do people REALLY want these comments? Hmm. /* if (forceSections() || oppub.count()) { writeComment(QLatin1String("public operations"), m_indentation, java); writeBlankLine(java); } */ writeOperations(oppub, java); /* if (forceSections() || opprot.count()) { writeComment(QLatin1String("protected operations"), m_indentation, java); writeBlankLine(java); } */ writeOperations(opprot, java); /* if (forceSections() || oppriv.count()) { writeComment(QLatin1String("private operations"), m_indentation, java); writeBlankLine(java); } */ writeOperations(oppriv, java); } /** * Write a list of operations for a given class. * @param list the list of operations you want to write * @param j the stream associated with the output file */ void JavaWriter::writeOperations(UMLOperationList &oplist, QTextStream &java) { UMLAttributeList atl; int i, j; QString str; // generate method decl for each operation given foreach(UMLOperation* op, oplist){ QString doc; // write documentation QString methodReturnType = fixTypeName(op->getTypeName()); if (methodReturnType != QLatin1String("void")) doc += QLatin1String("@return ") + methodReturnType + QLatin1Char('\n'); str = QString(); // reset for next method str += ((op->isAbstract() && !m_isInterface) ? QLatin1String("abstract ") : QString()); str += Uml::Visibility::toString(op->visibility()) + QLatin1Char(' '); str += (op->isStatic() ? QLatin1String("static ") : QString()); str += methodReturnType + QLatin1Char(' ') + cleanName(op->name()) + QLatin1Char('('); atl = op->getParmList(); i= atl.count(); j=0; foreach (UMLAttribute* at, atl) { QString typeName = fixTypeName(at->getTypeName()); QString atName = cleanName(at->name()); str += typeName + QLatin1Char(' ') + atName + (!(at->getInitialValue().isEmpty()) ? (QLatin1String(" = ") + at->getInitialValue()) : QString()) + ((j < i-1) ? QLatin1String(", ") : QString()); doc += QLatin1String("@param ") + atName + QLatin1Char(' ') + at->doc() + QLatin1Char('\n'); j++; } doc = doc.remove(doc.size() - 1, 1); // remove last endl of comment str += QLatin1Char(')'); // method only gets a body IF it is not abstract if (op->isAbstract() || m_isInterface) str += QLatin1String(";\n\n"); // terminate now else { str += m_startline + QLatin1Char('{') + m_endl; QString sourceCode = op->getSourceCode(); if (sourceCode.isEmpty()) { // empty method body - TODO: throw exception } else { str += formatSourceCode(sourceCode, m_indentation + m_indentation); } str += m_indentation + QLatin1Char('}') + m_endl + m_endl; } // write it out writeDocumentation(QString(), op->doc(), doc, m_indentation, java); java << m_startline << str; } } /** * Check that initial values of strings have quotes around them. */ QString JavaWriter::fixInitialStringDeclValue(const QString& val, const QString& type) { QString value = val; // check for strings only if (!value.isEmpty() && type == QLatin1String("String")) { if (!value.startsWith(QLatin1Char('"'))) value.prepend(QLatin1Char('"')); if (!value.endsWith(QLatin1Char('"'))) value.append(QLatin1Char('"')); } return value; } /** * Returns the name of the given object (if it exists). */ QString JavaWriter::getUMLObjectName(UMLObject *obj) { return (obj ? obj->name() : QLatin1String("NULL")); } /** * Write a blank line. * Note: Methods like this _shouldn't_ be needed IF we properly did things thruought the code. */ void JavaWriter::writeBlankLine(QTextStream &java) { java << m_endl; } diff --git a/umbrello/optionstate.cpp b/umbrello/optionstate.cpp index 8940972bb..35dfd2dc6 100644 --- a/umbrello/optionstate.cpp +++ b/umbrello/optionstate.cpp @@ -1,434 +1,436 @@ /*************************************************************************** * 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) 2006-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ #include "optionstate.h" #include "umbrellosettings.h" #if QT_VERSION < 0x050000 #include #endif namespace Settings { void GeneralState::load() { undo = UmbrelloSettings::undo(); tabdiagrams = UmbrelloSettings::tabdiagrams(); #ifdef ENABLE_NEW_CODE_GENERATORS newcodegen = UmbrelloSettings::newcodegen(); #endif angularlines = UmbrelloSettings::angularlines(); layoutType = UmbrelloSettings::layoutType(); footerPrinting = UmbrelloSettings::footerPrinting(); uml2 = UmbrelloSettings::uml2(); autosave = UmbrelloSettings::autosave(); time = UmbrelloSettings::time(); //old autosavetime value kept for compatibility autosavetime = UmbrelloSettings::autosavetime(); //if we don't have a "new" autosavetime value, convert the old one if (autosavetime == 0) { switch (time) { case 0: autosavetime = 5; break; case 1: autosavetime = 10; break; case 2: autosavetime = 15; break; case 3: autosavetime = 20; break; case 4: autosavetime = 25; break; default: autosavetime = 5; break; } } autosavesuffix = UmbrelloSettings::autosavesuffix(); loadlast = UmbrelloSettings::loadlast(); diagram = UmbrelloSettings::diagram(); defaultLanguage = UmbrelloSettings::defaultLanguage(); } void GeneralState::save() { UmbrelloSettings::setUndo(undo); UmbrelloSettings::setTabdiagrams(tabdiagrams); UmbrelloSettings::setNewcodegen(newcodegen); UmbrelloSettings::setAngularlines(angularlines); UmbrelloSettings::setFooterPrinting(footerPrinting); UmbrelloSettings::setAutosave(autosave); UmbrelloSettings::setTime(time); UmbrelloSettings::setAutosavetime(autosavetime); UmbrelloSettings::setAutosavesuffix(autosavesuffix); UmbrelloSettings::setLoadlast(loadlast); UmbrelloSettings::setUml2(uml2); UmbrelloSettings::setDiagram(diagram); UmbrelloSettings::setDefaultLanguage(defaultLanguage); } void ClassState::load() { showVisibility = UmbrelloSettings::showVisibility(); showAtts = UmbrelloSettings::showAtts(); showOps = UmbrelloSettings::showOps(); showStereoType = UmbrelloSettings::showStereoType(); showAttSig = UmbrelloSettings::showAttSig(); showOpSig = UmbrelloSettings::showOpSig(); showPackage = UmbrelloSettings::showPackage(); showAttribAssocs = UmbrelloSettings::showAttribAssocs(); showPublicOnly = UmbrelloSettings::showPublicOnly(); defaultAttributeScope = UmbrelloSettings::defaultAttributeScope(); defaultOperationScope = UmbrelloSettings::defaultOperationScope(); } void ClassState::save() { UmbrelloSettings::setShowVisibility(showVisibility); UmbrelloSettings::setShowAtts(showAtts); UmbrelloSettings::setShowOps(showOps); UmbrelloSettings::setShowStereoType(showStereoType); UmbrelloSettings::setShowAttSig(showAttSig); UmbrelloSettings::setShowOpSig(showOpSig); UmbrelloSettings::setShowPackage(showPackage); UmbrelloSettings::setShowAttribAssocs(showAttribAssocs); UmbrelloSettings::setShowPublicOnly(showPublicOnly); UmbrelloSettings::setDefaultAttributeScope(defaultAttributeScope); UmbrelloSettings::setDefaultOperationScope(defaultOperationScope); } /** * Save instance into a QDomElement. * @param element A QDomElement representing xml element data. */ void ClassState::saveToXMI1(QDomElement &element) { element.setAttribute(QLatin1String("showattribassocs"), showAttribAssocs); element.setAttribute(QLatin1String("showatts"), showAtts); element.setAttribute(QLatin1String("showattsig"), showAttSig); element.setAttribute(QLatin1String("showops"), showOps); element.setAttribute(QLatin1String("showopsig"), showOpSig); element.setAttribute(QLatin1String("showpackage"), showPackage); element.setAttribute(QLatin1String("showpubliconly"), showPublicOnly); element.setAttribute(QLatin1String("showscope"), showVisibility); #ifdef ENABLE_WIDGET_SHOW_DOC element.setAttribute(QLatin1String("showdocumentation"),showDocumentation); #endif element.setAttribute(QLatin1String("showstereotype"), showStereoType); } /** * Load instance from a QDomElement. * @param element A QDomElement representing xml element data. * @return true on success * @return false on error */ bool ClassState::loadFromXMI1(QDomElement &element) { QString temp = element.attribute(QLatin1String("showattribassocs"), QLatin1String("0")); showAttribAssocs = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showatts"), QLatin1String("0")); showAtts = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showattsig"), QLatin1String("0")); showAttSig = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showops"), QLatin1String("0")); showOps = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showopsig"), QLatin1String("0")); showOpSig = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showpackage"), QLatin1String("0")); showPackage = (bool)temp.toInt(); #ifdef ENABLE_WIDGET_SHOW_DOC temp = element.attribute(QLatin1String("showdocumentation"), QLatin1String("0")); showDocumentation = (bool)temp.toInt(); #endif temp = element.attribute(QLatin1String("showpubliconly"), QLatin1String("0")); showPublicOnly = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showscope"), QLatin1String("0")); showVisibility = (bool)temp.toInt(); temp = element.attribute(QLatin1String("showstereotype"), QLatin1String("0")); showStereoType = (bool)temp.toInt(); return true; } void UIState::load() { useFillColor = UmbrelloSettings::useFillColor(); fillColor = UmbrelloSettings::fillColor(); lineColor = UmbrelloSettings::lineColor(); lineWidth = UmbrelloSettings::lineWidth(); textColor = UmbrelloSettings::textColor(); font = UmbrelloSettings::uiFont(); backgroundColor = UmbrelloSettings::backgroundColor(); gridDotColor = UmbrelloSettings::gridDotColor(); } void UIState::save() { UmbrelloSettings::setUseFillColor(useFillColor); UmbrelloSettings::setFillColor(fillColor); UmbrelloSettings::setLineColor(lineColor); UmbrelloSettings::setLineWidth(lineWidth); UmbrelloSettings::setTextColor(textColor); UmbrelloSettings::setUiFont(font); UmbrelloSettings::setBackgroundColor(backgroundColor); UmbrelloSettings::setGridDotColor(gridDotColor); } /** * Save instance into a QDomElement. * @param element A QDomElement representing xml element data. */ void UIState::saveToXMI1(QDomElement &element) { element.setAttribute(QLatin1String("backgroundcolor"), backgroundColor.name()); element.setAttribute(QLatin1String("fillcolor"), fillColor.name()); element.setAttribute(QLatin1String("font"), font.toString()); element.setAttribute(QLatin1String("griddotcolor"), gridDotColor.name()); element.setAttribute(QLatin1String("linecolor"), lineColor.name()); element.setAttribute(QLatin1String("linewidth"), lineWidth); element.setAttribute(QLatin1String("textcolor"), textColor.name()); element.setAttribute(QLatin1String("usefillcolor"), useFillColor); } /** * Load instance from a QDomElement. * @param element A QDomElement representing xml element data. * @return true on success * @return false on error */ bool UIState::loadFromXMI1(QDomElement &element) { QString backgroundColor = element.attribute(QLatin1String("backgroundcolor")); if (!backgroundColor.isEmpty()) this->backgroundColor = QColor(backgroundColor); QString fillcolor = element.attribute(QLatin1String("fillcolor")); if (!fillcolor.isEmpty()) this->fillColor = QColor(fillcolor); QString font = element.attribute(QLatin1String("font")); if (!font.isEmpty()) { this->font.fromString(font); this->font.setUnderline(false); } QString gridDotColor = element.attribute(QLatin1String("griddotcolor")); if (!gridDotColor.isEmpty()) this->gridDotColor = QColor(gridDotColor); QString linecolor = element.attribute(QLatin1String("linecolor")); if (!linecolor.isEmpty()) this->lineColor = QColor(linecolor); QString linewidth = element.attribute(QLatin1String("linewidth")); if (!linewidth.isEmpty()) this->lineWidth = linewidth.toInt(); QString textColor = element.attribute(QLatin1String("textcolor")); if (!textColor.isEmpty()) this->textColor = QColor(textColor); QString usefillcolor = element.attribute(QLatin1String("usefillcolor"), QLatin1String("0")); this->useFillColor = (bool)usefillcolor.toInt(); return true; } void CodeImportState::load() { // code importer options createArtifacts = UmbrelloSettings::createArtifacts(); resolveDependencies = UmbrelloSettings::resolveDependencies(); supportCPP11 = UmbrelloSettings::supportCPP11(); } void CodeImportState::save() { UmbrelloSettings::setCreateArtifacts(createArtifacts); UmbrelloSettings::setResolveDependencies(resolveDependencies); UmbrelloSettings::setSupportCPP11(supportCPP11); } /** * Save instance into a QDomElement. * @param element A QDomElement representing xml element data. */ void CodeImportState::saveToXMI1(QDomElement &element) { element.setAttribute(QLatin1String("createartifacts"), createArtifacts); element.setAttribute(QLatin1String("resolvedependencies"), resolveDependencies); element.setAttribute(QLatin1String("supportcpp11"), supportCPP11); } /** * Load instance from a QDomElement. * @param element A QDomElement representing xml element data. * @return true on success * @return false on error */ bool CodeImportState::loadFromXMI1(QDomElement &element) { QString temp = element.attribute(QLatin1String("createartifacts"), QLatin1String("0")); createArtifacts = (bool)temp.toInt(); temp = element.attribute(QLatin1String("resolvedependencies"), QLatin1String("0")); resolveDependencies = (bool)temp.toInt(); temp = element.attribute(QLatin1String("supportcpp11"), QLatin1String("0")); supportCPP11 = (bool)temp.toInt(); return true; } void CodeGenerationState::load() { // CPP code generation options cppCodeGenerationState.autoGenAccessors = UmbrelloSettings::autoGenAccessors(); cppCodeGenerationState.inlineAccessors = UmbrelloSettings::inlineAccessors(); cppCodeGenerationState.publicAccessors = UmbrelloSettings::publicAccessors(); cppCodeGenerationState.inlineOps = UmbrelloSettings::inlineOps(); cppCodeGenerationState.virtualDestructors = UmbrelloSettings::virtualDestructors(); cppCodeGenerationState.packageIsNamespace = UmbrelloSettings::packageIsNamespace(); cppCodeGenerationState.stringClassName = UmbrelloSettings::stringClassName(); cppCodeGenerationState.stringClassNameInclude = UmbrelloSettings::stringClassNameInclude(); cppCodeGenerationState.stringIncludeIsGlobal = UmbrelloSettings::stringIncludeIsGlobal(); cppCodeGenerationState.vectorClassName = UmbrelloSettings::vectorClassName(); cppCodeGenerationState.vectorClassNameInclude = UmbrelloSettings::vectorClassNameInclude(); cppCodeGenerationState.vectorIncludeIsGlobal = UmbrelloSettings::vectorIncludeIsGlobal(); cppCodeGenerationState.docToolTag = UmbrelloSettings::docToolTag(); // Java code generation options javaCodeGenerationState.autoGenerateAttributeAccessors = UmbrelloSettings::autoGenerateAttributeAccessorsJava(); javaCodeGenerationState.autoGenerateAssocAccessors = UmbrelloSettings::autoGenerateAssocAccessorsJava(); // D code generation options dCodeGenerationState.autoGenerateAttributeAccessors = UmbrelloSettings::autoGenerateAttributeAccessorsD(); dCodeGenerationState.autoGenerateAssocAccessors = UmbrelloSettings::autoGenerateAssocAccessorsD(); // Ruby code generation options rubyCodeGenerationState.autoGenerateAttributeAccessors = UmbrelloSettings::autoGenerateAttributeAccessorsRuby(); rubyCodeGenerationState.autoGenerateAssocAccessors = UmbrelloSettings::autoGenerateAssocAccessorsRuby(); } void CodeGenerationState::save() { // write config for CPP code generation options UmbrelloSettings::setAutoGenAccessors(cppCodeGenerationState.autoGenAccessors); UmbrelloSettings::setInlineAccessors(cppCodeGenerationState.inlineAccessors); UmbrelloSettings::setPublicAccessors(cppCodeGenerationState.publicAccessors); UmbrelloSettings::setInlineOps(cppCodeGenerationState.inlineOps); UmbrelloSettings::setVirtualDestructors(cppCodeGenerationState.virtualDestructors); UmbrelloSettings::setGetterWithGetPrefix(cppCodeGenerationState.getterWithGetPrefix); UmbrelloSettings::setRemovePrefixFromAccessorMethods(cppCodeGenerationState.removePrefixFromAccessorMethods); UmbrelloSettings::setAccessorMethodsStartWithUpperCase(cppCodeGenerationState.accessorMethodsStartWithUpperCase); UmbrelloSettings::setPackageIsNamespace(cppCodeGenerationState.packageIsNamespace); UmbrelloSettings::setStringClassName(cppCodeGenerationState.stringClassName); UmbrelloSettings::setStringClassNameInclude(cppCodeGenerationState.stringClassNameInclude); UmbrelloSettings::setStringIncludeIsGlobal(cppCodeGenerationState.stringIncludeIsGlobal); UmbrelloSettings::setVectorClassName(cppCodeGenerationState.vectorClassName); UmbrelloSettings::setVectorClassNameInclude(cppCodeGenerationState.vectorClassNameInclude); UmbrelloSettings::setVectorIncludeIsGlobal(cppCodeGenerationState.vectorIncludeIsGlobal); + UmbrelloSettings::setDocToolTag(cppCodeGenerationState.docToolTag); + UmbrelloSettings::setClassMemberPrefix(cppCodeGenerationState.classMemberPrefix); // write config for Java code generation options UmbrelloSettings::setAutoGenerateAttributeAccessorsJava(javaCodeGenerationState.autoGenerateAttributeAccessors); UmbrelloSettings::setAutoGenerateAssocAccessorsJava(javaCodeGenerationState.autoGenerateAssocAccessors); // CodeGenerator *codegen = getGenerator(); // JavaCodeGenerator *javacodegen = dynamic_cast(codegen); // if (javacodegen) // UmbrelloSettings::setBuildANTDocumentJava(javacodegen->getCreateANTBuildFile()); // write config for D code generation options UmbrelloSettings::setAutoGenerateAttributeAccessorsD(dCodeGenerationState.autoGenerateAttributeAccessors); UmbrelloSettings::setAutoGenerateAssocAccessorsD(dCodeGenerationState.autoGenerateAssocAccessors); // write config for Ruby code generation options UmbrelloSettings::setAutoGenerateAttributeAccessorsRuby(rubyCodeGenerationState.autoGenerateAttributeAccessors); UmbrelloSettings::setAutoGenerateAssocAccessorsRuby(rubyCodeGenerationState.autoGenerateAssocAccessors); } void AutoLayoutState::load() { autoDotPath = UmbrelloSettings::autoDotPath(); dotPath = UmbrelloSettings::dotPath(); showExportLayout = UmbrelloSettings::showExportLayout(); } void AutoLayoutState::save() { UmbrelloSettings::setAutoDotPath(autoDotPath); UmbrelloSettings::setDotPath(dotPath); UmbrelloSettings::setShowExportLayout(showExportLayout); } OptionState& optionState() { return OptionState::instance(); } void setOptionState(const OptionState& optstate) { OptionState::instance() = optstate; } OptionState::OptionState() { } void OptionState::load() { generalState.load(); uiState.load(); classState.load(); codeViewerState.load(); codeGenerationState.load(); codeImportState.load(); autoLayoutState.load(); } void OptionState::save() { generalState.save(); uiState.save(); classState.save(); codeViewerState.save(); codeGenerationState.save(); codeImportState.save(); autoLayoutState.save(); } /** * Save instance into a QDomElement. * @param element A QDomElement representing xml element data. */ void OptionState::saveToXMI1(QDomElement& element) { uiState.saveToXMI1(element); classState.saveToXMI1(element); } /** * Load instance from a QDomElement. * @param element A QDomElement representing xml element data. * @return true on success * @return false on error */ bool OptionState::loadFromXMI1(QDomElement& element) { uiState.loadFromXMI1(element); classState.loadFromXMI1(element); return true; } OptionState &OptionState::instance() { /* * Impt: This ensures creation of OptionState object after * QApplication thereby avoiding nasty font rendering issues * which occurs due to creation of QFont objects before * QApplication object is created. * * QScopedPointer usage covers object destroy on application * exit to avoid a memory leak. */ static QScopedPointer optionState(new OptionState); return *optionState; } } // namespace Settings diff --git a/umbrello/optionstate.h b/umbrello/optionstate.h index d0b96f69c..9b08c575b 100644 --- a/umbrello/optionstate.h +++ b/umbrello/optionstate.h @@ -1,339 +1,340 @@ /*************************************************************************** * 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) 2002-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ #ifndef OPTIONSTATE_H #define OPTIONSTATE_H #include "basictypes.h" #include "codeviewerstate.h" #include "codegenerationpolicy.h" #include namespace Settings { enum Page { page_general = 0, page_font, page_UI, page_class, page_codeimport, page_codegen, page_codeview }; //public structs class GeneralState { public: GeneralState() : undo(false), tabdiagrams(false), newcodegen(false), angularlines(false), footerPrinting(false), autosave(false), time(0), autosavetime(0), loadlast(false), diagram(Uml::DiagramType::Class), defaultLanguage(Uml::ProgrammingLanguage::Cpp), uml2(false) { } void load(); void save(); bool undo; bool tabdiagrams; bool newcodegen; bool angularlines; Uml::LayoutType::Enum layoutType; bool footerPrinting; bool autosave; int time; ///< old autosave time, kept for compatibility int autosavetime; QString autosavesuffix; ///< Text input field for suffix of autosave bool loadlast; Uml::DiagramType::Enum diagram; Uml::ProgrammingLanguage::Enum defaultLanguage; QString lastFile; bool uml2; }; class UIState { public: UIState() : useFillColor(false), lineWidth(0) { } void load(); void save(); void saveToXMI1(QDomElement& element); bool loadFromXMI1(QDomElement& element); bool useFillColor; QColor fillColor; QColor lineColor; uint lineWidth; QColor textColor; QFont font; QColor backgroundColor; QColor gridDotColor; }; class ClassState { public: ClassState() : showVisibility(false), showAtts(false), showOps(false), showStereoType(false), showAttSig(false), showOpSig(false), showPackage(false), showAttribAssocs(false), showDocumentation(false), showPublicOnly(false), defaultAttributeScope(Uml::Visibility::Public), defaultOperationScope(Uml::Visibility::Public) { } void load(); void save(); void saveToXMI1(QDomElement& element); bool loadFromXMI1(QDomElement& element); bool showVisibility; bool showAtts; bool showOps; bool showStereoType; bool showAttSig; bool showOpSig; bool showPackage; bool showAttribAssocs; bool showDocumentation; bool showPublicOnly; Uml::Visibility::Enum defaultAttributeScope; Uml::Visibility::Enum defaultOperationScope; }; class CodeGenerationState { public: CodeGenerationState() : autoGenEmptyConstructors(false), commentStyle(CodeGenerationPolicy::SingleLine), defaultAssocFieldScope(Uml::Visibility::Public), defaultAttributeAccessorScope(Uml::Visibility::Public), forceDoc(false), forceSections(false), includeHeadings(false), indentationAmount(false), indentationType(CodeGenerationPolicy::NONE), #ifdef Q_OS_WIN lineEndingType(CodeGenerationPolicy::DOS), #elif defined(Q_OS_MAC) lineEndingType(CodeGenerationPolicy::MAC), #else lineEndingType(CodeGenerationPolicy::UNIX), #endif modnamePolicy(CodeGenerationPolicy::No), overwritePolicy(CodeGenerationPolicy::Ok) { } void load(); void save(); bool autoGenEmptyConstructors; CodeGenerationPolicy::CommentStyle commentStyle; Uml::Visibility::Enum defaultAssocFieldScope; Uml::Visibility::Enum defaultAttributeAccessorScope; bool forceDoc; bool forceSections; QDir headingsDirectory; bool includeHeadings; int indentationAmount; CodeGenerationPolicy::IndentationType indentationType; CodeGenerationPolicy::NewLineType lineEndingType; CodeGenerationPolicy::ModifyNamePolicy modnamePolicy; QDir outputDirectory; CodeGenerationPolicy::OverwritePolicy overwritePolicy; class CPPCodeGenerationState { public: CPPCodeGenerationState() : autoGenAccessors(false), inlineAccessors(false), inlineOps(false), packageIsNamespace(false), publicAccessors(false), stringIncludeIsGlobal(false), vectorIncludeIsGlobal(false), virtualDestructors(false), getterWithGetPrefix(false), removePrefixFromAccessorMethods(false), accessorMethodsStartWithUpperCase(false) { } bool autoGenAccessors; bool inlineAccessors; bool inlineOps; bool packageIsNamespace; bool publicAccessors; QString stringClassName; QString stringClassNameInclude; bool stringIncludeIsGlobal; QString vectorClassName; QString vectorClassNameInclude; + QString classMemberPrefix; QString docToolTag; bool vectorIncludeIsGlobal; bool virtualDestructors; bool getterWithGetPrefix; bool removePrefixFromAccessorMethods; bool accessorMethodsStartWithUpperCase; }; class DCodeGenerationState { public: DCodeGenerationState() : autoGenerateAttributeAccessors(false), autoGenerateAssocAccessors(false), buildANTDocument(false) { } bool autoGenerateAttributeAccessors; bool autoGenerateAssocAccessors; bool buildANTDocument; }; class JavaCodeGenerationState { public: JavaCodeGenerationState() : autoGenerateAttributeAccessors(false), autoGenerateAssocAccessors(false), buildANTDocument(false) { } bool autoGenerateAttributeAccessors; bool autoGenerateAssocAccessors; bool buildANTDocument; }; class RubyCodeGenerationState { public: RubyCodeGenerationState() : autoGenerateAttributeAccessors(false), autoGenerateAssocAccessors(false) { } bool autoGenerateAttributeAccessors; bool autoGenerateAssocAccessors; }; CPPCodeGenerationState cppCodeGenerationState; DCodeGenerationState dCodeGenerationState; JavaCodeGenerationState javaCodeGenerationState; RubyCodeGenerationState rubyCodeGenerationState; }; class CodeImportState { public: CodeImportState() : createArtifacts(false), resolveDependencies(false), supportCPP11(true) { } void load(); void save(); void saveToXMI1(QDomElement& element); bool loadFromXMI1(QDomElement& element); bool createArtifacts; bool resolveDependencies; bool supportCPP11; }; class AutoLayoutState { public: AutoLayoutState() : autoDotPath(false), showExportLayout(false) { } void load(); void save(); void saveToXMI1(QDomElement& element); bool loadFromXMI1(QDomElement& element); bool autoDotPath; ///< determine path to dot executable automatically QString dotPath; ///< path to dot executable bool showExportLayout; ///< flag for display export layout }; class LayoutTypeState { public: LayoutTypeState() : showExportLayout(Uml::LayoutType::Enum::Direct) { } void load(); void save(); void saveToXMI1(QDomElement& element); bool loadFromXMI1(QDomElement& element); Uml::LayoutType::Enum showExportLayout; ///< flag for display export layout }; class OptionState { public: OptionState(); void load(); void save(); void saveToXMI1(QDomElement& element); bool loadFromXMI1(QDomElement& element); static OptionState &instance(); GeneralState generalState; LayoutTypeState layoutTypeState; UIState uiState; ClassState classState; CodeViewerState codeViewerState; CodeGenerationState codeGenerationState; CodeImportState codeImportState; AutoLayoutState autoLayoutState; }; OptionState& optionState(); void setOptionState(const OptionState& optstate); } // namespace Settings #endif diff --git a/umbrello/umbrello.kcfg b/umbrello/umbrello.kcfg index 1e5010368..742ee67e9 100644 --- a/umbrello/umbrello.kcfg +++ b/umbrello/umbrello.kcfg @@ -1,607 +1,612 @@ basictypes.h codegenerationpolicy.h codegenerators/cpp/cppcodegenerationpolicy.h Geometry The Mime Type of the Images image/png Undo Support is enabled when this is true true Enables/Disables Tabbed View of Diagrams in the view area true Enables/Disables Support for the New Code Generator false Enables/Disables Support for Angular Lines in diagrams true The layout type to use for new lines Uml::LayoutType::Direct Enables/Disables Support for footer printing true Enables/Disables Auto Saving at Regular Intervals true Auto Save Time Interval ( Old ) 0 0 25 0 0 25 The Suffix for the auto save file .xmi Enables/Disables Loading of the last open file false The Diagram to load at startup Uml::DiagramType::Class The Language that Umbrello should start with by default Uml::ProgrammingLanguage::Cpp Enables/Disables UML2 notation true Enables/Disables usage of fill color true The Fill Color to be used yellow The Color of the Lines red The Width of the Line 0 The Color of the Text black Enables/Disables showing of the doc window true The Font to be used Uml::systemFont() The Color of the diagram background white The Color of the grid dots lightGray Enable/disable user interface direction from right to left false Show the Visibility of the Attributes ( eg: private, public, protected) true Show attributes of the class true Show Operations true Enables/Disables showing of packages true Show Stereotypes true Show Attribute Associations true Enables/Disables showing of public attributes/methods false Show Attribute Signature true Show operation signature true Default Attribute Scope Uml::Visibility::Public Default Operation Scope Uml::Visibility::Public Height of the code viewer 40 100 Width of the Code Viewer 80 100 Show Hidden Blocks true Enables/Disables Highlighting of blocks true Font to be used in the Code Viewer Uml::systemFont() Color of the Paper white Color of the Font black Selected Color yellow Color of the Edit Block pink Non Edit Block Color pink Color of the UML Object grey Hidden Color grey Create an artifact in the component view for each imported file true Resolve dependencies when importing file true Support C++11 standard on code import true Enables/Disables Auto Generation of Empty Constructors true Sets the Style of Comments to be used CodeGenerationPolicy::SingleLine Sets the default Association field scope Uml::Visibility::FromParent Sets the default attribute accessor scope Uml::Visibility::FromParent Enables/Disables Verbose Documentation true Enables/Disables verbose section documentation true The Path in which the headings are stored $HOME/kde/share/apps/umbrello/headings Enables/Disables inclusion of headings true The amount of indentation 2 10 The Type of Indentation CodeGenerationPolicy::SPACE The type of line ending ( or new line type ) CodeGenerationPolicy::UNIX Modifier Name Policy CodeGenerationPolicy::Capitalise The directory to which the code has to be outputted $HOME/uml-generated-code The policy to be followed when there are name conflicts CodeGenerationPolicy::Ask Enables/Disables auto generation of accessors true + + + The prefix for class members + + Enables/Disables Inline accessors true Enables/Disables Inline Operations true Enables/Disables treating a package as a namespace true Enables/Disables public accessors true The name of the string class std::string The name of the string class to be included <string> Enables/Disables global inclusion of string true The name of the vector class std::vector The name of the vector class to be included <vector> Enables/Disables global inclusion of vector class true Enables/Disables virtual destructors true If enabled, create getters with 'get' prefix true If enabled, remove prefix '[a-zA-Z]_' from accessor methods false If enabled, accessor methods start with capital letters true The tag used for generating doxygen documentation (\\, @) @ Enables/Disables auto generation of attribute accessors ( D ) true Enables/Disables auto generation of association accessors ( D ) true Enables/Disables building of ANT Document (D) false Enables/Disables auto generation of attribute accessors (Java) true Enables/Disables auto generation of association accessors (Java) true Enables/Disables building of ANT Document (Java) false Enables/Disables auto generation of attribute accessors (Ruby) true Enables/Disables auto generation of association accessors (Ruby) true determine automatically the path of dot executable true set path to dot executable (optional) show export layout false diff --git a/umbrello/umldoc.cpp b/umbrello/umldoc.cpp index 5abefe6ca..802a38c97 100644 --- a/umbrello/umldoc.cpp +++ b/umbrello/umldoc.cpp @@ -1,3509 +1,3512 @@ /*************************************************************************** * 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) 2002-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "umldoc.h" // app includes #include "debug_utils.h" #include "uniqueid.h" #include "association.h" #include "package.h" #include "folder.h" #include "codegenerator.h" #include "classifier.h" #include "dialog_utils.h" #include "enum.h" #include "entity.h" #include "docwindow.h" #include "operation.h" #include "attribute.h" #include "template.h" #include "enumliteral.h" #include "stereotype.h" #include "classifierlistitem.h" #include "object_factory.h" #include "import_argo.h" #include "import_rose.h" #include "model_utils.h" #include "uml.h" #include "umllistview.h" #include "umllistviewitem.h" #include "umlview.h" #include "entityconstraint.h" #include "idchangelog.h" #include "umllistviewpopupmenu.h" #include "cmds.h" #include "diagramprintpage.h" #include "umlscene.h" #include "version.h" #include "worktoolbar.h" #include "models/diagramsmodel.h" #include "models/objectsmodel.h" #include "models/stereotypesmodel.h" // kde includes #include #if QT_VERSION < 0x050000 #include #endif #if QT_VERSION >= 0x050000 #include #endif #include #include #if QT_VERSION < 0x050000 #include #endif #include #if QT_VERSION < 0x050000 #include #include #include #endif // qt includes #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #include #endif #include #include #include #if QT_VERSION >= 0x050000 #include #include #endif #include #include DEBUG_REGISTER(UMLDoc) /** * Constructor for the fileclass of the application. */ UMLDoc::UMLDoc() : m_datatypeRoot(0), m_stereoList(UMLStereotypeList()), m_Name(i18n("UML Model")), m_modelID("m1"), m_count(0), m_modified(false), #if QT_VERSION >= 0x050000 m_doc_url(QUrl()), #else m_doc_url(KUrl()), #endif m_pChangeLog(0), m_bLoading(false), m_importing(false), m_Doc(QString()), m_pAutoSaveTimer(0), m_nViewID(Uml::ID::None), m_bTypesAreResolved(true), m_pCurrentRoot(0), m_bClosing(false), m_diagramsModel(new DiagramsModel), m_objectsModel(new ObjectsModel), m_stereotypesModel(new StereotypesModel(&m_stereoList)), m_resolution(0.0) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) m_root[i] = 0; } /** * Initialize the UMLDoc. * To be called after the constructor, before anything else. */ void UMLDoc::init() { // Initialize predefined folders. const char* nativeRootName[Uml::ModelType::N_MODELTYPES] = { "Logical View", "Use Case View", "Component View", "Deployment View", "Entity Relationship Model" }; const QString localizedRootName[Uml::ModelType::N_MODELTYPES] = { i18n("Logical View"), i18n("Use Case View"), i18n("Component View"), i18n("Deployment View"), i18n("Entity Relationship Model") }; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { const QString rootName = QString::fromLatin1(nativeRootName[i]); QString id = rootName; id.replace(QLatin1Char(' '), QLatin1Char('_')); m_root[i] = new UMLFolder(rootName, Uml::ID::fromString(id)); m_root[i]->setLocalName(localizedRootName[i]); } createDatatypeFolder(); // Connect signals. UMLApp * pApp = UMLApp::app(); connect(this, SIGNAL(sigDiagramCreated(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); connect(this, SIGNAL(sigDiagramRemoved(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); connect(this, SIGNAL(sigDiagramRenamed(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); connect(this, SIGNAL(sigCurrentViewChanged()), pApp, SLOT(slotCurrentViewChanged())); } /** * Create the datatype folder and add it to the logical folder. */ void UMLDoc::createDatatypeFolder() { delete m_datatypeRoot; m_datatypeRoot = new UMLFolder(QLatin1String("Datatypes"), "Datatypes"); m_datatypeRoot->setLocalName(i18n("Datatypes")); m_datatypeRoot->setUMLPackage(m_root[Uml::ModelType::Logical]); Q_ASSERT(m_root[Uml::ModelType::Logical]); m_root[Uml::ModelType::Logical]->addObject(m_datatypeRoot); } /** * Destructor for the fileclass of the application. */ UMLDoc::~UMLDoc() { UMLApp * pApp = UMLApp::app(); disconnect(this, SIGNAL(sigDiagramCreated(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); disconnect(this, SIGNAL(sigDiagramRemoved(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); disconnect(this, SIGNAL(sigDiagramRenamed(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); disconnect(this, SIGNAL(sigCurrentViewChanged()), pApp, SLOT(slotCurrentViewChanged())); disconnect(m_pAutoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); delete m_pAutoSaveTimer; m_root[Uml::ModelType::Logical]->removeObject(m_datatypeRoot); delete m_datatypeRoot; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { delete m_root[i]; } delete m_pChangeLog; qDeleteAll(m_stereoList); delete m_stereotypesModel; delete m_diagramsModel; delete m_objectsModel; } /** * Adds a view to the document which represents the document * contents. Usually this is your main view. * * @param view Pointer to the UMLView to add. */ void UMLDoc::addView(UMLView *view) { if (view == 0) { uError() << "argument is NULL"; return; } UMLFolder *f = view->umlScene()->folder(); if (f == 0) { uError() << "view folder is not set"; return; } DEBUG(DBG_SRC) << view->umlScene()->name() << " to folder " << *f << " (" << f->name() << ")"; f->addView(view); m_diagramsModel->addDiagram(view); UMLApp * pApp = UMLApp::app(); if (pApp->listView()) { connect(this, SIGNAL(sigObjectRemoved(UMLObject*)), view->umlScene(), SLOT(slotObjectRemoved(UMLObject*))); } if (!m_bLoading || pApp->currentView() == 0) { pApp->setCurrentView(view); } if (!m_bLoading) { view->show(); emit sigDiagramChanged(view->umlScene()->type()); } pApp->setDiagramMenuItemsState(true); pApp->slotUpdateViews(); } /** * Removes a view from the list of currently connected views. * * @param view Pointer to the UMLView to remove. * @param enforceCurrentView Switch to determine if we have a current view or not. * Most of the time, we DO want this, except when exiting the program. */ void UMLDoc::removeView(UMLView *view, bool enforceCurrentView) { if (!view) { uError() << "UMLDoc::removeView(UMLView *view) called with view = 0"; return; } DEBUG(DBG_SRC) << "<" << view->umlScene()->name() << ">"; if (UMLApp::app()->listView()) { disconnect(this, SIGNAL(sigObjectRemoved(UMLObject*)), view->umlScene(), SLOT(slotObjectRemoved(UMLObject*))); } view->hide(); UMLFolder *f = view->umlScene()->folder(); if (f == 0) { uError() << view->umlScene()->name() << ": view->getFolder() returns NULL"; return; } m_diagramsModel->removeDiagram(view); f->removeView(view); UMLView *currentView = UMLApp::app()->currentView(); if (currentView == view) { UMLApp::app()->setCurrentView(0); UMLViewList viewList; m_root[Uml::ModelType::Logical]->appendViews(viewList); UMLView* firstView = 0; if (!viewList.isEmpty()) { firstView = viewList.first(); } if (!firstView && enforceCurrentView) { //create a diagram QString name = createDiagramName(Uml::DiagramType::Class, false); createDiagram(m_root[Uml::ModelType::Logical], Uml::DiagramType::Class, name); qApp->processEvents(); m_root[Uml::ModelType::Logical]->appendViews(viewList); firstView = viewList.first(); } if (firstView) { changeCurrentView(firstView->umlScene()->ID()); UMLApp::app()->setDiagramMenuItemsState(true); } } delete view; } /** * Sets the URL of the document. * * @param url The KUrl to set. */ #if QT_VERSION >= 0x050000 void UMLDoc::setUrl(const QUrl &url) #else void UMLDoc::setUrl(const KUrl &url) #endif { m_doc_url = url; } /** * Returns the KUrl of the document. * * @return The KUrl of this UMLDoc. */ #if QT_VERSION >= 0x050000 const QUrl& UMLDoc::url() const #else const KUrl& UMLDoc::url() const #endif { return m_doc_url; } /** * Sets the URL of the document to "Untitled". */ void UMLDoc::setUrlUntitled() { #if QT_VERSION >= 0x050000 m_doc_url.setUrl(m_doc_url.toString(QUrl::RemoveFilename) + i18n("Untitled")); #else m_doc_url.setFileName(i18n("Untitled")); #endif } /** * "save modified" - Asks the user for saving if the document * is modified. * * @return True if document can be closed. */ bool UMLDoc::saveModified() { bool completed(true); if (!m_modified) { return completed; } UMLApp *win = UMLApp::app(); int want_save = KMessageBox::warningYesNoCancel(win, i18n("The current file has been modified.\nDo you want to save it?"), i18nc("warning message", "Warning"), KStandardGuiItem::save(), KStandardGuiItem::discard()); switch(want_save) { case KMessageBox::Yes: if (m_doc_url.fileName() == i18n("Untitled")) { if (win->slotFileSaveAs()) { closeDocument(); completed=true; } else { completed=false; } } else { saveDocument(url()); closeDocument(); completed=true; } break; case KMessageBox::No: setModified(false); closeDocument(); completed=true; break; case KMessageBox::Cancel: completed=false; break; default: completed=false; break; } return completed; } /** * Closes the current document. */ void UMLDoc::closeDocument() { m_bClosing = true; UMLApp::app()->setGenerator(Uml::ProgrammingLanguage::Reserved); // delete the codegen m_Doc = QString(); DocWindow* dw = UMLApp::app()->docWindow(); if (dw) { dw->reset(); } UMLApp::app()->logWindow()->clear(); UMLListView *listView = UMLApp::app()->listView(); if (listView) { listView->clean(); // store old setting - for restore of last setting bool m_bLoading_old = m_bLoading; m_bLoading = true; // This is to prevent document becoming modified. // For reference, here is an example of a call sequence that would // otherwise result in futile addToUndoStack() calls: // removeAllViews() => // UMLView::removeAllAssociations() => // UMLView::removeAssoc() => // UMLDoc::setModified(true, true) => // addToUndoStack(). removeAllViews(); m_bLoading = m_bLoading_old; // Remove all objects from the predefined folders. // @fixme With advanced code generation enabled, this crashes. removeAllObjects(); // Remove any stereotypes. if (stereotypes().count() > 0) { foreach(UMLStereotype *s, stereotypes()) { m_stereotypesModel->removeStereotype(s); delete s; } m_stereoList.clear(); } // Restore the datatype folder, it has been deleted above. createDatatypeFolder(); // this creates to much items only Logical View should be created listView->init(); } m_bClosing = false; } /** * Initializes the document generally. * * @return True if operation successful. */ bool UMLDoc::newDocument() { bool state = UMLApp::app()->document()->loading(); UMLApp::app()->document()->setLoading(true); closeDocument(); UMLApp::app()->setCurrentView(0); setUrlUntitled(); setResolution(qApp->desktop()->logicalDpiX()); //see if we need to start with a new diagram Settings::OptionState optionState = Settings::optionState(); Uml::DiagramType::Enum dt = optionState.generalState.diagram; Uml::ModelType::Enum mt = Model_Utils::convert_DT_MT(dt); if (mt == Uml::ModelType::N_MODELTYPES) { // don't allow no diagram dt = Uml::DiagramType::Class; mt = Uml::ModelType::Logical; } QString name = createDiagramName(dt, false); createDiagram(m_root[mt], dt, name); UMLApp::app()->initGenerator(); setModified(false); initSaveTimer(); UMLApp::app()->enableUndoAction(false); UMLApp::app()->clearUndoStack(); UMLApp::app()->document()->setLoading(state); return true; } /** * Loads the document by filename and format and emits the * updateViews() signal. * * @param url The filename in KUrl format. * @param format The format (optional.) * @return True if operation successful. */ #if QT_VERSION >= 0x050000 bool UMLDoc::openDocument(const QUrl& url, const char* format /* =0 */) #else bool UMLDoc::openDocument(const KUrl& url, const char* format /* =0 */) #endif { Q_UNUSED(format); if (url.fileName().length() == 0) { newDocument(); return false; } m_doc_url = url; closeDocument(); setResolution(0.0); // IMPORTANT: set m_bLoading to true // _AFTER_ the call of UMLDoc::closeDocument() // as it sets m_bLoading to false after it was temporarily // changed to true to block recording of changes in redo-buffer m_bLoading = true; #if QT_VERSION >= 0x050000 QTemporaryFile tmpfile; tmpfile.open(); QUrl dest(QUrl::fromLocalFile(tmpfile.fileName())); DEBUG(DBG_SRC) << "UMLDoc::openDocument: copy from " << url << " to " << dest << "."; KIO::FileCopyJob *job = KIO::file_copy(url, dest, -1, KIO::Overwrite); KJobWidgets::setWindow(job, UMLApp::app()); job->exec(); QFile file(tmpfile.fileName()); if (job->error() || !file.exists()) { if (!file.exists()) DEBUG(DBG_SRC) << "UMLDoc::openDocument: temporary file <" << file.fileName() << "> failed!"; if (job->error()) DEBUG(DBG_SRC) << "UMLDoc::openDocument: " << job->errorString(); KMessageBox::error(0, i18n("The file <%1> does not exist.", url.toString()), i18n("Load Error")); setUrlUntitled(); m_bLoading = false; newDocument(); return false; } #else QString tmpfile; KIO::NetAccess::download(url, tmpfile, UMLApp::app()); QFile file(tmpfile); if (!file.exists()) { KMessageBox::error(0, i18n("The file %1 does not exist.", url.pathOrUrl()), i18n("Load Error")); setUrlUntitled(); m_bLoading = false; newDocument(); return false; } #endif // status of XMI loading bool status = false; // check if the xmi file is a compressed archive like tar.bzip2 or tar.gz QString filetype = m_doc_url.fileName(); QString mimetype; if (filetype.endsWith(QLatin1String(".tgz")) || filetype.endsWith(QLatin1String(".tar.gz"))) { mimetype = QLatin1String("application/x-gzip"); } else if (filetype.endsWith(QLatin1String(".tar.bz2"))) { mimetype = QLatin1String("application/x-bzip"); } if (mimetype.isEmpty() == false) { #if QT_VERSION >= 0x050000 KTar archive(file.fileName(), mimetype); #else KTar archive(tmpfile, mimetype); #endif if (archive.open(QIODevice::ReadOnly) == false) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("The file %1 seems to be corrupted.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("The file %1 seems to be corrupted.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } // get the root directory and all entries in const KArchiveDirectory * rootDir = archive.directory(); const QStringList entries = rootDir->entries(); QString entryMimeType; bool foundXMI = false; QStringList::ConstIterator it; QStringList::ConstIterator end(entries.end()); // now go through all entries till we find an xmi file for (it = entries.begin(); it != end; ++it) { // only check files, we do not go in subdirectories if (rootDir->entry(*it)->isFile() == true) { // we found a file, check the mimetype #if QT_VERSION >= 0x050000 QMimeDatabase db; entryMimeType = db.mimeTypeForFile(*it, QMimeDatabase::MatchExtension).name(); #else entryMimeType = KMimeType::findByPath(*it, 0, true)->name(); #endif if (entryMimeType == QLatin1String("application/x-uml")) { foundXMI = true; break; } } } // if we found an XMI file, we have to extract it to a temporary file if (foundXMI == true) { #if QT_VERSION >= 0x050000 QTemporaryDir tmp_dir; #else KTempDir tmp_dir; #endif KArchiveEntry * entry; KArchiveFile * fileEntry; // try to cast the file entry in the archive to an archive entry entry = const_cast(rootDir->entry(*it)); if (entry == 0) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } // now try to cast the archive entry to a file entry, so that we can // extract the file fileEntry = dynamic_cast(entry); if (fileEntry == 0) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } // now we can extract the file to the temporary directory #if QT_VERSION >= 0x050000 fileEntry->copyTo(tmp_dir.path() + QLatin1Char('/')); // now open the extracted file for reading QFile xmi_file(tmp_dir.path() + QLatin1Char('/') + *it); #else fileEntry->copyTo(tmp_dir.name()); // now open the extracted file for reading QFile xmi_file(tmp_dir.name() + *it); #endif if(!xmi_file.open(QIODevice::ReadOnly)) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem loading the extracted file: %1", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was a problem loading the extracted file: %1", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } m_bTypesAreResolved = false; status = loadFromXMI1(xmi_file, ENC_UNKNOWN); // close the extracted file and the temporary directory xmi_file.close(); } else { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } archive.close(); } else { // no, it seems to be an ordinary file if (!file.open(QIODevice::ReadOnly)) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem loading file: %1", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was a problem loading file: %1", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } if (filetype.endsWith(QLatin1String(".mdl"))) { setUrlUntitled(); m_bTypesAreResolved = false; status = Import_Rose::loadFromMDL(file); if (status) { if (UMLApp::app()->currentView() == 0) { QString name = createDiagramName(Uml::DiagramType::Class, false); createDiagram(m_root[Uml::ModelType::Logical], Uml::DiagramType::Class, name); setCurrentRoot(Uml::ModelType::Logical); } } } else if (filetype.endsWith(QLatin1String(".zargo"))) { setUrlUntitled(); status = Import_Argo::loadFromZArgoFile(file); } else { m_bTypesAreResolved = false; status = loadFromXMI1(file, ENC_UNKNOWN); } } if (file.isOpen()) file.close(); #if QT_VERSION < 0x050000 KIO::NetAccess::removeTempFile(tmpfile); #endif m_bLoading = false; m_bTypesAreResolved = true; if (!status) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem loading file: %1", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was a problem loading file: %1", url.pathOrUrl()), i18n("Load Error")); #endif newDocument(); return false; } setModified(false); initSaveTimer(); UMLApp::app()->enableUndoAction(false); UMLApp::app()->clearUndoStack(); // for compatibility addDefaultStereotypes(); return true; } /** * Saves the document using the given filename and format. * * @param url The filename in KUrl format. * @param format The format (optional.) * @return True if operation successful. */ #if QT_VERSION >= 0x050000 bool UMLDoc::saveDocument(const QUrl& url, const char * format) #else bool UMLDoc::saveDocument(const KUrl& url, const char * format) #endif { Q_UNUSED(format); m_doc_url = url; bool uploaded = true; // first, we have to find out which format to use #if QT_VERSION >= 0x050000 QString strFileName = url.path(); #else QString strFileName = url.path(KUrl::RemoveTrailingSlash); #endif QFileInfo fileInfo(strFileName); QString fileExt = fileInfo.completeSuffix(); QString fileFormat = QLatin1String("xmi"); if (fileExt == QLatin1String("xmi") || fileExt == QLatin1String("bak.xmi")) { fileFormat = QLatin1String("xmi"); } else if (fileExt == QLatin1String("xmi.tgz") || fileExt == QLatin1String("bak.xmi.tgz")) { fileFormat = QLatin1String("tgz"); } else if (fileExt == QLatin1String("xmi.tar.bz2") || fileExt == QLatin1String("bak.xmi.tar.bz2")) { fileFormat = QLatin1String("bz2"); } else { fileFormat = QLatin1String("xmi"); } initSaveTimer(); if (fileFormat == QLatin1String("tgz") || fileFormat == QLatin1String("bz2")) { KTar * archive; #if QT_VERSION >= 0x050000 QTemporaryFile tmp_tgz_file; #else KTemporaryFile tmp_tgz_file; #endif tmp_tgz_file.setAutoRemove(false); tmp_tgz_file.open(); // first we have to check if we are saving to a local or remote file if (url.isLocalFile()) { if (fileFormat == QLatin1String("tgz")) { // check tgz or bzip archive = new KTar(url.toLocalFile(), QLatin1String("application/x-gzip")); } else { archive = new KTar(url.toLocalFile(), QLatin1String("application/x-bzip")); } } else { if (fileFormat == QLatin1String("tgz")) { // check tgz or bzip2 archive = new KTar(tmp_tgz_file.fileName(), QLatin1String("application/x-gzip")); } else { archive = new KTar(tmp_tgz_file.fileName(), QLatin1String("application/x-bzip")); } } // now check if we can write to the file if (archive->open(QIODevice::WriteOnly) == false) { uError() << "could not open" << archive->fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif delete archive; return false; } // we have to create a temporary xmi file // we will add this file later to the archive #if QT_VERSION >= 0x050000 QTemporaryFile tmp_xmi_file; #else KTemporaryFile tmp_xmi_file; #endif tmp_xmi_file.setAutoRemove(false); if (!tmp_xmi_file.open()) { uError() << "could not open" << tmp_xmi_file.fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif delete archive; return false; } saveToXMI1(tmp_xmi_file); // save XMI to this file... // now add this file to the archive, but without the extension QString tmpQString = url.fileName(); if (fileFormat == QLatin1String("tgz")) { tmpQString.remove(QRegExp(QLatin1String("\\.tgz$"))); } else { tmpQString.remove(QRegExp(QLatin1String("\\.tar\\.bz2$"))); } archive->addLocalFile(tmp_xmi_file.fileName(), tmpQString); if (!archive->close()) { uError() << "could not close" << archive->fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif delete archive; return false; } // now the xmi file was added to the archive, so we can delete it tmp_xmi_file.setAutoRemove(true); // now we have to check, if we have to upload the file if (!url.isLocalFile()) { #if QT_VERSION >= 0x050000 KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(tmp_tgz_file.fileName()), m_doc_url); KJobWidgets::setWindow(job, UMLApp::app()); job->exec(); uploaded = !job->error(); #else uploaded = KIO::NetAccess::upload(tmp_tgz_file.fileName(), m_doc_url, UMLApp::app()); #endif if (!uploaded) uError() << "could not upload file" << tmp_tgz_file.fileName() << "to" << url; } // now the archive was written to disk (or remote) so we can delete the // objects tmp_tgz_file.setAutoRemove(true); delete archive; } else { // save as normal uncompressed XMI #if QT_VERSION >= 0x050000 QTemporaryFile tmpfile; // we need this tmp file if we are writing to a remote file #else KTemporaryFile tmpfile; // we need this tmp file if we are writing to a remote file #endif tmpfile.setAutoRemove(false); // save in _any_ case to a temp file // -> if something goes wrong during saveToXMI1, the // original content is preserved // (e.g. if umbrello dies in the middle of the document model parsing // for saveToXMI1 due to some problems) /// @todo insert some checks in saveToXMI1 to detect a failed save attempt // lets open the file for writing if (!tmpfile.open()) { uError() << "could not open" << tmpfile.fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif return false; } saveToXMI1(tmpfile); // save the xmi stuff to it // if it is a remote file, we have to upload the tmp file if (!url.isLocalFile()) { #if QT_VERSION >= 0x050000 KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(tmpfile.fileName()), m_doc_url); KJobWidgets::setWindow(job, UMLApp::app()); job->exec(); uploaded = !job->error(); #else uploaded = KIO::NetAccess::upload(tmpfile.fileName(), m_doc_url, UMLApp::app()); #endif if (!uploaded) uError() << "could not upload file" << tmpfile.fileName() << "to" << url; } else { // now remove the original file #ifdef Q_OS_WIN tmpfile.setAutoRemove(true); #if QT_VERSION >= 0x050000 KIO::FileCopyJob* fcj = KIO::file_copy(QUrl::fromLocalFile(tmpfile.fileName()), url, -1, KIO::Overwrite); #else KIO::FileCopyJob* fcj = KIO::file_copy(tmpfile.fileName(), url, -1, KIO::Overwrite); #endif #else #if QT_VERSION >= 0x050000 KIO::FileCopyJob* fcj = KIO::file_move(QUrl::fromLocalFile(tmpfile.fileName()), url, -1, KIO::Overwrite); #else KIO::FileCopyJob* fcj = KIO::file_move(tmpfile.fileName(), url, -1, KIO::Overwrite); #endif #endif #if QT_VERSION >= 0x050000 KJobWidgets::setWindow(fcj, (QWidget*)UMLApp::app()); fcj->exec(); if (fcj->error()) { uError() << "Could not move" << tmpfile.fileName() << "to" << url; KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else if (KIO::NetAccess::synchronousRun(fcj, (QWidget*)UMLApp::app()) == false) { KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif setUrlUntitled(); return false; } } } if (!uploaded) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem uploading: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem uploading file: %1", url.pathOrUrl()), i18n("Save Error")); #endif setUrlUntitled(); } setModified(false); return uploaded; } /** * Sets up the signals needed by the program for it to work. */ void UMLDoc::setupSignals() { WorkToolBar *tb = UMLApp::app()->workToolBar(); connect(this, SIGNAL(sigDiagramChanged(Uml::DiagramType::Enum)), tb, SLOT(slotCheckToolBar(Uml::DiagramType::Enum))); } /** * Finds a view (diagram) by the ID given to method. * * @param id The ID of the view to search for. * @return Pointer to the view found, or NULL if not found. */ UMLView * UMLDoc::findView(Uml::ID::Type id) { UMLView *v = 0; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { v = m_root[i]->findView(id); if (v) { break; } } return v; } /** * Finds a view (diagram) by the type and name given. * * @param type The type of view to find. * @param name The name of the view to find. * @param searchAllScopes Search in all subfolders (default: false.) * @return Pointer to the view found, or NULL if not found. */ UMLView * UMLDoc::findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes /* =false */) { Uml::ModelType::Enum mt = Model_Utils::convert_DT_MT(type); return m_root[mt]->findView(type, name, searchAllScopes); } /** * Used to find a reference to a @ref UMLObject by its ID. * * @param id The @ref UMLObject to find. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findObjectById(Uml::ID::Type id) { UMLObject *o = 0; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { if (id == m_root[i]->id()) { return m_root[i]; } o = m_root[i]->findObjectById(id); if (o) { return o; } } o = findStereotypeById(id); return o; } /** * Used to find a @ref UMLObject by its type and name. * * @param name The name of the @ref UMLObject to find. * @param type ObjectType of the object to find (optional.) * When the given type is ot_UMLObject the type is * disregarded, i.e. the given name is the only * search criterion. * @param currentObj Object relative to which to search (optional.) * If given then the enclosing scope(s) of this * object are searched before the global scope. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObject(const QString &name, UMLObject::ObjectType type /* = ot_UMLObject */, UMLObject *currentObj /* = 0 */) { UMLObject *o = m_datatypeRoot->findObject(name); if (o) { return o; } for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { UMLObjectList &list = m_root[i]->containedObjects(); if (list.size() == 0) continue; o = Model_Utils::findUMLObject(list, name, type, currentObj); if (o) { return o; } if ((type == UMLObject::ot_UMLObject || type == UMLObject::ot_Folder) && name == m_root[i]->name()) { return m_root[i]; } } return 0; } /** * Used to find a @ref UMLObject by its type and raw name. * * @param modelType The model type in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRaw(Uml::ModelType::Enum modelType, const QString &name, UMLObject::ObjectType type) { return findUMLObjectRaw(rootFolder(modelType), name, type); } /** * Used to find a @ref UMLObject by its type and raw name. * * @param folder The UMLFolder in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRaw(UMLFolder *folder, const QString &name, UMLObject::ObjectType type) { if (folder == 0) return 0; UMLObjectList &list = folder->containedObjects(); if (list.size() == 0) return 0; return Model_Utils::findUMLObjectRaw(list, name, type, 0); } /** * Used to find a @ref UMLObject by its type and raw name recursivly * * @param modelType The model type in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRecursive(Uml::ModelType::Enum modelType, const QString &name, UMLObject::ObjectType type) { return findUMLObjectRecursive(rootFolder(modelType), name, type); } /** * Used to find a @ref UMLObject by its type and raw name recursivly * * @param folder The UMLFolder in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRecursive(UMLFolder *folder, const QString &name, UMLObject::ObjectType type) { if (folder == 0) return 0; UMLObjectList &list = folder->containedObjects(); if (list.size() == 0) return 0; return Model_Utils::findUMLObjectRecursive(list, name, type); } /** * Used to find a @ref UMLClassifier by its name. * * @param name The name of the @ref UMLObject to find. */ UMLClassifier* UMLDoc::findUMLClassifier(const QString &name) { //this is used only by code generator so we don't need to look at Datatypes UMLObject * obj = findUMLObject(name); return obj->asUMLClassifier(); } /** * Adds a UMLObject thats already created but doesn't change * any ids or signal. Use AddUMLObjectPaste if pasting. * * @param object The object to add. * @return True if the object was actually added. */ bool UMLDoc::addUMLObject(UMLObject* object) { if (object->isUMLStereotype()) { DEBUG(DBG_SRC) << object->name() << ": not adding type " << object->baseTypeStr(); return false; } UMLPackage *pkg = object->umlPackage(); if (pkg == 0) { pkg = currentRoot(); DEBUG(DBG_SRC) << object->name() << ": no parent package set, assuming " << pkg->name(); object->setUMLPackage(pkg); } // FIXME restore stereotype UMLClassifierListItem *c = object->asUMLClassifierListItem(); if (c) { if (!pkg->subordinates().contains(c)) pkg->subordinates().append(c); return true; } return pkg->addObject(object); } /** * Write text to the status bar. * @param text the text to write */ void UMLDoc::writeToStatusBar(const QString &text) { emit sigWriteToStatusBar(text); } /** * Simple removal of an object. * @param object the UMLObject to be removed */ void UMLDoc::slotRemoveUMLObject(UMLObject* object) { //m_objectList.remove(object); UMLPackage *pkg = object->umlPackage(); if (pkg == 0) { uError() << object->name() << ": parent package is not set !"; return; } pkg->removeObject(object); } /** * Returns true if the given name is unique within its scope. * * @param name The name to check. * @return True if name is unique. */ bool UMLDoc::isUnique(const QString &name) { UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem *currentItem = (UMLListViewItem*)listView->currentItem(); UMLListViewItem *parentItem = 0; // check for current item, if its a package, then we do a check on that // otherwise, if current item exists, find its parent and check if thats // a package.. if (currentItem) { // its possible that the current item *is* a package, then just // do check now if (Model_Utils::typeIsContainer(currentItem->type())) { return isUnique (name, (UMLPackage*) currentItem->umlObject()); } parentItem = (UMLListViewItem*)currentItem->parent(); } // item is in a package so do check only in that if (parentItem != 0 && Model_Utils::typeIsContainer(parentItem->type())) { UMLPackage *parentPkg = parentItem->umlObject()->asUMLPackage(); return isUnique(name, parentPkg); } uError() << name << ": Not currently in a package"; /* Check against all objects that _don't_ have a parent package. for (UMLObjectListIt oit(m_objectList); oit.current(); ++oit) { UMLObject *obj = oit.current(); if ((obj->getUMLPackage() == 0) && (obj->getName() == name)) return false; } */ return true; } /** * Returns true if the given name is unique within its scope of given package. * * @param name The name to check. * @param package The UMLPackage in which we have to determine the unique-ness * @return True if name is unique. */ bool UMLDoc::isUnique(const QString &name, UMLPackage *package) { // if a package, then only do check in that if (package) { return (package->findObject(name) == 0); } // Not currently in a package: ERROR uError() << name << " (2): Not currently in a package"; /* Check against all objects that _don't_ have a parent package. for (UMLObjectListIt oit(m_objectList); oit.current(); ++oit) { UMLObject *obj = oit.current(); if ((obj->getUMLPackage() == 0) && (obj->getName() == name)) return false; } */ return true; } /** * Creates a stereotype for the parent object. * @param name the name of the stereotype */ UMLStereotype* UMLDoc::createStereotype(const QString &name) { UMLStereotype *s = new UMLStereotype(name, Uml::ID::fromString(name)); addStereotype(s); return s; } /** * Finds a UMLStereotype by its name. * * @param name The name of the UMLStereotype to find. * @return Pointer to the UMLStereotype found, or NULL if not found. */ UMLStereotype* UMLDoc::findStereotype(const QString &name) { foreach (UMLStereotype *s, m_stereoList) { if (s->name() == name) { return s; } } return 0; } /** * Finds or creates a stereotype for the parent object. * @param name the name of the stereotype * @return the found stereotype object or a just created one */ UMLStereotype* UMLDoc::findOrCreateStereotype(const QString &name) { UMLStereotype *s = findStereotype(name); if (s != 0) { return s; } return createStereotype(name); } /** * Find a UMLStereotype by its unique ID. * @param id the unique ID * @return the found stereotype or NULL */ UMLStereotype * UMLDoc::findStereotypeById(Uml::ID::Type id) { foreach (UMLStereotype *s, m_stereoList) { if (s->id() == id) return s; } return 0; } /** * Add a UMLStereotype to the application. * @param s the stereotype to be added */ void UMLDoc::addStereotype(UMLStereotype *s) { if (m_stereotypesModel->addStereotype(s)) emit sigObjectCreated(s); } /** * Remove a UMLStereotype from the application. * @param s the stereotype to be removed */ void UMLDoc::removeStereotype(UMLStereotype *s) { if (m_stereotypesModel->removeStereotype(s)) emit sigObjectRemoved(s); } /** * Add a stereotype if it doesn't already exist. * Used by code generators, operations and attribute dialog. */ void UMLDoc::addDefaultStereotypes() { CodeGenerator *gen = UMLApp::app()->generator(); if (gen) { gen->createDefaultStereotypes(); } } /** * Returns a list of the stereotypes in this UMLDoc. * * @return List of UML stereotypes. */ const UMLStereotypeList& UMLDoc::stereotypes() const { return m_stereoList; } /** * Removes an association. * * @param assoc Pointer to the UMLAssociation to remove. * @param doSetModified Whether to mark the document as modified (default: true.) */ void UMLDoc::removeAssociation (UMLAssociation * assoc, bool doSetModified /*=true*/) { if (!assoc) { return; } // Remove the UMLAssociation from m_objectList. UMLPackage *pkg = assoc->umlPackage(); if (pkg == 0) { uError() << assoc->name() << ": parent package is not set !"; return; } pkg->removeObject(assoc); if (doSetModified) { // so we will save our document setModified(true); } } /** * Finds an association. * * @param assocType Type of the UMLAssociation to seek. * @param roleAObj Pointer to the role A UMLCanvasObject. * @param roleBObj Pointer to the role B UMLCanvasObject. * @param swap Optional pointer to boolean. * The bool is set to true if the association * matched with swapped roles, else it is set * to false. * @return Pointer to the UMLAssociation found or NULL if not found. */ UMLAssociation * UMLDoc::findAssociation(Uml::AssociationType::Enum assocType, const UMLObject *roleAObj, const UMLObject *roleBObj, bool *swap) { UMLAssociationList assocs = associations(); UMLAssociation *ret = 0; foreach (UMLAssociation* a, assocs) { if (a->getAssocType() != assocType) { continue; } if (a->getObject(Uml::RoleType::A) == roleAObj && a->getObject(Uml::RoleType::B) == roleBObj) { return a; } if (a->getObject(Uml::RoleType::A) == roleBObj && a->getObject(Uml::RoleType::B) == roleAObj) { ret = a; } } if (swap) { *swap = (ret != 0); } return ret; } /** * Creates AND adds an association between two UMLObjects. * Used by refactoring assistant. * NOTE: this method does not check if the association is valid / legal * * @param a The UMLObject "A" for the association (source) * @param b The UMLObject "B" for the association (destination) * @param type The association's type * @return The Association created */ UMLAssociation* UMLDoc::createUMLAssociation(UMLObject *a, UMLObject *b, Uml::AssociationType::Enum type) { bool swap; UMLAssociation *assoc = findAssociation(type, a, b, &swap); if (assoc == 0) { assoc = new UMLAssociation(type, a, b); assoc->setUMLPackage(a->umlPackage()); addAssociation(assoc); } return assoc; } /** * Adds an association. * * @param assoc Pointer to the UMLAssociation to add. */ void UMLDoc::addAssociation(UMLAssociation *assoc) { if (assoc == 0) { return; } // First, check that this association has not already been added. // This may happen when loading old XMI files where all the association // information was taken from the tag. UMLAssociationList assocs = associations(); foreach (UMLAssociation* a, assocs) { // check if its already been added (shouldn't be the case right now // as UMLAssociations only belong to one associationwidget at a time) if (a == assoc) { DEBUG(DBG_SRC) << "duplicate addition attempted"; return; } } // If we get here it's really a new association. // Add the UMLAssociation at the owning UMLPackage. UMLPackage *pkg = assoc->umlPackage(); if (pkg == 0) { uError() << assoc->name() << ": parent package is not set !"; return; } pkg->addObject(assoc); // I don't believe this appropriate, UMLAssociations ARENT UMLWidgets -b.t. // emit sigObjectCreated(o); setModified(true); } /** * Returns a name for the new object, appended with a number * if the default name is taken e.g. class diagram, class * diagram_1 etc. * @param type the diagram type * @return the unique view name */ QString UMLDoc::uniqueViewName(const Uml::DiagramType::Enum type) { QString dname; switch (type) { case Uml::DiagramType::UseCase: dname = i18n("use case diagram"); break; case Uml::DiagramType::Class: dname = i18n("class diagram"); break; case Uml::DiagramType::Sequence: dname = i18n("sequence diagram"); break; case Uml::DiagramType::Collaboration: dname = i18n("communication diagram"); break; case Uml::DiagramType::Object: dname = i18n("object diagram"); break; case Uml::DiagramType::State: dname = i18n("state diagram"); break; case Uml::DiagramType::Activity: dname = i18n("activity diagram"); break; case Uml::DiagramType::Component: dname = i18n("component diagram"); break; case Uml::DiagramType::Deployment: dname = i18n("deployment diagram"); break; case Uml::DiagramType::EntityRelationship: dname = i18n("entity relationship diagram"); break; default: uWarning() << "called with unknown diagram type"; break; } QString name = dname; for (int number = 1; findView(type, name, true); ++number) { name = dname + QLatin1Char('_') + QString::number(number); } return name; } /** * Returns true when loading a document file. * @return the value of the flag */ bool UMLDoc::loading() const { return m_bLoading || !m_bTypesAreResolved; } /** * Sets loading boolean flag to the value given. * @param state value to set */ void UMLDoc::setLoading(bool state /* = true */) { m_bLoading = state; } /** * Returns true when importing file(s). * @return the value of the flag */ bool UMLDoc::importing() const { return m_importing; } /** * Sets importing boolean flag to the value given. * @param state value to set */ void UMLDoc::setImporting(bool state /* = true */) { m_importing = state; } /** * Returns the m_bClosing flag. * @return the value of the flag */ bool UMLDoc::closing() const { return m_bClosing; } /** * Creates the name of the given diagram type. * @param type The type of diagram to create. * @param askForName If true shows a dialog box asking for name, * else uses a default name. * @return name of the new diagram */ QString UMLDoc::createDiagramName(Uml::DiagramType::Enum type, bool askForName /*= true */) { QString defaultName = uniqueViewName(type); QString name = defaultName; while (true) { if (askForName && !Dialog_Utils::askName(i18nc("diagram name", "Name"), i18n("Enter name:"), name)) break; if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name for a diagram."), i18n("Invalid Name")); } else if (findView(type, name)) { KMessageBox::error(0, i18n("A diagram is already using that name."), i18n("Not a Unique Name")); } else { return name; } } // end while return QString(); } /** * Creates a diagram of the given type. * * @param folder the folder in which tp create the diagram. * @param type the type of diagram to create * @param name the name for the diagram to create * @param id optional ID of new diagram * @return pointer to the UMLView of the new diagram */ UMLView* UMLDoc::createDiagram(UMLFolder *folder, Uml::DiagramType::Enum type, const QString& name, Uml::ID::Type id) { DEBUG(DBG_SRC) << "folder=" << folder->name() << " / type=" << Uml::DiagramType::toString(type) << " / name=" << name; if (id == Uml::ID::None) { id = UniqueID::gen(); } if (name.length() > 0) { UMLView* view = new UMLView(folder); view->umlScene()->setOptionState(Settings::optionState()); view->umlScene()->setName(name); view->umlScene()->setType(type); view->umlScene()->setID(id); addView(view); emit sigDiagramCreated(id); setModified(true); UMLApp::app()->enablePrint(true); changeCurrentView(id); return view; } return 0; } /** * Used to rename a document. This method takes care of everything. * You just need to give the ID of the diagram to the method. * * @param id The ID of the diagram to rename. */ void UMLDoc::renameDiagram(Uml::ID::Type id) { UMLView *view = findView(id); Uml::DiagramType::Enum type = view->umlScene()->type(); QString name = view->umlScene()->name(); while (true) { bool ok = Dialog_Utils::askName(i18nc("renaming diagram", "Name"), i18n("Enter name:"), name); if (!ok) { break; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name for a diagram."), i18n("Invalid Name")); } else if (!findView(type, name)) { view->umlScene()->setName(name); emit sigDiagramRenamed(id); setModified(true); break; } else { KMessageBox::error(0, i18n("A diagram is already using that name."), i18n("Not a Unique Name")); } } } /** * Used to rename a @ref UMLObject. The @ref UMLObject is to be an * actor, use case or concept. * * @param o The object to rename. */ void UMLDoc::renameUMLObject(UMLObject *o) { QString name = o->name(); while (true) { bool ok = Dialog_Utils::askName(i18nc("renaming uml object", "Name"), i18n("Enter name:"), name); if (!ok) { break; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); } else if (isUnique(name)) { UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(o, name)); setModified(true); break; } else { KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); } } return; } /** * Used to rename an operation or attribute of a concept. * * @param o The attribute or operation to rename. */ void UMLDoc::renameChildUMLObject(UMLObject *o) { UMLClassifier* p = o->umlParent()->asUMLClassifier(); if (!p) { DEBUG(DBG_SRC) << "Cannot create object, no parent found."; return; } QString name = o->name(); while (true) { bool ok = Dialog_Utils::askName(i18nc("renaming child uml object", "Name"), i18n("Enter name:"), name); if (!ok) { break; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); } else if (p->findChildObject(name) == 0 || ((o->baseType() == UMLObject::ot_Operation) && KMessageBox::warningYesNo(0, i18n("The name you entered was not unique.\nIs this what you wanted?"), i18n("Name Not Unique"), KGuiItem(i18n("Use Name")), KGuiItem(i18n("Enter New Name"))) == KMessageBox::Yes)) { UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(o, name)); setModified(true); break; } else { KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); } } } /** * Changes the current view (diagram) to the view with the given ID. * * @param id The ID of the view to change to. */ void UMLDoc::changeCurrentView(Uml::ID::Type id) { DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id); UMLView* view = findView(id); if (view) { UMLScene* scene = view->umlScene(); scene->setIsOpen(true); UMLApp::app()->setCurrentView(view); emit sigDiagramChanged(scene->type()); UMLApp::app()->setDiagramMenuItemsState(true); setModified(true); emit sigCurrentViewChanged(); // when clicking on a tab, the documentation of diagram is upated in docwindow UMLApp::app()->docWindow()->showDocumentation(scene); } else { uWarning() << "New current view was not found with id=" << Uml::ID::toString(id) << "!"; } } /** * Deletes a diagram from the current file. * * Undo command * * @param id The ID of the diagram to delete. */ void UMLDoc::removeDiagram(Uml::ID::Type id) { UMLView* umlView = findView(id); if (!umlView) { uError() << "Request to remove diagram " << Uml::ID::toString(id) << ": Diagram not found!"; return; } UMLScene* umlScene = umlView->umlScene(); if (Dialog_Utils::askDeleteDiagram(umlScene->name())) { UMLApp::app()->executeCommand(new Uml::CmdRemoveDiagram( umlScene->folder(), umlScene->type(), umlScene->name(), id )); } } /** * Deletes a diagram from the current file. * * @param id The ID of the diagram to delete. */ void UMLDoc::removeDiagramCmd(Uml::ID::Type id) { UMLApp::app()->docWindow()->updateDocumentation(true); UMLView* umlview = findView(id); if (!umlview) { uError() << "Request to remove diagram " << Uml::ID::toString(id) << ": Diagram not found!"; return; } removeView(umlview); emit sigDiagramRemoved(id); setModified(true); } /** * Return the currently selected root folder. * This will be an element from the m_root[] array. * @return the currently selected root folder or NULL */ UMLFolder *UMLDoc::currentRoot() { UMLView *currentView = UMLApp::app()->currentView(); if (currentView == 0) { if (m_pCurrentRoot) { return m_pCurrentRoot; } uError() << "m_pCurrentRoot is NULL"; return 0; } UMLFolder *f = currentView->umlScene()->folder(); while (f && f->umlPackage()) { f = f->umlParent()->asUMLFolder(); } return f; } /** * Set the current root folder. * * @param rootType The type of the root folder to set. * The element from m_root[] which is indexed * by this type is selected. */ void UMLDoc::setCurrentRoot(Uml::ModelType::Enum rootType) { m_pCurrentRoot = m_root[rootType]; } /** * Removes an @ref UMLObject from the current file. If this object * is being represented on a diagram it will also delete all those * representations. * * @param umlobject Pointer to the UMLObject to delete. * @param deleteObject Delete the UMLObject instance. */ void UMLDoc::removeUMLObject(UMLObject* umlobject, bool deleteObject) { if (umlobject == 0) { uError() << "called with NULL parameter"; return; } UMLApp::app()->docWindow()->updateDocumentation(true); UMLObject::ObjectType type = umlobject->baseType(); umlobject->setUMLStereotype(0); // triggers possible cleanup of UMLStereotype if (umlobject->asUMLClassifierListItem()) { UMLClassifier* parent = umlobject->umlParent()->asUMLClassifier(); if (parent == 0) { uError() << "parent of umlobject is NULL"; return; } if (type == UMLObject::ot_Operation) { parent->removeOperation(umlobject->asUMLOperation()); if (deleteObject) delete umlobject->asUMLOperation(); } else if (type == UMLObject::ot_EnumLiteral) { UMLEnum *e = parent->asUMLEnum(); e->removeEnumLiteral(umlobject->asUMLEnumLiteral()); } else if (type == UMLObject::ot_EntityAttribute) { UMLEntity *ent = parent->asUMLEntity(); ent->removeEntityAttribute(umlobject->asUMLClassifierListItem()); } else if (type == UMLObject::ot_UniqueConstraint || type == UMLObject::ot_ForeignKeyConstraint || type == UMLObject::ot_CheckConstraint) { UMLEntity* ent = parent->asUMLEntity(); ent->removeConstraint(umlobject->asUMLEntityConstraint()); } else { UMLClassifier* pClass = parent->asUMLClassifier(); if (pClass == 0) { uError() << "parent of umlobject has unexpected type " << parent->baseType(); return; } if (type == UMLObject::ot_Attribute) { pClass->removeAttribute(umlobject->asUMLAttribute()); } else if (type == UMLObject::ot_Template) { pClass->removeTemplate(umlobject->asUMLTemplate()); if (deleteObject) delete umlobject->asUMLTemplate(); } else { uError() << "umlobject has unexpected type " << type; } } } else { if (type == UMLObject::ot_Association) { UMLAssociation *a = umlobject->asUMLAssociation(); removeAssociation(a, false); // don't call setModified here, it's done below emit sigObjectRemoved(umlobject); if (deleteObject) delete a; } else { UMLPackage* pkg = umlobject->umlPackage(); if (pkg) { // Remove associations that this object may participate in. UMLCanvasObject *c = umlobject->asUMLCanvasObject(); if (c) { // In the current implementation, all associations live in the // root folder. UMLPackage* rootPkg = Model_Utils::rootPackage(c); if (rootPkg == 0) { uError() << umlobject->name() << ": root package is not set !"; return; } UMLObjectList &rootObjects = rootPkg->containedObjects(); // Store the associations to remove in a buffer because we // should not remove elements from m_objectList while it is // being iterated over. UMLAssociationList assocsToRemove; foreach (UMLObject *obj, rootObjects) { uIgnoreZeroPointer(obj); if (obj->baseType() == UMLObject::ot_Association) { UMLAssociation *assoc = obj->asUMLAssociation(); if (c->hasAssociation(assoc)) { assocsToRemove.append(assoc); } } } foreach (UMLAssociation *a, assocsToRemove) { removeAssociation(a, false); } } pkg->removeObject(umlobject); emit sigObjectRemoved(umlobject); if (deleteObject) delete umlobject; } else { uError() << umlobject->name() << ": parent package is not set !"; } } } setModified(true); } /** * Signal that a UMLObject has been created. * * @param o The object that has been created. */ void UMLDoc::signalUMLObjectCreated(UMLObject * o) { emit sigObjectCreated(o); /* This is the wrong place to do: setModified(true); Instead, that should be done by the callers when object creation and all its side effects (e.g. new widget in view, new list view item, etc.) is finalized. */ } /** * Set the name of this model. */ void UMLDoc::setName(const QString& name) { m_Name = name; } /** * Return the name of this model. */ QString UMLDoc::name() const { return m_Name; } /** * Set coordinates resolution for current document. * @param resolution document resolution in DPI */ void UMLDoc::setResolution(qreal resolution) { m_resolution = resolution; uDebug() << "screen dpi:" << qApp->desktop()->logicalDpiX() << "file dpi:" << resolution << "scale:" << qApp->desktop()->logicalDpiX() / resolution; } /** * Returns coordinates resolution for current document. * @return document resolution in DPI */ qreal UMLDoc::resolution() const { return m_resolution; } /** * Returns scale factor for recalculation of document coordinates. * @return scale factor */ qreal UMLDoc::dpiScale() const { #ifdef ENABLE_XMIRESOLUTION if (resolution() != 0.0) return (qreal)qApp->desktop()->logicalDpiX() / resolution(); else #endif return 1.0; } /** * Return the m_modelID (currently this a fixed value: * Umbrello supports only a single document.) */ Uml::ID::Type UMLDoc::modelID() const { return m_modelID; } /** * This method is called for saving the given model as a XMI file. * It is virtual and calls the corresponding saveToXMI1() functions * of the derived classes. * * @param file The file to be saved to. */ void UMLDoc::saveToXMI1(QIODevice& file) { QDomDocument doc; QDomProcessingInstruction xmlHeading = doc.createProcessingInstruction(QLatin1String("xml"), QString::fromLatin1("version=\"1.0\" encoding=\"UTF-8\"")); doc.appendChild(xmlHeading); QDomElement root = doc.createElement(QLatin1String("XMI")); root.setAttribute(QLatin1String("xmi.version"), QLatin1String("1.2")); QDateTime now = QDateTime::currentDateTime(); root.setAttribute(QLatin1String("timestamp"), now.toString(Qt::ISODate)); root.setAttribute(QLatin1String("verified"), QLatin1String("false")); root.setAttribute(QLatin1String("xmlns:UML"), QLatin1String("http://schema.omg.org/spec/UML/1.4")); doc.appendChild(root); QDomElement header = doc.createElement(QLatin1String("XMI.header")); QDomElement meta = doc.createElement(QLatin1String("XMI.metamodel")); meta.setAttribute(QLatin1String("xmi.name"), QLatin1String("UML")); meta.setAttribute(QLatin1String("xmi.version"), QLatin1String("1.4")); meta.setAttribute(QLatin1String("href"), QLatin1String("UML.xml")); header.appendChild(meta); /** * bugs.kde.org/56184 comment by M. Alanen 2004-12-19: * " XMI.model requires xmi.version. (or leave the whole XMI.model out, * it's not required) " QDomElement model = doc.createElement("XMI.model"); QFile* qfile = dynamic_cast(&file); if (qfile) { QString modelName = qfile->name(); modelName = modelName.section('/', -1); modelName = modelName.section('.', 0, 0); model.setAttribute("xmi.name", modelName); model.setAttribute("href", qfile->name()); } */ QDomElement documentation = doc.createElement(QLatin1String("XMI.documentation")); // If we consider it useful we might add user and contact details // QDomElement owner = doc.createElement("XMI.owner"); // owner.appendChild(doc.createTextNode("Jens Kruger")); // Add a User // documentation.appendChild(owner); // QDomElement contact = doc.createElement("XMI.contact"); // contact.appendChild(doc.createTextNode("je.krueger@web.de")); // add a contact // documentation.appendChild(contact); QDomElement exporter = doc.createElement(QLatin1String("XMI.exporter")); exporter.appendChild(doc.createTextNode(QLatin1String("umbrello uml modeller http://umbrello.kde.org"))); documentation.appendChild(exporter); QDomElement exporterVersion = doc.createElement(QLatin1String("XMI.exporterVersion")); exporterVersion.appendChild(doc.createTextNode(QLatin1String(XMI_FILE_VERSION))); documentation.appendChild(exporterVersion); // all files are now saved with correct Unicode encoding, we add this // information to the header, so that the file will be loaded correctly QDomElement exporterEncoding = doc.createElement(QLatin1String("XMI.exporterEncoding")); exporterEncoding.appendChild(doc.createTextNode(QLatin1String("UnicodeUTF8"))); documentation.appendChild(exporterEncoding); header.appendChild(documentation); // See comment on above // header.appendChild(model); header.appendChild(meta); root.appendChild(header); QDomElement content = doc.createElement(QLatin1String("XMI.content")); QDomElement contentNS = doc.createElement(QLatin1String("UML:Namespace.contents")); QDomElement objectsElement = doc.createElement(QLatin1String("UML:Model")); objectsElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_modelID)); objectsElement.setAttribute(QLatin1String("name"), m_Name); objectsElement.setAttribute(QLatin1String("isSpecification"), QLatin1String("false")); objectsElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("false")); objectsElement.setAttribute(QLatin1String("isRoot"), QLatin1String("false")); objectsElement.setAttribute(QLatin1String("isLeaf"), QLatin1String("false")); QDomElement ownedNS = doc.createElement(QLatin1String("UML:Namespace.ownedElement")); // Save stereotypes and toplevel datatypes first so that upon loading // they are known first. // There is a bug causing duplication of the same stereotype in m_stereoList. // As a workaround, we use a string list to memorize which stereotype has been saved. QStringList stereoNames; foreach (UMLStereotype *s, m_stereoList) { QString stName = s->name(); if (!stereoNames.contains(stName)) { s->saveToXMI1(doc, ownedNS); stereoNames.append(stName); } } for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->saveToXMI1(doc, ownedNS); } objectsElement.appendChild(ownedNS); content.appendChild(objectsElement); root.appendChild(content); // Save the XMI extensions: docsettings, diagrams, listview, and codegeneration. QDomElement extensions = doc.createElement(QLatin1String("XMI.extensions")); extensions.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello")); QDomElement docElement = doc.createElement(QLatin1String("docsettings")); Uml::ID::Type viewID = Uml::ID::None; UMLView *currentView = UMLApp::app()->currentView(); if (currentView) { viewID = currentView->umlScene()->ID(); } docElement.setAttribute(QLatin1String("viewid"), Uml::ID::toString(viewID)); docElement.setAttribute(QLatin1String("documentation"), m_Doc); docElement.setAttribute(QLatin1String("uniqueid"), Uml::ID::toString(UniqueID::get())); extensions.appendChild(docElement); // save listview UMLApp::app()->listView()->saveToXMI1(doc, extensions); // save code generator CodeGenerator *codegen = UMLApp::app()->generator(); if (codegen) { QDomElement codeGenElement = doc.createElement(QLatin1String("codegeneration")); codegen->saveToXMI1(doc, codeGenElement); extensions.appendChild(codeGenElement); } root.appendChild(extensions); QTextStream stream(&file); stream.setCodec("UTF-8"); stream << doc.toString(); } /** * Checks the given XMI file if it was saved with correct Unicode * encoding set or not. * * @param file The file to be checked. */ short UMLDoc::encoding(QIODevice & file) { QTextStream stream(&file); stream.setCodec("UTF-8"); QString data = stream.readAll(); QString error; int line; QDomDocument doc; if (!doc.setContent(data, false, &error, &line)) { uWarning() << "Cannot set content: " << error << " Line: " << line; return ENC_UNKNOWN; } // we start at the beginning and go to the point in the header where we can // find out if the file was saved using Unicode QDomNode node = doc.firstChild(); short enc = ENC_UNKNOWN; while (node.isComment() || node.isProcessingInstruction()) { if (node.isProcessingInstruction()) { const QDomProcessingInstruction& pi = node.toProcessingInstruction(); QRegExp rx(QLatin1String("\\bencoding=['\"]([^'\"]+)['\"]")); const int pos = rx.indexIn(pi.data()); if (pos >= 0) { const QString& encData = rx.cap(1); if (encData == QLatin1String("UTF-8")) { enc = ENC_UNICODE; } else if (encData == QLatin1String("windows-1252")) { enc = ENC_WINDOWS; } else { uDebug() << "ProcessingInstruction encoding=" << encData << " is not yet implemented"; enc = ENC_OLD_ENC; } } } node = node.nextSibling(); } QDomElement root = node.toElement(); if (root.isNull()) { uDebug() << "Null element at " << node.nodeName() << " : " << node.nodeValue(); return enc; } // make sure it is an XMI file if (root.tagName() != QLatin1String("XMI") && root.tagName() != QLatin1String("xmi:XMI")) { uDebug() << "Unknown tag at " << root.tagName(); return enc; } if (node.firstChild().isNull()) { uDebug() << "No child at " << node.nodeName() << " : " << node.nodeValue(); return enc; } node = node.firstChild(); QDomElement element = node.toElement(); // check header if (element.isNull()) { uDebug() << "No element at " << node.nodeName() << " : " << node.nodeValue(); return enc; } if (element.tagName() != QLatin1String("XMI.header")) { uDebug() << "Expecting XMI.header at " << element.tagName(); return enc; } QDomNode headerNode = node.firstChild(); while (!headerNode.isNull()) { QDomElement headerElement = headerNode.toElement(); // the information if Unicode was used is now stored in the // XMI.documentation section of the header if (headerElement.isNull() || headerElement.tagName() != QLatin1String("XMI.documentation")) { headerNode = headerNode.nextSibling(); continue; } QDomNode docuNode = headerNode.firstChild(); while (!docuNode.isNull()) { QDomElement docuElement = docuNode.toElement(); // a tag XMI.exporterEncoding was added since version 1.2 to // mark a file as saved with Unicode if (! docuElement.isNull() && docuElement.tagName() == QLatin1String("XMI.exporterEncoding")) { // at the moment this isn't really necessary but maybe // later we will have other encoding standards if (docuElement.text() == QLatin1String("UnicodeUTF8")) { return ENC_UNICODE; // stop here } } docuNode = docuNode.nextSibling(); } break; } return ENC_OLD_ENC; } /** * Load a given XMI model from a file. If the encoding of the file * is already known it can be passed to the function. If this info * isn't given, loadFromXMI1 will check which encoding was used. * * @param file The file to be loaded. * @param encode The encoding used. */ bool UMLDoc::loadFromXMI1(QIODevice & file, short encode) { // old Umbrello versions (version < 1.2) didn't save the XMI in Unicode // this wasn't correct, because non Latin1 chars where lost // to ensure backward compatibility we have to ensure to load the old files // with non Unicode encoding if (encode == ENC_UNKNOWN) { if ((encode = encoding(file)) == ENC_UNKNOWN) { return false; } file.reset(); } QTextStream stream(&file); if (encode == ENC_UNICODE) { stream.setCodec("UTF-8"); } else if (encode == ENC_WINDOWS) { stream.setCodec("windows-1252"); } QString data = stream.readAll(); qApp->processEvents(); // give UI events a chance QString error; int line; QDomDocument doc; if (!doc.setContent(data, false, &error, &line)) { uWarning() << "Cannot set content:" << error << " Line:" << line; return false; } qApp->processEvents(); // give UI events a chance QDomNode node = doc.firstChild(); //Before Umbrello 1.1-rc1 we didn't add a listView(); lv->setTitle(0, m_Name); recognized = true; } if (outerTag != QLatin1String("XMI.content")) { if (!recognized) { DEBUG(DBG_SRC) << "skipping <" << outerTag << ">"; } continue; } bool seen_UMLObjects = false; //process content for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { if (child.isComment()) { continue; } element = child.toElement(); QString tag = element.tagName(); if (tag == QLatin1String("umlobjects") // for bkwd compat. || tagEq(tag, QLatin1String("Subsystem")) || tagEq(tag, QLatin1String("Project")) // Embarcadero's Describe || tagEq(tag, QLatin1String("Model"))) { if(!loadUMLObjectsFromXMI1(element)) { uWarning() << "failed load on objects"; return false; } m_Name = element.attribute(QLatin1String("name"), i18n("UML Model")); UMLListView *lv = UMLApp::app()->listView(); lv->setTitle(0, m_Name); seen_UMLObjects = true; } else if (tagEq(tag, QLatin1String("Package")) || tagEq(tag, QLatin1String("Class")) || tagEq(tag, QLatin1String("Interface"))) { // These tests are only for foreign XMI files that // are missing the tag (e.g. NSUML) QString stID = element.attribute(QLatin1String("stereotype")); UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag, stID); if (!pObject) { uWarning() << "Unknown type of umlobject to create: " << tag; // We want a best effort, therefore this is handled as a // soft error. continue; } UMLObject::ObjectType ot = pObject->baseType(); // Set the parent root folder. UMLPackage *pkg = 0; if (ot != UMLObject::ot_Stereotype) { if (ot == UMLObject::ot_Datatype) { pkg = m_datatypeRoot; } else { Uml::ModelType::Enum guess = Model_Utils::guessContainer(pObject); if (guess != Uml::ModelType::N_MODELTYPES) { pkg = m_root[guess]; } else { uError() << "Guess is Uml::ModelType::N_MODELTYPES - package not set correctly for " << pObject->name() << " / base type " << pObject->baseTypeStr(); pkg = m_root[Uml::ModelType::Logical]; } } } pObject->setUMLPackage(pkg); bool status = pObject->loadFromXMI1(element); if (!status) { delete pObject; return false; } seen_UMLObjects = true; } else if (tagEq(tag, QLatin1String("TaggedValue"))) { // This tag is produced here, i.e. outside of , // by the Unisys.JCR.1 Rose-to-XMI tool. if (! seen_UMLObjects) { DEBUG(DBG_SRC) << "skipping TaggedValue because not seen_UMLObjects"; continue; } tag = element.attribute(QLatin1String("tag")); if (tag != QLatin1String("documentation")) { continue; } QString modelElement = element.attribute(QLatin1String("modelElement")); if (modelElement.isEmpty()) { DEBUG(DBG_SRC) << "skipping TaggedValue(documentation) because " << "modelElement.isEmpty()"; continue; } UMLObject *o = findObjectById(Uml::ID::fromString(modelElement)); if (o == 0) { DEBUG(DBG_SRC) << "TaggedValue(documentation): cannot find object" << " for modelElement " << modelElement; continue; } QString value = element.attribute(QLatin1String("value")); if (! value.isEmpty()) { o->setDoc(value); } } else { // for backward compatibility loadExtensionsFromXMI1(child); } } } resolveTypes(); loadDiagrams1(); // set a default code generator if no tag seen if (UMLApp::app()->generator() == 0) { UMLApp::app()->setGenerator(UMLApp::app()->defaultLanguage()); } emit sigWriteToStatusBar(i18n("Setting up the document...")); qApp->processEvents(); // give UI events a chance activateAllViews(); UMLView *viewToBeSet = 0; if (m_nViewID != Uml::ID::None) { viewToBeSet = findView(m_nViewID); } if (viewToBeSet) { changeCurrentView(m_nViewID); } else { QString name = createDiagramName(Uml::DiagramType::Class, false); createDiagram(m_root[Uml::ModelType::Logical], Uml::DiagramType::Class, name); m_pCurrentRoot = m_root[Uml::ModelType::Logical]; } emit sigResetStatusbarProgress(); return true; } /** * Type resolution pass. */ void UMLDoc::resolveTypes() { // Resolve the types. // This is done in a separate pass because of possible forward references. if (m_bTypesAreResolved) { return; } writeToStatusBar(i18n("Resolving object references...")); for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { UMLFolder *obj = m_root[i]; #ifdef VERBOSE_DEBUGGING DEBUG(DBG_SRC) << "UMLDoc: invoking resolveRef() for " << obj->name() << " (id=" << Uml::ID::toString(obj->id()) << ")"; #endif obj->resolveRef(); } m_bTypesAreResolved = true; qApp->processEvents(); // give UI events a chance } /** * Load all diagrams collected from the xmi file. * * Loading diagrams is implemented as additional pass to avoid unresolved * uml objects which are defined later in the xmi file. */ bool UMLDoc::loadDiagrams1() { bool result = true; DiagramsMap::const_iterator i; for (i = m_diagramsToLoad.constBegin(); i != m_diagramsToLoad.constEnd(); i++) { UMLFolder *f = i.key(); foreach(QDomNode node, i.value()) if (!f->loadDiagramsFromXMI1(node)) result = false; } m_diagramsToLoad.clear(); return result; } /** * Add a xml node containing a diagram to the list of diagrams to load. * Helper function for loadDiagrams(). * * @param folder pointer to UMFolder instance the diagrams belongs to * @param node xml document node containing the diagram */ void UMLDoc::addDiagramToLoad(UMLFolder *folder, QDomNode node) { if (m_diagramsToLoad.contains(folder)) m_diagramsToLoad[folder].append(node); else m_diagramsToLoad[folder] = QList() << node; } DiagramsModel *UMLDoc::diagramsModel() { return m_diagramsModel; } ObjectsModel *UMLDoc::objectsModel() { return m_objectsModel; } StereotypesModel *UMLDoc::stereotypesModel() { return m_stereotypesModel; } /** * Ensures the XMI file is a valid UML file. * Currently only checks for metamodel=UML. * * @param headerNode The node */ bool UMLDoc::validateXMI1Header(QDomNode& headerNode) { QDomElement headerElement = headerNode.toElement(); while (!headerNode.isNull()) { /* //Seems older Umbrello files used a different metamodel, so don't validate it for now if(!headerElement.isNull() && headerElement.tagName() == "XMI.metamodel") { String metamodel = headerElement.attribute("xmi.name"); if (metamodel != "UML") { return false; } } */ headerNode = headerNode.nextSibling(); headerElement = headerNode.toElement(); } return true; } /** * Loads all UML objects from XMI into the current UMLDoc. * * @return True if operation successful. */ bool UMLDoc::loadUMLObjectsFromXMI1(QDomElement& element) { /* FIXME need a way to make status bar actually reflect how much of the file has been loaded rather than just counting to 10 (an arbitrary number) emit sigResetStatusbarProgress(); emit sigSetStatusbarProgress(0); emit sigSetStatusbarProgressSteps(10); m_count = 0; */ emit sigWriteToStatusBar(i18n("Loading UML elements...")); // For Umbrello native XMI files, when called from loadFromXMI1() we // get here with Element.tagName() == "UML:Model" from the XMI input: // for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isComment()) { continue; } QDomElement tempElement = node.toElement(); QString type = tempElement.tagName(); if (tagEq(type, QLatin1String("Model"))) { // Handling of Umbrello native XMI files: // We get here from a recursive call to loadUMLObjectsFromXMI() // a few lines below, see // if (tagEq(type, "Namespace.ownedElement") .... // Inside this Namespace.ownedElement envelope there are the // four submodels: // // // // // These are ultimately loaded by UMLFolder::loadFromXMI1() // Furthermore, in Umbrello native XMI format this // Namespace.ownedElement is the container of all stereotypes // (). bool foundUmbrelloRootFolder = false; QString name = tempElement.attribute(QLatin1String("name")); for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { if (name == m_root[i]->name()) { m_pCurrentRoot = m_root[i]; m_root[i]->loadFromXMI1(tempElement); foundUmbrelloRootFolder = true; break; } } if (foundUmbrelloRootFolder) { continue; } } if (tagEq(type, QLatin1String("Namespace.ownedElement")) || tagEq(type, QLatin1String("Namespace.contents")) || tagEq(type, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe tagEq(type, QLatin1String("Model"))) { //CHECK: Umbrello currently assumes that nested elements // are ownedElements anyway. // Therefore the tag is of no // significance. // The tagEq(type, "Namespace.contents") and tagEq(type, "Model") // tests do not become true for Umbrello native files, only for // some foreign XMI files. if (!loadUMLObjectsFromXMI1(tempElement)) { uWarning() << "failed load on " << type; return false; } continue; } // From here on, it's support for stereotypes, pre 1.5.5 versions, // and foreign files if (Model_Utils::isCommonXMI1Attribute(type)) { continue; } else if (tagEq(type, QLatin1String("packagedElement")) || tagEq(type, QLatin1String("ownedElement"))) { type = tempElement.attribute(QLatin1String("xmi:type")); } if (!tempElement.hasAttribute(QLatin1String("xmi.id")) && !tempElement.hasAttribute(QLatin1String("xmi:id"))) { QString idref = tempElement.attribute(QLatin1String("xmi.idref")); if (! idref.isEmpty()) { DEBUG(DBG_SRC) << "resolution of xmi.idref " << idref << " is not yet implemented"; } else { uError() << "Cannot load " << type << " because xmi.id is missing"; } continue; } QString stID = tempElement.attribute(QLatin1String("stereotype")); UMLObject *pObject = Object_Factory::makeObjectFromXMI(type, stID); if (!pObject) { uWarning() << "Unknown type of umlobject to create: " << type; // We want a best effort, therefore this is handled as a // soft error. continue; } UMLObject::ObjectType ot = pObject->baseType(); // Set the parent root folder. UMLPackage *pkg = 0; if (ot != UMLObject::ot_Stereotype) { if (ot == UMLObject::ot_Datatype) { pkg = m_datatypeRoot; } else { Uml::ModelType::Enum guess = Model_Utils::guessContainer(pObject); if (guess != Uml::ModelType::N_MODELTYPES) { pkg = m_root[guess]; } else { uError() << "Guess is Uml::ModelType::N_MODELTYPES - package not set correctly for " << pObject->name() << " / base type " << pObject->baseTypeStr(); pkg = m_root[Uml::ModelType::Logical]; } } } pObject->setUMLPackage(pkg); bool status = pObject->loadFromXMI1(tempElement); if (!status) { delete pObject; return false; } pkg = pObject->umlPackage(); if (ot == UMLObject::ot_Stereotype) { UMLStereotype *s = pObject->asUMLStereotype(); UMLStereotype *exist = findStereotype(pObject->name()); if (exist) { if (exist->id() == pObject->id()) { delete pObject; } else { DEBUG(DBG_SRC) << "Stereotype " << pObject->name() << "(id=" << Uml::ID::toString(pObject->id()) << ") already exists with id=" << Uml::ID::toString(exist->id()); addStereotype(s); } } else { addStereotype(s); } continue; } if (pkg) { UMLObjectList &objects = pkg->containedObjects(); if (! objects.contains(pObject)) { DEBUG(DBG_SRC) << "CHECK: adding " << pObject->name() << " to " << pkg->name(); pkg->addObject(pObject); } } else if (ot != UMLObject::ot_Stereotype) { uError() << "Package is NULL for " << pObject->name(); return false; } /* FIXME see comment at loadUMLObjectsFromXMI1 emit sigSetStatusbarProgress(++m_count); */ } return true; } /** * Sets m_nViewID. */ void UMLDoc::setMainViewID(Uml::ID::Type viewID) { m_nViewID = viewID; } /** * Loads umbrello specific extensions from XMI to the UMLDoc. * The extension tags are: "docsettings", "diagrams", "listview", * and "codegeneration". */ void UMLDoc::loadExtensionsFromXMI1(QDomNode& node) { QDomElement element = node.toElement(); QString tag = element.tagName(); if (tag == QLatin1String("docsettings")) { QString viewID = element.attribute(QLatin1String("viewid"), QLatin1String("-1")); m_Doc = element.attribute(QLatin1String("documentation")); QString uniqueid = element.attribute(QLatin1String("uniqueid"), QLatin1String("0")); m_nViewID = Uml::ID::fromString(viewID); UniqueID::set(Uml::ID::fromString(uniqueid)); UMLApp::app()->docWindow()->reset(); } else if (tag == QLatin1String("diagrams") || tag == QLatin1String("UISModelElement")) { // For backward compatibility only: // Since version 1.5.5 diagrams are saved as part of the UMLFolder. QDomNode diagramNode = node.firstChild(); if (tag == QLatin1String("UISModelElement")) { // Unisys.IntegratePlus.2 element = diagramNode.toElement(); tag = element.tagName(); if (tag != QLatin1String("uisOwnedDiagram")) { uError() << "unknown child node " << tag; return; } diagramNode = diagramNode.firstChild(); } else { qreal resolution = 0.0; QString res = node.toElement().attribute(QLatin1String("resolution"), QLatin1String("")); if (!res.isEmpty()) { resolution = res.toDouble(); } if (resolution != 0.0) { UMLApp::app()->document()->setResolution(resolution); } else { // see UMLFolder::loadDiagramsFromXMI() UMLApp::app()->document()->setResolution(0.0); } } if (!loadDiagramsFromXMI1(diagramNode)) { uWarning() << "failed load on diagrams"; } } else if (tag == QLatin1String("listview")) { //FIXME: Need to resolveTypes() before loading listview, // else listview items are duplicated. resolveTypes(); if (!UMLApp::app()->listView()->loadFromXMI1(element)) { uWarning() << "failed load on listview"; } } else if (tag == QLatin1String("codegeneration")) { QDomNode cgnode = node.firstChild(); QDomElement cgelement = cgnode.toElement(); while (!cgelement.isNull()) { QString nodeName = cgelement.tagName(); QString lang = cgelement.attribute(QLatin1String("language"), QLatin1String("UNKNOWN")); Uml::ProgrammingLanguage::Enum pl = Uml::ProgrammingLanguage::fromString(lang); - CodeGenerator *g = UMLApp::app()->setGenerator(pl); - g->loadFromXMI1(cgelement); + if (pl != Uml::ProgrammingLanguage::Reserved) { + CodeGenerator *g = UMLApp::app()->setGenerator(pl); + g->loadFromXMI1(cgelement); + } else + uError() << "failed to setup unsupported code generator" << lang; cgnode = cgnode.nextSibling(); cgelement = cgnode.toElement(); } if (UMLApp::app()->generator() == 0) { UMLApp::app()->setGenerator(UMLApp::app()->defaultLanguage()); } } } /** * Loads all diagrams from XMI into the current UMLDoc. * For backward compatibility only: * Since version 1.5.5 diagrams are saved as part of the UMLFolder. * * @return True if operation successful. */ bool UMLDoc::loadDiagramsFromXMI1(QDomNode & node) { emit sigWriteToStatusBar(i18n("Loading diagrams...")); emit sigResetStatusbarProgress(); emit sigSetStatusbarProgress(0); emit sigSetStatusbarProgressSteps(10); //FIX ME QDomElement element = node.toElement(); if (element.isNull()) { return true; //return ok as it means there is no umlobjects } const Settings::OptionState state = Settings::optionState(); UMLView * pView = 0; int count = 0; while (!element.isNull()) { QString tag = element.tagName(); if (tag == QLatin1String("diagram") || tag == QLatin1String("UISDiagram")) { pView = new UMLView(0); // IMPORTANT: Set OptionState of new UMLView _BEFORE_ // reading the corresponding diagram: // + allow using per-diagram color and line-width settings // + avoid crashes due to uninitialized values for lineWidth pView->umlScene()->setOptionState(state); bool success = false; if (tag == QLatin1String("UISDiagram")) { success = pView->umlScene()->loadUISDiagram(element); } else { success = pView->umlScene()->loadFromXMI1(element); } if (!success) { uWarning() << "failed load on viewdata loadfromXMI"; delete pView; return false; } // Put diagram in default predefined folder. // @todo pass in the parent folder - it might be a user defined one. Uml::ModelType::Enum mt = Model_Utils::convert_DT_MT(pView->umlScene()->type()); pView->umlScene()->setFolder(m_root[mt]); pView->hide(); addView(pView); emit sigSetStatusbarProgress(++count); qApp->processEvents(); // give UI events a chance } node = node.nextSibling(); element = node.toElement(); } return true; } /** * Call to remove all the views (diagrams) in the current file. */ void UMLDoc::removeAllViews() { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->removeAllViews(); } UMLApp::app()->setCurrentView(0); emit sigDiagramChanged(Uml::DiagramType::Undefined); UMLApp::app()->setDiagramMenuItemsState(false); } /** * Call to remove all objects in the current file. */ void UMLDoc::removeAllObjects() { m_root[Uml::ModelType::Logical]->removeObject(m_datatypeRoot); for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->removeAllObjects(); } } /** * Returns a list of the packages in this UMLDoc, * * @return List of UMLPackages. */ UMLPackageList UMLDoc::packages(bool includeNested /* = true */, Uml::ModelType::Enum model) { UMLPackageList packageList; m_root[model]->appendPackages(packageList, includeNested); return packageList; } /** * Returns the datatype folder. * * @return Pointer to the predefined folder for datatypes. */ UMLFolder * UMLDoc::datatypeFolder() const { return m_datatypeRoot; } /** * Returns a list of the concepts in this UMLDoc. * * @param includeNested Whether to include the concepts from * nested packages (default: true.) * @return List of UML concepts. */ UMLClassifierList UMLDoc::concepts(bool includeNested /* =true */) { UMLClassifierList conceptList; m_root[Uml::ModelType::Logical]->appendClassifiers(conceptList, includeNested); return conceptList; } /** * Returns a list of the classes and interfaces in this UMLDoc. * * @param includeNested Whether to include the concepts from * nested packages (default: true.) * @return List of UML concepts. */ UMLClassifierList UMLDoc::classesAndInterfaces(bool includeNested /* =true */) { UMLClassifierList conceptList; m_root[Uml::ModelType::Logical]->appendClassesAndInterfaces(conceptList, includeNested); return conceptList; } /** * Returns a list of the entities in this UMLDoc. * * @param includeNested Whether to include the entities from * nested packages (default: true.) * @return List of UML Entities. */ UMLEntityList UMLDoc::entities(bool includeNested /* =true */) { UMLEntityList entityList; m_root[Uml::ModelType::EntityRelationship]->appendEntities(entityList, includeNested); return entityList; } /** * Returns a list of the datatypes in this UMLDoc. * * @return List of datatypes. */ UMLClassifierList UMLDoc::datatypes() { UMLObjectList &objects = m_datatypeRoot->containedObjects(); UMLClassifierList datatypeList; foreach (UMLObject *obj, objects) { uIgnoreZeroPointer(obj); if (obj->isUMLDatatype()) { datatypeList.append(obj->asUMLClassifier()); } } return datatypeList; } /** * Returns a list of the associations in this UMLDoc. * * @return List of UML associations. */ UMLAssociationList UMLDoc::associations() { UMLAssociationList associationList; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { UMLAssociationList assocs = m_root[i]->getAssociations(); foreach (UMLAssociation* a, assocs) { associationList.append(a); } } return associationList; } /** * Controls the printing of the program. * * @param pPrinter The printer (object) to use. * @param selectPage The DiagramPrintPage by which diagrams are selected for printing */ void UMLDoc::print(QPrinter * pPrinter, DiagramPrintPage * selectPage) { UMLView * printView = 0; int count = selectPage->printUmlCount(); QPainter painter(pPrinter); for (int i = 0; i < count; ++i) { if (i>0) { pPrinter->newPage(); } QString sID = selectPage->printUmlDiagram(i); Uml::ID::Type id = Uml::ID::fromString(sID); printView = findView(id); if (printView) { printView->umlScene()->print(pPrinter, painter); } printView = 0; } painter.end(); } /** * Return the list of views for this document. * * @return List of UML views. */ UMLViewList UMLDoc::viewIterator() { UMLViewList accumulator; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->appendViews(accumulator, true); } return accumulator; } /** * Sets the modified flag for the document after a modifying * action on the view connected to the document. * * @param modified The value to set the modified flag to. */ void UMLDoc::setModified(bool modified /*=true*/) { if (!m_bLoading) { m_modified = modified; UMLApp::app()->setModified(modified); } } /** * Returns if the document is modified or not. Use this to * determine if your document needs saving by the user on * closing. * * @return True if this UMLDoc is modified. */ bool UMLDoc::isModified() { return m_modified; } /** * Assigns an already created UMLObject a new ID. * If the object is a classifier then the operations/attributes * are also assigned new IDs. * * @param obj Pointer to the UMLObject to add. * @return True if operation successful. */ bool UMLDoc::assignNewIDs(UMLObject* obj) { if (!obj || !m_pChangeLog) { DEBUG(DBG_SRC) << "no obj || Changelog"; return false; } Uml::ID::Type result = assignNewID(obj->id()); obj->setID(result); //If it is a CONCEPT then change the ids of all its operations and attributes if (obj->baseType() == UMLObject::ot_Class) { UMLClassifier *c = obj->asUMLClassifier(); UMLClassifierListItemList attributes = c->getFilteredList(UMLObject::ot_Attribute); foreach (UMLObject* listItem, attributes) { result = assignNewID(listItem->id()); listItem->setID(result); } UMLClassifierListItemList templates = c->getFilteredList(UMLObject::ot_Template); foreach (UMLObject* listItem, templates) { result = assignNewID(listItem->id()); listItem->setID(result); } } if (obj->baseType() == UMLObject::ot_Interface || obj->baseType() == UMLObject::ot_Class) { UMLOperationList operations(((UMLClassifier*)obj)->getOpList()); foreach (UMLObject* listItem, operations) { result = assignNewID(listItem->id()); listItem->setID(result); } } setModified(true); return true; } /** * Return the predefined root folder of the given type. */ UMLFolder *UMLDoc::rootFolder(Uml::ModelType::Enum mt) { if (mt < Uml::ModelType::Logical || mt >= Uml::ModelType::N_MODELTYPES) { uError() << "illegal input value " << Uml::ModelType::toString(mt); return 0; } return m_root[mt]; } /** * Return the corresponding Model_Type if the given object * is one of the root folders. * When the given object is not one of the root folders then * return Uml::ModelType::N_MODELTYPES. */ Uml::ModelType::Enum UMLDoc::rootFolderType(UMLObject *obj) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { const Uml::ModelType::Enum m = Uml::ModelType::fromInt(i); if (obj == m_root[m]) { return m; } } return Uml::ModelType::N_MODELTYPES; } /** * Read property of IDChangeLog* m_pChangeLog. * * @return Pointer to the IDChangeLog object. */ IDChangeLog* UMLDoc::changeLog() { return m_pChangeLog; } /** * Opens a Paste session, deletes the old ChangeLog and * creates an empty one. */ void UMLDoc::beginPaste() { if (m_pChangeLog) { delete m_pChangeLog; m_pChangeLog = 0; } m_pChangeLog = new IDChangeLog; } /** * Closes a paste session, deletes the ChangeLog. */ void UMLDoc::endPaste() { if (m_pChangeLog) { delete m_pChangeLog; m_pChangeLog = 0; } } /** * Assigns a New ID to an Object, and also logs the assignment * to its internal ChangeLog. * * @param oldID The present ID of the object. * @return The new ID assigned to the object. */ Uml::ID::Type UMLDoc::assignNewID(Uml::ID::Type oldID) { Uml::ID::Type result = UniqueID::gen(); if (m_pChangeLog) { m_pChangeLog->addIDChange(oldID, result); } return result; } /** * Returns the documentation for the project. * * @return The documentation text of this UMLDoc. */ QString UMLDoc::documentation() const { return m_Doc; } /** * Sets the documentation for the project. * * @param doc The documentation to set for this UMLDoc. */ void UMLDoc::setDocumentation(const QString &doc) { m_Doc = doc; } /** * Adds an already created UMLView to the document, it gets * assigned a new ID, if its name is already in use then the * function appends a number to it to differentiate it from * the others; this number is incremental so if number 1 is in * use then it tries 2 and then 3 and so on * * @param pView Pointer to the UMLView to add. * @return True if operation successful. */ bool UMLDoc::addUMLView(UMLView * pView) { if (!pView || !m_pChangeLog) { return false; } Uml::ID::Type oldID = pView->umlScene()->ID(); int i = 0; QString viewName = pView->umlScene()->name(); QString name = viewName; while (findView(pView->umlScene()->type(), name) != 0) { name = viewName + QLatin1Char('_') + QString::number(++i); } if (i) { //If name was modified pView->umlScene()->setName(name); } Uml::ID::Type newID = assignNewID(oldID); pView->umlScene()->setID(newID); pView->umlScene()->activateAfterLoad(true); pView->umlScene()->endPartialWidgetPaste(); pView->umlScene()->setOptionState(Settings::optionState()); addView(pView); emit sigDiagramCreated(pView->umlScene()->ID()); setModified(true); return true; } /** * Activate all the diagrams/views after loading so all their * widgets keep their IDs. */ void UMLDoc::activateAllViews() { // store old setting - for restore of last setting bool m_bLoading_old = m_bLoading; m_bLoading = true; //this is to prevent document becoming modified when activating a view for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->activateViews(); } m_bLoading = m_bLoading_old; } /** * Sets the default settings to the given settings. * @param optionState settings */ void UMLDoc::settingsChanged(Settings::OptionState &optionState) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->setViewOptions(optionState); } initSaveTimer(); } /** * Sets up the autosave timer. */ void UMLDoc::initSaveTimer() { if (m_pAutoSaveTimer) { m_pAutoSaveTimer->stop(); disconnect(m_pAutoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); delete m_pAutoSaveTimer; m_pAutoSaveTimer = 0; } Settings::OptionState optionState = Settings::optionState(); if (optionState.generalState.autosave) { m_pAutoSaveTimer = new QTimer(this); connect(m_pAutoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); m_pAutoSaveTimer->setSingleShot(false); m_pAutoSaveTimer->start(optionState.generalState.autosavetime * 60000); } } /** * Called after a specified time to autosave the document. */ void UMLDoc::slotAutoSave() { //Only save if modified. if (!m_modified) { return; } #if QT_VERSION >= 0x050000 QUrl tempUrl = m_doc_url; #else KUrl tempUrl = m_doc_url; #endif if (tempUrl.fileName() == i18n("Untitled")) { #if QT_VERSION >= 0x050000 tempUrl.setScheme(QLatin1String("file")); #endif tempUrl.setPath(QDir::homePath() + i18n("/autosave%1", QLatin1String(".xmi"))); saveDocument(tempUrl); setUrlUntitled(); m_modified = true; UMLApp::app()->setModified(m_modified); } else { // 2004-05-17 Achim Spangler #if QT_VERSION >= 0x050000 QUrl orgDocUrl = m_doc_url; #else KUrl orgDocUrl = m_doc_url; #endif QString orgFileName = m_doc_url.fileName(); // don't overwrite manually saved file with autosave content QString fileName = tempUrl.fileName(); Settings::OptionState optionState = Settings::optionState(); fileName.replace(QLatin1String(".xmi"), optionState.generalState.autosavesuffix); #if QT_VERSION >= 0x050000 tempUrl.setUrl(tempUrl.toString(QUrl::RemoveFilename) + fileName); #else tempUrl.setFileName(fileName); #endif // End Achim Spangler saveDocument(tempUrl); // 2004-05-17 Achim Spangler // re-activate m_modified if autosave is writing to other file // than the main project file->autosave-suffix != ".xmi" if (optionState.generalState.autosavesuffix != QLatin1String(".xmi")) { m_modified = true; UMLApp::app()->setModified(m_modified); } // restore original file name - // UMLDoc::saveDocument() sets doc_url to filename which is given as autosave-filename setUrl(orgDocUrl); UMLApp * pApp = UMLApp::app(); pApp->setCaption(orgFileName, isModified()); // End Achim Spangler } } /** * Signal a view/diagram has been renamed. */ void UMLDoc::signalDiagramRenamed(UMLView* view) { if (view) { Settings::OptionState optionState = Settings::optionState(); if (optionState.generalState.tabdiagrams) { UMLApp::app()->tabWidget()->setTabText(UMLApp::app()->tabWidget()->indexOf(view), view->umlScene()->name()); } emit sigDiagramRenamed(view->umlScene()->ID()); } else { uError() << "Cannot signal diagram renamed - view is NULL!"; } } /** * Calls the active code generator to create its default datatypes. */ void UMLDoc::addDefaultDatatypes() { CodeGenerator *cg = UMLApp::app()->generator(); if (cg == 0) { DEBUG(DBG_SRC) << "CodeGenerator is still NULL"; return; } QStringList entries = cg->defaultDatatypes(); QStringList::Iterator end(entries.end()); for (QStringList::Iterator it = entries.begin(); it != end; ++it) { createDatatype(*it); } UMLApp::app()->listView()->closeDatatypesFolder(); } /** * Add a datatype if it doesn't already exist. * Used by code generators and attribute dialog. */ void UMLDoc::createDatatype(const QString &name) { UMLObjectList &datatypes = m_datatypeRoot->containedObjects(); UMLObject* umlobject = Model_Utils::findUMLObject(datatypes, name, UMLObject::ot_Datatype, m_datatypeRoot); if (!umlobject) { Object_Factory::createUMLObject(UMLObject::ot_Datatype, name, m_datatypeRoot); } } /** * Make a popup menu for the tabs * signalled from tabWidget's contextMenu(). */ void UMLDoc::slotDiagramPopupMenu(QWidget* umlview, const QPoint& point) { UMLView* view = (UMLView*) umlview; UMLListViewItem::ListViewType type = UMLListViewItem::lvt_Unknown; switch (view->umlScene()->type()) { case Uml::DiagramType::Class: type = UMLListViewItem::lvt_Class_Diagram; break; case Uml::DiagramType::UseCase: type = UMLListViewItem::lvt_UseCase_Diagram; break; case Uml::DiagramType::Sequence: type = UMLListViewItem::lvt_Sequence_Diagram; break; case Uml::DiagramType::Collaboration: type = UMLListViewItem::lvt_Collaboration_Diagram; break; case Uml::DiagramType::State: type = UMLListViewItem::lvt_State_Diagram; break; case Uml::DiagramType::Activity: type = UMLListViewItem::lvt_Activity_Diagram; break; case Uml::DiagramType::Component: type = UMLListViewItem::lvt_Component_Diagram; break; case Uml::DiagramType::Deployment: type = UMLListViewItem::lvt_Deployment_Diagram; break; case Uml::DiagramType::EntityRelationship: type = UMLListViewItem::lvt_EntityRelationship_Diagram; break; default: uWarning() << "unknown diagram type " << view->umlScene()->type(); return; }//end switch UMLListViewItem item((UMLListView *)0, QString(), type); UMLListViewPopupMenu popup(UMLApp::app()->mainViewWidget(), &item); QAction *triggered = popup.exec(point); view->umlScene()->slotMenuSelection(triggered); } /** * Function for comparing tags in XMI files. */ bool UMLDoc::tagEq (const QString& inTag, const QString& inPattern) { QString tag = inTag; QString pattern = inPattern; tag.remove(QRegExp(QLatin1String("^\\w+:"))); // remove leading "UML:" or other int patSections = pattern.count(QLatin1Char('.')) + 1; QString tagEnd = tag.section(QLatin1Char('.'), -patSections); return (tagEnd.toLower() == pattern.toLower()); }