diff -Nru umbrello-4.12.97/debian/changelog umbrello-4.13.0/debian/changelog --- umbrello-4.12.97/debian/changelog 2014-04-02 10:04:33.000000000 +0000 +++ umbrello-4.13.0/debian/changelog 2014-04-10 21:35:56.000000000 +0000 @@ -1,3 +1,9 @@ +umbrello (4:4.13.0-0ubuntu1) trusty; urgency=medium + + * New upstream KDE Software Compilation release + + -- Jonathan Riddell Thu, 10 Apr 2014 22:35:55 +0100 + umbrello (4:4.12.97-0ubuntu1) trusty; urgency=medium * New upstream release candidate diff -Nru umbrello-4.12.97/debian/control umbrello-4.13.0/debian/control --- umbrello-4.12.97/debian/control 2014-04-02 10:04:33.000000000 +0000 +++ umbrello-4.13.0/debian/control 2014-04-10 21:35:56.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Kubuntu Developers Build-Depends: kde-sc-dev-latest (>= 4:4.10.2), cmake, debhelper (>= 9), pkg-kde-tools (>= 0.12), - kdelibs5-dev (>= 4:4.12.97), + kdelibs5-dev (>= 4:4.13.0), libxslt1-dev, libxml2-dev, libboost1.54-dev Standards-Version: 3.9.4 Homepage: http://www.kde.org diff -Nru umbrello-4.12.97/umbrello/CMakeLists.txt umbrello-4.13.0/umbrello/CMakeLists.txt --- umbrello-4.12.97/umbrello/CMakeLists.txt 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/CMakeLists.txt 2014-03-30 00:15:38.000000000 +0000 @@ -392,6 +392,7 @@ foreignkeyconstraint.cpp icon_utils.cpp import_rose.cpp + layoutgenerator.cpp listpopupmenu.cpp main.cpp model_utils.cpp diff -Nru umbrello-4.12.97/umbrello/dialogs/assocrolepage.cpp umbrello-4.13.0/umbrello/dialogs/assocrolepage.cpp --- umbrello-4.12.97/umbrello/dialogs/assocrolepage.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/dialogs/assocrolepage.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -102,7 +102,7 @@ propsBLayout->setMargin(margin); QStringList multiplicities; - multiplicities << "1" << "*" << "1..*" << "0..1"; + multiplicities << "" << "1" << "*" << "1..*" << "0..1"; // Properties // diff -Nru umbrello-4.12.97/umbrello/dialogs/diagrampropertiespage.cpp umbrello-4.13.0/umbrello/dialogs/diagrampropertiespage.cpp --- umbrello-4.12.97/umbrello/dialogs/diagrampropertiespage.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/dialogs/diagrampropertiespage.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -41,7 +41,8 @@ ui_gridSpaceX->setValue(scene->snapX()); ui_gridSpaceY->setValue(scene->snapY()); ui_documentation->setText(scene->documentation()); - if (scene->type() == Uml::DiagramType::Sequence) { + if (scene->type() == Uml::DiagramType::Sequence || + scene->type() == Uml::DiagramType::Collaboration) { ui_autoIncrementSequence->setVisible(true); ui_autoIncrementSequence->setChecked(scene->autoIncrementSequence()); } else { @@ -108,7 +109,8 @@ m_scene->setSnapToGrid(ui_snapToGrid->isChecked()); m_scene->setSnapComponentSizeToGrid(ui_snapComponentSizeToGrid->isChecked()); m_scene->setSnapGridVisible(ui_checkBoxShowGrid->isChecked()); - if (m_scene->type() == Uml::DiagramType::Sequence) { + if (m_scene->type() == Uml::DiagramType::Sequence || + m_scene->type() == Uml::DiagramType::Collaboration) { m_scene->setAutoIncrementSequence(ui_autoIncrementSequence->isChecked()); } emit applyClicked(); diff -Nru umbrello-4.12.97/umbrello/dialogs/selectopdlg.cpp umbrello-4.13.0/umbrello/dialogs/selectopdlg.cpp --- umbrello-4.12.97/umbrello/dialogs/selectopdlg.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/dialogs/selectopdlg.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -17,6 +17,7 @@ #include "debug_utils.h" #include "operation.h" #include "umlclassifierlistitemlist.h" +#include "umlscene.h" #include "umlview.h" #include "dialog_utils.h" @@ -44,9 +45,10 @@ * * @param parent The parent to this instance. * @param c The concept to get the operations from. + * @param enableAutoIncrement Flag to enable auto increment checkbox */ -SelectOpDlg::SelectOpDlg(QWidget * parent, UMLClassifier * c) - : KDialog(parent), m_classifier(c) +SelectOpDlg::SelectOpDlg(UMLView *parent, UMLClassifier * c, bool enableAutoIncrement) + : KDialog(parent), m_pView(parent), m_classifier(c) { setCaption(i18n("Select Operation")); setButtons(Ok | Cancel); @@ -73,6 +75,7 @@ m_pOpAS = new QCheckBox(i18n("Auto increment:"), m_pOpGB); mainLayout->addWidget(m_pOpAS, 0, 2); connect(m_pOpAS, SIGNAL(toggled(bool)), this, SLOT(slotAutoIncrementChecked(bool))); + m_pOpAS->setEnabled(enableAutoIncrement); m_pOpRB = new QLabel(i18n("Class operation:"), m_pOpGB); mainLayout->addWidget(m_pOpRB, 1, 0); @@ -94,6 +97,7 @@ connect(m_pOpLE, SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString))); mainLayout->addWidget(m_pOpLE, 2, 1, 1, 2); setupOperationsList(); + enableButtonOk(false); } /** @@ -145,7 +149,7 @@ void SelectOpDlg::slotAutoIncrementChecked(bool state) { if (state && m_pSeqLE->text().isEmpty()) - m_pSeqLE->setText(QLatin1String("1")); + m_pSeqLE->setText(m_pView->umlScene()->autoIncrementSequenceValue()); } /** @@ -158,6 +162,7 @@ return; setupOperationsList(); setClassOp(op->toString(Uml::SignatureType::SigNoVis)); + enableButtonOk(true); } /** @@ -168,6 +173,7 @@ if (index != -1) { m_pOpLE->setText(""); m_id = OP; + enableButtonOk(true); } } @@ -179,6 +185,7 @@ if (!text.isEmpty()) { m_pOpCB->setCurrentIndex(-1); m_id = CUSTOM; + enableButtonOk(true); } } diff -Nru umbrello-4.12.97/umbrello/dialogs/selectopdlg.h umbrello-4.13.0/umbrello/dialogs/selectopdlg.h --- umbrello-4.12.97/umbrello/dialogs/selectopdlg.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/dialogs/selectopdlg.h 2014-03-30 00:15:38.000000000 +0000 @@ -33,7 +33,7 @@ { Q_OBJECT public: - SelectOpDlg(QWidget * parent, UMLClassifier * c); + SelectOpDlg(UMLView * parent, UMLClassifier * c, bool enableAutoIncrement = true); ~SelectOpDlg(); QString getOpText(); diff -Nru umbrello-4.12.97/umbrello/layoutgenerator.cpp umbrello-4.13.0/umbrello/layoutgenerator.cpp --- umbrello-4.12.97/umbrello/layoutgenerator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ umbrello-4.13.0/umbrello/layoutgenerator.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -0,0 +1,572 @@ +/*************************************************************************** + * 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) 2012-2014 * + * Umbrello UML Modeller Authors * + ***************************************************************************/ + +#include "layoutgenerator.h" + +#include "associationline.h" +#include "associationwidget.h" +#include "debug_utils.h" +#include "floatingtextwidget.h" +#include "umlwidget.h" + +// app includes +#include +#include +#include + +// qt includes +#include +#include +#include +#include +#include +#include +#include +//#include + +#define LAYOUTGENERATOR_DEBUG +//#define LAYOUTGENERATOR_DATA_DEBUG + +#ifdef LAYOUTGENERATOR_DEBUG + +static QString pngViewer() +{ +#ifdef Q_WS_WIN + return "start"; +#else +#ifdef Q_WS_MAC + return "unknown"; +#else + return "okular"; +#endif +#endif +} + +static QString textViewer() +{ +#ifdef Q_WS_WIN + return "start"; +#else +#ifdef Q_WS_MAC + return "unknown"; +#else + return "mcedit"; +#endif +#endif +} +#endif + +/** + * constructor +*/ +LayoutGenerator::LayoutGenerator() +{ + setUseFullNodeLabels(false); +} + +/** + * Return state if layout generator is enabled. + * It is enabled when the dot application has been found. + * + * @return true if enabled +*/ +bool LayoutGenerator::isEnabled() +{ + Settings::OptionState& optionState = Settings::optionState(); + if (optionState.autoLayoutState.autoDotPath) { + m_dotPath = currentDotPath(); + } + else if (!optionState.autoLayoutState.dotPath.isEmpty()) { + m_dotPath = optionState.autoLayoutState.dotPath; + } + return !m_dotPath.isEmpty(); +} + +/** + * Return the path where dot is installed. + * + * @return string with dot path + */ +QString LayoutGenerator::currentDotPath() +{ + QString executable = KStandardDirs::findExe("dot"); + if (!executable.isEmpty()) { + QFileInfo fi(executable); + return fi.absolutePath(); + } +#ifdef Q_OS_WIN + // search for dot installation + QString appDir(qgetenv("ProgramFiles")); + QDir dir(appDir); + dir.setFilter(QDir::Dirs); + dir.setNameFilters(QStringList() << "Graphviz*"); + dir.setSorting(QDir::Reversed); + QFileInfoList list = dir.entryInfoList(); + if (list.size() > 0) { + QString dotPath = list.at(0).absoluteFilePath(); + QString exePath = QFile::exists(dotPath + "\\bin") ? dotPath + "\\bin" : dotPath; + return QFile::exists(exePath + "\\dot.exe") ? exePath : ""; + } +#endif + return QString(); +} + +/** + * generate layout and apply it to the given diagram. + * + * @return true if generating succeeded +*/ +bool LayoutGenerator::generate(UMLScene *scene, const QString &variant) +{ + QTemporaryFile in; + QTemporaryFile out; + QTemporaryFile xdotOut; + if (!isEnabled()) { + uWarning() << "Could not apply autolayout because graphviz installation has not been found."; + return false; + } + +#ifdef LAYOUTGENERATOR_DEBUG + in.setAutoRemove(false); + out.setAutoRemove(false); + xdotOut.setAutoRemove(false); +#endif + + // generate filenames + in.open(); + in.close(); + out.open(); + out.close(); + xdotOut.open(); + xdotOut.close(); + +#ifdef LAYOUTGENERATOR_DEBUG + qDebug() << textViewer() << in.fileName(); + qDebug() << textViewer() << out.fileName(); + qDebug() << textViewer() << xdotOut.fileName(); +#endif + + if (!createDotFile(scene, in.fileName(), variant)) + return false; + + QString executable = m_dotPath + "/" + m_generator; + + QProcess p; + QStringList args; + args << "-o" << out.fileName() << "-Tplain-ext" << in.fileName(); + p.start(executable, args); + p.waitForFinished(); + + args.clear(); + args << "-o" << xdotOut.fileName() << "-Txdot" << in.fileName(); + p.start(executable, args); + p.waitForFinished(); + +#ifdef LAYOUTGENERATOR_DEBUG + QTemporaryFile pngFile; + pngFile.setAutoRemove(false); + pngFile.setFileTemplate(QDir::tempPath() + "/umbrello-layoutgenerator-XXXXXX.png"); + pngFile.open(); + pngFile.close(); + qDebug() << pngViewer() << pngFile.fileName(); + args.clear(); + args << "-o" << pngFile.fileName() << "-Tpng" << in.fileName(); + p.start(executable, args); + p.waitForFinished(); +#endif +#ifndef USE_XDOT + if (!readGeneratedDotFile(out.fileName())) +#else + if (!readGeneratedDotFile(xdotOut.fileName())) +#endif + return false; + + return true; +} + +/** + * apply auto layout to the given scene + * @param scene + * @return true if autolayout has been applied + */ +bool LayoutGenerator::apply(UMLScene *scene) +{ + foreach(AssociationWidget *assoc, scene->associationList()) { + AssociationLine *path = assoc->associationLine(); + QString type = Uml::AssociationType::toString(assoc->associationType()).toLower(); + QString key = "type::" + type; + + QString id; + if (m_edgeParameters.contains("id::" + key) && m_edgeParameters["id::" + key] == "swap") + id = fixID(Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::A)) + Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::B))); + else + id = fixID(Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::B)) + Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::A))); + + // adjust associations not used in the dot file + if (!m_edges.contains(id)) { + // shorten line path + AssociationLine *path = assoc->associationLine(); + if (path->count() > 2 && assoc->widgetLocalIDForRole(Uml::RoleType::A) != assoc->widgetLocalIDForRole(Uml::RoleType::B)) { + while(path->count() > 2) + path->removePoint(1); + } + continue; + } + + EdgePoints &p = m_edges[id]; + int len = p.size(); + + while(path->count() > 1) { + path->removePoint(0); + } + path->setEndPoints(mapToScene(p[0]), mapToScene(p[len-1])); + + // set label position + QPointF &l = m_edgeLabelPosition[id]; + FloatingTextWidget *tw = assoc->nameWidget(); + if (tw) { + tw->setPos(mapToScene(l)); + } + // FIXME: set remaining association line points + /* + for(int i = 1; i < len-1; i++) { + path->insertPoint(i, mapToScene((p[i])); + } + */ + /* + * here stuff could be added to add more points from information returned by dot. + */ + } + + foreach(UMLWidget *widget, scene->widgetList()) { + QString id = Uml::ID::toString(widget->localID()); + if (!m_nodes.contains(id)) + continue; + QPoint p = origin(id); + widget->setX(p.x()); + widget->setY(p.y()-widget->height()); + widget->adjustAssocs(widget->x(), widget->y()); // adjust assoc lines + } + + foreach(AssociationWidget *assoc, scene->associationList()) { + assoc->calculateEndingPoints(); + if (assoc->associationLine()) + assoc->associationLine()->update(); + assoc->resetTextPositions(); + } + return true; +} + +/** + * Return a list of available templates for a given scene type + * + * @param scene The diagram + * @param configFiles will contain the collected list of config files + * @return true if collecting succeeds + */ +bool LayoutGenerator::availableConfigFiles(UMLScene *scene, QHash &configFiles) +{ + QString diagramType = Uml::DiagramType::toString(scene->type()).toLower(); + KStandardDirs dirs; + + QStringList fileNames = dirs.findAllResources("data", QString("umbrello/layouts/%1*.desktop").arg(diagramType)); + foreach(const QString &fileName, fileNames) { + QFileInfo fi(fileName); + QString baseName; + if (fi.baseName().contains("-")) + baseName = fi.baseName().remove(diagramType + "-"); + else if (fi.baseName() == diagramType) + baseName = fi.baseName(); + else + baseName = "default"; + KDesktopFile desktopFile(fileName); + configFiles[baseName] = desktopFile.readName(); + } + return true; +} + +/** + * Return the origin of node based on the bottom/left corner + * + * @param id The widget id to fetch the origin from + * @return QPoint instance with the coordinates + */ +QPoint LayoutGenerator::origin(const QString &id) +{ + QString key = fixID(id); + if (!m_nodes.contains(key)) { +#ifdef LAYOUTGENERATOR_DATA_DEBUG + uDebug() << key; +#endif + return QPoint(0,0); + } + QRectF &r = m_nodes[key]; + QPoint p(m_origin.x() + r.x() - r.width()/2, m_boundingRect.height() - r.y() + r.height()/2 + m_origin.y()); +#ifdef LAYOUTGENERATOR_DATA_DEBUG + uDebug() << r << p; +#endif + return p; +} + +/** + * Read generated dot file and extract positions + * of the contained widgets. + * + * @return true if extracting succeeded +*/ +bool LayoutGenerator::readGeneratedDotFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + QTextStream in(&file); + while (!in.atEnd()) { + QString line = in.readLine(); + while(line.endsWith(',')) + line += in.readLine(); + parseLine(line); + } + return true; +} + +#ifndef USE_XDOT +/** + * Parse line from dot generated plain-ext output format + * + * The format is documented at http://graphviz.org/content/output-formats#dplain-ext and looks like: + * + * graph 1 28.083 10.222 + * node ITfDmJvJE00m 8.0833 8.7361 0.86111 0.45833 QObject solid box black lightgrey + * edge sL4cKPpHnJkU sL4cKPpHnJkU 7 8.1253 7.2568 8.2695 7.2687 8.375 7.3127 8.375 7.3889 8.375 7.4377 8.3317 7.4733 8.2627 7.4957 Aggregation 8.8472 7.3889 solid black + * + * @param line line in dot plain-ext output format + * @return true if line could be parsed successfully +*/ +bool LayoutGenerator::parseLine(const QString &line) +{ + QStringList a = line.split(' '); + if (a[0] == "graph") { + m_boundingRect = QRectF(0, 0, a[2].toDouble()*m_scale, a[3].toDouble()*m_scale); + return true; + } else if (a[0] == "node") { + QString key = fixID(a[1]); + m_nodes[key] = QRectF(a[2].toDouble()*m_scale, a[3].toDouble()*m_scale, a[4].toDouble()*m_scale, a[5].toDouble()*m_scale); + return true; + } else if (a[0] == "edge") { + QString key = fixID(a[1]+a[2]); + EdgePoints p; + int len = a[3].toInt(); + for(int i = 0; i < len; i++) + p.append(QPointF(a[i*2+4].toDouble()*m_scale, a[i*2+5].toDouble()*m_scale)); + m_edges[key] = p; + + int b = len*2 + 4; + bool ok; + double x = a[b+1].toDouble(&ok); + if (!ok) + return true; + double y = a[b+2].toDouble(&ok); + if (!ok) + return true; + m_edgeLabelPosition[key] = QPointF(x*m_scale, y*m_scale); + + return true; + } else if (a[0] == "stop") { + return true; + } + return false; +} + +#else +typedef QMap ParameterList; + +bool LayoutGenerator::splitParameters(QMap &map, const QString &s) +{ + // FIXME: add shape=box without '"' + static QRegExp rx("([a-zA-Z_]+)=\"([a-zA-Z0-9.- #]+)\""); + static QRegExp rx2("([a-zA-Z_]+)=([a-zA-Z0-9.- #]+)"); + int pos = 0; + int count = 0; + /* + * while ((pos = rx2.indexIn(s, pos)) != -1) { + * QString key = rx2.cap(1); + * QString value = rx2.cap(2); + * ++count; + * pos += rx2.matchedLength(); + * //qDebug() << key << value; + * if (map.contains(key)) + * map[key] << value; + * else + * map[key] = QStringList() << value; + } + */ + pos = 0; + while ((pos = rx.indexIn(s, pos)) != -1) { + QString key = rx.cap(1); + QString value = rx.cap(2); + ++count; + pos += rx.matchedLength(); + //qDebug() << key << value; + + QStringList data; + if (key == "pos") { + value.remove("e,"); + data = value.split(' '); + } else if (key.startsWith('_')) { + data = value.split(' '); + } + else if (key == "label") + data = QStringList() << value; + else + data = value.split(','); + + if (map.contains(key)) + map[key] << data; + else + map[key] = data; + } + return true; +} + +/** + * +digraph G { + graph [splines=polyline, rankdir=BT, outputorder=nodesfirst, ranksep="0.5", nodesep="0.5"]; + node [label="\N"]; + graph [bb="0,0,2893,638", + _draw_="c 9 -#ffffffff C 9 -#ffffffff P 4 0 -1 0 638 2894 638 2894 -1 ", + xdotversion="1.2"]; + XC0weWhArzOJ [label=note, shape=box, width="2.5833", height="0.86111", pos="93,31", _draw_="c 9 -#000000ff p 4 186 62 0 62 0 0 186 0 ", _ldraw_="F 14.000000 11 -Times-Roman c 9 -#000000ff T 93 27 0 24 4 -note "]; + sL4cKPpHnJkU -> ITfDmJvJE00m [arrowhead=normal, weight="1.0", label=" ", pos="e,2326.3,600.47 2299.7,543.57 2306.1,557.22 2314.9,575.99 2322.1,591.39", lp="2319,572", _draw_="c 9 -#000000ff B 4 2300 544 2306 557 2315 576 2322 591 ", _hdraw_="S 5 -solid c 9 -#000000ff C 9 -#000000ff P 3 2319 593 2326 600 2325 590 ", _ldraw_="F 14.000000 11 -Times-Roman c 9 -#000000ff T 2319 568 0 4 1 - "]; + sL4cKPpHnJkU -> sL4cKPpHnJkU [label=" ", arrowtail=odiamond, dir=back, constraint=false, pos="s,2339.3,516.43 2351.5,516.59 2365.1,517.35 2375,520.16 2375,525 2375,531.2 2358.7,534.06 2339.3,533.57", lp="2377,525", _draw_="c 9 -#000000ff B 7 2351 517 2365 517 2375 520 2375 525 2375 531 2359 534 2339 534 ", _tdraw_="S 5 -solid c 9 -#000000ff p 4 2351 517 2345 521 2339 516 2345 513 ", _ldraw_="F 14.000000 11 -Times-Roman c 9 -#000000ff T 2377 521 0 4 1 - "]; +*/ + +bool LayoutGenerator::parseLine(const QString &line) +{ + static QRegExp m_cols("^[\t ]*(.*)[\t ]*\\[(.*)\\]"); + static int m_level = -1; + + if (line.contains('{')) { + m_level++; + return true; + } + else if (line.contains('}')) { + m_level--; + return true; + } + int pos = 0; + if (m_cols.indexIn(line, pos) == -1) + return false; + + QString keyword = m_cols.cap(1).trimmed(); + QString attributeString = m_cols.cap(2); + uDebug() << keyword << attributeString; + ParameterList attributes; + splitParameters(attributes, attributeString); + uDebug() << attributes; + + if (keyword == "graph") { + if (attributes.contains("bb")) { + QStringList &a = attributes["bb"]; + m_boundingRect.setLeft(a[0].toDouble()); + m_boundingRect.setTop(a[1].toDouble()); + m_boundingRect.setRight(a[2].toDouble()); + m_boundingRect.setBottom(a[3].toDouble()); + } + } else if (keyword == "node") { + return true; + } else if (keyword == "edge") { + return true; + // transistion + } else if (line.contains("->")) { + QStringList k = keyword.split(" "); + if (k.size() < 3) + return false; + QString key = fixID(k[0]+k[2]); + + if (attributes.contains("pos")) { + QStringList &a = attributes["pos"]; + EdgePoints points; + + for(int i = 1; i < a.size(); i++) { + QStringList b = a[i].split(','); + QPointF p(b[0].toDouble(), b[1].toDouble()); + points.append(p); + } + QStringList b = a[0].split(','); + QPointF p(b[0].toDouble(), b[1].toDouble()); + points.append(p); + + m_edges[key] = points; + } + if (0 && attributes.contains("_draw_")) { + QStringList &a = attributes["_draw_"]; + if (a.size() < 5 || (a[3] != "L" && a[3] != "p")) + return false; + int size = a[4].toInt(); + EdgePoints points; + + for(int i = 0; i < size; i++) { + QPointF p(a[i*2+5].toDouble(), a[i*2+6].toDouble()); + points.append(p); + } + m_edges[key] = points; + } + return true; + // single node + } else { + double scale = 72.0; + QRectF f(0, 0, 0, 0); + QString id = fixID(keyword); + if (attributes.contains("pos")) { + QStringList &a = attributes["pos"]; + QStringList b = a[0].split(","); + f.setLeft(b[0].toDouble()); + f.setTop(b[1].toDouble()); + } + if (attributes.contains("height")) { + QStringList &a = attributes["height"]; + f.setHeight(a[0].toDouble()*scale); + } + + if (attributes.contains("width")) { + QStringList &a = attributes["width"]; + f.setWidth(a[0].toDouble()*scale); + } + uDebug() << "adding" << id << f; + m_nodes[id] = f; + } +return true; +} +#endif + +/** + * map dot coordinate to scene coordinate + * @param p dot point to map + * @return uml scene coordinate + */ +QPointF LayoutGenerator::mapToScene(const QPointF &p) +{ + return QPointF(p.x()+ m_origin.x(), m_boundingRect.height() - p.y() + m_origin.y()); +} + +#if 0 +static QDebug operator<<(QDebug out, LayoutGenerator &c) +{ + out << "LayoutGenerator:" + << "m_boundingRect:" << c.m_boundingRect + << "m_nodes:" << c.m_nodes + << "m_edges:" << c.m_edges + << "m_scale:" << c.m_scale + << "m_executable:" << c.m_executable; + return out; +} +#endif diff -Nru umbrello-4.12.97/umbrello/layoutgenerator.h umbrello-4.13.0/umbrello/layoutgenerator.h --- umbrello-4.12.97/umbrello/layoutgenerator.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/layoutgenerator.h 2014-03-30 00:15:38.000000000 +0000 @@ -10,62 +10,11 @@ #ifndef LAYOUTGENERATOR_H -#include "associationline.h" -#include "associationwidget.h" -#include "debug_utils.h" #include "dotgenerator.h" -#include "floatingtextwidget.h" #include "optionstate.h" -#include "umlwidget.h" -// app includes -#include -#include -#include - -// qt includes -#include -#include -#include -#include -#include +//// qt includes #include -#include -#include -#include -#include - -#define LAYOUTGENERATOR_DEBUG -//#define LAYOUTGENERATOR_DATA_DEBUG - -#ifdef LAYOUTGENERATOR_DEBUG - -static QString pngViewer() -{ -#ifdef Q_WS_WIN - return "start"; -#else -#ifdef Q_WS_MAC - return "unknown"; -#else - return "okular"; -#endif -#endif -} - -static QString textViewer() -{ -#ifdef Q_WS_WIN - return "start"; -#else -#ifdef Q_WS_MAC - return "unknown"; -#else - return "mcedit"; -#endif -#endif -} -#endif /** * The class LayoutGenerator provides calculated layouts of diagrams. @@ -92,503 +41,22 @@ typedef QHash NodeType; typedef QList EdgePoints; typedef QHash EdgeType; - - /** - * constructor - */ - LayoutGenerator() - { - setUseFullNodeLabels(false); - } - - /** - * Return state if layout generator is enabled. - * It is enabled when the dot application has been found. - * - * @return true if enabled - */ - bool isEnabled() - { - Settings::OptionState& optionState = Settings::optionState(); - if (optionState.autoLayoutState.autoDotPath) { - m_dotPath = currentDotPath(); - } - else if (!optionState.autoLayoutState.dotPath.isEmpty()) { - m_dotPath = optionState.autoLayoutState.dotPath; - } - return !m_dotPath.isEmpty(); - } - - /** - * Return the path where dot is installed. - * - * @return string with dot path - */ - static QString currentDotPath() - { - QString executable = KStandardDirs::findExe("dot"); - if (!executable.isEmpty()) { - QFileInfo fi(executable); - return fi.absolutePath(); - } -#ifdef Q_OS_WIN - // search for dot installation - QString appDir(qgetenv("ProgramFiles")); - QDir dir(appDir); - dir.setFilter(QDir::Dirs); - dir.setNameFilters(QStringList() << "Graphviz*"); - dir.setSorting(QDir::Reversed); - QFileInfoList list = dir.entryInfoList(); - if (list.size() > 0) { - QString dotPath = list.at(0).absoluteFilePath(); - QString exePath = QFile::exists(dotPath + "\\bin") ? dotPath + "\\bin" : dotPath; - return QFile::exists(exePath + "\\dot.exe") ? exePath : ""; - } -#endif - return QString(); - } - - /** - * generate layout and apply it to the given diagram. - * - * @return true if generating succeeded - */ - bool generate(UMLScene *scene, const QString &variant = QString()) - { - QTemporaryFile in; - QTemporaryFile out; - QTemporaryFile xdotOut; - if (!isEnabled()) { - uWarning() << "Could not apply autolayout because graphviz installation has not been found."; - return false; - } - -#ifdef LAYOUTGENERATOR_DEBUG - in.setAutoRemove(false); - out.setAutoRemove(false); - xdotOut.setAutoRemove(false); -#endif - - // generate filenames - in.open(); - in.close(); - out.open(); - out.close(); - xdotOut.open(); - xdotOut.close(); - -#ifdef LAYOUTGENERATOR_DEBUG - qDebug() << textViewer() << in.fileName(); - qDebug() << textViewer() << out.fileName(); - qDebug() << textViewer() << xdotOut.fileName(); -#endif - - if (!createDotFile(scene, in.fileName(), variant)) - return false; - - QString executable = m_dotPath + "/" + m_generator; - - QProcess p; - QStringList args; - args << "-o" << out.fileName() << "-Tplain-ext" << in.fileName(); - p.start(executable, args); - p.waitForFinished(); - - args.clear(); - args << "-o" << xdotOut.fileName() << "-Txdot" << in.fileName(); - p.start(executable, args); - p.waitForFinished(); - -#ifdef LAYOUTGENERATOR_DEBUG - QTemporaryFile pngFile; - pngFile.setAutoRemove(false); - pngFile.setFileTemplate(QDir::tempPath() + "/umbrello-layoutgenerator-XXXXXX.png"); - pngFile.open(); - pngFile.close(); - qDebug() << pngViewer() << pngFile.fileName(); - args.clear(); - args << "-o" << pngFile.fileName() << "-Tpng" << in.fileName(); - p.start(executable, args); - p.waitForFinished(); -#endif -#ifndef USE_XDOT - if (!readGeneratedDotFile(out.fileName())) -#else - if (!readGeneratedDotFile(xdotOut.fileName())) -#endif - return false; - - return true; - } - - /** - * apply auto layout to the given scene - * @param scene - * @return true if autolayout has been applied - */ - bool apply(UMLScene *scene) - { - foreach(AssociationWidget *assoc, scene->associationList()) { - AssociationLine *path = assoc->associationLine(); - QString type = Uml::AssociationType::toString(assoc->associationType()).toLower(); - QString key = "type::" + type; - - QString id; - if (m_edgeParameters.contains("id::" + key) && m_edgeParameters["id::" + key] == "swap") - id = fixID(Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::A)) + Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::B))); - else - id = fixID(Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::B)) + Uml::ID::toString(assoc->widgetLocalIDForRole(Uml::RoleType::A))); - - // adjust associations not used in the dot file - if (!m_edges.contains(id)) { - // shorten line path - AssociationLine *path = assoc->associationLine(); - if (path->count() > 2 && assoc->widgetLocalIDForRole(Uml::RoleType::A) != assoc->widgetLocalIDForRole(Uml::RoleType::B)) { - while(path->count() > 2) - path->removePoint(1); - } - continue; - } - - EdgePoints &p = m_edges[id]; - int len = p.size(); - - while(path->count() > 1) { - path->removePoint(0); - } - path->setEndPoints(mapToScene(p[0]), mapToScene(p[len-1])); - - // set label position - QPointF &l = m_edgeLabelPosition[id]; - FloatingTextWidget *tw = assoc->nameWidget(); - if (tw) { - tw->setPos(mapToScene(l)); - } - // FIXME: set remaining association line points - /* - for(int i = 1; i < len-1; i++) { - path->insertPoint(i, mapToScene((p[i])); - } - */ - /* - * here stuff could be added to add more points from information returned by dot. - */ - } - - foreach(UMLWidget *widget, scene->widgetList()) { - QString id = Uml::ID::toString(widget->localID()); - if (!m_nodes.contains(id)) - continue; - QPoint p = origin(id); - widget->setX(p.x()); - widget->setY(p.y()-widget->height()); - widget->adjustAssocs(widget->x(), widget->y()); // adjust assoc lines - } - - foreach(AssociationWidget *assoc, scene->associationList()) { - assoc->calculateEndingPoints(); - if (assoc->associationLine()) - assoc->associationLine()->update(); - assoc->resetTextPositions(); - } - return true; - } - - /** - * Return a list of available templates for a given scene type - * - * @param scene The diagram - * @param configFiles will contain the collected list of config files - * @return true if collecting succeeds - */ - static bool availableConfigFiles(UMLScene *scene, QHash &configFiles) - { - QString diagramType = Uml::DiagramType::toString(scene->type()).toLower(); - KStandardDirs dirs; - - QStringList fileNames = dirs.findAllResources("data", QString("umbrello/layouts/%1*.desktop").arg(diagramType)); - foreach(const QString &fileName, fileNames) { - QFileInfo fi(fileName); - QString baseName; - if (fi.baseName().contains("-")) - baseName = fi.baseName().remove(diagramType + "-"); - else if (fi.baseName() == diagramType) - baseName = fi.baseName(); - else - baseName = "default"; - KDesktopFile desktopFile(fileName); - configFiles[baseName] = desktopFile.readName(); - } - return true; - } - -protected: - /** - * Return the origin of node based on the bottom/left corner - * - * @param id The widget id to fetch the origin from - * @return QPoint instance with the coordinates - */ - QPoint origin(const QString &id) - { - QString key = fixID(id); - if (!m_nodes.contains(key)) { -#ifdef LAYOUTGENERATOR_DATA_DEBUG - uDebug() << key; -#endif - return QPoint(0,0); - } - QRectF &r = m_nodes[key]; - QPoint p(m_origin.x() + r.x() - r.width()/2, m_boundingRect.height() - r.y() + r.height()/2 + m_origin.y()); -#ifdef LAYOUTGENERATOR_DATA_DEBUG - uDebug() << r << p; -#endif - return p; - } - - /** - * Read generated dot file and extract positions - * of the contained widgets. - * - * @return true if extracting succeeded - */ - bool readGeneratedDotFile(const QString &fileName) - { - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - return false; - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - while(line.endsWith(',')) - line += in.readLine(); - parseLine(line); - } - return true; - } - -#ifndef USE_XDOT - /** - * Parse line from dot generated plain-ext output format - * - * The format is documented at http://graphviz.org/content/output-formats#dplain-ext and looks like: - * - * graph 1 28.083 10.222 - * node ITfDmJvJE00m 8.0833 8.7361 0.86111 0.45833 QObject solid box black lightgrey - * edge sL4cKPpHnJkU sL4cKPpHnJkU 7 8.1253 7.2568 8.2695 7.2687 8.375 7.3127 8.375 7.3889 8.375 7.4377 8.3317 7.4733 8.2627 7.4957 Aggregation 8.8472 7.3889 solid black - * - * @param line line in dot plain-ext output format - * @return true if line could be parsed successfully - */ - bool parseLine(const QString &line) - { - QStringList a = line.split(' '); - if (a[0] == "graph") { - m_boundingRect = QRectF(0, 0, a[2].toDouble()*m_scale, a[3].toDouble()*m_scale); - return true; - } else if (a[0] == "node") { - QString key = fixID(a[1]); - m_nodes[key] = QRectF(a[2].toDouble()*m_scale, a[3].toDouble()*m_scale, a[4].toDouble()*m_scale, a[5].toDouble()*m_scale); - return true; - } else if (a[0] == "edge") { - QString key = fixID(a[1]+a[2]); - EdgePoints p; - int len = a[3].toInt(); - for(int i = 0; i < len; i++) - p.append(QPointF(a[i*2+4].toDouble()*m_scale, a[i*2+5].toDouble()*m_scale)); - m_edges[key] = p; - - int b = len*2 + 4; - bool ok; - double x = a[b+1].toDouble(&ok); - if (!ok) - return true; - double y = a[b+2].toDouble(&ok); - if (!ok) - return true; - m_edgeLabelPosition[key] = QPointF(x*m_scale, y*m_scale); - - return true; - } else if (a[0] == "stop") { - return true; - } - return false; - } - -#else typedef QMap ParameterList; - bool splitParameters(QMap &map, const QString &s) - { - // FIXME: add shape=box without '"' - static QRegExp rx("([a-zA-Z_]+)=\"([a-zA-Z0-9.- #]+)\""); - static QRegExp rx2("([a-zA-Z_]+)=([a-zA-Z0-9.- #]+)"); - int pos = 0; - int count = 0; - /* - * while ((pos = rx2.indexIn(s, pos)) != -1) { - * QString key = rx2.cap(1); - * QString value = rx2.cap(2); - * ++count; - * pos += rx2.matchedLength(); - * //qDebug() << key << value; - * if (map.contains(key)) - * map[key] << value; - * else - * map[key] = QStringList() << value; - } - */ - pos = 0; - while ((pos = rx.indexIn(s, pos)) != -1) { - QString key = rx.cap(1); - QString value = rx.cap(2); - ++count; - pos += rx.matchedLength(); - //qDebug() << key << value; - - QStringList data; - if (key == "pos") { - value.remove("e,"); - data = value.split(' '); - } else if (key.startsWith('_')) { - data = value.split(' '); - } - else if (key == "label") - data = QStringList() << value; - else - data = value.split(','); + LayoutGenerator(); - if (map.contains(key)) - map[key] << data; - else - map[key] = data; - } - return true; - } - -/** - * - digraph G { - graph [splines=polyline, rankdir=BT, outputorder=nodesfirst, ranksep="0.5", nodesep="0.5"]; - node [label="\N"]; - graph [bb="0,0,2893,638", - _draw_="c 9 -#ffffffff C 9 -#ffffffff P 4 0 -1 0 638 2894 638 2894 -1 ", - xdotversion="1.2"]; - XC0weWhArzOJ [label=note, shape=box, width="2.5833", height="0.86111", pos="93,31", _draw_="c 9 -#000000ff p 4 186 62 0 62 0 0 186 0 ", _ldraw_="F 14.000000 11 -Times-Roman c 9 -#000000ff T 93 27 0 24 4 -note "]; - sL4cKPpHnJkU -> ITfDmJvJE00m [arrowhead=normal, weight="1.0", label=" ", pos="e,2326.3,600.47 2299.7,543.57 2306.1,557.22 2314.9,575.99 2322.1,591.39", lp="2319,572", _draw_="c 9 -#000000ff B 4 2300 544 2306 557 2315 576 2322 591 ", _hdraw_="S 5 -solid c 9 -#000000ff C 9 -#000000ff P 3 2319 593 2326 600 2325 590 ", _ldraw_="F 14.000000 11 -Times-Roman c 9 -#000000ff T 2319 568 0 4 1 - "]; - sL4cKPpHnJkU -> sL4cKPpHnJkU [label=" ", arrowtail=odiamond, dir=back, constraint=false, pos="s,2339.3,516.43 2351.5,516.59 2365.1,517.35 2375,520.16 2375,525 2375,531.2 2358.7,534.06 2339.3,533.57", lp="2377,525", _draw_="c 9 -#000000ff B 7 2351 517 2365 517 2375 520 2375 525 2375 531 2359 534 2339 534 ", _tdraw_="S 5 -solid c 9 -#000000ff p 4 2351 517 2345 521 2339 516 2345 513 ", _ldraw_="F 14.000000 11 -Times-Roman c 9 -#000000ff T 2377 521 0 4 1 - "]; - */ - - bool parseLine(const QString &line) - { - static QRegExp m_cols("^[\t ]*(.*)[\t ]*\\[(.*)\\]"); - static int m_level = -1; - - if (line.contains('{')) { - m_level++; - return true; - } - else if (line.contains('}')) { - m_level--; - return true; - } - int pos = 0; - if (m_cols.indexIn(line, pos) == -1) - return false; - - QString keyword = m_cols.cap(1).trimmed(); - QString attributeString = m_cols.cap(2); - uDebug() << keyword << attributeString; - ParameterList attributes; - splitParameters(attributes, attributeString); - uDebug() << attributes; - - if (keyword == "graph") { - if (attributes.contains("bb")) { - QStringList &a = attributes["bb"]; - m_boundingRect.setLeft(a[0].toDouble()); - m_boundingRect.setTop(a[1].toDouble()); - m_boundingRect.setRight(a[2].toDouble()); - m_boundingRect.setBottom(a[3].toDouble()); - } - } else if (keyword == "node") { - return true; - } else if (keyword == "edge") { - return true; - // transistion - } else if (line.contains("->")) { - QStringList k = keyword.split(" "); - if (k.size() < 3) - return false; - QString key = fixID(k[0]+k[2]); - - if (attributes.contains("pos")) { - QStringList &a = attributes["pos"]; - EdgePoints points; - - for(int i = 1; i < a.size(); i++) { - QStringList b = a[i].split(','); - QPointF p(b[0].toDouble(), b[1].toDouble()); - points.append(p); - } - QStringList b = a[0].split(','); - QPointF p(b[0].toDouble(), b[1].toDouble()); - points.append(p); - - m_edges[key] = points; - } - if (0 && attributes.contains("_draw_")) { - QStringList &a = attributes["_draw_"]; - if (a.size() < 5 || (a[3] != "L" && a[3] != "p")) - return false; - int size = a[4].toInt(); - EdgePoints points; - - for(int i = 0; i < size; i++) { - QPointF p(a[i*2+5].toDouble(), a[i*2+6].toDouble()); - points.append(p); - } - m_edges[key] = points; - } - return true; - // single node - } else { - double scale = 72.0; - QRectF f(0, 0, 0, 0); - QString id = fixID(keyword); - if (attributes.contains("pos")) { - QStringList &a = attributes["pos"]; - QStringList b = a[0].split(","); - f.setLeft(b[0].toDouble()); - f.setTop(b[1].toDouble()); - } - if (attributes.contains("height")) { - QStringList &a = attributes["height"]; - f.setHeight(a[0].toDouble()*scale); - } - - if (attributes.contains("width")) { - QStringList &a = attributes["width"]; - f.setWidth(a[0].toDouble()*scale); - } - uDebug() << "adding" << id << f; - m_nodes[id] = f; - } - return true; - } -#endif - - /** - * map dot coordinate to scene coordinate - * @param p dot point to map - * @return uml scene coordinate - */ - QPointF mapToScene(const QPointF &p) - { - return QPointF(p.x()+ m_origin.x(), m_boundingRect.height() - p.y() + m_origin.y()); - } + bool isEnabled(); + static QString currentDotPath(); + bool generate(UMLScene *scene, const QString &variant = QString()); + bool apply(UMLScene *scene); + static bool availableConfigFiles(UMLScene *scene, QHash &configFiles); + QPoint origin(const QString &id); + bool readGeneratedDotFile(const QString &fileName); + bool parseLine(const QString &line); + bool splitParameters(QMap &map, const QString &s); + QPointF mapToScene(const QPointF &p); +protected: QRectF m_boundingRect; NodeType m_nodes; ///< list of nodes found in parsed dot file EdgeType m_edges; ///< list of edges found in parsed dot file @@ -599,15 +67,7 @@ }; #if 0 -static QDebug operator<<(QDebug out, LayoutGenerator &c) -{ - out << "LayoutGenerator:" - << "m_boundingRect:" << c.m_boundingRect - << "m_nodes:" << c.m_nodes - << "m_edges:" << c.m_edges - << "m_scale:" << c.m_scale - << "m_executable:" << c.m_executable; - return out; -} +static QDebug operator<<(QDebug out, LayoutGenerator &c); #endif + #endif diff -Nru umbrello-4.12.97/umbrello/listpopupmenu.cpp umbrello-4.13.0/umbrello/listpopupmenu.cpp --- umbrello-4.12.97/umbrello/listpopupmenu.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/listpopupmenu.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -14,6 +14,7 @@ // app includes #include "activitywidget.h" #include "associationline.h" +#include "associationwidget.h" #include "category.h" #include "classifier.h" #include "classifierwidget.h" diff -Nru umbrello-4.12.97/umbrello/toolbarstateassociation.cpp umbrello-4.13.0/umbrello/toolbarstateassociation.cpp --- umbrello-4.12.97/umbrello/toolbarstateassociation.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/toolbarstateassociation.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -228,6 +228,9 @@ } if (valid) { AssociationWidget *temp = AssociationWidget::create(m_pUMLScene, widgetA, type, widgetB); + FloatingTextWidget *wt = temp->textWidgetByRole(Uml::TextRole::Coll_Message); + if (wt) + wt->showOperationDialog(); if (addAssociationInViewAndDoc(temp)) { if (type == Uml::AssociationType::Containment) { UMLObject *newContainer = widgetA->umlObject(); diff -Nru umbrello-4.12.97/umbrello/umlscene.cpp umbrello-4.13.0/umbrello/umlscene.cpp --- umbrello-4.12.97/umbrello/umlscene.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/umlscene.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -121,8 +121,7 @@ m_pIDChangesLog(0), m_isActivated(false), m_bPopupShowing(false), - m_autoIncrementSequence(false), - m_autoIncrementSequenceValue(0) + m_autoIncrementSequence(false) { //m_AssociationList.setAutoDelete(true); //m_WidgetList.setAutoDelete(true); @@ -224,14 +223,29 @@ m_autoIncrementSequence = state; } -QString UMLScene::autoIncrementSequenceValue(int increment) const -{ - return QString::number(m_autoIncrementSequenceValue + increment); -} - -void UMLScene::setAutoIncrementSequenceValue(const QString &value) +/** + * Return the next auto increment sequence value + */ +QString UMLScene::autoIncrementSequenceValue() { - m_autoIncrementSequenceValue = value.toInt(); + int sequenceNumber = 0; + if (type() == Uml::DiagramType::Sequence) { + foreach (MessageWidget* message, messageList()) { + bool ok; + int value = message->sequenceNumber().toInt(&ok); + if (ok && value > sequenceNumber) + sequenceNumber = value; + } + } + else if (type() == Uml::DiagramType::Collaboration) { + foreach (AssociationWidget* assoc, associationList()) { + bool ok; + int value = assoc->sequenceNumber().toInt(&ok); + if (ok && value > sequenceNumber) + sequenceNumber = value; + } + } + return QString::number(sequenceNumber + 1); } /** @@ -3548,6 +3562,8 @@ viewElement.setAttribute("canvasheight", height()); viewElement.setAttribute("canvaswidth", width()); viewElement.setAttribute("isopen", isOpen()); + if (type() == Uml::DiagramType::Sequence) + viewElement.setAttribute("autoincrementsequence", autoIncrementSequence()); //now save all the widgets QDomElement widgetElement = qDoc.createElement("widgets"); @@ -3671,6 +3687,11 @@ } m_nLocalID = Uml::ID::fromString(localid); + if (m_Type == Uml::DiagramType::Sequence) { + QString autoIncrementSequence = qElement.attribute("autoincrementsequence", "0"); + m_autoIncrementSequence = (bool)autoIncrementSequence.toInt(); + } + QDomNode node = qElement.firstChild(); bool widgetsLoaded = false, messagesLoaded = false, associationsLoaded = false; while (!node.isNull()) { diff -Nru umbrello-4.12.97/umbrello/umlscene.h umbrello-4.13.0/umbrello/umlscene.h --- umbrello-4.12.97/umbrello/umlscene.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/umlscene.h 2014-03-30 00:15:38.000000000 +0000 @@ -91,8 +91,7 @@ bool autoIncrementSequence() const; void setAutoIncrementSequence(bool state); - QString autoIncrementSequenceValue(int increment=0) const; - void setAutoIncrementSequenceValue(const QString &value); + QString autoIncrementSequenceValue(); QString name() const; void setName(const QString &name); @@ -385,7 +384,6 @@ UMLViewImageExporter* m_pImageExporter; ///< Used to export the view. LayoutGrid* m_layoutGrid; ///< layout grid in the background bool m_autoIncrementSequence; ///< state of auto increment sequence - int m_autoIncrementSequenceValue; ///< current auto increment value void createAutoAttributeAssociation(UMLClassifier *type, UMLAttribute *attr, diff -Nru umbrello-4.12.97/umbrello/version.h umbrello-4.13.0/umbrello/version.h --- umbrello-4.12.97/umbrello/version.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/version.h 2014-03-30 00:15:38.000000000 +0000 @@ -27,6 +27,6 @@ } // Update this version when changing the XMI file format -#define XMI_FILE_VERSION "1.6.3" +#define XMI_FILE_VERSION "1.6.4" #endif diff -Nru umbrello-4.12.97/umbrello/widgets/associationwidget.cpp umbrello-4.13.0/umbrello/widgets/associationwidget.cpp --- umbrello-4.12.97/umbrello/widgets/associationwidget.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/associationwidget.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -327,6 +327,8 @@ m_umlObject = op; if (m_umlObject) connect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); + if (m_nameWidget) + m_nameWidget->setMessageText(); } /** @@ -384,17 +386,16 @@ */ void AssociationWidget::setMessageText(FloatingTextWidget *ft) { - QString message; if (isCollaboration()) { + ft->setSequenceNumber(m_SequenceNumber); if (m_umlObject != NULL) { - message = multiplicity(RoleType::A) + ": " + operationText(m_scene); + ft->setText(operationText(m_scene)); } else { - message = multiplicity(RoleType::A) + ": " + name(); + ft->setText(name()); } } else { - message = name(); + ft->setText(name()); } - ft->setText(message); } /** @@ -469,7 +470,7 @@ */ UMLClassifier* AssociationWidget::seqNumAndOp(QString& seqNum, QString& op) { - seqNum = multiplicity(RoleType::A); + seqNum = m_SequenceNumber; op = name(); UMLObject *o = widgetForRole(RoleType::B)->umlObject(); UMLClassifier *c = dynamic_cast(o); @@ -488,7 +489,7 @@ if (!op.isEmpty()) { setName(op); } - setMultiplicity(seqNum, RoleType::A); + setSequenceNumber(seqNum); } /** @@ -3989,6 +3990,7 @@ QDomElement assocElement = qDoc.createElement("assocwidget"); WidgetBase::saveToXMI(qDoc, assocElement); + LinkWidget::saveToXMI(qDoc, assocElement); if (m_umlObject) { assocElement.setAttribute("xmi.id", Uml::ID::toString(m_umlObject->id())); } @@ -4063,6 +4065,10 @@ return false; } + if (!LinkWidget::loadFromXMI(qElement)) { + return false; + } + // load child widgets first QString widgetaid = qElement.attribute("widgetaid", "-1"); QString widgetbid = qElement.attribute("widgetbid", "-1"); @@ -4235,6 +4241,7 @@ // always need this ft->setParentItem(this); ft->setLink(this); + ft->setSequenceNumber(m_SequenceNumber); switch(role) { case Uml::TextRole::MultiA: diff -Nru umbrello-4.12.97/umbrello/widgets/floatingtextwidget.cpp umbrello-4.13.0/umbrello/widgets/floatingtextwidget.cpp --- umbrello-4.12.97/umbrello/widgets/floatingtextwidget.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/floatingtextwidget.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -105,10 +105,10 @@ if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { QString seqNum, op; m_linkWidget->seqNumAndOp(seqNum, op); - if (seqNum.length() > 0 || op.length() > 0) { - if (! m_scene->showOpSig()) + if (op.length() > 0) { + if (!m_scene->showOpSig()) op.replace(QRegExp("\\(.*\\)"), "()"); - m_Text = seqNum.append(": ").append(op); + m_Text = op; } else m_Text = t; @@ -154,7 +154,11 @@ */ QString FloatingTextWidget::displayText() const { - QString displayText = m_Text; + QString displayText; + if (!m_SequenceNumber.isEmpty()) + displayText = m_SequenceNumber + ": " + m_Text; + else + displayText = m_Text; displayText.prepend(m_preText); displayText.append(m_postText); return displayText; @@ -201,8 +205,10 @@ /** * Shows an operation dialog box. + * + * @param enableAutoIncrement Enable auto increment checkbox */ -void FloatingTextWidget::showOperationDialog() +void FloatingTextWidget::showOperationDialog(bool enableAutoIncrement) { if (!m_linkWidget) { uError() << "m_linkWidget is NULL"; @@ -215,9 +221,9 @@ return; } - QPointer selectDlg = new SelectOpDlg(m_scene->activeView(), c); - if (m_scene->autoIncrementSequence()) { - seqNum = m_scene->autoIncrementSequenceValue(1); + QPointer selectDlg = new SelectOpDlg(m_scene->activeView(), c, enableAutoIncrement); + if (enableAutoIncrement && m_scene->autoIncrementSequence()) { + seqNum = m_scene->autoIncrementSequenceValue(); selectDlg->setAutoIncrementSequence(true); } selectDlg->setSeqNumber(seqNum); @@ -260,10 +266,9 @@ m_linkWidget->setOperation(0); } m_linkWidget->setSeqNumAndOp(seqNum, opText); - m_scene->setAutoIncrementSequence(selectDlg->autoIncrementSequence()); - if (selectDlg->autoIncrementSequence()) - m_scene->setAutoIncrementSequenceValue(seqNum); - + if (enableAutoIncrement) { + m_scene->setAutoIncrementSequence(selectDlg->autoIncrementSequence()); + } setMessageText(); } delete selectDlg; @@ -279,7 +284,7 @@ { if (m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self || m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { - showOperationDialog(); + showOperationDialog(false); } else if (m_textRole == Uml::TextRole::Floating) { // double clicking on a text line opens the dialog to change the text handleRename(); @@ -453,6 +458,22 @@ } /** + * Write property of QString m_SequenceNumber. + */ +void FloatingTextWidget::setSequenceNumber(const QString &sequenceNumber) +{ + m_SequenceNumber = sequenceNumber; +} + +/** + * Read property of QString m_SequenceNumber. + */ +QString FloatingTextWidget::sequenceNumber() const +{ + return m_SequenceNumber; +} + +/** * For a text to be valid it must be non-empty, i.e. have a length * larger than zero, and have at least one non whitespace character. * @@ -689,7 +710,7 @@ break; case ListPopupMenu::mt_Select_Operation: - showOperationDialog(); + showOperationDialog(false); break; case ListPopupMenu::mt_Rename: diff -Nru umbrello-4.12.97/umbrello/widgets/floatingtextwidget.h umbrello-4.13.0/umbrello/widgets/floatingtextwidget.h --- umbrello-4.12.97/umbrello/widgets/floatingtextwidget.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/floatingtextwidget.h 2014-03-30 00:15:38.000000000 +0000 @@ -55,7 +55,7 @@ QString displayText() const; void showChangeTextDialog(); - void showOperationDialog(); + void showOperationDialog(bool enableAutoIncrement = true); virtual void showPropertiesDialog(); LinkWidget* link() const; @@ -69,6 +69,9 @@ void handleRename(); void changeName(const QString& newText); + void setSequenceNumber(const QString &sequenceNumber); + QString sequenceNumber() const; + static bool isTextValid(const QString &text); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); @@ -117,6 +120,8 @@ /// -1 means up, 1 means down. int m_movementDirectionY; + /// Contains sequence number for sequence or collaboration diagram message. + QString m_SequenceNumber; }; #endif diff -Nru umbrello-4.12.97/umbrello/widgets/linkwidget.cpp umbrello-4.13.0/umbrello/widgets/linkwidget.cpp --- umbrello-4.12.97/umbrello/widgets/linkwidget.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/linkwidget.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -83,3 +83,39 @@ void LinkWidget::calculateNameTextSegment() { } + + +/** + * Write property of QString m_SequenceNumber. + */ +void LinkWidget::setSequenceNumber(const QString &sequenceNumber) +{ + m_SequenceNumber = sequenceNumber; +} + +/** + * Read property of QString m_SequenceNumber. + */ +QString LinkWidget::sequenceNumber() const +{ + return m_SequenceNumber; +} + +/** + * Load data from XMI. + */ +bool LinkWidget::loadFromXMI(QDomElement &qElement) +{ + m_SequenceNumber = qElement.attribute("seqnum", ""); + return true; +} + +/** + * Save data to XMI. + */ +void LinkWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +{ + Q_UNUSED(qDoc); + + qElement.setAttribute("seqnum", m_SequenceNumber); +} diff -Nru umbrello-4.12.97/umbrello/widgets/linkwidget.h umbrello-4.13.0/umbrello/widgets/linkwidget.h --- umbrello-4.12.97/umbrello/widgets/linkwidget.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/linkwidget.h 2014-03-30 00:15:38.000000000 +0000 @@ -105,6 +105,14 @@ virtual void calculateNameTextSegment(); + void setSequenceNumber(const QString &sequenceNumber); + QString sequenceNumber() const; + + virtual bool loadFromXMI(QDomElement &qElement); + virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); + +protected: + QString m_SequenceNumber; }; #endif diff -Nru umbrello-4.12.97/umbrello/widgets/messagewidget.cpp umbrello-4.13.0/umbrello/widgets/messagewidget.cpp --- umbrello-4.12.97/umbrello/widgets/messagewidget.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/messagewidget.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -870,8 +870,8 @@ { if (ft == NULL) return; - QString displayText = m_SequenceNumber + ": " + operationText(m_scene); - ft->setText(displayText); + ft->setSequenceNumber(m_SequenceNumber); + ft->setText(operationText(m_scene)); setTextPosition(); } @@ -902,22 +902,6 @@ } /** - * Write property of QString m_SequenceNumber. - */ -void MessageWidget::setSequenceNumber(const QString &sequenceNumber) -{ - m_SequenceNumber = sequenceNumber; -} - -/** - * Read property of QString m_SequenceNumber. - */ -QString MessageWidget::sequenceNumber() const -{ - return m_SequenceNumber; -} - -/** * Implements operation from LinkWidget. * Required by FloatingTextWidget. */ @@ -1306,6 +1290,7 @@ { QDomElement messageElement = qDoc.createElement("messagewidget"); UMLWidget::saveToXMI(qDoc, messageElement); + LinkWidget::saveToXMI(qDoc, messageElement); messageElement.setAttribute("widgetaid", Uml::ID::toString(m_pOw[Uml::RoleType::A]->localID())); messageElement.setAttribute("widgetbid", Uml::ID::toString(m_pOw[Uml::RoleType::B]->localID())); UMLOperation *pOperation = operation(); @@ -1313,7 +1298,6 @@ messageElement.setAttribute("operation", Uml::ID::toString(pOperation->id())); else messageElement.setAttribute("operation", m_CustomOp); - messageElement.setAttribute("seqnum", m_SequenceNumber); messageElement.setAttribute("sequencemessagetype", m_sequenceMessageType); if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { messageElement.setAttribute("xclicked", xclicked); @@ -1337,11 +1321,13 @@ if (!UMLWidget::loadFromXMI(qElement)) { return false; } + if (!LinkWidget::loadFromXMI(qElement)) { + return false; + } QString textid = qElement.attribute("textid", "-1"); QString widgetaid = qElement.attribute("widgetaid", "-1"); QString widgetbid = qElement.attribute("widgetbid", "-1"); m_CustomOp = qElement.attribute("operation", ""); - m_SequenceNumber = qElement.attribute("seqnum", ""); QString sequenceMessageType = qElement.attribute("sequencemessagetype", "1001"); m_sequenceMessageType = Uml::SequenceMessage::fromInt(sequenceMessageType.toInt()); if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { @@ -1369,6 +1355,8 @@ delete m_pFText; m_pFText = NULL; } + else + m_pFText->setSequenceNumber(m_SequenceNumber); } else { uError() << "unknown tag " << tag; } diff -Nru umbrello-4.12.97/umbrello/widgets/messagewidget.h umbrello-4.13.0/umbrello/widgets/messagewidget.h --- umbrello-4.12.97/umbrello/widgets/messagewidget.h 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/messagewidget.h 2014-03-30 00:15:38.000000000 +0000 @@ -76,9 +76,6 @@ //---------- End LinkWidget Interface methods implemementation. - QString sequenceNumber() const; - void setSequenceNumber(const QString &sequenceNumber); - /// @return Whether the message is synchronous or asynchronous Uml::SequenceMessage::Enum sequenceMessageType() const { return m_sequenceMessageType; @@ -174,7 +171,6 @@ void paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option); // Data loaded/saved - QString m_SequenceNumber; QString m_CustomOp; /** * Whether the message is synchronous or asynchronous diff -Nru umbrello-4.12.97/umbrello/widgets/signalwidget.cpp umbrello-4.13.0/umbrello/widgets/signalwidget.cpp --- umbrello-4.12.97/umbrello/widgets/signalwidget.cpp 2014-03-25 08:28:52.000000000 +0000 +++ umbrello-4.13.0/umbrello/widgets/signalwidget.cpp 2014-03-30 00:15:38.000000000 +0000 @@ -141,13 +141,15 @@ setPenFromSettings(painter); } - if (m_pName->x() == 0 && m_pName->y() == 0) { - //the floating text has not been linked with the signal - m_pName->setX(w/2 - m_pName->width()/2); - m_pName->setY(h); + if (m_pName) { + if (m_pName->x() == 0 && m_pName->y() == 0) { + //the floating text has not been linked with the signal + m_pName->setX(w/2 - m_pName->width()/2); + m_pName->setY(h); + } + m_pName->setVisible((m_pName->text().length() > 0)); + m_pName->updateGeometry(); } - m_pName->setVisible((m_pName->text().length() > 0)); - m_pName->updateGeometry(); break; default: @@ -184,7 +186,14 @@ m_Text = strName; updateGeometry(); if (signalType() == SignalWidget::Time) { - m_pName->setText(m_Text); + if (!m_pName) { + m_pName = new FloatingTextWidget(umlScene(), Uml::TextRole::Floating, m_Text); + umlScene()->setupNewWidget(m_pName); + m_pName->setX(0); + m_pName->setY(0); + } + else + m_pName->setText(m_Text); } }