diff --git a/umbrello/dialogs/dialog_utils.cpp b/umbrello/dialogs/dialog_utils.cpp index fc22c741e..c1ff409dd 100644 --- a/umbrello/dialogs/dialog_utils.cpp +++ b/umbrello/dialogs/dialog_utils.cpp @@ -1,263 +1,256 @@ /*************************************************************************** * 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 "dialog_utils.h" // app includes #include "debug_utils.h" #include "uml.h" #include "umldoc.h" #include "stereotype.h" #include "umlwidget.h" #include "dontaskagain.h" #include "model_utils.h" #include "widget_utils.h" // kde includes #include #include #include #include // qt includes #include #include #include DefineDontAskAgainItem(allItem, QLatin1String("all"), i18n("Enable all messages")); DefineDontAskAgainItem(askDeleteAssociationItem, QLatin1String("delete-association"), i18n("Enable 'delete association' related messages")); DefineDontAskAgainItem(askDeleteDiagramItem, QLatin1String("delete-diagram"), i18n("Enable 'delete diagram' related messages")); namespace Dialog_Utils { /** * Create a labeled text lineedit widget. * * @param layout The QGridLayout to use. * @param row The row number within the QGridLayout. * @param label The QLabel object allocated (return value) * @param labelText The label text. * @param editField The KLineEdit object allocated (return value) * @param editFieldText Initialization text in the editField (optional.) * @return a pointer to the KLineEdit so you can setFocus() if necessary */ KLineEdit* makeLabeledEditField(QGridLayout* layout, int row, QLabel* &label, const QString& labelText, KLineEdit* &editField, const QString& editFieldText /* = QString() */) { label = new QLabel(labelText); layout->addWidget(label, row, 0); editField = new KLineEdit(editFieldText); layout->addWidget(editField, row, 1); label->setBuddy(editField); return editField; } /** * Helper function for requesting a name for an UMLWidget using a dialog. * * @param targetWidget By-reference pointer to the widget to request the name for. * The widget may be deallocated, and the pointer returned * set to 0, if the user presses Cancel in the dialog. * @param dialogTitle Title of the dialog. * @param dialogPrompt Prompt of the dialog. * @param defaultName Default value of the name field. */ void askNameForWidget(UMLWidget * &targetWidget, const QString& dialogTitle, const QString& dialogPrompt, const QString& defaultName) { QString name = defaultName; if (askName(dialogTitle, dialogPrompt, name)) { targetWidget->setName(name); } else { delete targetWidget; targetWidget = 0; } } /** * Helper function for requesting a name using a dialog. * * @param title Title of the dialog. * @param prompt Prompt of the dialog. * @param name Default value of the name field. * @return true on user pressed okay * @return false on user pressed cancel */ bool askName(const QString& title, const QString& prompt, QString& name) { bool ok; #if QT_VERSION >= 0x050000 name = QInputDialog::getText((QWidget*)UMLApp::app(), title, prompt, QLineEdit::Normal, name, &ok); #else name = KInputDialog::getText(title, prompt, name, &ok, (QWidget*)UMLApp::app()); #endif return ok; } /** * Ask the user for permission to delete an association. * * @return true - user want to continue * @return false - user want to cancel */ bool askDeleteAssociation() { return KMessageBox::warningContinueCancel( UMLApp::app(), i18n("You are about to delete an association. Do you really want to continue?"), i18n("Delete Association"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), askDeleteAssociationItem.name()) == KMessageBox::Continue; } /** * Ask the user for permission to delete a diagram. * * @return true - user want to continue * @return false - user want to cancel */ bool askDeleteDiagram(const QString &name) { QString text = name.isEmpty() ? i18n("You are about to delete the entire diagram.\nAre you sure?") : i18n("Are you sure you want to delete diagram %1?", name); return KMessageBox::warningContinueCancel( UMLApp::app(), text, i18n("Delete Diagram?"), KGuiItem(i18n("&Delete")), KStandardGuiItem::cancel(), askDeleteDiagramItem.name()) == KMessageBox::Continue; } /** * Ask the user for a new widget name * * @return true on user pressed okay * @return false on user pressed cancel */ bool askNewName(WidgetBase::WidgetType type, QString &name) { QString title = Widget_Utils::newTitle(type); QString text = Widget_Utils::newText(type); return askName(title, text, name); } /** * Ask the user for renaming a widget name * * @return true on user pressed okay * @return false on user pressed cancel */ bool askRenameName(WidgetBase::WidgetType type, QString &name) { QString title = Widget_Utils::renameTitle(type); QString text = Widget_Utils::renameText(type); return askName(title, text, name); } /** * Ask the user for a default new widget name * * The name is predefined by the widgets type default name * * @return true on user pressed okay * @return false on user pressed cancel */ bool askDefaultNewName(WidgetBase::WidgetType type, QString &name) { name = Widget_Utils::defaultWidgetName(type); return askNewName(type, name); } /** * Ask the user for a new object name * * @return true on user pressed okay * @return false on user pressed cancel */ bool askNewName(UMLObject::ObjectType type, QString &name) { QString title = Model_Utils::newTitle(type); QString text = Model_Utils::newText(type); return askName(title, text, name); } /** * Ask the user for renaming a widget name * * @return true on user pressed okay * @return false on user pressed cancel */ bool askRenameName(UMLObject::ObjectType type, QString &name) { QString title = Model_Utils::renameTitle(type); QString text = Model_Utils::renameText(type); return askName(title, text, name); } /** * Ask the user for a default new widget name * * The name is predefined by the widgets type default name * * @return true on user pressed okay * @return false on user pressed cancel */ bool askDefaultNewName(UMLObject::ObjectType type, QString &name) { - name = Model_Utils::uniqObjectName(type); + name = Model_Utils::uniqObjectName(type, nullptr); return askNewName(type, name); } /** * Helper function for inserting available stereotypes into a KComboBox * * @param kcb The KComboBox into which to insert the stereotypes * @param type The stereotype to activate */ void insertStereotypesSorted(KComboBox *kcb, const QString& type) { UMLDoc *umldoc = UMLApp::app()->document(); QStringList types; types << QString(); // an empty stereotype is the default foreach (UMLStereotype* ust, umldoc->stereotypes()) { types << ust->name(); } // add the given parameter if (!types.contains(type)) { types << type; } types.sort(); kcb->clear(); kcb->insertItems(-1, types); // select the given parameter int currentIndex = kcb->findText(type); if (currentIndex > -1) { kcb->setCurrentIndex(currentIndex); } kcb->completionObject()->addItem(type); } -bool askDefaultNewName(UMLObject::ObjectType type, QString &name) -{ - name = Model_Utils::uniqModelName(type); - return askNewName(type, name); - -} - } // end namespace Dialog_Utils diff --git a/umbrello/dialogs/dialog_utils.h b/umbrello/dialogs/dialog_utils.h index cc762c25c..8f8eb927d 100644 --- a/umbrello/dialogs/dialog_utils.h +++ b/umbrello/dialogs/dialog_utils.h @@ -1,62 +1,63 @@ /*************************************************************************** * 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 * ***************************************************************************/ #ifndef DIALOG_UTILS_H #define DIALOG_UTILS_H +#include "umlobject.h" #include "widgetbase.h" #include #if QT_VERSION < 0x050000 #include #else #include #endif class QGridLayout; class QLabel; class UMLWidget; class KLineEdit; class KComboBox; /** * Dialog utilities. * @author Oliver Kellogg * Bugs and comments to umbrello-devel@kde.org or http://bugs.kde.org */ namespace Dialog_Utils { KLineEdit* makeLabeledEditField(QGridLayout *layout, int row, QLabel * &label, const QString& labelText, KLineEdit * &editField, const QString& editFieldText = QString()); void askNameForWidget(UMLWidget * &targetWidget, const QString& dialogTitle, const QString& dialogPrompt, const QString& defaultName); bool askName(const QString& title, const QString& prompt, QString& name); bool askNewName(WidgetBase::WidgetType type, QString &name); bool askRenameName(WidgetBase::WidgetType type, QString &name); bool askDefaultNewName(WidgetBase::WidgetType type, QString &name); bool askNewName(UMLObject::ObjectType type, QString &name); bool askRenameName(UMLObject::ObjectType type, QString &name); bool askDefaultNewName(UMLObject::ObjectType type, QString &name); void insertStereotypesSorted(KComboBox *kcb, const QString& type); bool askDeleteAssociation(); bool askDeleteDiagram(const QString &name = QString()); } #endif diff --git a/umbrello/dialogs/pages/activitypage.cpp b/umbrello/dialogs/pages/activitypage.cpp index 7709dc782..e6ede50d0 100644 --- a/umbrello/dialogs/pages/activitypage.cpp +++ b/umbrello/dialogs/pages/activitypage.cpp @@ -1,370 +1,365 @@ /*************************************************************************** * 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 * ***************************************************************************/ #include "activitypage.h" #include "debug_utils.h" #include "dialog_utils.h" #include "dialogspopupmenu.h" #include "statewidget.h" #include "uml.h" #if QT_VERSION < 0x050000 #include #endif #include #include #include #include #if QT_VERSION >= 0x050000 #include #endif #include #include #include #include #include /** * Constructor. */ ActivityPage::ActivityPage(QWidget * pParent, StateWidget * pWidget) : DialogPageBase(pParent) { m_pStateWidget = pWidget; setupPage(); } /** * Destructor. */ ActivityPage::~ActivityPage() { } /** * Sets up the page. */ void ActivityPage::setupPage() { int margin = fontMetrics().height(); QVBoxLayout * mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(10); m_pActivityGB = new QGroupBox(i18n("Activities"), this); // vertical box layout for the activity lists, arrow buttons and the button box QVBoxLayout* listVBoxLayout = new QVBoxLayout(m_pActivityGB); listVBoxLayout->setMargin(margin); listVBoxLayout->setSpacing(10); //horizontal box contains the list box and the move up/down buttons QHBoxLayout* listHBoxLayout = new QHBoxLayout(); listHBoxLayout->setSpacing(10); listVBoxLayout->addItem(listHBoxLayout); m_pActivityLW = new QListWidget(m_pActivityGB); m_pActivityLW->setContextMenuPolicy(Qt::CustomContextMenu); listHBoxLayout->addWidget(m_pActivityLW); QVBoxLayout * buttonLayout = new QVBoxLayout(); listHBoxLayout->addItem(buttonLayout); m_pTopArrowB = new QToolButton(m_pActivityGB); m_pTopArrowB->setArrowType(Qt::UpArrow); m_pTopArrowB->setEnabled(false); m_pTopArrowB->setToolTip(i18n("Move selected item to the top")); buttonLayout->addWidget(m_pTopArrowB); m_pUpArrowB = new QToolButton(m_pActivityGB); m_pUpArrowB->setArrowType(Qt::UpArrow); m_pUpArrowB->setEnabled(false); m_pUpArrowB->setToolTip(i18n("Move selected item up")); buttonLayout->addWidget(m_pUpArrowB); m_pDownArrowB = new QToolButton(m_pActivityGB); m_pDownArrowB->setArrowType(Qt::DownArrow); m_pDownArrowB->setEnabled(false); m_pDownArrowB->setToolTip(i18n("Move selected item down")); buttonLayout->addWidget(m_pDownArrowB); m_pBottomArrowB = new QToolButton(m_pActivityGB); m_pBottomArrowB->setArrowType(Qt::DownArrow); m_pBottomArrowB->setEnabled(false); m_pBottomArrowB->setToolTip(i18n("Move selected item to the bottom")); buttonLayout->addWidget(m_pBottomArrowB); #if QT_VERSION >= 0x050000 QDialogButtonBox* buttonBox = new QDialogButtonBox(m_pActivityGB); QPushButton* newActivity = buttonBox->addButton(i18n("New Activity..."), QDialogButtonBox::ActionRole); connect(newActivity, SIGNAL(clicked()), this, SLOT(slotNewActivity())); m_pDeleteActivityButton = buttonBox->addButton(i18n("Delete"), QDialogButtonBox::ActionRole); connect(m_pDeleteActivityButton, SIGNAL(clicked()), this, SLOT(slotDelete())); m_pRenameButton = buttonBox->addButton(i18n("Rename"), QDialogButtonBox::ActionRole); connect(m_pRenameButton, SIGNAL(clicked()), this, SLOT(slotRename())); #else KDialogButtonBox* buttonBox = new KDialogButtonBox(m_pActivityGB); buttonBox->addButton(i18n("New Activity..."), KDialogButtonBox::ActionRole, this, SLOT(slotNewActivity())); m_pDeleteActivityButton = buttonBox->addButton(i18n("Delete"), KDialogButtonBox::ActionRole, this, SLOT(slotDelete())); m_pRenameButton = buttonBox->addButton(i18n("Rename"), KDialogButtonBox::ActionRole, this, SLOT(slotRename())); #endif listVBoxLayout->addWidget(buttonBox); mainLayout->addWidget(m_pActivityGB); //now fill activity list box QStringList list = m_pStateWidget->activities(); QStringList::ConstIterator end(list.end()); for(QStringList::ConstIterator it(list.begin()); it != end; ++it) { m_pActivityLW->addItem(*it); } //now setup the signals connect(m_pActivityLW, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotClicked(QListWidgetItem*))); connect(m_pActivityLW, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotRightButtonPressed(QPoint))); connect(m_pTopArrowB, SIGNAL(clicked()), this, SLOT(slotTopClicked())); connect(m_pUpArrowB, SIGNAL(clicked()), this, SLOT(slotUpClicked())); connect(m_pDownArrowB, SIGNAL(clicked()), this, SLOT(slotDownClicked())); connect(m_pBottomArrowB, SIGNAL(clicked()), this, SLOT(slotBottomClicked())); connect(m_pActivityLW, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(slotDoubleClicked(QListWidgetItem*))); enableWidgets(false); } /** * Sets the activities of the widget. */ void ActivityPage::updateActivities() { QStringList list; int count = m_pActivityLW->count(); for (int i = 0; i < count; ++i) { list.append(m_pActivityLW->item(i)->text()); } m_pStateWidget->setActivities(list); } /** * Popup menu item selected. */ void ActivityPage::slotMenuSelection(QAction* action) { ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); switch(sel) { case ListPopupMenu::mt_New_Activity: slotNewActivity(); break; case ListPopupMenu::mt_Delete: slotDelete(); break; case ListPopupMenu::mt_Rename: slotRename(); break; default: uDebug() << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; } } void ActivityPage::slotNewActivity() { - QString name = i18n("new activity"); - bool ok = Dialog_Utils::askName(i18n("New Activity"), - i18n("Enter the name of the new activity:"), - name); - if (ok && name.length() > 0) { + QString name; + if (Dialog_Utils::askDefaultNewName(WidgetBase::wt_Activity, name) && name.length() > 0) { m_pActivityLW->addItem(name); m_pActivityLW->setCurrentRow(m_pActivityLW->count() - 1); m_pStateWidget->addActivity(name); slotClicked(m_pActivityLW->item(m_pActivityLW->count() - 1)); } } void ActivityPage::slotDelete() { QString name = m_pActivityLW->currentItem()->text(); m_pStateWidget->removeActivity(name); m_pActivityLW->takeItem(m_pActivityLW->currentRow()); slotClicked(0); } void ActivityPage::slotRename() { QString name = m_pActivityLW->currentItem()->text(); QString oldName = name; - bool ok = Dialog_Utils::askName(i18n("Rename Activity"), - i18n("Enter the new name of the activity:"), - name); + bool ok = Dialog_Utils::askRenameName(WidgetBase::wt_Activity, name); if (ok && name.length() > 0) { QListWidgetItem* item = m_pActivityLW->currentItem(); item->setText(name); m_pStateWidget->renameActivity(oldName, name); slotClicked(item); } } void ActivityPage::slotRightButtonPressed(const QPoint & p) { DialogsPopupMenu::TriggerType type = DialogsPopupMenu::tt_Undefined; QListWidgetItem* item = m_pActivityLW->itemAt(p); if (item) { //pressed on an item type = DialogsPopupMenu::tt_Activity_Selected; } else { //pressed into fresh air type = DialogsPopupMenu::tt_New_Activity; } DialogsPopupMenu popup(this, type); QAction *triggered = popup.exec(m_pActivityLW->mapToGlobal(p)); slotMenuSelection(triggered); } void ActivityPage::slotTopClicked() { int count = m_pActivityLW->count(); int index = m_pActivityLW->currentRow(); //shouldn't occur, but just in case if (count <= 1 || index <= 0) return; //swap the text around in the ListBox QListWidgetItem* item = m_pActivityLW->takeItem(index); m_pActivityLW->insertItem(0, item); //set the moved item selected m_pActivityLW->setCurrentRow(0); slotClicked(m_pActivityLW->currentItem()); } void ActivityPage::slotUpClicked() { int count = m_pActivityLW->count(); int index = m_pActivityLW->currentRow(); //shouldn't occur, but just in case if (count <= 1 || index <= 0) { return; } QListWidgetItem* item = m_pActivityLW->takeItem(index); m_pActivityLW->insertItem(index - 1, item); //set the moved atttribute selected m_pActivityLW->setCurrentRow(index - 1); slotClicked(m_pActivityLW->currentItem()); } void ActivityPage::slotDownClicked() { int count = m_pActivityLW->count(); int index = m_pActivityLW->currentRow(); //shouldn't occur, but just in case if (count <= 1 || index >= count - 1) { return; } QListWidgetItem* item = m_pActivityLW->takeItem(index); m_pActivityLW->insertItem(index + 1, item); //set the moved atttribute selected m_pActivityLW->setCurrentRow(index + 1); slotClicked(m_pActivityLW->currentItem()); } void ActivityPage::slotBottomClicked() { int count = m_pActivityLW->count(); int index = m_pActivityLW->currentRow(); //shouldn't occur, but just in case if (count <= 1 || index >= count - 1) return; QListWidgetItem* item = m_pActivityLW->takeItem(index); m_pActivityLW->insertItem(m_pActivityLW->count(), item); //set the moved item selected m_pActivityLW->setCurrentRow(m_pActivityLW->count() - 1); slotClicked(m_pActivityLW->currentItem()); } void ActivityPage::slotClicked(QListWidgetItem *item) { //make sure clicked on an item if (!item) { enableWidgets(false); m_pActivityLW->clearSelection(); } else { enableWidgets(true); } } void ActivityPage::slotDoubleClicked(QListWidgetItem* item) { if (item) { slotRename(); } } /** * Set the state of the widgets on the page with the given value. * @param state The state to set the widgets as. */ void ActivityPage::enableWidgets(bool state) { if (!state) { m_pTopArrowB->setEnabled(false); m_pUpArrowB->setEnabled(false); m_pDownArrowB->setEnabled(false); m_pBottomArrowB->setEnabled(false); m_pDeleteActivityButton->setEnabled(false); m_pRenameButton->setEnabled(false); return; } /*now check the order buttons. Double check an item is selected If only one att. in list make sure there disabled. If at top item, only allow down arrow to be enabled. If at bottom item. only allow up arrow to be enabled. */ int index = m_pActivityLW->currentRow(); if (m_pActivityLW->count() == 1 || index == -1) { m_pTopArrowB->setEnabled(false); m_pUpArrowB->setEnabled(false); m_pDownArrowB->setEnabled(false); m_pBottomArrowB->setEnabled(false); } else if (index == 0) { m_pTopArrowB->setEnabled(false); m_pUpArrowB->setEnabled(false); m_pDownArrowB->setEnabled(true); m_pBottomArrowB->setEnabled(true); } else if(index == (int)m_pActivityLW->count() - 1) { m_pTopArrowB->setEnabled(true); m_pUpArrowB->setEnabled(true); m_pDownArrowB->setEnabled(false); m_pBottomArrowB->setEnabled(false); } else { m_pTopArrowB->setEnabled(true); m_pUpArrowB->setEnabled(true); m_pDownArrowB->setEnabled(true); m_pBottomArrowB->setEnabled(true); } m_pDeleteActivityButton->setEnabled(true); m_pRenameButton->setEnabled(true); } diff --git a/umbrello/object_factory.cpp b/umbrello/object_factory.cpp index e5d1da275..aff513332 100644 --- a/umbrello/object_factory.cpp +++ b/umbrello/object_factory.cpp @@ -1,446 +1,444 @@ /*************************************************************************** * 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 * ***************************************************************************/ // own header #include "object_factory.h" // app includes #include "actor.h" #include "artifact.h" #include "association.h" #include "attribute.h" #include "category.h" #include "checkconstraint.h" #include "classifier.h" #include "cmds.h" #include "codegenerator.h" #include "component.h" #include "datatype.h" #include "debug_utils.h" #include "dialog_utils.h" #include "enum.h" #include "entity.h" #include "folder.h" #include "foreignkeyconstraint.h" #include "instance.h" #include "model_utils.h" #include "node.h" #include "package.h" #include "port.h" #include "operation.h" #include "stereotype.h" #include "usecase.h" #include "uml.h" #include "umldoc.h" #include "umlobject.h" #include "umlpackagelist.h" #include "uniqueconstraint.h" #include "uniqueid.h" // kde includes #include #include // qt includes // qt includes #include #include #include namespace Object_Factory { Uml::ID::Type g_predefinedId = Uml::ID::None; /** * Control whether the createUMLObject() solicits a new unique ID for the * created object. * By default, unique ID generation is turned on. * * @param yesno False turns UID generation off, true turns it on. */ void assignUniqueIdOnCreation(bool yesno) { if (yesno) g_predefinedId = Uml::ID::None; else g_predefinedId = Uml::ID::Reserved; } /** * Return whether unique ID generation is on or off. */ bool assignUniqueIdOnCreation() { return (g_predefinedId == Uml::ID::None); } /** * Creates a new UMLObject of the given type. * No check is made for whether the object named \a name already exists. * If the name shall be checked then use @ref createUMLObject. * * @param type The type of @ref UMLObject to create. * @param name Name to give to the object (mandatory.) * @param parentPkg The object's parent package. * @param undoable Whether to insert the object creation into the undo stack (default: true.) */ UMLObject* createNewUMLObject(UMLObject::ObjectType type, const QString &name, UMLPackage *parentPkg, bool undoable /* = true */) { if (parentPkg == 0) { uError() << name << ": parentPkg is NULL"; return 0; } QPointer o = 0; switch (type) { case UMLObject::ot_Actor: o = new UMLActor(name, g_predefinedId); break; case UMLObject::ot_UseCase: o = new UMLUseCase(name, g_predefinedId); break; case UMLObject::ot_Class: o = new UMLClassifier(name, g_predefinedId); break; case UMLObject::ot_Package: o = new UMLPackage(name, g_predefinedId); break; case UMLObject::ot_Component: o = new UMLComponent(name, g_predefinedId); break; case UMLObject::ot_Port: o = new UMLPort(name, g_predefinedId); break; case UMLObject::ot_Node: o = new UMLNode(name, g_predefinedId); break; case UMLObject::ot_Artifact: o = new UMLArtifact(name, g_predefinedId); break; case UMLObject::ot_Interface: { UMLClassifier *c = new UMLClassifier(name, g_predefinedId); c->setBaseType(UMLObject::ot_Interface); o = c; break; } case UMLObject::ot_Datatype: { UMLDatatype *c = new UMLDatatype(name, g_predefinedId); o = c; break; } case UMLObject::ot_Instance: o = new UMLInstance(name, g_predefinedId); break; case UMLObject::ot_Enum: o = new UMLEnum(name, g_predefinedId); break; case UMLObject::ot_Entity: o = new UMLEntity(name, g_predefinedId); break; case UMLObject::ot_Folder: o = new UMLFolder(name, g_predefinedId); break; case UMLObject::ot_Category: o = new UMLCategory(name, g_predefinedId); break; case UMLObject::ot_SubSystem: { o = new UMLPackage(name, g_predefinedId); o->setStereotypeCmd(QLatin1String("subsystem")); break; } default: uWarning() << "error unknown type: " << UMLObject::toString(type); return 0; } if (!undoable) { o->setUMLPackage(parentPkg); UMLApp::app()->document()->signalUMLObjectCreated(o); qApp->processEvents(); return o; } // One user action can result in multiple commands when adding objects via // the toolbar. E.g. "create uml object" and "create widget". Wrap all // commands in one macro. When adding items via list view, this macro will // contain only the "create uml object" command. UMLApp::app()->beginMacro(i18n("Create UML object : %1", name)); o->setUMLPackage(parentPkg); UMLApp::app()->executeCommand(new Uml::CmdCreateUMLObject(o)); UMLApp::app()->document()->signalUMLObjectCreated(o); qApp->processEvents(); UMLApp::app()->endMacro(); return o; } /** * Creates a UMLObject of the given type. * * @param type The type of @ref UMLObject to create. * @param n A name to give to the object (optional.) * If not given then an input dialog prompts * the user to supply a name. * @param parentPkg The object's parent package. * @param solicitNewName Ask user for a different name if an object * of the given name already exists. * If set to false and the name already exists * then the existing object is returned. * The default is to ask for the new name. */ UMLObject* createUMLObject(UMLObject::ObjectType type, const QString &n, UMLPackage *parentPkg /* = 0 */, bool solicitNewName /* = true */) { UMLDoc *doc = UMLApp::app()->document(); if (parentPkg == 0) { if (type == UMLObject::ot_Datatype) { parentPkg = doc->datatypeFolder(); } else { Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(type); uDebug() << "Object_Factory::createUMLObject(" << n << "): " << "parentPkg is not set, assuming Model_Type " << Uml::ModelType::toString(mt); parentPkg = doc->rootFolder(mt); } } if (!n.isEmpty()) { UMLObject *o = doc->findUMLObject(n, type, parentPkg); if (o == 0) { o = createNewUMLObject(type, n, parentPkg); return o; } if (!solicitNewName) { if (type == UMLObject::ot_UMLObject || o->baseType() == type) { uDebug() << o->name() << " already known - returning existing object"; return o; } uWarning() << o->name() << " exists but is of type " << UMLObject::toString(o->baseType()) << " - creating new object of type " << UMLObject::toString(type); o = createNewUMLObject(type, n, parentPkg, false); return o; } } bool bValidNameEntered = false; QString name = Model_Utils::uniqObjectName(type, parentPkg, n); if (name == n) { bValidNameEntered = true; } while (bValidNameEntered == false) { - bool ok = Dialog_Utils::askName(i18nc("UMLObject name", "Name"), - i18n("Enter name:"), - name); + bool ok = Dialog_Utils::askNewName(type, name); if (!ok) { return 0; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); continue; } if (type != UMLObject::ot_Datatype) { CodeGenerator *codegen = UMLApp::app()->generator(); if (codegen != 0 && codegen->isReservedKeyword(name)) { KMessageBox::error(0, i18n("This is a reserved keyword for the language of the configured code generator."), i18n("Reserved Keyword")); continue; } } if (! doc->isUnique(name, parentPkg) && type != UMLObject::ot_Instance) { KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); continue; } bValidNameEntered = true; } UMLObject *o = createNewUMLObject(type, name, parentPkg); return o; } UMLAttribute *createAttribute(UMLObject *parent, const QString& name, UMLObject *type) { UMLAttribute *attr = new UMLAttribute(parent); attr->setName(name); attr->setType(type); if (g_predefinedId == Uml::ID::None) attr->setID(UniqueID::gen()); return attr; } UMLOperation *createOperation(UMLClassifier *parent, const QString& name) { UMLOperation *op = new UMLOperation(parent, name, g_predefinedId); return op; } /** * Creates an operation, attribute, template, or enum literal * for the parent classifier. * * @param parent The parent concept * @param type The type to create * @param name Optional name of object (skips creation dialog) * @return Pointer to the UMLClassifierListItem created */ UMLClassifierListItem* createChildObject(UMLClassifier* parent, UMLObject::ObjectType type, const QString& name) { UMLObject* returnObject = 0; switch (type) { case UMLObject::ot_Attribute: { UMLClassifier *c = parent->asUMLClassifier(); if (c && !c->isInterface()) returnObject = c->createAttribute(name); break; } case UMLObject::ot_EntityAttribute: { UMLEntity *e = parent->asUMLEntity(); if (e) { returnObject = e->createAttribute(name); } break; } case UMLObject::ot_InstanceAttribute: { UMLInstance *c = parent->asUMLInstance(); if(c){ returnObject = c->createAttribute(name); } break; } case UMLObject::ot_Operation: { UMLClassifier *c = parent->asUMLClassifier(); if (c) returnObject = c->createOperation(name); break; } case UMLObject::ot_Template: { UMLClassifier *c = parent->asUMLClassifier(); if (c) returnObject = c->createTemplate(name); break; } case UMLObject::ot_EnumLiteral: { UMLEnum* umlenum = parent->asUMLEnum(); if (umlenum) { returnObject = umlenum->createEnumLiteral(name); } break; } case UMLObject::ot_UniqueConstraint: { UMLEntity* umlentity = parent->asUMLEntity(); if (umlentity) { returnObject = umlentity->createUniqueConstraint(name); } break; } case UMLObject::ot_ForeignKeyConstraint: { UMLEntity* umlentity = parent->asUMLEntity(); if (umlentity) { returnObject = umlentity->createForeignKeyConstraint(name); } break; } case UMLObject::ot_CheckConstraint: { UMLEntity* umlentity = parent->asUMLEntity(); if (umlentity) { returnObject = umlentity->createCheckConstraint(name); } break; } default: uDebug() << "ERROR UMLDoc::createChildObject type:" << UMLObject::toString(type); } return returnObject->asUMLClassifierListItem(); } /** * Make a new UMLObject according to the given XMI tag. * Used by loadFromXMI1 and clipboard paste. */ UMLObject* makeObjectFromXMI(const QString& xmiTag, const QString& stereoID /* = QString() */) { UMLObject* pObject = 0; if (UMLDoc::tagEq(xmiTag, QLatin1String("UseCase"))) { pObject = new UMLUseCase(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Actor"))) { pObject = new UMLActor(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Class"))) { pObject = new UMLClassifier(); } else if(UMLDoc::tagEq(xmiTag, QLatin1String("Instance"))) { pObject = new UMLInstance(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Package"))) { if (!stereoID.isEmpty()) { UMLDoc *doc = UMLApp::app()->document(); UMLObject *stereo = doc->findStereotypeById(Uml::ID::fromString(stereoID)); if (stereo && stereo->name() == QLatin1String("folder")) pObject = new UMLFolder(); } if (pObject == 0) pObject = new UMLPackage(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Component"))) { pObject = new UMLComponent(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Port"))) { pObject = new UMLPort(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Node"))) { pObject = new UMLNode(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Artifact"))) { pObject = new UMLArtifact(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Interface"))) { UMLClassifier *c = new UMLClassifier(); c->setBaseType(UMLObject::ot_Interface); pObject = c; } else if (UMLDoc::tagEq(xmiTag, QLatin1String("DataType")) || UMLDoc::tagEq(xmiTag, QLatin1String("Datatype")) // for bkwd compat. || UMLDoc::tagEq(xmiTag, QLatin1String("Primitive")) || UMLDoc::tagEq(xmiTag, QLatin1String("PrimitiveType"))) { UMLDatatype *c = new UMLDatatype(); pObject = c; } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Enumeration")) || UMLDoc::tagEq(xmiTag, QLatin1String("Enum"))) { // for bkwd compat. pObject = new UMLEnum(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Entity"))) { pObject = new UMLEntity(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Category"))) { pObject = new UMLCategory(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Stereotype"))) { pObject = new UMLStereotype(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Association")) || UMLDoc::tagEq(xmiTag, QLatin1String("AssociationClass"))) { pObject = new UMLAssociation(); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Generalization")) || UMLDoc::tagEq(xmiTag, QLatin1String("generalization"))) { pObject = new UMLAssociation(Uml::AssociationType::Generalization); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Realization")) || UMLDoc::tagEq(xmiTag, QLatin1String("Abstraction"))) { pObject = new UMLAssociation(Uml::AssociationType::Realization); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Dependency"))) { pObject = new UMLAssociation(Uml::AssociationType::Dependency); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Aggregation"))) { // Embarcadero's Describe pObject = new UMLAssociation(Uml::AssociationType::Aggregation); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Child2Category"))) { pObject = new UMLAssociation(Uml::AssociationType::Child2Category); } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Category2Parent"))) { pObject = new UMLAssociation(Uml::AssociationType::Category2Parent); } return pObject; } } // end namespace Object_Factory diff --git a/umbrello/stereotypeswindow.cpp b/umbrello/stereotypeswindow.cpp index 96678ed4b..ef677279b 100644 --- a/umbrello/stereotypeswindow.cpp +++ b/umbrello/stereotypeswindow.cpp @@ -1,87 +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) 2015 * * Umbrello UML Modeller Authors * ***************************************************************************/ #include "stereotypeswindow.h" // app includes #include "dialog_utils.h" #include "stereotype.h" #include "models/stereotypesmodel.h" #include "uml.h" #include "umldoc.h" // kde includes #include // qt includes #include #include #include #include StereotypesWindow::StereotypesWindow(const QString &title, QWidget *parent) : QDockWidget(title, parent) { setObjectName(QLatin1String("StereotypesWindow")); QSortFilterProxyModel *proxy = new QSortFilterProxyModel; proxy->setSourceModel(UMLApp::app()->document()->stereotypesModel()); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); m_stereotypesTree = new QTableView; m_stereotypesTree->setModel(proxy); m_stereotypesTree->setSortingEnabled(true); m_stereotypesTree->verticalHeader()->setDefaultSectionSize(20); m_stereotypesTree->verticalHeader()->setVisible(false); #if QT_VERSION >= 0x050000 m_stereotypesTree->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); #else m_stereotypesTree->horizontalHeader()->setResizeMode(QHeaderView::Stretch); #endif setWidget(m_stereotypesTree); connect(m_stereotypesTree, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotStereotypesDoubleClicked(QModelIndex))); } StereotypesWindow::~StereotypesWindow() { QAbstractItemModel *proxy = m_stereotypesTree->model(); delete m_stereotypesTree; delete proxy; } void StereotypesWindow::modified() { UMLStereotype *o = dynamic_cast(QObject::sender()); if (!o) return; int index = UMLApp::app()->document()->stereotypes().indexOf(o); UMLApp::app()->document()->stereotypesModel()->emitDataChanged(index); } void StereotypesWindow::slotStereotypesDoubleClicked(QModelIndex index) { QVariant v = m_stereotypesTree->model()->data(index, Qt::UserRole); if (v.canConvert()) { UMLStereotype *s = v.value(); s->showPropertiesDialog(this); } } void StereotypesWindow::contextMenuEvent(QContextMenuEvent *event) { Q_UNUSED(event); QString name; - if (!Dialog_Utils::askName(i18n("New Stereotype"), i18n("Enter name for new stereotype"), name)) + if (!Dialog_Utils::askDefaultNewName(UMLObject::ot_Stereotype, name)) return; if (UMLApp::app()->document()->findStereotype(name)) return; UMLStereotype *s = new UMLStereotype(name); UMLApp::app()->document()->stereotypesModel()->addStereotype(s); } diff --git a/umbrello/uml1model/folder.cpp b/umbrello/uml1model/folder.cpp index af58d2e83..6edcb7960 100644 --- a/umbrello/uml1model/folder.cpp +++ b/umbrello/uml1model/folder.cpp @@ -1,598 +1,596 @@ /*************************************************************************** * 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 * ***************************************************************************/ // own header #include "folder.h" // app includes #include "debug_utils.h" #include "dialog_utils.h" #include "model_utils.h" #include "object_factory.h" #include "optionstate.h" #include "uml.h" #include "umldoc.h" #include "umlscene.h" #include "umlview.h" // kde includes #include #include // qt includes #include /** * Sets up a Folder. * @param name The name of the Folder. * @param id The unique id of the Folder. A new ID will be generated * if this argument is left away. */ UMLFolder::UMLFolder(const QString & name, Uml::ID::Type id) : UMLPackage(name, id) { m_BaseType = UMLObject::ot_Folder; UMLObject::setStereotypeCmd(QLatin1String("folder")); } /** * Empty destructor. */ UMLFolder::~UMLFolder() { qDeleteAll(m_diagrams); m_diagrams.clear(); } /** * Make a clone of this object. */ UMLObject* UMLFolder::clone() const { UMLFolder *clone = new UMLFolder(); UMLObject::copyInto(clone); return clone; } /** * Set the localized name of this folder. * This is set for the predefined root views (Logical, * UseCase, Component, Deployment, EntityRelationship, * and the Datatypes folder inside the Logical View.) */ void UMLFolder::setLocalName(const QString& localName) { m_localName = localName; } /** * Return the localized name of this folder. * Only useful for the predefined root folders. */ QString UMLFolder::localName() const { return m_localName; } /** * Add a view to the diagram list. */ void UMLFolder::addView(UMLView *view) { m_diagrams.append(view); } /** * Remove a view from the diagram list. */ void UMLFolder::removeView(UMLView *view) { m_diagrams.removeAll(view); } /** * Append the views in this folder to the given diagram list. * @param viewList The UMLViewList to which to append the diagrams. * @param includeNested Whether to include diagrams from nested folders * (default: true.) */ void UMLFolder::appendViews(UMLViewList& viewList, bool includeNested) { if (includeNested) { foreach (UMLObject* o, m_objects) { uIgnoreZeroPointer(o); if (o->baseType() == UMLObject::ot_Folder) { UMLFolder *f = o->asUMLFolder(); f->appendViews(viewList); } } } foreach (UMLView* v, m_diagrams) { viewList.append(v); } } /** * Acivate the views in this folder. * "Activation": Some widgets require adjustments after loading from file, * those are done here. */ void UMLFolder::activateViews() { foreach (UMLObject* o, m_objects) { uIgnoreZeroPointer(o); if (o->baseType() == UMLObject::ot_Folder) { UMLFolder *f = o->asUMLFolder(); f->activateViews(); } } foreach (UMLView* v, m_diagrams) { v->umlScene()->activateAfterLoad(); } // Make sure we have a treeview item for each diagram. // It may happen that we are missing them after switching off tabbed widgets. Settings::OptionState optionState = Settings::optionState(); if (optionState.generalState.tabdiagrams) { return; } Model_Utils::treeViewAddViews(m_diagrams); } /** * Seek a view of the given ID in this folder. * @param id ID of the view to find. * @return Pointer to the view if found, NULL if no view found. */ UMLView *UMLFolder::findView(Uml::ID::Type id) { foreach (UMLView* v, m_diagrams) { if (v && v->umlScene() && v->umlScene()->ID() == id) { return v; } } UMLView* v = 0; UMLPackageList packages; appendPackages(packages); foreach (UMLPackage *o, packages) { if (o->baseType() != UMLObject::ot_Folder) { continue; } UMLFolder *f = o->asUMLFolder(); v = f->findView(id); if (v) { break; } } return v; } /** * Seek a view 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: true.) * @return Pointer to the view found, or NULL if not found. */ UMLView *UMLFolder::findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes) { foreach (UMLView* v, m_diagrams) { if (v->umlScene()->type() == type && v->umlScene()->name() == name) { return v; } } UMLView* v = 0; if (searchAllScopes) { foreach (UMLObject* o, m_objects) { uIgnoreZeroPointer(o); if (o->baseType() != UMLObject::ot_Folder) { continue; } UMLFolder *f = o->asUMLFolder(); v = f->findView(type, name, searchAllScopes); if (v) { break; } } } return v; } /** * Set the options for the views in this folder. */ void UMLFolder::setViewOptions(const Settings::OptionState& optionState) { // for each view update settings foreach (UMLView* v, m_diagrams) { v->umlScene()->setOptionState(optionState); } } /** * Remove all views in this folder. */ void UMLFolder::removeAllViews() { foreach (UMLObject* o, m_objects) { uIgnoreZeroPointer(o); if (o->baseType() != UMLObject::ot_Folder) continue; UMLFolder *f = o->asUMLFolder(); f->removeAllViews(); } foreach (UMLView* v, m_diagrams) { // TODO ------------------ check this code - bad: calling back to UMLDoc::removeView() v->umlScene()->removeAllAssociations(); // note : It may not be apparent, but when we remove all associations // from a view, it also causes any UMLAssociations that lack parent // association widgets (but once had them) to remove themselves from // this document. uDebug() << "removing " << v->umlScene()->name(); UMLApp::app()->document()->removeView(v, false); } qDeleteAll(m_diagrams); m_diagrams.clear(); } /** * Set the folder file name for a separate submodel. */ void UMLFolder::setFolderFile(const QString& fileName) { m_folderFile = fileName; } /** * Get the folder file name for a separate submodel. */ QString UMLFolder::folderFile() const { return m_folderFile; } /** * Auxiliary to saveToXMI1(): Save the contained objects and diagrams. * Can be used regardless of whether saving to the main model file * or to an external folder file (see m_folderFile.) */ void UMLFolder::saveContents1(QDomDocument& qDoc, QDomElement& qElement) { QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); UMLObject *obj = 0; // Save contained objects if any. for (UMLObjectListIt oit(m_objects); oit.hasNext();) { obj = oit.next(); uIgnoreZeroPointer(obj); obj->saveToXMI1 (qDoc, ownedElement); } // Save asscociations if any. for (UMLObjectListIt ait(subordinates()); ait.hasNext();) { obj = ait.next(); obj->saveToXMI1 (qDoc, ownedElement); } qElement.appendChild(ownedElement); // Save diagrams to `extension'. if (m_diagrams.count()) { QDomElement diagramsElement = qDoc.createElement(QLatin1String("diagrams")); if (UMLApp::app()->document()->resolution() != 0.0) diagramsElement.setAttribute(QLatin1String("resolution"), UMLApp::app()->document()->resolution()); foreach (UMLView* pView, m_diagrams) { pView->umlScene()->saveToXMI1(qDoc, diagramsElement); } QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello")); extension.appendChild(diagramsElement); qElement.appendChild(extension); } } /** * Auxiliary to saveToXMI1(): Creates a element when saving * a predefined modelview, or a element when saving a * user created folder. Invokes saveContents() with the newly created * element. */ void UMLFolder::save1(QDomDocument& qDoc, QDomElement& qElement) { UMLDoc *umldoc = UMLApp::app()->document(); QString elementName(QLatin1String("UML:Package")); const Uml::ModelType::Enum mt = umldoc->rootFolderType(this); if (mt != Uml::ModelType::N_MODELTYPES) { elementName = QLatin1String("UML:Model"); } QDomElement folderElement = UMLObject::save1(elementName, qDoc); saveContents1(qDoc, folderElement); qElement.appendChild(folderElement); } /** * Creates a UML:Model or UML:Package element: * UML:Model is created for the predefined fixed folders, * UML:Package with stereotype "folder" is created for all else. */ void UMLFolder::saveToXMI1(QDomDocument& qDoc, QDomElement& qElement) { if (m_folderFile.isEmpty()) { save1(qDoc, qElement); return; } // See if we can create the external file. // If not then internalize the folder. UMLDoc *umldoc = UMLApp::app()->document(); #if QT_VERSION >= 0x050000 QString fileName = umldoc->url().adjusted(QUrl::RemoveFilename).path() + m_folderFile; #else QString fileName = umldoc->url().directory() + QLatin1Char('/') + m_folderFile; #endif QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { uError() << m_folderFile << QLatin1String(": ") << "cannot create file, contents will be saved in main model file"; m_folderFile.clear(); save1(qDoc, qElement); return; } // Okay, external file is writable. Wrap up main file. QDomElement folderElement = UMLObject::save1(QLatin1String("UML:Package"), qDoc); QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello")); QDomElement fileElement = qDoc.createElement(QLatin1String("external_file")); fileElement.setAttribute(QLatin1String("name"), m_folderFile); extension.appendChild(fileElement); folderElement.appendChild(extension); qElement.appendChild(folderElement); // Save folder to external file. QDomDocument folderDoc; QDomElement folderRoot; QDomProcessingInstruction xmlHeading = folderDoc.createProcessingInstruction(QLatin1String("xml"), QString::fromLatin1("version=\"1.0\" encoding=\"UTF-8\"")); folderDoc.appendChild(xmlHeading); folderRoot = folderDoc.createElement(QLatin1String("external_file")); folderRoot.setAttribute(QLatin1String("name"), name()); folderRoot.setAttribute(QLatin1String("filename"), m_folderFile); folderRoot.setAttribute(QLatin1String("mainModel"), umldoc->url().fileName()); folderRoot.setAttribute(QLatin1String("parentId"), Uml::ID::toString(umlPackage()->id())); folderRoot.setAttribute(QLatin1String("parent"), umlPackage()->fullyQualifiedName(QLatin1String("::"), true)); saveContents1(folderDoc, folderRoot); folderDoc.appendChild(folderRoot); QTextStream stream(&file); stream.setCodec("UTF-8"); stream << folderDoc.toString(); file.close(); } /** * Auxiliary to load(): * Load the diagrams from the "diagrams" in the */ bool UMLFolder::loadDiagramsFromXMI1(QDomNode& node) { 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 { /* FIXME how to get dpi ? * 1. from user -> will open a dialog box for any old file * 2. after loading from user changeable document settings * 3. estimated from contained widgets */ UMLApp::app()->document()->setResolution(0.0); } QDomNode diagrams = node.firstChild(); const Settings::OptionState optionState = Settings::optionState(); UMLDoc *umldoc = UMLApp::app()->document(); bool totalSuccess = true; for (QDomElement diagram = diagrams.toElement(); !diagram.isNull(); diagrams = diagrams.nextSibling(), diagram = diagrams.toElement()) { QString tag = diagram.tagName(); if (tag != QLatin1String("diagram")) { uDebug() << "ignoring " << tag << " in "; continue; } UMLView * pView = new UMLView(this); pView->umlScene()->setOptionState(optionState); if (pView->umlScene()->loadFromXMI1(diagram)) { pView->hide(); umldoc->addView(pView); } else { delete pView; totalSuccess = false; } } return totalSuccess; } /** * Folders in the listview can be marked such that their contents * are saved to a separate file. * This method loads the separate folder file. * CAVEAT: This is not XMI standard compliant. * If standard compliance is an issue then avoid folder files. * @param path Fully qualified file name, i.e. absolute directory * plus file name. * @return True for success. */ bool UMLFolder::loadFolderFile(const QString& path) { QFile file(path); if (!file.exists()) { KMessageBox::error(0, i18n("The folderfile %1 does not exist.", path), i18n("Load Error")); return false; } if (!file.open(QIODevice::ReadOnly)) { KMessageBox::error(0, i18n("The folderfile %1 cannot be opened.", path), i18n("Load Error")); return false; } QTextStream stream(&file); QString data = stream.readAll(); file.close(); QDomDocument doc; QString error; int line; if (!doc.setContent(data, false, &error, &line)) { uError() << "Cannot set content:" << error << " line:" << line; return false; } QDomNode rootNode = doc.firstChild(); while (rootNode.isComment() || rootNode.isProcessingInstruction()) { rootNode = rootNode.nextSibling(); } if (rootNode.isNull()) { uError() << "Root node is Null"; return false; } QDomElement element = rootNode.toElement(); QString type = element.tagName(); if (type != QLatin1String("external_file")) { uError() << "Root node has unknown type " << type; return false; } return load1(element); } /** * Loads the owned elements of the . */ bool UMLFolder::load1(QDomElement& element) { UMLDoc *umldoc = UMLApp::app()->document(); bool totalSuccess = true; for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isComment()) continue; QDomElement tempElement = node.toElement(); QString type = tempElement.tagName(); if (Model_Utils::isCommonXMI1Attribute(type)) continue; if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { //CHECK: Umbrello currently assumes that nested elements // are ownedElements anyway. // Therefore these tags are not further interpreted. if (! load1(tempElement)) { uDebug() << "An error happened while loading the " << type << " of the " << name(); totalSuccess = false; } continue; } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { type = tempElement.attribute(QLatin1String("xmi:type")); } else if (type == QLatin1String("XMI.extension")) { for (QDomNode xtnode = node.firstChild(); !xtnode.isNull(); xtnode = xtnode.nextSibling()) { QDomElement el = xtnode.toElement(); const QString xtag = el.tagName(); if (xtag == QLatin1String("diagrams")) { umldoc->addDiagramToLoad(this, xtnode); } else if (xtag == QLatin1String("external_file")) { #if QT_VERSION >= 0x050000 const QString rootDir(umldoc->url().adjusted(QUrl::RemoveFilename).path()); #else const QString rootDir(umldoc->url().directory()); #endif QString fileName = el.attribute(QLatin1String("name")); const QString path(rootDir + QLatin1Char('/') + fileName); if (loadFolderFile(path)) m_folderFile = fileName; } else { uDebug() << name() << ": ignoring XMI.extension " << xtag; continue; } } continue; } // Do not re-create the predefined Datatypes folder in the Logical View, // it already exists. UMLFolder *logicalView = umldoc->rootFolder(Uml::ModelType::Logical); if (this == logicalView && UMLDoc::tagEq(type, QLatin1String("Package"))) { QString thisName = tempElement.attribute(QLatin1String("name")); if (thisName == QLatin1String("Datatypes")) { UMLFolder *datatypeFolder = umldoc->datatypeFolder(); if (!datatypeFolder->loadFromXMI1(tempElement)) totalSuccess = false; continue; } } UMLObject *pObject = 0; // Avoid duplicate creation of forward declared object QString idStr = Model_Utils::getXmiId(tempElement); if (!idStr.isEmpty()) { Uml::ID::Type id = Uml::ID::fromString(idStr); pObject = umldoc->findObjectById(id); if (pObject) { uDebug() << "object " << idStr << "already exists"; } } if (pObject == 0) { QString stereoID = tempElement.attribute(QLatin1String("stereotype")); pObject = Object_Factory::makeObjectFromXMI(type, stereoID); if (!pObject) { uWarning() << "Unknown type of umlobject to create: " << type; continue; } } // check for invalid namespaces QString ns = tempElement.attribute(QLatin1String("namespace")); Uml::ID::Type id = Uml::ID::fromString(ns); if (id != this->id()) { uError() << "namespace" << ns << "not present; ignoring object with id" << idStr; delete pObject; pObject = 0; totalSuccess = false; continue; } pObject->setUMLPackage(this); if (!pObject->loadFromXMI1(tempElement)) { removeObject(pObject); delete pObject; totalSuccess = false; } } return totalSuccess; } bool UMLFolder::showPropertiesDialog(QWidget *parent) { Q_UNUSED(parent); QString folderName = this->name(); - bool ok = Dialog_Utils::askName(i18n("Folder"), - i18n("Enter name:"), - folderName); + bool ok = Dialog_Utils::askRenameName(UMLObject::ot_Folder, folderName); if (ok) { setName(folderName); } return ok; } /** * Overloading operator for debugging output. */ QDebug operator<<(QDebug out, const UMLFolder& item) { out.nospace() << "UMLFolder: localName=" << item.m_localName << ", folderFile=" << item.m_folderFile << ", diagrams=" << item.m_diagrams.count(); return out.space(); } diff --git a/umbrello/uml1model/stereotype.cpp b/umbrello/uml1model/stereotype.cpp index 37af6ba3c..ca2b3202b 100644 --- a/umbrello/uml1model/stereotype.cpp +++ b/umbrello/uml1model/stereotype.cpp @@ -1,155 +1,153 @@ /*************************************************************************** * 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 * ***************************************************************************/ // own header #include "stereotype.h" // local includes #include "debug_utils.h" #include "dialog_utils.h" #include "umldoc.h" #include "uml.h" // kde includes #include /** * Sets up a stereotype. * * @param name The name of this UMLStereotype. * @param id The unique id given to this UMLStereotype. */ UMLStereotype::UMLStereotype(const QString &name, Uml::ID::Type id /* = Uml::id_None */) : UMLObject(name, id) { m_BaseType = UMLObject::ot_Stereotype; UMLStereotype * existing = UMLApp::app()->document()->findStereotype(name); if (existing) { uError() << "UMLStereotype constructor: " << name << " already exists"; } m_refCount = 0; } /** * Sets up a stereotype. */ UMLStereotype::UMLStereotype() : UMLObject() { m_BaseType = UMLObject::ot_Stereotype; m_refCount = 0; } /** * Destructor. */ UMLStereotype::~UMLStereotype() { //Q_ASSERT(m_refCount == 0); } /** * Overloaded '==' operator. */ bool UMLStereotype::operator==(const UMLStereotype &rhs) const { if (this == &rhs) { return true; } if (!UMLObject::operator==(rhs)) { return false; } return true; } /** * Copy the internal presentation of this object into the new * object. */ void UMLStereotype::copyInto(UMLObject *lhs) const { UMLObject::copyInto(lhs); } /** * Make a clone of this object. */ UMLObject* UMLStereotype::clone() const { UMLStereotype *clone = new UMLStereotype(); copyInto(clone); return clone; } /** * Saves to the XMI element. */ void UMLStereotype::saveToXMI1(QDomDocument& qDoc, QDomElement& qElement) { //FIXME: uml13.dtd compliance QDomElement stereotypeElement = UMLObject::save1(QLatin1String("UML:Stereotype"), qDoc); qElement.appendChild(stereotypeElement); } /** * Display the properties configuration dialog for the stereotype * (just a line edit). */ bool UMLStereotype::showPropertiesDialog(QWidget* parent) { Q_UNUSED(parent); QString stereoTypeName = name(); - bool ok = Dialog_Utils::askName(i18n("Stereotype"), - i18n("Enter name:"), - stereoTypeName); + bool ok = Dialog_Utils::askRenameName(baseType(), stereoTypeName); if (ok) { setName(stereoTypeName); } return ok; } /** * Increments the reference count for this stereotype. */ void UMLStereotype::incrRefCount() { m_refCount++; } /** * Decrements the reference count for this stereotype. */ void UMLStereotype::decrRefCount() { m_refCount--; } /** * Returns the reference count for this stereotype. */ int UMLStereotype::refCount() const { return m_refCount; } /** * Returns the name as string */ QString UMLStereotype::name(bool includeAdornments) const { if (includeAdornments) return QString::fromUtf8("«") + UMLObject::name() + QString::fromUtf8("»"); else return UMLObject::name(); } diff --git a/umbrello/umlwidgets/activitywidget.cpp b/umbrello/umlwidgets/activitywidget.cpp index 29da8c8ad..245c22981 100644 --- a/umbrello/umlwidgets/activitywidget.cpp +++ b/umbrello/umlwidgets/activitywidget.cpp @@ -1,446 +1,444 @@ /*************************************************************************** * 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 "activitywidget.h" // app includes #include "activitydialog.h" #include "debug_utils.h" #include "dialog_utils.h" #include "docwindow.h" #include "dialogspopupmenu.h" #include "uml.h" #include "umldoc.h" #include "umlscene.h" #include "umlview.h" // kde includes #include // qt includes #include /** * Creates a Activity widget. * * @param scene The parent of the widget. * @param activityType The type of activity. * @param id The ID to assign (-1 will prompt a new ID.) */ ActivityWidget::ActivityWidget(UMLScene * scene, ActivityType activityType, Uml::ID::Type id) : UMLWidget(scene, WidgetBase::wt_Activity, id), m_activityType(activityType) { // set non zero size to avoid crash on painting setSize(1, 1); } /** * Destructor. */ ActivityWidget::~ActivityWidget() { } /** * Returns the type of activity. */ ActivityWidget::ActivityType ActivityWidget::activityType() const { return m_activityType; } /** * Returns the type string of activity. */ QString ActivityWidget::activityTypeStr() const { return QLatin1String(ENUM_NAME(ActivityWidget, ActivityType, m_activityType)); } /** * Sets the type of activity. */ void ActivityWidget::setActivityType(ActivityType activityType) { m_activityType = activityType; updateGeometry(); UMLWidget::m_resizable = true; } /** * Determines whether a toolbar button represents an Activity. * CHECK: currently unused - can this be removed? * * @param tbb The toolbar button enum input value. * @param resultType The ActivityType corresponding to tbb. * This is only set if tbb is an Activity. * @return True if tbb represents an Activity. */ bool ActivityWidget::isActivity(WorkToolBar::ToolBar_Buttons tbb, ActivityType& resultType) { bool status = true; switch (tbb) { case WorkToolBar::tbb_Initial_Activity: resultType = Initial; break; case WorkToolBar::tbb_Activity: resultType = Normal; break; case WorkToolBar::tbb_End_Activity: resultType = End; break; case WorkToolBar::tbb_Final_Activity: resultType = Final; break; case WorkToolBar::tbb_Branch: resultType = Branch; break; default: status = false; break; } return status; } /** * This method get the name of the preText attribute. */ QString ActivityWidget::preconditionText() const { return m_preconditionText; } /** * This method set the name of the preText attribute */ void ActivityWidget::setPreconditionText(const QString& aPreText) { m_preconditionText = aPreText; updateGeometry(); adjustAssocs(x(), y()); } /** * This method get the name of the postText attribute. */ QString ActivityWidget::postconditionText() const { return m_postconditionText; } /** * This method set the name of the postText attribute */ void ActivityWidget::setPostconditionText(const QString& aPostText) { m_postconditionText = aPostText; updateGeometry(); adjustAssocs(x(), y()); } /** * Reimplemented from UMLWidget::showPropertiesDialog to show a * properties dialog for an ActivityWidget. */ bool ActivityWidget::showPropertiesDialog() { bool result = false; UMLApp::app()->docWindow()->updateDocumentation(false); QPointer dialog = new ActivityDialog(umlScene()->activeView(), this); if (dialog->exec() && dialog->getChangesMade()) { UMLApp::app()->docWindow()->showDocumentation(this, true); UMLApp::app()->document()->setModified(true); result = true; } delete dialog; return result; } /** * Overrides the standard paint event. */ void ActivityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); int w = width(); int h = height(); // Only for the final activity float x; float y; QPen pen = painter->pen(); switch (m_activityType) { case Normal: UMLWidget::setPenFromSettings(painter); if (UMLWidget::useFillColor()) { painter->setBrush(UMLWidget::fillColor()); } { const QFontMetrics &fm = getFontMetrics(FT_NORMAL); const int fontHeight = fm.lineSpacing(); int textStartY = (h / 2) - (fontHeight / 2); painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); painter->setPen(textColor()); painter->setFont(UMLWidget::font()); painter->drawText(ACTIVITY_MARGIN, textStartY, w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); } break; case Initial: painter->setPen(QPen(WidgetBase::lineColor(), 1)); painter->setBrush(WidgetBase::lineColor()); painter->drawEllipse(0, 0, w, h); break; case Final: UMLWidget::setPenFromSettings(painter); painter->setBrush(Qt::white); pen.setWidth(2); pen.setColor (Qt::red); painter->setPen(pen); painter->drawEllipse(0, 0, w, h); x = w/2 ; y = h/2 ; { const float w2 = 0.7071 * (float)w / 2.0; painter->drawLine((int)(x - w2 + 1), (int)(y - w2 + 1), (int)(x + w2), (int)(y + w2)); painter->drawLine((int)(x + w2 - 1), (int)(y - w2 + 1), (int)(x - w2), (int)(y + w2)); } break; case End: painter->setPen(QPen(WidgetBase::lineColor(), 1)); painter->setBrush(WidgetBase::lineColor()); painter->drawEllipse(0, 0, w, h); painter->setBrush(Qt::white); painter->drawEllipse(1, 1, w - 2, h - 2); painter->setBrush(WidgetBase::lineColor()); painter->drawEllipse(3, 3, w - 6, h - 6); break; case Branch: UMLWidget::setPenFromSettings(painter); if (UMLWidget::useFillColor()) { painter->setBrush(UMLWidget::fillColor()); } { QPolygon array(4); array[ 0 ] = QPoint(w / 2, 0); array[ 1 ] = QPoint(w, h / 2); array[ 2 ] = QPoint(w / 2, h); array[ 3 ] = QPoint(0, h / 2); painter->drawPolygon(array); painter->drawPolyline(array); } break; case Invok: UMLWidget::setPenFromSettings(painter); if (UMLWidget::useFillColor()) { painter->setBrush(UMLWidget::fillColor()); } { const QFontMetrics &fm = getFontMetrics(FT_NORMAL); const int fontHeight = fm.lineSpacing(); int textStartY = (h / 2) - (fontHeight / 2); painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); painter->setPen(textColor()); painter->setFont(UMLWidget::font()); painter->drawText(ACTIVITY_MARGIN, textStartY, w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); } x = w - (w/5); y = h - (h/3); painter->drawLine((int)x, (int) y, (int)x, (int)(y + 20)); painter->drawLine((int)(x - 10), (int)(y + 10), (int)(x + 10), (int)(y + 10)); painter->drawLine((int)(x - 10), (int)(y + 10), (int)(x - 10), (int)(y + 20)); painter->drawLine((int)(x + 10), (int)(y + 10), (int)(x + 10), (int)(y + 20)); break; case Param: UMLWidget::setPenFromSettings(painter); if (UMLWidget::useFillColor()) { painter->setBrush(UMLWidget::fillColor()); } { const QFontMetrics &fm = getFontMetrics(FT_NORMAL); const int fontHeight = fm.lineSpacing(); QString preCond= QLatin1String("<> ") + preconditionText(); QString postCond= QLatin1String("<> ") + postconditionText(); //int textStartY = (h / 2) - (fontHeight / 2); painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); painter->setPen(textColor()); painter->setFont(UMLWidget::font()); painter->drawText(ACTIVITY_MARGIN, fontHeight + 10, w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, preCond); painter->drawText(ACTIVITY_MARGIN, fontHeight * 2 + 10, w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, postCond); painter->drawText(ACTIVITY_MARGIN, (fontHeight / 2), w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); } break; } UMLWidget::paint(painter, option, widget); } /** * Overridden from UMLWidget due to emission of signal sigActMoved() */ void ActivityWidget::moveWidgetBy(qreal diffX, qreal diffY) { UMLWidget::moveWidgetBy(diffX, diffY); emit sigActMoved(diffX, diffY); } /** * Loads the widget from the "activitywidget" XMI element. */ bool ActivityWidget::loadFromXMI1(QDomElement& qElement) { if(!UMLWidget::loadFromXMI1(qElement)) return false; setName(qElement.attribute(QLatin1String("activityname"))); setDocumentation(qElement.attribute(QLatin1String("documentation"))); setPreconditionText(qElement.attribute(QLatin1String("precondition"))); setPostconditionText(qElement.attribute(QLatin1String("postcondition"))); QString type = qElement.attribute(QLatin1String("activitytype"), QLatin1String("1")); setActivityType((ActivityType)type.toInt()); return true; } /** * Saves the widget to the "activitywidget" XMI element. */ void ActivityWidget::saveToXMI1(QDomDocument & qDoc, QDomElement & qElement) { QDomElement activityElement = qDoc.createElement(QLatin1String("activitywidget")); UMLWidget::saveToXMI1(qDoc, activityElement); activityElement.setAttribute(QLatin1String("activityname"), name()); activityElement.setAttribute(QLatin1String("documentation"), documentation()); activityElement.setAttribute(QLatin1String("precondition"), preconditionText()); activityElement.setAttribute(QLatin1String("postcondition"), postconditionText()); activityElement.setAttribute(QLatin1String("activitytype"), m_activityType); qElement.appendChild(activityElement); } /** * Overrides Method from UMLWidget. */ void ActivityWidget::constrain(qreal& width, qreal& height) { if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { UMLWidget::constrain(width, height); return; } if (width > height) width = height; else if (height > width) height = width; UMLWidget::constrain(width, height); } /** * Captures any popup menu signals for menus it created. */ void ActivityWidget::slotMenuSelection(QAction* action) { ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); switch(sel) { case ListPopupMenu::mt_Rename: { QString n = name(); - bool ok = Dialog_Utils::askName(i18n("Enter Activity Name"), - i18n("Enter the name of the new activity:"), - n); + bool ok = Dialog_Utils::askRenameName(WidgetBase::wt_Activity, n); if (ok && !n.isEmpty()) { setName(n); } } break; case ListPopupMenu::mt_Properties: showPropertiesDialog(); break; default: UMLWidget::slotMenuSelection(action); } } /** * Overrides method from UMLWidget */ QSizeF ActivityWidget::minimumSize() const { if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { const QFontMetrics &fm = getFontMetrics(FT_NORMAL); const int fontHeight = fm.lineSpacing(); int textWidth = fm.width(name()); int height = fontHeight; height = height > ACTIVITY_HEIGHT ? height : ACTIVITY_HEIGHT; height += ACTIVITY_MARGIN * 2; textWidth = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH; if (m_activityType == Invok) { height += 40; } else if (m_activityType == Param) { QString maxSize; maxSize = name().length() > postconditionText().length() ? name() : postconditionText(); maxSize = maxSize.length() > preconditionText().length() ? maxSize : preconditionText(); textWidth = fm.width(maxSize); textWidth = textWidth + 50; height += 100; } int width = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH; width += ACTIVITY_MARGIN * 4; return QSizeF(width, height); } else if (m_activityType == Branch) { return QSizeF(20, 20); } return QSizeF(15, 15); } /** * Overrides method from UMLWidget */ QSizeF ActivityWidget::maximumSize() { if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { return UMLWidget::maximumSize(); } if (m_activityType == Branch) { return QSizeF(50, 50); } return QSizeF(30, 30); } diff --git a/umbrello/umlwidgets/pinwidget.cpp b/umbrello/umlwidgets/pinwidget.cpp index 8ed7d3dd7..c3548e755 100644 --- a/umbrello/umlwidgets/pinwidget.cpp +++ b/umbrello/umlwidgets/pinwidget.cpp @@ -1,80 +1,78 @@ /*************************************************************************** * 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 "pinwidget.h" // app includes #include "debug_utils.h" #include "dialog_utils.h" #include "floatingtextwidget.h" #include "listpopupmenu.h" #include "umlscene.h" #include "activitywidget.h" // kde includes #include // qt includes #include DEBUG_REGISTER_DISABLED(PinWidget) /** * Creates a Pin widget. * * @param scene The parent of the widget. * @param owner The widget to which this pin is attached. * @param id The ID to assign (-1 will prompt a new ID). */ PinWidget::PinWidget(UMLScene* scene, UMLWidget* owner, Uml::ID::Type id) : PinPortBase(scene, WidgetBase::wt_Pin, owner, id) { // setParent(a); // m_nY = y() < getMinY() ? getMinY() : y(); m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); m_pName->setParentItem(this); m_pName->setText(name()); // to get geometry update m_pName->activate(); setVisible(true); } /** * Destructor. */ PinWidget::~PinWidget() { } /** * Captures any popup menu signals for menus it created. */ void PinWidget::slotMenuSelection(QAction* action) { ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); switch(sel) { case ListPopupMenu::mt_Rename: { QString name = m_Text; - bool ok = Dialog_Utils::askName(i18n("Enter Pin Name"), - i18n("Enter the pin name :"), - name); + bool ok = Dialog_Utils::askNewName(WidgetBase::wt_Pin, name); if (ok) { setName(name); } } break; default: PinPortBase::slotMenuSelection(action); } } diff --git a/umbrello/umlwidgets/portwidget.cpp b/umbrello/umlwidgets/portwidget.cpp index c171d21c8..cc93b7040 100644 --- a/umbrello/umlwidgets/portwidget.cpp +++ b/umbrello/umlwidgets/portwidget.cpp @@ -1,84 +1,80 @@ /*************************************************************************** * 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) 2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "portwidget.h" // app includes #include "port.h" #include "package.h" #include "debug_utils.h" #include "dialog_utils.h" #include "listpopupmenu.h" #include "uml.h" #include "umldoc.h" #include "umllistview.h" #include "umlscene.h" #include "componentwidget.h" #include "floatingtextwidget.h" // kde includes #include // qt includes #include #include /** * Constructs a PortWidget. * * @param scene The parent of this PortWidget. * @param d The UMLPort this will be representing. */ PortWidget::PortWidget(UMLScene *scene, UMLPort *d, UMLWidget *owner) : PinPortBase(scene, WidgetBase::wt_Port, owner, d) { setToolTip(d->name()); } /** * Standard deconstructor. */ PortWidget::~PortWidget() { } /** * Override function from PinPortWidget. */ UMLWidget* PortWidget::ownerWidget() const { return PinPortBase::ownerWidget(); } /** * Captures any popup menu signals for menus it created. */ void PortWidget::slotMenuSelection(QAction* action) { ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); switch(sel) { case ListPopupMenu::mt_Rename: { QString newName = name(); - bool ok = Dialog_Utils::askName(i18n("Enter Port Name"), - i18n("Enter the port name :"), - newName); - if (ok) { + if (Dialog_Utils::askNewName(WidgetBase::wt_Port, newName)) setName(newName); - } } break; default: PinPortBase::slotMenuSelection(action); } } diff --git a/umbrello/umlwidgets/preconditionwidget.cpp b/umbrello/umlwidgets/preconditionwidget.cpp index 2e93ea1ab..c1c33d290 100644 --- a/umbrello/umlwidgets/preconditionwidget.cpp +++ b/umbrello/umlwidgets/preconditionwidget.cpp @@ -1,321 +1,319 @@ /*************************************************************************** * 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 "preconditionwidget.h" // app includes #include "debug_utils.h" #include "dialog_utils.h" #include "listpopupmenu.h" #include "objectwidget.h" #include "uml.h" #include "umlscene.h" #include "uniqueid.h" #include "idchangelog.h" // kde includes #include // qt includes #include DEBUG_REGISTER_DISABLED(PreconditionWidget) #define PRECONDITION_MARGIN 5 #define PRECONDITION_WIDTH 30 #define PRECONDITION_HEIGHT 10 /** * Creates a Precondition widget. * * @param scene The parent of the widget. * @param a The role A widget for this precondition. * @param id The ID to assign (-1 will prompt a new ID). */ PreconditionWidget::PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id) : UMLWidget(scene, WidgetBase::wt_Precondition, id), m_objectWidget(a) { m_ignoreSnapToGrid = true; m_ignoreSnapComponentSizeToGrid = true; m_resizable = true ; setVisible(true); //updateResizability(); // calculateWidget(); if (y() < minY()) m_nY = minY(); else if (y() > maxY()) m_nY = maxY(); else m_nY = y(); activate(); } /** * Destructor. */ PreconditionWidget::~PreconditionWidget() { } /** * Overrides the standard paint event. */ void PreconditionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); int w = width(); int h = height(); int x = m_objectWidget->x() + m_objectWidget->width() / 2; x -= w/2; setX(x); int y = this->y(); //test if y isn't above the object if (y <= m_objectWidget->y() + m_objectWidget->height()) { y = m_objectWidget->y() + m_objectWidget->height() + 15; } if (y + h >= m_objectWidget->getEndLineY()) { y = m_objectWidget->getEndLineY() - h; } setY(y); setPenFromSettings(painter); if (UMLWidget::useFillColor()) { painter->setBrush(UMLWidget::fillColor()); } { const QFontMetrics &fm = getFontMetrics(FT_NORMAL); const int fontHeight = fm.lineSpacing(); const QString precondition_value = QLatin1String("{ ") + name() + QLatin1String(" }"); //int middleX = w / 2; int textStartY = (h / 2) - (fontHeight / 2); painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); painter->setPen(textColor()); painter->setFont(UMLWidget::font()); painter->drawText(PRECONDITION_MARGIN, textStartY, w - PRECONDITION_MARGIN * 2, fontHeight, Qt::AlignCenter, precondition_value); } UMLWidget::paint(painter, option, widget); } /** * Overrides method from UMLWidget. */ QSizeF PreconditionWidget::minimumSize() const { int width = 10, height = 10; const QFontMetrics &fm = getFontMetrics(FT_NORMAL); const int fontHeight = fm.lineSpacing(); const int textWidth = fm.width(name()) + 25; height = fontHeight; width = textWidth > PRECONDITION_WIDTH ? textWidth : PRECONDITION_WIDTH; height = height > PRECONDITION_HEIGHT ? height : PRECONDITION_HEIGHT; width += PRECONDITION_MARGIN * 2; height += PRECONDITION_MARGIN * 2; return QSizeF(width, height); } /** * Calculate the geometry of the widget. */ void PreconditionWidget::calculateWidget() { calculateDimensions(); setVisible(true); setX(m_nPosX); setY(m_nY); } /** * Activates a PreconditionWidget. Connects the WidgetMoved signal from * its m_objectWidget pointer so that PreconditionWidget can adjust to the move of * the object widget. */ bool PreconditionWidget::activate(IDChangeLog * Log /*= 0*/) { m_scene->resetPastePoint(); UMLWidget::activate(Log); loadObjectWidget(); if (!m_objectWidget) { DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) << " could not be found"; return false; } connect(m_objectWidget, SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); calculateDimensions(); return true; } /** * Resolve references of this precondition so it references the correct * new object widget after paste. */ void PreconditionWidget::resolveObjectWidget(IDChangeLog* log) { m_widgetAId = log->findNewID(m_widgetAId); } /** * Calculates the size of the widget. */ void PreconditionWidget::calculateDimensions() { int x = 0; int w = 0; int h = 0; int x1 = m_objectWidget->x(); int w1 = m_objectWidget->width() / 2; x1 += w1; QSizeF q = minimumSize(); w = q.width() > width() ? q.width() : width(); h = q.height() > height() ? q.height() : height(); x = x1 - w/2; m_nPosX = x; setSize(w, h); } /** * Slot when widget is moved. */ void PreconditionWidget::slotWidgetMoved(Uml::ID::Type id) { const Uml::ID::Type idA = m_objectWidget->localID(); if (idA != id) { DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA); return; } m_nY = y(); if (m_nY < minY()) m_nY = minY(); if (m_nY > maxY()) m_nY = maxY(); calculateDimensions(); if (m_scene->selectedCount(true) > 1) return; } /** * Returns the minimum height this widget should be set at on * a sequence diagrams. Takes into account the widget positions * it is related to. */ int PreconditionWidget::minY() const { if (m_objectWidget) { return m_objectWidget->y() + m_objectWidget->height(); } return 0; } /** * Returns the maximum height this widget should be set at on * a sequence diagrams. Takes into account the widget positions * it is related to. */ int PreconditionWidget::maxY() const { if (m_objectWidget) { return ((int)m_objectWidget->getEndLineY() - height()); } return 0; } /** * Captures any popup menu signals for menus it created. */ void PreconditionWidget::slotMenuSelection(QAction* action) { ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); switch(sel) { case ListPopupMenu::mt_Rename: { QString text = name(); - bool ok = Dialog_Utils::askName(i18n("Enter Precondition Name"), - i18n("Enter the precondition :"), - text); + bool ok = Dialog_Utils::askNewName(WidgetBase::wt_Precondition, text); if (ok && !text.isEmpty()) { setName(text); } calculateWidget(); } break; default: UMLWidget::slotMenuSelection(action); } } /** * Saves the widget to the "preconditionwidget" XMI element. */ void PreconditionWidget::saveToXMI1(QDomDocument& qDoc, QDomElement& qElement) { QDomElement preconditionElement = qDoc.createElement(QLatin1String("preconditionwidget")); UMLWidget::saveToXMI1(qDoc, preconditionElement); preconditionElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_objectWidget->localID())); preconditionElement.setAttribute(QLatin1String("preconditionname"), name()); preconditionElement.setAttribute(QLatin1String("documentation"), documentation()); qElement.appendChild(preconditionElement); } /** * Loads the widget from the "preconditionwidget" XMI element. */ bool PreconditionWidget::loadFromXMI1(QDomElement& qElement) { if(!UMLWidget::loadFromXMI1(qElement)) return false; QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); setName(qElement.attribute(QLatin1String("preconditionname"))); setDocumentation(qElement.attribute(QLatin1String("documentation"))); m_widgetAId = Uml::ID::fromString(widgetaid); // Lookup the ObjectWidget, if it can't be found, assume it will be // resolved later loadObjectWidget(); return true; } /** * Load the object widget from m_widgetAId * * This method is called in loadFromXMI1() when loading an XMI file, and called * from activate() when activating a widget after pasting. */ void PreconditionWidget::loadObjectWidget() { if (m_objectWidget == 0) { m_objectWidget = dynamic_cast( umlScene()->findWidget(m_widgetAId) ); } } diff --git a/umbrello/umlwidgets/toolbarstateonewidget.cpp b/umbrello/umlwidgets/toolbarstateonewidget.cpp index 1beb52569..95719e6c2 100644 --- a/umbrello/umlwidgets/toolbarstateonewidget.cpp +++ b/umbrello/umlwidgets/toolbarstateonewidget.cpp @@ -1,240 +1,240 @@ /*************************************************************************** * 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 "toolbarstateonewidget.h" // app includes #include "activitywidget.h" #include "dialog_utils.h" #include "floatingtextwidget.h" #include "messagewidget.h" #include "model_utils.h" #include "objectwidget.h" #include "pinwidget.h" #include "portwidget.h" #include "preconditionwidget.h" #include "regionwidget.h" #include "uml.h" #include "umldoc.h" #include "port.h" #include "umlscene.h" #include "umlwidget.h" #include "object_factory.h" #include "package.h" #include "widget_factory.h" #include "widget_utils.h" // kde includes #include #include // qt includes // using namespace Uml; /** * Creates a new ToolBarStateOneWidget. * * @param umlScene The UMLScene to use. */ ToolBarStateOneWidget::ToolBarStateOneWidget(UMLScene *umlScene) : ToolBarStatePool(umlScene), m_firstObject(0), m_isObjectWidgetLine(false) { } /** * Destroys this ToolBarStateOneWidget. */ ToolBarStateOneWidget::~ToolBarStateOneWidget() { } /** * Called when the current tool is changed to use another tool. * Executes base method and cleans the message. */ void ToolBarStateOneWidget::cleanBeforeChange() { ToolBarStatePool::cleanBeforeChange(); } /** * Called when a mouse event happened. * It executes the base method and then updates the position of the * message line, if any. */ void ToolBarStateOneWidget::mouseMove(QGraphicsSceneMouseEvent* ome) { ToolBarStatePool::mouseMove(ome); } /** * A widget was removed from the UMLView. * If the widget removed was the current widget, the current widget is set * to 0. * Also, if it was the first object, the message is cleaned. */ void ToolBarStateOneWidget::slotWidgetRemoved(UMLWidget* widget) { ToolBarState::slotWidgetRemoved(widget); } /** * Selects only widgets, but no associations. * Overrides base class method. * If the press event happened on the line of an object, the object is set * as current widget. If the press event happened on a widget, the widget is * set as current widget. */ void ToolBarStateOneWidget::setCurrentElement() { m_isObjectWidgetLine = false; ObjectWidget* objectWidgetLine = m_pUMLScene->onWidgetLine(m_pMouseEvent->scenePos()); if (objectWidgetLine) { setCurrentWidget(objectWidgetLine); m_isObjectWidgetLine = true; return; } UMLWidget *widget = m_pUMLScene->widgetAt(m_pMouseEvent->scenePos()); if (widget) { setCurrentWidget(widget); return; } } /** * Called when the release event happened on a widget. * If the button pressed isn't left button or the widget isn't an object * widget, the message is cleaned. * If the release event didn't happen on the line of an object and the first * object wasn't selected, nothing is done. If the first object was already * selected, a creation message is made. * If the event happened on the line of an object, the first object or the * second are set, depending on whether the first object was already set or * not. */ void ToolBarStateOneWidget::mouseReleaseWidget() { WidgetBase::WidgetType type = widgetType(); if (type == WidgetBase::wt_Precondition) { m_firstObject = 0; } if (type == WidgetBase::wt_Pin || type == WidgetBase::wt_Port) { m_firstObject = 0; } if (m_pMouseEvent->button() != Qt::LeftButton || (!currentWidget()->isObjectWidget() && !currentWidget()->isActivityWidget() && !currentWidget()->isComponentWidget() && !currentWidget()->isRegionWidget())) { return; } if (!m_firstObject && (type == WidgetBase::wt_Pin || type == WidgetBase::wt_Port)) { setWidget(currentWidget()); return ; } if (!m_isObjectWidgetLine && !m_firstObject) { return; } if (!m_firstObject) { setWidget(currentWidget()); } } /** * Called when the release event happened on an empty space. * Cleans the message. * Empty spaces are not only actual empty spaces, but also associations. */ void ToolBarStateOneWidget::mouseReleaseEmpty() { } /** * Sets the first object of the message using the specified object. * The temporal visual message is created and mouse tracking enabled, so * mouse events will be delivered. * * @param firstObject The first object of the message. */ void ToolBarStateOneWidget::setWidget(UMLWidget* firstObject) { m_firstObject = firstObject; UMLWidget * umlwidget = 0; //m_pUMLScene->viewport()->setMouseTracking(true); if (widgetType() == WidgetBase::wt_Precondition) { - umlwidget = new PreconditionWidget(m_pUMLScene, static_cast(m_firstObject)); - - Dialog_Utils::askNameForWidget(umlwidget, i18n("Enter Precondition Name"), i18n("Enter the precondition"), i18n("new precondition")); - // Create the widget. Some setup functions can remove the widget. - } - - if (widgetType() == WidgetBase::wt_Pin && m_firstObject->isActivityWidget()) { - QString name = i18n("new pin"); - if (Dialog_Utils::askName(i18n("Enter Pin Name"), i18n("Enter the Pin"), name)) { + QString name = Widget_Utils::defaultWidgetName(WidgetBase::wt_Precondition); + if (Dialog_Utils::askNewName(WidgetBase::wt_Precondition, name)) { + umlwidget = new PreconditionWidget(m_pUMLScene, firstObject->asObjectWidget()); + umlwidget->setName(name); + } + } else if (widgetType() == WidgetBase::wt_Pin && m_firstObject->isActivityWidget()) { + QString name = Widget_Utils::defaultWidgetName(WidgetBase::wt_Pin); + if (Dialog_Utils::askNewName(WidgetBase::wt_Pin, name)) { umlwidget = new PinWidget(m_pUMLScene, m_firstObject); + umlwidget->setName(name); } } else if (widgetType() == WidgetBase::wt_Port && m_firstObject->isComponentWidget()) { UMLPackage* component = m_firstObject->umlObject()->asUMLPackage(); QString name = Model_Utils::uniqObjectName(UMLObject::ot_Port, component); - if (Dialog_Utils::askName(i18n("Enter Port Name"), i18n("Enter the port"), name)) { + if (Dialog_Utils::askNewName(WidgetBase::wt_Port, name)) { UMLPort *port = Object_Factory::createUMLObject(UMLObject::ot_Port, name, component)->asUMLPort(); umlwidget = new PortWidget(m_pUMLScene, port, m_firstObject); } } if (umlwidget) { m_pUMLScene->setupNewWidget(umlwidget); } emit finished(); } /** * Returns the widget type of this tool. * * @return The widget type of this tool. */ WidgetBase::WidgetType ToolBarStateOneWidget::widgetType() { if (getButton() == WorkToolBar::tbb_Seq_Precondition) { return WidgetBase::wt_Precondition; } if (getButton() == WorkToolBar::tbb_Pin) { return WidgetBase::wt_Pin; } if (getButton() == WorkToolBar::tbb_Port) { return WidgetBase::wt_Port; } // Shouldn't happen Q_ASSERT(0); return WidgetBase::wt_Pin; } /** * Goes back to the initial state. */ void ToolBarStateOneWidget::init() { ToolBarStatePool::init(); } diff --git a/umbrello/umlwidgets/umlwidget.cpp b/umbrello/umlwidgets/umlwidget.cpp index fcc000933..fbf6df00f 100644 --- a/umbrello/umlwidgets/umlwidget.cpp +++ b/umbrello/umlwidgets/umlwidget.cpp @@ -1,2183 +1,2187 @@ /*************************************************************************** * 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 * ***************************************************************************/ #include "umlwidget.h" // local includes #include "artifact.h" #include "artifactwidget.h" #include "activitywidget.h" #include "actor.h" #include "actorwidget.h" #include "associationwidget.h" #include "classifier.h" #include "classpropertiesdialog.h" #include "cmds.h" #include "component.h" #include "componentwidget.h" #include "debug_utils.h" #include "dialog_utils.h" #include "docwindow.h" #include "floatingtextwidget.h" #include "forkjoinwidget.h" #include "interfacewidget.h" #include "notewidget.h" #include "messagewidget.h" #include "object_factory.h" #include "idchangelog.h" #include "menus/listpopupmenu.h" #include "objectnodewidget.h" #include "pinwidget.h" #include "port.h" #include "portwidget.h" #include "regionwidget.h" #include "signalwidget.h" #include "settingsdialog.h" #include "statewidget.h" #include "uml.h" #include "umldoc.h" #include "umllistview.h" #include "umlobject.h" #include "umlscene.h" #include "umlview.h" #include "usecase.h" #include "usecasewidget.h" #include "uniqueid.h" #include "widget_factory.h" // kde includes #include #include // qt includes #include #include #include #include using namespace Uml; DEBUG_REGISTER_DISABLED(UMLWidget) const QSizeF UMLWidget::DefaultMinimumSize(50, 20); const QSizeF UMLWidget::DefaultMaximumSize(1000, 5000); const int UMLWidget::defaultMargin = 5; const int UMLWidget::selectionMarkerSize = 4; const int UMLWidget::resizeMarkerLineCount = 3; /** * Creates a UMLWidget object. * * @param scene The view to be displayed on. * @param type The WidgetType to construct. * This must be set to the appropriate value by the constructors of inheriting classes. * @param o The UMLObject to represent. */ UMLWidget::UMLWidget(UMLScene * scene, WidgetType type, UMLObject * o) : WidgetBase(scene, type) { init(); m_umlObject = o; if (m_umlObject) { connect(m_umlObject, SIGNAL(modified()), this, SLOT(updateWidget())); m_nId = m_umlObject->id(); } } /** * Creates a UMLWidget object. * * @param scene The view to be displayed on. * @param type The WidgetType to construct. * This must be set to the appropriate value by the constructors of inheriting classes. * @param id The id of the widget. * The default value (id_None) will prompt generation of a new ID. */ UMLWidget::UMLWidget(UMLScene *scene, WidgetType type, Uml::ID::Type id) : WidgetBase(scene, type) { init(); if (id == Uml::ID::None) m_nId = UniqueID::gen(); else m_nId = id; } /** * Destructor. */ UMLWidget::~UMLWidget() { cleanup(); } /** * Assignment operator */ UMLWidget& UMLWidget::operator=(const UMLWidget & other) { if (this == &other) return *this; WidgetBase::operator=(other); // assign members loaded/saved m_useFillColor = other.m_useFillColor; m_usesDiagramFillColor = other.m_usesDiagramFillColor; m_usesDiagramUseFillColor = other.m_usesDiagramUseFillColor; m_fillColor = other.m_fillColor; m_Assocs = other.m_Assocs; m_isInstance = other.m_isInstance; m_instanceName = other.m_instanceName; m_instanceName = other.m_instanceName; m_showStereotype = other.m_showStereotype; setX(other.x()); setY(other.y()); setRect(rect().x(), rect().y(), other.width(), other.height()); // assign volatile (non-saved) members m_startMove = other.m_startMove; m_nPosX = other.m_nPosX; m_doc = other.m_doc; //new m_resizable = other.m_resizable; for (unsigned i = 0; i < FT_INVALID; ++i) m_pFontMetrics[i] = other.m_pFontMetrics[i]; m_activated = other.m_activated; m_ignoreSnapToGrid = other.m_ignoreSnapToGrid; m_ignoreSnapComponentSizeToGrid = other.m_ignoreSnapComponentSizeToGrid; return *this; } /** * Overload '==' operator */ bool UMLWidget::operator==(const UMLWidget& other) const { if (this == &other) return true; if (baseType() != other.baseType()) { return false; } if (id() != other.id()) return false; /* Testing the associations is already an exaggeration, no? The type and ID should uniquely identify an UMLWidget. */ if (m_Assocs.count() != other.m_Assocs.count()) { return false; } // if(getBaseType() != wt_Text) // DON'T do this for floatingtext widgets, an infinite loop will result // { AssociationWidgetListIt assoc_it(m_Assocs); AssociationWidgetListIt assoc_it2(other.m_Assocs); AssociationWidget * assoc = 0, *assoc2 = 0; while (assoc_it.hasNext() && assoc_it2.hasNext()) { assoc = assoc_it.next(); assoc2 = assoc_it2.next(); if (!(*assoc == *assoc2)) { return false; } } // } return true; // NOTE: In the comparison tests we are going to do, we don't need these values. // They will actually stop things functioning correctly so if you change these, be aware of that. /* if(m_useFillColor != other.m_useFillColor) return false; if(m_nId != other.m_nId) return false; if(m_nX != other.m_nX) return false; if(m_nY != other.m_nY) return false; */ } /** * Sets the local id of the object. * * @param id The local id of the object. */ void UMLWidget::setLocalID(Uml::ID::Type id) { m_nLocalID = id; } /** * Returns the local ID for this object. This ID is used so that * many objects of the same @ref UMLObject instance can be on the * same diagram. * * @return The local ID. */ Uml::ID::Type UMLWidget::localID() const { return m_nLocalID; } /** * Returns the widget with the given ID. * The default implementation tests the following IDs: * - m_nLocalID * - if m_umlObject is non NULL: m_umlObject->id() * - m_nID * Composite widgets override this function to test further owned widgets. * * @param id The ID to test this widget against. * @return 'this' if id is either of m_nLocalID, m_umlObject->id(), or m_nId; * else NULL. */ UMLWidget* UMLWidget::widgetWithID(Uml::ID::Type id) { if (id == m_nLocalID || (m_umlObject != 0 && id == m_umlObject->id()) || id == m_nId) return this; return 0; } /** * Compute the minimum possible width and height. * * @return QSizeF(mininum_width, minimum_height) */ QSizeF UMLWidget::minimumSize() const { return m_minimumSize; } /** * This method is used to set the minimum size variable for this * widget. * * @param newSize The size being set as minimum. */ void UMLWidget::setMinimumSize(const QSizeF& newSize) { m_minimumSize = newSize; } /** * Compute the maximum possible width and height. * * @return maximum size */ QSizeF UMLWidget::maximumSize() { return m_maximumSize; } /** * This method is used to set the maximum size variable for this * widget. * * @param newSize The size being set as maximum. */ void UMLWidget::setMaximumSize(const QSizeF& newSize) { m_maximumSize = newSize; } /** * Event handler for context menu events. */ void UMLWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { WidgetBase::contextMenuEvent(event); } /** * Moves the widget to a new position using the difference between the * current position and the new position. * This method doesn't adjust associations. It only moves the widget. * * It can be overridden to constrain movement only in one axis even when * the user isn't constraining the movement with shift or control buttons, for example. * The movement policy set here is applied whenever the widget is moved, being it * moving it explicitly, or as a part of a selection but not receiving directly the * mouse events. * * Default behaviour is move the widget to the new position using the diffs. * @see constrainMovementForAllWidgets * * @param diffX The difference between current X position and new X position. * @param diffY The difference between current Y position and new Y position. */ void UMLWidget::moveWidgetBy(qreal diffX, qreal diffY) { setX(x() + diffX); setY(y() + diffY); } /** * Modifies the value of the diffX and diffY variables used to move the widgets. * * It can be overridden to constrain movement of all the selected widgets only in one * axis even when the user isn't constraining the movement with shift or control * buttons, for example. * The difference with moveWidgetBy is that the diff positions used here are * applied to all the selected widgets instead of only to m_widget, and that * moveWidgetBy, in fact, moves the widget, and here simply the diff positions * are modified. * * Default behaviour is do nothing. * @see moveWidgetBy * * @param diffX The difference between current X position and new X position. * @param diffY The difference between current Y position and new Y position. */ void UMLWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) { Q_UNUSED(diffX) Q_UNUSED(diffY) } /** * Bring the widget at the pressed position to the foreground. */ void UMLWidget::toForeground() { QRectF rect = QRectF(scenePos(), QSizeF(width(), height())); QList items = scene()->items(rect, Qt::IntersectsItemShape, Qt::DescendingOrder); DEBUG(DBG_SRC) << "items at " << rect << " = " << items.count(); if (items.count() > 1) { foreach(QGraphicsItem* i, items) { UMLWidget* w = dynamic_cast(i); if (w) { DEBUG(DBG_SRC) << "item=" << w->name() << " with zValue=" << w->zValue(); if (w->name() != name()) { if (w->zValue() >= zValue()) { setZValue(w->zValue() + 1.0); DEBUG(DBG_SRC) << "bring to foreground with zValue: " << zValue(); } } } } } else { setZValue(0.0); } DEBUG(DBG_SRC) << "zValue is " << zValue(); } /** * Handles a mouse press event. * It'll select the widget (or mark it to be deselected) and prepare it to * be moved or resized. Go on reading for more info about this. * * Widget values and message bar status are saved. * * If shift or control buttons are pressed, we're in move area no matter * where the button was pressed in the widget. Moreover, if the widget * wasn't already selected, it's added to the selection. If already selected, * it's marked to be deselected when releasing the button (provided it isn't * moved). * Also, if the widget is already selected with other widgets but shift nor * control buttons are pressed, we're in move area. If finally we don't move * the widget, it's selected and the other widgets deselected when releasing * the left button. * * If shift nor control buttons are pressed, we're facing a single selection. * Depending on the position of the cursor, we're in move or in resize area. * If the widget wasn't selected (both when there are no widgets selected, or * when there're other widgets selected but not the one receiving the press * event) it's selected and the others deselected, if any. If already selected, * it's marked to be deselected when releasing the button (provided it wasn't * moved or resized). * * @param event The QGraphicsSceneMouseEvent event. */ void UMLWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() != Qt::LeftButton) { event->ignore(); return; } event->accept(); DEBUG(DBG_SRC) << "widget = " << name() << " / type = " << baseTypeStr(); toForeground(); m_startMovePostion = pos(); m_startResizeSize = QSizeF(width(), height()); // saving the values of the widget m_pressOffset = event->scenePos() - pos(); DEBUG(DBG_SRC) << "press offset=" << m_pressOffset; m_oldStatusBarMsg = UMLApp::app()->statusBarMsg(); if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) { m_shiftPressed = true; if (event->button() == Qt::LeftButton) { m_inMoveArea = true; } if (!isSelected()) { selectMultiple(event); } return; } m_shiftPressed = false; int count = m_scene->selectedCount(true); if (event->button() == Qt::LeftButton) { if (isSelected() && count > 1) { // single selection is made in release event if the widget wasn't moved m_inMoveArea = true; m_oldPos = pos(); return; } if (isInResizeArea(event)) { m_inResizeArea = true; m_oldW = width(); m_oldH = height(); } else { m_inMoveArea = true; } } // if widget wasn't selected, or it was selected but with other widgets also selected if (!isSelected() || count > 1) { selectSingle(event); } } /** * Handles a mouse move event. * It resizes or moves the widget, depending on where the cursor is pressed * on the widget. Go on reading for more info about this. * * If resizing, the widget is resized using UMLWidget::resizeWidget (where specific * widget resize constraint can be applied), and then the associations are * adjusted. * The resizing can be constrained also to a specific axis using control * and shift buttons. If on or another is pressed, it's constrained to X axis. * If both are pressed, it's constrained to Y axis. * * If not resizing, the widget is being moved. If the move is being started, * the selection bounds are set (which includes updating the list of selected * widgets). * The difference between the previous position of the selection and the new * one is got (taking in account the selection bounds so widgets don't go * beyond the scene limits). Then, it's constrained to X or Y axis depending * on shift and control buttons. * A further constraint is made using constrainMovementForAllWidgets (for example, * if the widget that receives the event can only be moved in Y axis, with this * method the movement of all the widgets in the selection can be constrained to * be moved only in Y axis). * Then, all the selected widgets are moved using moveWidgetBy (where specific * widget movement constraint can be applied) and, if a certain amount of time * passed from the last move event, the associations are also updated (they're * not updated always to be easy on the CPU). Finally, the scene is resized, * and selection bounds updated. * * @param event The QGraphicsSceneMouseEvent event. */ void UMLWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { if (m_inResizeArea) { resize(event); return; } if (!m_moved) { UMLApp::app()->document()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel move.")); m_moved = true; //Maybe needed by AssociationWidget m_startMove = true; setSelectionBounds(); } QPointF position = event->scenePos() - m_pressOffset; qreal diffX = position.x() - x(); qreal diffY = position.y() - y(); if ((event->modifiers() & Qt::ShiftModifier) && (event->modifiers() & Qt::ControlModifier)) { // move only in Y axis diffX = 0; } else if ((event->modifiers() & Qt::ShiftModifier) || (event->modifiers() & Qt::ControlModifier)) { // move only in X axis diffY = 0; } constrainMovementForAllWidgets(diffX, diffY); // nothing to move if (diffX == 0 && diffY == 0) { return; } QPointF delta = event->scenePos() - event->lastScenePos(); DEBUG(DBG_SRC) << "diffX=" << diffX << " / diffY=" << diffY; foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { if ((widget->parentItem() == 0) || (!widget->parentItem()->isSelected())) { widget->moveWidgetBy(diffX, diffY); widget->adjustUnselectedAssocs(delta.x(), delta.y()); widget->slotSnapToGrid(); } } // Move any selected associations. foreach(AssociationWidget* aw, m_scene->selectedAssocs()) { if (aw->isSelected()) { aw->moveEntireAssoc(diffX, diffY); } } umlScene()->resizeSceneToItems(); } /** * Handles a mouse release event. * It selects or deselects the widget and cancels or confirms the move or * resize. Go on reading for more info about this. * No matter which tool is selected, Z position of widget is updated. * * Middle button release resets the selection. * Left button release, if it wasn't moved nor resized, selects the widget * and deselect the others if it wasn't selected and there were other widgets * selected. If the widget was marked to be deselected, deselects it. * If it was moved or resized, the document is set to modified if position * or size changed. Also, if moved, all the associations are adjusted because * the timer could have prevented the adjustment in the last move event before * the release. * If mouse was pressed in resize area, cursor is set again to normal cursor * Right button release if right button was pressed shows the pop up menu for * the widget. * If left button was pressed, it cancels the move or resize with a mouse move * event at the same position than the cursor was when pressed. Another left * button release is also sent. * * @param event The QGraphicsSceneMouseEvent event. */ void UMLWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (!m_moved && !m_resized) { if (!m_shiftPressed && (m_scene->selectedCount(true) > 1)) { selectSingle(event); } else if (!isSelected()) { deselect(event); } } else { // Commands if (m_moved) { int selectionCount = umlScene()->selectedWidgets().count(); if (selectionCount > 1) { UMLApp::app()->beginMacro(i18n("Move widgets")); } foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { UMLApp::app()->executeCommand(new Uml::CmdMoveWidget(widget)); } if (selectionCount > 1) { UMLApp::app()->endMacro(); } m_moved = false; } else { UMLApp::app()->executeCommand(new Uml::CmdResizeWidget(this)); m_autoResize = false; m_resized = false; } if ((m_inMoveArea && wasPositionChanged()) || (m_inResizeArea && wasSizeChanged())) { umlDoc()->setModified(true); } UMLApp::app()->document()->writeToStatusBar(m_oldStatusBarMsg); } if (m_inResizeArea) { m_inResizeArea = false; m_scene->activeView()->setCursor(Qt::ArrowCursor); } else { m_inMoveArea = false; } m_startMove = false; } /** * Event handler for mouse double click events. * @param event the QGraphicsSceneMouseEvent event. */ void UMLWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { DEBUG(DBG_SRC) << "widget = " << name() << " / type = " << baseTypeStr(); showPropertiesDialog(); event->accept(); } } /** * Return the start position of the move action. * @return point where the move began */ QPointF UMLWidget::startMovePosition() const { return m_startMovePostion; } /** * Set the start position of the move action. * @param position point where the move began */ void UMLWidget::setStartMovePosition(const QPointF &position) { m_startMovePostion = position; } /** * Return the start size of the resize action. * @return size where the resize began */ QSizeF UMLWidget::startResizeSize() const { return m_startResizeSize; } /** * Resizes the widget. * It's called from resize, after the values are constrained and before * the associations are adjusted. * * Default behaviour is resize the widget using the new size values. * @see resize * * @param newW The new width for the widget. * @param newH The new height for the widget. */ void UMLWidget::resizeWidget(qreal newW, qreal newH) { setSize(newW, newH); } /** * Notify child widget about parent resizes. * Child widgets can override this function to move when their parent is resized. */ void UMLWidget::notifyParentResize() { } /** * When a widget changes this slot captures that signal. */ void UMLWidget::updateWidget() { updateGeometry(); switch (baseType()) { case WidgetBase::wt_Class: m_scene->createAutoAttributeAssociations(this); break; case WidgetBase::wt_Entity: m_scene->createAutoConstraintAssociations(this); break; default: break; } if (isVisible()) update(); } /** * Apply possible constraints to the given candidate width and height. * The default implementation limits input values to the bounds returned * by minimumSize()/maximumSize(). * * @param width input value, may be modified by the constraint * @param height input value, may be modified by the constraint */ void UMLWidget::constrain(qreal& width, qreal& height) { QSizeF minSize = minimumSize(); if (width < minSize.width()) width = minSize.width(); if (height < minSize.height()) height = minSize.height(); QSizeF maxSize = maximumSize(); if (width > maxSize.width()) width = maxSize.width(); if (height > maxSize.height()) height = maxSize.height(); if (fixedAspectRatio()) { QSizeF size = rect().size(); float aspectRatio = size.width() > 0 ? (float)size.height()/size.width() : 1; height = width * aspectRatio; } } /** * Initializes key attributes of the class. */ void UMLWidget::init() { m_nId = Uml::ID::None; m_nLocalID = UniqueID::gen(); m_isInstance = false; setMinimumSize(DefaultMinimumSize); setMaximumSize(DefaultMaximumSize); m_font = QApplication::font(); for (int i = (int)FT_INVALID - 1; i >= 0; --i) { FontType fontType = (FontType)i; setupFontType(m_font, fontType); m_pFontMetrics[fontType] = new QFontMetrics(m_font); } if (m_scene) { m_useFillColor = true; m_usesDiagramFillColor = true; m_usesDiagramUseFillColor = true; const Settings::OptionState& optionState = m_scene->optionState(); m_fillColor = optionState.uiState.fillColor; m_showStereotype = optionState.classState.showStereoType; } else { uError() << "SERIOUS PROBLEM - m_scene is NULL"; m_useFillColor = false; m_usesDiagramFillColor = false; m_usesDiagramUseFillColor = false; m_showStereotype = false; } m_resizable = true; m_fixedAspectRatio = false; m_startMove = false; m_activated = false; m_ignoreSnapToGrid = false; m_ignoreSnapComponentSizeToGrid = false; m_doc = UMLApp::app()->document(); m_nPosX = 0; connect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); connect(m_scene, SIGNAL(sigLineColorChanged(Uml::ID::Type)), this, SLOT(slotLineColorChanged(Uml::ID::Type))); connect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); connect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); m_umlObject = 0; m_oldPos = QPointF(); m_pressOffset = QPointF(); m_oldW = 0; m_oldH = 0; m_shiftPressed = false; m_inMoveArea = false; m_inResizeArea = false; m_moved = false; m_resized = false; // propagate line color set by base class constructor // which does not call the virtual methods from this class. setLineColor(lineColor()); setZValue(2.0); // default for most widgets } /** * This is usually called synchronously after menu.exec() and \a * trigger's parent is always the ListPopupMenu which can be used to * get the type of action of \a trigger. * * @note Subclasses can reimplement to handle specific actions and * leave the rest to WidgetBase::slotMenuSelection. */ void UMLWidget::slotMenuSelection(QAction *trigger) { if (!trigger) { return; } ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); switch (sel) { case ListPopupMenu::mt_Resize: umlScene()->resizeSelection(); break; case ListPopupMenu::mt_AutoResize: setAutoResize(trigger->isChecked()); updateGeometry(); break; case ListPopupMenu::mt_Rename_Object: { QString name = m_instanceName; bool ok = Dialog_Utils::askName(i18n("Rename Object"), i18n("Enter object name:"), name); if (ok) { m_instanceName = name; updateGeometry(); moveEvent(0); update(); UMLApp::app()->document()->setModified(true); } break; } case ListPopupMenu::mt_FloatText: { FloatingTextWidget* ft = new FloatingTextWidget(umlScene()); ft->showChangeTextDialog(); //if no text entered delete if (!FloatingTextWidget::isTextValid(ft->text())) { delete ft; } else { ft->setID(UniqueID::gen()); addWidget(ft, false); } break; } case ListPopupMenu::mt_Actor: { UMLActor *actor = new UMLActor; UMLWidget *widget = new ActorWidget(umlScene(), actor); addConnectedWidget(widget, Uml::AssociationType::Association); break; } case ListPopupMenu::mt_Artifact: { UMLArtifact *a = new UMLArtifact(); ArtifactWidget *widget = new ArtifactWidget(umlScene(), a); addConnectedWidget(widget, Uml::AssociationType::Association); break; } case ListPopupMenu::mt_Component: { UMLComponent *c = new UMLComponent(); ComponentWidget *widget = new ComponentWidget(umlScene(), c); addConnectedWidget(widget, Uml::AssociationType::Association, SetupSize); break; } case ListPopupMenu::mt_Interface: { - UMLClassifier *c = new UMLClassifier(); - c->setBaseType(UMLObject::ot_Interface); - ClassifierWidget *widget = new ClassifierWidget(umlScene(), c); - addConnectedWidget(widget, Uml::AssociationType::Association); + UMLPackage* component = umlObject()->asUMLPackage(); + QString name = Model_Utils::uniqObjectName(UMLObject::ot_Interface, component); + if (Dialog_Utils::askNewName(WidgetBase::wt_Interface, name)) { + UMLClassifier *c = new UMLClassifier(); + c->setBaseType(UMLObject::ot_Interface); + ClassifierWidget *widget = new ClassifierWidget(umlScene(), c); + addConnectedWidget(widget, Uml::AssociationType::Association); + } break; } case ListPopupMenu::mt_InterfaceComponent: case ListPopupMenu::mt_InterfaceProvided: { UMLObject *o = Object_Factory::createUMLObject(UMLObject::ot_Interface); InterfaceWidget *w = new InterfaceWidget(umlScene(), o->asUMLClassifier()); w->setDrawAsCircle(true); addConnectedWidget(w, Uml::AssociationType::Association, SetupSize); break; } case ListPopupMenu::mt_InterfaceRequired: { UMLObject *o = Object_Factory::createUMLObject(UMLObject::ot_Interface); InterfaceWidget *w = new InterfaceWidget(umlScene(), o->asUMLClassifier()); w->setDrawAsCircle(true); addConnectedWidget(w, Uml::AssociationType::Association, SetupSize | SwitchDirection); break; } case ListPopupMenu::mt_Note: { NoteWidget *widget = new NoteWidget(umlScene()); addConnectedWidget(widget, Uml::AssociationType::Anchor); break; } case ListPopupMenu::mt_Port: { // TODO: merge with ToolbarStateOneWidget::setWidget() UMLPackage* component = umlObject()->asUMLPackage(); QString name = Model_Utils::uniqObjectName(UMLObject::ot_Port, component); - if (Dialog_Utils::askName(i18n("Enter Port Name"), i18n("Enter the port"), name)) { + if (Dialog_Utils::askNewName(WidgetBase::wt_Port, name)) { UMLPort *port = Object_Factory::createUMLObject(UMLObject::ot_Port, name, component)->asUMLPort(); UMLWidget *umlWidget = Widget_Factory::createWidget(umlScene(), port); umlWidget->setParentItem(this); umlScene()->setupNewWidget(umlWidget); } break; } case ListPopupMenu::mt_UseCase: { UMLUseCase *useCase = new UMLUseCase; UMLWidget *widget = new UseCaseWidget(umlScene(), useCase); addConnectedWidget(widget, Uml::AssociationType::Association); break; } case ListPopupMenu::mt_MessageSynchronous: // MessageWidget *widget = new MessageWidget(umlScene(), this); // addConnectedWidget(widget, Uml::AssociationType::Coll_Message_Synchronous); case ListPopupMenu::mt_MessageAsynchronous: case ListPopupMenu::mt_MessageFound: case ListPopupMenu::mt_MessageLost: break; // activity diagrams case ListPopupMenu::mt_Accept_Signal: addConnectedWidget(new SignalWidget(umlScene(), SignalWidget::Accept), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Accept_Time_Event: addConnectedWidget(new SignalWidget(umlScene(), SignalWidget::Time), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Activity: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Normal), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Activity_Transition: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Final), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Branch: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Branch), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Exception: umlScene()->triggerToolbarButton(WorkToolBar::tbb_Exception); break; case ListPopupMenu::mt_Final_Activity: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Final), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Fork: addConnectedWidget(new ForkJoinWidget(umlScene()), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_End_Activity: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::End), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Initial_Activity: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Initial), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Invoke_Activity: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Invok), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Object_Node: addConnectedWidget(new ObjectNodeWidget(umlScene(), ObjectNodeWidget::Data), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Pin: umlScene()->triggerToolbarButton(WorkToolBar::tbb_Pin); break; case ListPopupMenu::mt_Param_Activity: addConnectedWidget(new ActivityWidget(umlScene(), ActivityWidget::Param), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_PrePostCondition: addConnectedWidget(new NoteWidget(umlScene(), NoteWidget::Normal), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Region: addConnectedWidget(new RegionWidget(umlScene()), Uml::AssociationType::Activity, NoOption); break; case ListPopupMenu::mt_Send_Signal: addConnectedWidget(new SignalWidget(umlScene(), SignalWidget::Send), Uml::AssociationType::Activity, NoOption); break; // state diagrams case ListPopupMenu::mt_Choice: addConnectedWidget(new StateWidget(umlScene(), StateWidget::Choice), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_DeepHistory: addConnectedWidget(new StateWidget(umlScene(), StateWidget::DeepHistory), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_End_State: addConnectedWidget(new StateWidget(umlScene(), StateWidget::End), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_Junction: addConnectedWidget(new StateWidget(umlScene(), StateWidget::Junction), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_ShallowHistory: addConnectedWidget(new StateWidget(umlScene(), StateWidget::ShallowHistory), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_State: addConnectedWidget(new StateWidget(umlScene(), StateWidget::Normal), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_StateFork: addConnectedWidget(new StateWidget(umlScene(), StateWidget::Fork), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_StateJoin: addConnectedWidget(new StateWidget(umlScene(), StateWidget::Join), Uml::AssociationType::State, NoOption); break; case ListPopupMenu::mt_StateTransition: umlScene()->triggerToolbarButton(WorkToolBar::tbb_State_Transition); break; default: WidgetBase::slotMenuSelection(trigger); break; } } /** * Captures when another widget moves if this widget is linked to it. * @see sigWidgetMoved * * @param id The id of object behind the widget. */ void UMLWidget::slotWidgetMoved(Uml::ID::Type /*id*/) { } /** * Captures a color change signal. * * @param viewID The id of the UMLScene behind the widget. */ void UMLWidget::slotFillColorChanged(Uml::ID::Type viewID) { //only change if on the diagram concerned if (m_scene->ID() != viewID) { return; } if (m_usesDiagramFillColor) { WidgetBase::setFillColor(m_scene->fillColor()); } if (m_usesDiagramUseFillColor) { WidgetBase::setUseFillColor(m_scene->useFillColor()); } update(); } /** * Captures a text color change signal. * * @param viewID The id of the UMLScene behind the widget. */ void UMLWidget::slotTextColorChanged(Uml::ID::Type viewID) { //only change if on the diagram concerned if (m_scene->ID() != viewID) return; WidgetBase::setTextColor(m_scene->textColor()); update(); } /** * Captures a line color change signal. * * @param viewID The id of the UMLScene behind the widget. */ void UMLWidget::slotLineColorChanged(Uml::ID::Type viewID) { //only change if on the diagram concerned if (m_scene->ID() != viewID) return; if (m_usesDiagramLineColor) { WidgetBase::setLineColor(m_scene->lineColor()); } update(); } /** * Captures a linewidth change signal. * * @param viewID The id of the UMLScene behind the widget. */ void UMLWidget::slotLineWidthChanged(Uml::ID::Type viewID) { //only change if on the diagram concerned if (m_scene->ID() != viewID) { return; } if (m_usesDiagramLineWidth) { WidgetBase::setLineWidth(m_scene->lineWidth()); } update(); } /** * Set the status of using fill color (undo action) * * @param fc the status of using fill color. */ void UMLWidget::setUseFillColor(bool fc) { if (useFillColor() != fc) { UMLApp::app()->executeCommand(new CmdChangeUseFillColor(this, fc)); } } /** * Set the status of using fill color. * * @param fc the status of using fill color. */ void UMLWidget::setUseFillColorCmd(bool fc) { WidgetBase::setUseFillColor(fc); update(); } /** * Overrides the method from WidgetBase. */ void UMLWidget::setTextColorCmd(const QColor &color) { WidgetBase::setTextColor(color); update(); } /** * Overrides the method from WidgetBase. */ void UMLWidget::setTextColor(const QColor &color) { if (textColor() != color) { UMLApp::app()->executeCommand(new CmdChangeTextColor(this, color)); update(); } } /** * Overrides the method from WidgetBase. */ void UMLWidget::setLineColorCmd(const QColor &color) { WidgetBase::setLineColor(color); update(); } /** * Overrides the method from WidgetBase. */ void UMLWidget::setLineColor(const QColor &color) { if (lineColor() != color) { UMLApp::app()->executeCommand(new CmdChangeLineColor(this, color)); } } /** * Overrides the method from WidgetBase, execute CmdChangeLineWidth */ void UMLWidget::setLineWidth(uint width) { if (lineWidth() != width) { UMLApp::app()->executeCommand(new CmdChangeLineWidth(this, width)); } } /** * Overrides the method from WidgetBase. */ void UMLWidget::setLineWidthCmd(uint width) { WidgetBase::setLineWidth(width); update(); } /** * Sets the background fill color * * @param color the new fill color */ void UMLWidget::setFillColor(const QColor &color) { if (fillColor() != color) { UMLApp::app()->executeCommand(new CmdChangeFillColor(this, color)); } } /** * Sets the background fill color * * @param color the new fill color */ void UMLWidget::setFillColorCmd(const QColor &color) { WidgetBase::setFillColor(color); update(); } /** * Activate the object after serializing it from a QDataStream * * @param ChangeLog * @return true for success */ bool UMLWidget::activate(IDChangeLog* /*ChangeLog = 0 */) { if (widgetHasUMLObject(baseType()) && m_umlObject == 0) { m_umlObject = m_doc->findObjectById(m_nId); if (m_umlObject == 0) { uError() << "cannot find UMLObject with id=" << Uml::ID::toString(m_nId); return false; } } setFontCmd(m_font); setSize(width(), height()); m_activated = true; updateGeometry(); if (m_scene->getPaste()) { FloatingTextWidget * ft = 0; QPointF point = m_scene->getPastePoint(); int x = point.x() + this->x(); int y = point.y() + this->y(); if (m_scene->isSequenceDiagram()) { switch (baseType()) { case WidgetBase::wt_Object: case WidgetBase::wt_Precondition : setY(this->y()); setX(x); break; case WidgetBase::wt_Message: setY(this->y()); setX(x); break; case WidgetBase::wt_Text: ft = static_cast(this); if (ft->textRole() == Uml::TextRole::Seq_Message) { setX(x); setY(this->y()); } else { setX(this->x()); setY(this->y()); } break; default: setY(y); break; }//end switch base type }//end if sequence else { setX(x); setY(y); } }//end if pastepoint else { setX(this->x()); setY(this->y()); } if (m_scene->getPaste()) m_scene->createAutoAssociations(this); updateGeometry(); return true; } /** * Returns true if the Activate method has been called for this instance * * @return The activate status. */ bool UMLWidget::isActivated() const { return m_activated; } /** * Set the m_activated flag of a widget but does not perform the Activate method * * @param active Status of activation is to be set. */ void UMLWidget::setActivated(bool active /*=true*/) { m_activated = active; } /** * Adds an already created association to the list of * associations that include this UMLWidget */ void UMLWidget::addAssoc(AssociationWidget* pAssoc) { if (pAssoc && !associationWidgetList().contains(pAssoc)) { associationWidgetList().append(pAssoc); } } /** * Returns the list of associations connected to this widget. */ AssociationWidgetList &UMLWidget::associationWidgetList() const { m_Assocs.removeAll(0); return m_Assocs; } /** * Removes an already created association from the list of * associations that include this UMLWidget */ void UMLWidget::removeAssoc(AssociationWidget* pAssoc) { if (pAssoc) { associationWidgetList().removeAll(pAssoc); } if (changesShape()) { updateGeometry(); } } /** * Adjusts associations with the given co-ordinates * * @param dx The amount by which the widget moved in X direction. * @param dy The amount by which the widget moved in Y direction. */ void UMLWidget::adjustAssocs(qreal dx, qreal dy) { qDebug() << this; // don't adjust Assocs on file load, as // the original positions, which are stored in XMI // should be reproduced exactly // (don't try to reposition assocs as long // as file is only partly loaded -> reposition // could be misguided) /// @todo avoid trigger of this event during load if (m_doc->loading()) { // don't recalculate the assocs during load of XMI // -> return immediately without action return; } foreach(AssociationWidget* assocwidget, associationWidgetList()) { assocwidget->saveIdealTextPositions(); } foreach(AssociationWidget* assocwidget, associationWidgetList()) { assocwidget->widgetMoved(this, dx, dy); } } /** * Adjusts all unselected associations with the given co-ordinates * * @param dx The amount by which the widget moved in X direction. * @param dy The amount by which the widget moved in Y direction. */ void UMLWidget::adjustUnselectedAssocs(qreal dx, qreal dy) { foreach(AssociationWidget* assocwidget, associationWidgetList()) { if (!assocwidget->isSelected()) assocwidget->saveIdealTextPositions(); } foreach(AssociationWidget* assocwidget, associationWidgetList()) { if (!assocwidget->isSelected()) { assocwidget->widgetMoved(this, dx, dy); } } } /** * Show a properties dialog for a UMLWidget. */ bool UMLWidget::showPropertiesDialog() { bool result = false; // will already be selected so make sure docWindow updates the doc // back it the widget UMLApp::app()->docWindow()->updateDocumentation(false); QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); if (dlg->exec()) { UMLApp::app()->docWindow()->showDocumentation(umlObject(), true); m_doc->setModified(true); result = true; } dlg->close(); //wipe from memory delete dlg; return result; } /** * Move the widget by an X and Y offset relative to * the current position. */ void UMLWidget::moveByLocal(qreal dx, qreal dy) { qreal newX = x() + dx; qreal newY = y() + dy; setX(newX); setY(newY); adjustAssocs(dx, dy); } /** * Set the pen. */ void UMLWidget::setPenFromSettings(QPainter & p) { p.setPen(QPen(m_lineColor, m_lineWidth)); } /** * Set the pen. */ void UMLWidget::setPenFromSettings(QPainter *p) { p->setPen(QPen(m_lineColor, m_lineWidth)); } /** * Returns the cursor to be shown when resizing the widget. * Default cursor is KCursor::sizeFDiagCursor(). * * @return The cursor to be shown when resizing the widget. */ QCursor UMLWidget::resizeCursor() const { return Qt::SizeFDiagCursor; } /** * Checks if the mouse is in resize area (right bottom corner), and sets * the cursor depending on that. * The cursor used when resizing is gotten from resizeCursor(). * * @param me The QMouseEVent to check. * @return true if the mouse is in resize area, false otherwise. */ bool UMLWidget::isInResizeArea(QGraphicsSceneMouseEvent *me) { qreal m = 10.0; const qreal w = width(); const qreal h = height(); // If the widget itself is very small then make the resize area small, too. // Reason: Else it becomes impossible to do a move instead of resize. if (w - m < m || h - m < m) { m = 2.0; } if (m_resizable && me->scenePos().x() >= (x() + w - m) && me->scenePos().y() >= (y() + h - m)) { m_scene->activeView()->setCursor(resizeCursor()); return true; } else { m_scene->activeView()->setCursor(Qt::ArrowCursor); return false; } } /** * calculate content related size of widget. * * @return calculated widget size */ QSizeF UMLWidget::calculateSize(bool withExtensions /* = true */) const { Q_UNUSED(withExtensions) const QFontMetrics &fm = getFontMetrics(UMLWidget::FT_NORMAL); const int fontHeight = fm.lineSpacing(); if (m_umlObject) { qreal width = 0, height = defaultMargin; if (!m_umlObject->stereotype().isEmpty()) { height += fontHeight; const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD); const int stereoWidth = bfm.size(0, m_umlObject->stereotype(true)).width(); if (stereoWidth > width) width = stereoWidth; } height += fontHeight; const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD); const int nameWidth = bfm.size(0, m_umlObject->name()).width(); if (nameWidth > width) width = nameWidth; return QSizeF(width + 2*defaultMargin, height); } else return QSizeF(width(), height()); } /** * Resize widget to minimum size. */ void UMLWidget::resize() { qreal oldW = width(); qreal oldH = height(); // @TODO minimumSize() do not work in all cases, we need a dedicated autoResize() method QSizeF size = minimumSize(); setSize(size.width(), size.height()); DEBUG(DBG_SRC) << "size=" << size; adjustAssocs(size.width()-oldW, size.height()-oldH); } /** * Resizes the widget and adjusts the associations. * It's called when a mouse move event happens and the cursor was * in resize area when pressed. * Resizing can be constrained to an specific axis using control and shift buttons. * * @param me The QGraphicsSceneMouseEvent to get the values from. */ void UMLWidget::resize(QGraphicsSceneMouseEvent *me) { QString msgX = i18n("Hold shift or control to move in X axis."); QString msgY = i18n("Hold shift and control to move in Y axis."); QString msg; if (isMessageWidget()) msg = msgY; else if (isObjectWidget()) msg = msgX; else msg = QString(QLatin1String("%1 %2")).arg(msgX, msgY); UMLApp::app()->document()->writeToStatusBar(msg); m_resized = true; qreal newW = m_oldW + me->scenePos().x() - x() - m_pressOffset.x(); qreal newH = m_oldH + me->scenePos().y() - y() - m_pressOffset.y(); if ((me->modifiers() & Qt::ShiftModifier) && (me->modifiers() & Qt::ControlModifier)) { //Move in Y axis newW = m_oldW; } else if ((me->modifiers() & Qt::ShiftModifier) || (me->modifiers() & Qt::ControlModifier)) { //Move in X axis newH = m_oldH; } constrain(newW, newH); resizeWidget(newW, newH); DEBUG(DBG_SRC) << "event=" << me->scenePos() << "/ pos=" << pos() << " / newW=" << newW << " / newH=" << newH; QPointF delta = me->scenePos() - me->lastScenePos(); adjustAssocs(delta.x(), delta.y()); m_scene->resizeSceneToItems(); } /** * Checks if the size of the widget changed respect to the size that * it had when press event was fired. * * @return true if was resized, false otherwise. */ bool UMLWidget::wasSizeChanged() { return m_oldW != width() || m_oldH != height(); } /** * Checks if the position of the widget changed respect to the position that * it had when press event was fired. * * @return true if was moved, false otherwise. */ bool UMLWidget::wasPositionChanged() { return m_oldPos != pos(); } /** * Fills m_selectedWidgetsList and sets the selection bounds ((m_min/m_max)X/Y attributes). */ void UMLWidget::setSelectionBounds() { } void UMLWidget::setSelectedFlag(bool _select) { WidgetBase::setSelected(_select); } /** * Sets the state of whether the widget is selected. * * @param _select The state of whether the widget is selected. */ void UMLWidget::setSelected(bool _select) { WidgetBase::setSelected(_select); const WidgetBase::WidgetType wt = baseType(); if (_select) { if (m_scene->selectedCount() == 0) { if (widgetHasUMLObject(wt)) { UMLApp::app()->docWindow()->showDocumentation(m_umlObject, false); } else { UMLApp::app()->docWindow()->showDocumentation(this, false); } }//end if /* if (wt != wt_Text && wt != wt_Box) { setZ(9);//keep text on top and boxes behind so don't touch Z value } */ } else { /* if (wt != wt_Text && wt != wt_Box) { setZ(m_origZ); } */ if (isSelected()) UMLApp::app()->docWindow()->updateDocumentation(true); } update(); // selection changed, we have to make sure the copy and paste items // are correctly enabled/disabled UMLApp::app()->slotCopyChanged(); // select in tree view as done for diagrams if (_select) { UMLListViewItem * item = UMLApp::app()->listView()->findItem(id()); if (item) UMLApp::app()->listView()->setCurrentItem(item); else UMLApp::app()->listView()->clearSelection(); } } /** * Selects the widget and clears the other selected widgets, if any. * * @param me The QGraphicsSceneMouseEvent which made the selection. */ void UMLWidget::selectSingle(QGraphicsSceneMouseEvent *me) { m_scene->clearSelected(); // Adds the widget to the selected widgets list, but as it has been cleared // only the current widget is selected. selectMultiple(me); } /** * Selects the widget and adds it to the list of selected widgets. * * @param me The QGraphicsSceneMouseEvent which made the selection. */ void UMLWidget::selectMultiple(QGraphicsSceneMouseEvent *me) { Q_UNUSED(me); setSelected(true); } /** * Deselects the widget and removes it from the list of selected widgets. * * @param me The QGraphicsSceneMouseEvent which made the selection. */ void UMLWidget::deselect(QGraphicsSceneMouseEvent *me) { Q_UNUSED(me); setSelected(false); } /** * Clears the selection, resets the toolbar and deselects the widget. */ //void UMLWidget::resetSelection() //{ // m_scene->clearSelected(); // m_scene->resetToolbar(); // setSelected(false); //} /** * Sets the view the widget is on. * * @param scene The UMLScene the widget is on. */ void UMLWidget::setScene(UMLScene *scene) { //remove signals from old view - was probably 0 anyway disconnect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); disconnect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); disconnect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); m_scene = scene; connect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); connect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); connect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); } /** * Sets the x-coordinate. * Currently, the only class that reimplements this method is * ObjectWidget. * * @param x The x-coordinate to be set. */ void UMLWidget::setX(qreal x) { QGraphicsObject::setX(x); } /** * Sets the y-coordinate. * Currently, the only class that reimplements this method is * ObjectWidget. * * @param y The y-coordinate to be set. */ void UMLWidget::setY(qreal y) { QGraphicsObject::setY(y); } /** * Used to cleanup any other widget it may need to delete. * Used by child classes. This should be called before deleting a widget of a diagram. */ void UMLWidget::cleanup() { } /** * Tells the widget to snap to grid. * Will use the grid settings of the @ref UMLView it belongs to. */ void UMLWidget::slotSnapToGrid() { if (!m_ignoreSnapToGrid) { qreal newX = m_scene->snappedX(x()); setX(newX); qreal newY = m_scene->snappedY(y()); setY(newY); } } /** * Returns whether the widget type has an associated UMLObject */ bool UMLWidget::widgetHasUMLObject(WidgetBase::WidgetType type) { if (type == WidgetBase::wt_Actor || type == WidgetBase::wt_UseCase || type == WidgetBase::wt_Class || type == WidgetBase::wt_Interface || type == WidgetBase::wt_Enum || type == WidgetBase::wt_Datatype || type == WidgetBase::wt_Package || type == WidgetBase::wt_Component || type == WidgetBase::wt_Port || type == WidgetBase::wt_Node || type == WidgetBase::wt_Artifact || type == WidgetBase::wt_Object) { return true; } else { return false; } } /** * Set m_ignoreSnapToGrid. */ void UMLWidget::setIgnoreSnapToGrid(bool to) { m_ignoreSnapToGrid = to; } /** * Return the value of m_ignoreSnapToGrid. */ bool UMLWidget::getIgnoreSnapToGrid() const { return m_ignoreSnapToGrid; } /** * Sets the size. * If m_scene->snapComponentSizeToGrid() is true, then * set the next larger size that snaps to the grid. */ void UMLWidget::setSize(qreal width, qreal height) { // snap to the next larger size that is a multiple of the grid if (!m_ignoreSnapComponentSizeToGrid && m_scene->snapComponentSizeToGrid()) { // integer divisions int numX = width / m_scene->snapX(); int numY = height / m_scene->snapY(); // snap to the next larger valid value if (width > numX * m_scene->snapX()) width = (numX + 1) * m_scene->snapX(); if (height > numY * m_scene->snapY()) height = (numY + 1) * m_scene->snapY(); } const QRectF newRect(rect().x(), rect().y(), width, height); setRect(newRect); foreach(QGraphicsItem* child, childItems()) { UMLWidget* umlChild = static_cast(child); umlChild->notifyParentResize(); } } /** * Sets the size with another size. */ void UMLWidget::setSize(const QSizeF& size) { setSize(size.width(), size.height()); } /** * Update the size of this widget. * * @param withAssocs true - update associations too */ void UMLWidget::updateGeometry(bool withAssocs) { if (m_doc->loading()) { return; } if (!m_autoResize) return; qreal oldW = width(); qreal oldH = height(); QSizeF size = calculateSize(); qreal clipWidth = size.width(); qreal clipHeight = size.height(); constrain(clipWidth, clipHeight); setSize(clipWidth, clipHeight); slotSnapToGrid(); if (withAssocs) adjustAssocs(size.width()-oldW, size.height()-oldH); update(); } /** * clip the size of this widget against the * minimal and maximal limits. */ void UMLWidget::clipSize() { qreal clipWidth = width(); qreal clipHeight = height(); constrain(clipWidth, clipHeight); setSize(clipWidth, clipHeight); } /** * Template Method, override this to set the default font metric. */ void UMLWidget::setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType) { setupFontType(font, fontType); setFontMetrics(fontType, QFontMetrics(font)); } void UMLWidget::setupFontType(QFont &font, UMLWidget::FontType fontType) { switch (fontType) { case FT_NORMAL: font.setBold(false); font.setItalic(false); font.setUnderline(false); break; case FT_BOLD: font.setBold(true); font.setItalic(false); font.setUnderline(false); break; case FT_ITALIC: font.setBold(false); font.setItalic(true); font.setUnderline(false); break; case FT_UNDERLINE: font.setBold(false); font.setItalic(false); font.setUnderline(true); break; case FT_BOLD_ITALIC: font.setBold(true); font.setItalic(true); font.setUnderline(false); break; case FT_BOLD_UNDERLINE: font.setBold(true); font.setItalic(false); font.setUnderline(true); break; case FT_ITALIC_UNDERLINE: font.setBold(false); font.setItalic(true); font.setUnderline(true); break; case FT_BOLD_ITALIC_UNDERLINE: font.setBold(true); font.setItalic(true); font.setUnderline(true); break; default: return; } } void UMLWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); if (option->state & QStyle::State_Selected) { const qreal w = width(); const qreal h = height(); const qreal s = selectionMarkerSize; QBrush brush(Qt::blue); painter->fillRect(0, 0, s, s, brush); painter->fillRect(0, 0 + h - s, s, s, brush); painter->fillRect(0 + w - s, 0, s, s, brush); // Draw the resize anchor in the lower right corner. // Don't draw it if the widget is so small that the // resize anchor would cover up most of the widget. if (m_resizable && w >= s+8 && h >= s+8) { brush.setColor(Qt::red); const int right = 0 + w; const int bottom = 0 + h; painter->drawLine(right - s, 0 + h - 1, 0 + w - 1, 0 + h - s); painter->drawLine(right - (s*2), bottom - 1, right - 1, bottom - (s*2)); painter->drawLine(right - (s*3), bottom - 1, right - 1, bottom - (s*3)); } else { painter->fillRect(0 + w - s, 0 + h - s, s, s, brush); } // debug info if (Tracer::instance()->isEnabled(QLatin1String(metaObject()->className()))) { painter->setPen(Qt::green); painter->setBrush(Qt::NoBrush); painter->drawPath(shape()); painter->setPen(Qt::blue); painter->drawRect(boundingRect()); // origin painter->drawLine(-10, 0, 10, 0); painter->drawLine(0, -10, 0, 10); } } if (umlScene()->isShowDocumentationIndicator() && hasDocumentation()) { const qreal h = height(); const qreal d = 8; QPolygonF p; p << QPointF(0, h - d) << QPointF(d, h) << QPointF(0, h); painter->setPen(Qt::blue); painter->setBrush(Qt::red); painter->drawPolygon(p); } } /** * Template Method, override this to set the default font metric. */ void UMLWidget::setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType, QPainter &painter) { setupFontType(font, fontType); painter.setFont(font); setFontMetrics(fontType, painter.fontMetrics()); } /** * Returns the font metric used by this object for Text * which uses bold/italic fonts. */ QFontMetrics &UMLWidget::getFontMetrics(UMLWidget::FontType fontType) const { return *m_pFontMetrics[fontType]; } /** * Set the font metric to use. */ void UMLWidget::setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm) { delete m_pFontMetrics[fontType]; m_pFontMetrics[fontType] = new QFontMetrics(fm); } /** * Sets the font the widget is to use. * * @param font Font to be set. */ void UMLWidget::setFont(const QFont &font) { QFont newFont = font; forceUpdateFontMetrics(newFont, 0); if (m_font != newFont) { UMLApp::app()->executeCommand(new CmdChangeFont(this, font)); } } /** * Sets the font the widget is to use. * * @param font Font to be set. */ void UMLWidget::setFontCmd(const QFont &font) { WidgetBase::setFont(font); forceUpdateFontMetrics(0); if (m_doc->loading()) return; update(); } /** * Updates font metrics for widgets current m_font */ void UMLWidget::forceUpdateFontMetrics(QPainter *painter) { forceUpdateFontMetrics(m_font, painter); } /** * @note For performance Reasons, only FontMetrics for already used * font types are updated. Not yet used font types will not get a font metric * and will get the same font metric as if painter was zero. * This behaviour is acceptable, because diagrams will always be shown on Display * first before a special painter like a printer device is used. */ void UMLWidget::forceUpdateFontMetrics(QFont& font, QPainter *painter) { if (painter == 0) { for (int i = (int)FT_INVALID - 1; i >= 0; --i) { if (m_pFontMetrics[(UMLWidget::FontType)i] != 0) setDefaultFontMetrics(font, (UMLWidget::FontType)i); } } else { for (int i2 = (int)FT_INVALID - 1; i2 >= 0; --i2) { if (m_pFontMetrics[(UMLWidget::FontType)i2] != 0) setDefaultFontMetrics(font, (UMLWidget::FontType)i2, *painter); } } if (m_doc->loading()) return; // calculate the size, based on the new font metric updateGeometry(); } /** * Set the status of whether to show Stereotype. * * @param flag True if stereotype shall be shown. */ void UMLWidget::setShowStereotype(bool flag) { m_showStereotype = flag; updateGeometry(); update(); } /** * Returns the status of whether to show Stereotype. * * @return True if stereotype is shown. */ bool UMLWidget::showStereotype() const { return m_showStereotype; } /** * Overrides the standard operation. * * @param me The move event. */ void UMLWidget::moveEvent(QGraphicsSceneMouseEvent* me) { Q_UNUSED(me) } void UMLWidget::saveToXMI1(QDomDocument & qDoc, QDomElement & qElement) { /* Call after required actions in child class. Type must be set in the child class. */ WidgetBase::saveToXMI1(qDoc, qElement); qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(id())); qreal dpiScale = UMLApp::app()->document()->dpiScale(); qElement.setAttribute(QLatin1String("x"), QString::number(x() / dpiScale)); qElement.setAttribute(QLatin1String("y"), QString::number(y() / dpiScale)); qElement.setAttribute(QLatin1String("width"), QString::number(width() / dpiScale)); qElement.setAttribute(QLatin1String("height"), QString::number(height() / dpiScale)); qElement.setAttribute(QLatin1String("isinstance"), m_isInstance); if (!m_instanceName.isEmpty()) qElement.setAttribute(QLatin1String("instancename"), m_instanceName); if (m_showStereotype) qElement.setAttribute(QLatin1String("showstereotype"), m_showStereotype); // Unique identifier for widget (todo: id() should be unique, new attribute // should indicate the UMLObject's ID it belongs to) qElement.setAttribute(QLatin1String("localid"), Uml::ID::toString(m_nLocalID)); } bool UMLWidget::loadFromXMI1(QDomElement & qElement) { QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); m_nId = Uml::ID::fromString(id); WidgetBase::loadFromXMI1(qElement); QString x = qElement.attribute(QLatin1String("x"), QLatin1String("0")); QString y = qElement.attribute(QLatin1String("y"), QLatin1String("0")); QString h = qElement.attribute(QLatin1String("height"), QLatin1String("0")); QString w = qElement.attribute(QLatin1String("width"), QLatin1String("0")); qreal dpiScale = UMLApp::app()->document()->dpiScale(); setSize(toDoubleFromAnyLocale(w) * dpiScale, toDoubleFromAnyLocale(h) * dpiScale); setX(toDoubleFromAnyLocale(x) * dpiScale); setY(toDoubleFromAnyLocale(y) * dpiScale); QString isinstance = qElement.attribute(QLatin1String("isinstance"), QLatin1String("0")); m_isInstance = (bool)isinstance.toInt(); m_instanceName = qElement.attribute(QLatin1String("instancename")); QString showstereo = qElement.attribute(QLatin1String("showstereotype"), QLatin1String("0")); m_showStereotype = (bool)showstereo.toInt(); QString localid = qElement.attribute(QLatin1String("localid"), QLatin1String("0")); if (localid != QLatin1String("0")) { m_nLocalID = Uml::ID::fromString(localid); } return true; } /** * Adds a widget to the diagram, which is connected to the current widget * @param widget widget instance to add to diagram * @param type association type * @param setupSize if true setup size to a predefined value * @param switchAssocDirection switch direction of association */ void UMLWidget::addConnectedWidget(UMLWidget *widget, Uml::AssociationType::Enum type, AddWidgetOptions options) { umlScene()->addItem(widget); widget->setX(x() + rect().width() + 100); widget->setY(y()); if (options & SetupSize) { widget->setSize(100, 40); QSizeF size = widget->minimumSize(); widget->setSize(size); } AssociationWidget* assoc = options & SwitchDirection ? AssociationWidget::create(umlScene(), widget, type, this) : AssociationWidget::create(umlScene(), this, type, widget); umlScene()->addAssociation(assoc); umlScene()->clearSelected(); umlScene()->selectWidget(widget); if (options & ShowProperties) widget->showPropertiesDialog(); } /** * Adds a widget to the diagram, which is connected to the current widget * @param widget widget instance to add to diagram * @param showProperties whether to show properties of the widget */ void UMLWidget::addWidget(UMLWidget *widget, bool showProperties) { umlScene()->addItem(widget); widget->setX(x() + rect().width() + 100); widget->setY(y()); widget->setSize(100, 40); if (showProperties) widget->showPropertiesDialog(); QSizeF size = widget->minimumSize(); widget->setSize(size); } diff --git a/umbrello/umlwidgets/umlwidget.h b/umbrello/umlwidgets/umlwidget.h index be11afb20..96ec367ff 100644 --- a/umbrello/umlwidgets/umlwidget.h +++ b/umbrello/umlwidgets/umlwidget.h @@ -1,354 +1,356 @@ /*************************************************************************** * 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 UMLWIDGET_H #define UMLWIDGET_H #include "associationwidgetlist.h" #include "basictypes.h" #include "optionstate.h" +#include "umlobject.h" #include "umlwidgetlist.h" #include "widgetbase.h" #include #include class IDChangeLog; class UMLDoc; class UMLObject; class UMLScene; class QPainter; class QFontMetrics; /** * This is the base class for nearly all graphical widgets. * * @short The base class for graphical UML objects. * @author Paul Hensgen * Bugs and comments to umbrello-devel@kde.org or http://bugs.kde.org */ class UMLWidget : public WidgetBase { Q_OBJECT public: friend class ToolBarStateArrow; // for calling the mouse*Event handlers static const QSizeF DefaultMinimumSize; static const QSizeF DefaultMaximumSize; static const int defaultMargin; static const int selectionMarkerSize; static const int resizeMarkerLineCount; explicit UMLWidget(UMLScene *scene, WidgetType type = wt_UMLWidget, UMLObject *o = 0); explicit UMLWidget(UMLScene *scene, WidgetType type = wt_UMLWidget, Uml::ID::Type id = Uml::ID::None); virtual ~UMLWidget(); // Copy constructor - not implemented. // UMLWidget(const UMLWidget& other); UMLWidget& operator=(const UMLWidget& other); bool operator==(const UMLWidget& other) const; void setLocalID(Uml::ID::Type id); Uml::ID::Type localID() const; virtual UMLWidget* widgetWithID(Uml::ID::Type id); virtual QSizeF minimumSize() const; void setMinimumSize(const QSizeF &size); virtual QSizeF maximumSize(); void setMaximumSize(const QSizeF &size); virtual void setUseFillColor(bool fc); void setUseFillColorCmd(bool fc); virtual void setTextColor(const QColor &color); void setTextColorCmd(const QColor &color); virtual void setLineColor(const QColor &color); virtual void setLineColorCmd(const QColor &color); virtual void setLineWidth(uint width); void setLineWidthCmd(uint width); virtual void setFillColor(const QColor &color); void setFillColorCmd(const QColor &color); void setSelectedFlag(bool _select); virtual void setSelected(bool _select); void setScene(UMLScene *scene); virtual bool activate(IDChangeLog* ChangeLog = 0); void setPenFromSettings(QPainter &p); void setPenFromSettings(QPainter *p); virtual void setFont(const QFont &font); void setFontCmd(const QFont &font); /** * Returns whether we triggered the update of position movement. * If so, you probably don't want to move it. * * @return The moving state. */ bool getStartMove() const { return m_startMove; } virtual void setX(qreal x); virtual void setY(qreal y); /** * Returns the height of widget. */ qreal height() const { return rect().height(); } /** * Returns the width of the widget. */ qreal width() const { return rect().width(); } void setSize(qreal width, qreal height); void setSize(const QSizeF& size); virtual void resizeWidget(qreal newW, qreal newH); virtual void notifyParentResize(); bool getIgnoreSnapToGrid() const; void setIgnoreSnapToGrid(bool to); void moveByLocal(qreal dx, qreal dy); void removeAssoc(AssociationWidget* pAssoc); void addAssoc(AssociationWidget* pAssoc); AssociationWidgetList &associationWidgetList() const; /** * Read property of bool m_isInstance */ bool isInstance() const { return m_isInstance; } /** * Write property of bool m_isInstance */ void setIsInstance(bool isInstance) { m_isInstance = isInstance; } /** * Write property of m_instanceName */ void setInstanceName(const QString &instanceName) { m_instanceName = instanceName; } /** * Read property of m_instanceName */ QString instanceName() const { return m_instanceName; } bool showStereotype() const; virtual void setShowStereotype(bool flag); virtual bool showPropertiesDialog(); virtual void adjustAssocs(qreal dx, qreal dy); virtual void adjustUnselectedAssocs(qreal dx, qreal dy); bool isActivated() const; void setActivated(bool active = true); virtual void cleanup(); static bool widgetHasUMLObject(WidgetBase::WidgetType type); void updateGeometry(bool withAssocs = true); void clipSize(); void forceUpdateFontMetrics(QPainter *painter); void forceUpdateFontMetrics(QFont &font, QPainter *painter); virtual bool loadFromXMI1(QDomElement &qElement); virtual void saveToXMI1(QDomDocument &qDoc, QDomElement &qElement); QPointF startMovePosition() const; void setStartMovePosition(const QPointF &position); QSizeF startResizeSize() const; virtual QSizeF calculateSize(bool withExtensions = true) const; void resize(); bool fixedAspectRatio() const { return m_fixedAspectRatio; } void setFixedAspectRatio(bool state) { m_fixedAspectRatio = state; } typedef enum { FT_NORMAL = 0, FT_BOLD = 1, FT_ITALIC = 2, FT_UNDERLINE = 3, FT_BOLD_ITALIC = 4, FT_BOLD_UNDERLINE = 5, FT_ITALIC_UNDERLINE = 6, FT_BOLD_ITALIC_UNDERLINE = 7, FT_INVALID = 8 } FontType; virtual void setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType); virtual void setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType, QPainter &painter); QFontMetrics &getFontMetrics(UMLWidget::FontType fontType) const; void setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm); void setupFontType(QFont &font, UMLWidget::FontType fontType); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); public Q_SLOTS: virtual void updateWidget(); virtual void slotMenuSelection(QAction* action); virtual void slotWidgetMoved(Uml::ID::Type id); virtual void slotFillColorChanged(Uml::ID::Type viewID); virtual void slotLineColorChanged(Uml::ID::Type viewID); virtual void slotTextColorChanged(Uml::ID::Type viewID); virtual void slotLineWidthChanged(Uml::ID::Type viewID); void slotSnapToGrid(); signals: /** * Emit when the widget moves its' position. * @param id The id of the object behind the widget. */ void sigWidgetMoved(Uml::ID::Type id); protected: virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent* event); virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); virtual void moveEvent(QGraphicsSceneMouseEvent *event); virtual void moveWidgetBy(qreal diffX, qreal diffY); virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); virtual void constrain(qreal& width, qreal& height); virtual bool isInResizeArea(QGraphicsSceneMouseEvent *me); virtual QCursor resizeCursor() const; void selectSingle(QGraphicsSceneMouseEvent *me); void selectMultiple(QGraphicsSceneMouseEvent *me); void deselect(QGraphicsSceneMouseEvent *me); // void resetSelection(); void setSelectionBounds(); void resize(QGraphicsSceneMouseEvent *me); bool wasSizeChanged(); bool wasPositionChanged(); virtual void toForeground(); public: enum AddWidgetOption { NoOption = 0, SetupSize = 1, SwitchDirection = 2, ShowProperties = 4, Default = SetupSize | ShowProperties }; Q_DECLARE_FLAGS(AddWidgetOptions, AddWidgetOption) protected: void addConnectedWidget(UMLWidget *widget, Uml::AssociationType::Enum type = Uml::AssociationType::Association, AddWidgetOptions options = Default); + void addConnectedUMLObject(UMLObject::ObjectType otype, Uml::AssociationType::Enum type); void addWidget(UMLWidget *widget, bool showProperties = true); ///////////////// Data Loaded/Saved ///////////////////////////////// QString m_instanceName; ///< instance name (used if on a deployment diagram) bool m_isInstance; ///< holds whether this widget is a component instance (i.e. on a deployment diagram) bool m_showStereotype; ///< should the stereotype be displayed ///////////////// End of Data Loaded/Saved ////////////////////////// Uml::ID::Type m_nLocalID; bool m_startMove; QPointF m_startMovePostion; QSizeF m_startResizeSize; int m_nPosX; UMLDoc *m_doc; ///< shortcut for UMLApp::app()->getDocument() bool m_resizable; QFontMetrics *m_pFontMetrics[FT_INVALID]; QSizeF m_minimumSize; QSizeF m_maximumSize; /// true if the activate function has been called for this class instance bool m_activated; /** * Change Widget Behaviour */ bool m_ignoreSnapToGrid; bool m_ignoreSnapComponentSizeToGrid; bool m_fixedAspectRatio; /// The text in the status bar when the cursor was pressed. QString m_oldStatusBarMsg; /// The X/Y offset from the position of the cursor when it was pressed to the /// upper left corner of the widget. QPointF m_pressOffset; /// The X/Y position the widget had when the movement started. QPointF m_oldPos; /// The width/height the widget had when the resize started. qreal m_oldW, m_oldH; /// If shift or control button were pressed in mouse press event. bool m_shiftPressed; /** * If cursor was in move/resize area when left button was pressed (and no * other widgets were selected). */ bool m_inMoveArea, m_inResizeArea; /** * If the widget was selected/moved/resized in the press and release cycle. * Moved/resized is true if the widget was moved/resized even if the final * position/size is the same as the starting one. */ bool m_moved, m_resized; private: void init(); /// A list of AssociationWidgets between the UMLWidget and other UMLWidgets in the diagram mutable AssociationWidgetList m_Assocs; }; Q_DECLARE_OPERATORS_FOR_FLAGS(UMLWidget::AddWidgetOptions) #endif