diff --git a/desktop/kde6/applications/libkmahjongg-kf6/actions.py b/desktop/kde6/applications/libkmahjongg-kf6/actions.py new file mode 100755 index 0000000000..40877119e1 --- /dev/null +++ b/desktop/kde6/applications/libkmahjongg-kf6/actions.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import pisitools +from pisi.actionsapi import kde6 + +def setup(): + kde6.configure() + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("README") diff --git a/desktop/kde6/applications/libkmahjongg-kf6/pspec.xml b/desktop/kde6/applications/libkmahjongg-kf6/pspec.xml new file mode 100755 index 0000000000..6a7c520d0e --- /dev/null +++ b/desktop/kde6/applications/libkmahjongg-kf6/pspec.xml @@ -0,0 +1,76 @@ + + + + + + libkmahjongg-kf6 + https://www.kde.org + + Pisi Linux Admins + admin@pisilinux.org + + LGPLv2 + app:library + desktop.kde.games + Common code, backgrounds and tile sets for games using Mahjongg tiles + Common code, backgrounds and tile sets for games using Mahjongg tiles. + mirrors://kde/stable/release-service/24.02.0/src/libkmahjongg-24.02.0.tar.xz + + qt6-base-devel + qt6-svg-devel + extra-cmake-modules-kf6 + gettext-devel + kdoctools-kf6-devel + ki18n-kf6-devel + kconfig-kf6-devel + kcompletion-kf6-devel + kconfigwidgets-kf6-devel + kwidgetsaddons-kf6-devel + kcoreaddons-kf6-devel + mesa-devel + + + + + libkmahjongg-kf6 + + qt6-base + qt6-svg + libgcc + ki18n-kf6 + kconfig-kf6 + kcompletion-kf6 + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + + + /etc/xdg + /usr/bin + /usr/share + /usr/lib + /usr/share/doc + + + + libkmahjongg-kf6-devel + Development files for libkmahjongg-kf6 + + libkmahjongg-kf6 + + + /usr/include + /usr/lib/cmake + /usr/lib/pkgconfig + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/libksane-kf6/actions.py b/desktop/kde6/applications/libksane-kf6/actions.py new file mode 100755 index 0000000000..ef25e7fccf --- /dev/null +++ b/desktop/kde6/applications/libksane-kf6/actions.py @@ -0,0 +1,18 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + + +from pisi.actionsapi import kde6 + + +def setup(): + kde6.configure() + +def build(): + kde6.make() + +def install(): + kde6.install() diff --git a/desktop/kde6/applications/libksane-kf6/pspec.xml b/desktop/kde6/applications/libksane-kf6/pspec.xml new file mode 100755 index 0000000000..dad9cc0d4b --- /dev/null +++ b/desktop/kde6/applications/libksane-kf6/pspec.xml @@ -0,0 +1,72 @@ + + + + + + libksane-kf6 + https://www.kde.org + + PisiLinux Community + admins@pisilinux.org + + GPLv2 + library + desktop.kde.graphics + SANE library interface for KDE + libksane-kf6 is a SANE library interface for KDE. + mirrors://kde/stable/release-service/24.02.0/src/libksane-24.02.0.tar.xz + + ki18n-kf6-devel + kwallet-kf6-devel + qt6-base-devel + ktextwidgets-kf6-devel + sane-backends-devel + kwidgetsaddons-kf6-devel + extra-cmake-modules-kf6 + ksanecore-kf6-devel + + + + + libksane-kf6 + + ki18n-kf6 + kwallet-kf6 + libgcc + qt6-base + ktextwidgets-kf6 + sane-backends + kwidgetsaddons-kf6 + ksanecore-kf6 + + + /usr/lib + /usr/share/icons + /usr/share/locale + + + + + libksane-kf6-devel + Development files for libksane-kf6 + + libksane-kf6 + ksanecore-kf6-devel + + + /usr/lib/cmake + /usr/include + /usr/lib/pkgconfig + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/libksane-kf6/translations.xml b/desktop/kde6/applications/libksane-kf6/translations.xml new file mode 100755 index 0000000000..59692a0edd --- /dev/null +++ b/desktop/kde6/applications/libksane-kf6/translations.xml @@ -0,0 +1,13 @@ + + + + libksane-kf6 + KDE için SANE kitaplık arayüzü + libksane-kf6, KDE için bir SANE kitaplık arayüzüdür. + + + + libksane-kf6-devel + libksane-kf6 için geliştirme dosyaları + + diff --git a/desktop/kde6/applications/lokalize-kf6/actions.py b/desktop/kde6/applications/lokalize-kf6/actions.py new file mode 100755 index 0000000000..7fa61bd934 --- /dev/null +++ b/desktop/kde6/applications/lokalize-kf6/actions.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import kde6 +from pisi.actionsapi import pisitools + +def setup(): + kde6.configure("") + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("LICENSES/*") diff --git a/desktop/kde6/applications/lokalize-kf6/files/lokalize_build_with_hunspell1.6.patch b/desktop/kde6/applications/lokalize-kf6/files/lokalize_build_with_hunspell1.6.patch new file mode 100755 index 0000000000..e31249039d --- /dev/null +++ b/desktop/kde6/applications/lokalize-kf6/files/lokalize_build_with_hunspell1.6.patch @@ -0,0 +1,11 @@ +--- lokalize-kf6-16.12.0/cmake/FindHUNSPELL.cmake.old 2016-12-23 16:15:35.394980599 -0600 ++++ lokalize-kf6-16.12.0/cmake/FindHUNSPELL.cmake 2016-12-23 16:16:02.782697414 -0600 +@@ -14,7 +14,7 @@ + + FIND_PATH(HUNSPELL_INCLUDE_DIR hunspell/hunspell.hxx ) + +-FIND_LIBRARY(HUNSPELL_LIBRARIES NAMES hunspell-2.0 hunspell-1.5 hunspell-1.4 hunspell-1.3 hunspell-1.2) ++FIND_LIBRARY(HUNSPELL_LIBRARIES NAMES hunspell-2.0 hunspell-1.6 hunspell-1.5 hunspell-1.4 hunspell-1.3 hunspell-1.2) + + # handle the QUIETLY and REQUIRED arguments and set HUNSPELL_FOUND to TRUE if + # all listed variables are TRUE diff --git a/desktop/kde6/applications/lokalize-kf6/pspec.xml b/desktop/kde6/applications/lokalize-kf6/pspec.xml new file mode 100755 index 0000000000..514183538e --- /dev/null +++ b/desktop/kde6/applications/lokalize-kf6/pspec.xml @@ -0,0 +1,89 @@ + + + + + + lokalize-kf6 + http://www.kde.org/ + + Pisi Linux Admins + admin@pisilinux.org + + GPLv2 + app:gui + desktop.kde.sdk + lokalize-kf6 is the localization tool for KDE and other open source software + lokalize-kf6 is also a general computer-aided translation system (CAT) with which you can translate OpenDocument files (*.odt). + mirrors://kde/stable/release-service/24.02.0/src/lokalize-24.02.0.tar.xz + + qt6-base-devel + hunspell-devel + extra-cmake-modules-kf6 + kdoctools-kf6-devel + kio-kf6-devel + enchant-devel + kitemviews-kf6-devel + ki18n-kf6-devel + kross-kf6-devel + kparts-kf6-devel + sonnet-kf6-devel + kconfig-kf6-devel + kxmlgui-kf6-devel + kcompletion-kf6-devel + kcoreaddons-kf6-devel + kdbusaddons-kf6-devel + ktextwidgets-kf6-devel + kconfigwidgets-kf6-devel + knotifications-kf6-devel + kwidgetsaddons-kf6-devel + pkgconfig + qt6-sql-postgresql + qt6-sql-mysql + qt6-sql-sqlite + qt6-sql-odbc + + + + + + + + lokalize-kf6 + + qt6-base + kio-kf6 + kitemviews-kf6 + ki18n-kf6 + kross-kf6 + kparts-kf6 + libgcc + sonnet-kf6 + kconfig-kf6 + kxmlgui-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + kdbusaddons-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6 + knotifications-kf6 + kwidgetsaddons-kf6 + hunspell + + + /etc/xdg + /usr/share + /usr/share/doc + /usr/bin + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/lokalize-kf6/translations.xml b/desktop/kde6/applications/lokalize-kf6/translations.xml new file mode 100755 index 0000000000..63174b391d --- /dev/null +++ b/desktop/kde6/applications/lokalize-kf6/translations.xml @@ -0,0 +1,8 @@ + + + + lokalize-kf6 + Uygulama yerelleştirme yardımcısı. + lokalize-kf6, uygulamalar için kolaylıkla yerelleştirme yapabileceğiniz bir programdır. + + diff --git a/desktop/kde6/applications/marble-kf6/actions.py b/desktop/kde6/applications/marble-kf6/actions.py new file mode 100755 index 0000000000..5c654a5b67 --- /dev/null +++ b/desktop/kde6/applications/marble-kf6/actions.py @@ -0,0 +1,27 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import pisitools +from pisi.actionsapi import kde6 + +def setup(): + kde6.configure("-DWITH_libshp=OFF \ + -DWITH_libgps=OFF \ + -DWITH_QextSerialPort=OFF \ + -DWITH_liblocation=OFF \ + -DBUILD_marble-kf6_TOOLS=YES \ + -DBUILD_TESTING=OFF \ + -DBUILD_marble-kf6_EXAMPLES=OFF \ + -DBUILD_marble-kf6_TESTS=OFF \ + -DMOBILE=OFF") + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("BUGS", "ChangeLog", "CODING", "COPYING*", "CREDITS", "LICENSES/*", "MANIFESTO.txt", "USECASES") diff --git a/desktop/kde6/applications/marble-kf6/pspec.xml b/desktop/kde6/applications/marble-kf6/pspec.xml new file mode 100755 index 0000000000..7ce4acdcd6 --- /dev/null +++ b/desktop/kde6/applications/marble-kf6/pspec.xml @@ -0,0 +1,114 @@ + + + + + + marble-kf6 + http://edu.kde.org/applications/all/marble-kf6 + + PisiLinux Community + admins@pisilinux.org + + GPLv2 + marble-kf6 + app:gui + Virtual globe and eorld atlas + marble-kf6 is a virtual globe and world atlas that you can use to learn more about the Earth. + mirrors://kde/stable/release-service/24.02.0/src/marble-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-base-devel + + qt6-designer-devel + + qt6-svg-devel + qt6-declarative-devel + qt6-sql-postgresql + qt6-sql-mysql + qt6-sql-odbc + qt6-sql-sqlite + qt6-location-devel + qt6-linguist + qt6-webengine-devel + kdoctools-kf6-devel + qt6-phonon-devel + kio-kf6-devel + quazip-devel + kwallet-kf6-devel + knewstuff-kf6-devel + kparts-kf6-devel + kcoreaddons-kf6-devel + ki18n-kf6-devel + kconfig-kf6-devel + krunner-devel + kservice-kf6-devel + libwlocate-devel + shared-mime-info + qt6-serialport-devel + plasma-desktop-kf6 + + + + + marble-kf6 + + kio-kf6 + zlib + ki18n-kf6 + kcrash-kf6 + kparts-kf6 + libgcc + kconfig-kf6 + krunner + kxmlgui-kf6 + qt6-svg + qt6-base + knewstuff-kf6 + libwlocate + qt6-phonon + + + kcoreaddons-kf6 + qt6-location + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + qt6-declarative + qt6-serialport + + + /usr/lib + /usr/bin + /usr/share + /usr/share/appdata + /usr/share/applications + /usr/share/config.kcfg + /usr/share/doc + /usr/share/icons + /usr/share/kservice-kf6s5 + /usr/share/kxmlgui-kf65 + /usr/share/marble-kf6 + /etc/xdg + + + + + marble-kf6-devel + Development files for marble-kf6 + + marble-kf6 + + + /usr/include + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/marble-kf6/translations.xml b/desktop/kde6/applications/marble-kf6/translations.xml new file mode 100755 index 0000000000..2df38d0a52 --- /dev/null +++ b/desktop/kde6/applications/marble-kf6/translations.xml @@ -0,0 +1,13 @@ + + + + marble-kf6 + Sanal küre ve Dünya atlası + marble-kf6, sanal küre ve Dünya atlası uygulamasıdır. + + + + marble-kf6-devel + marble-kf6 için geliştirme dosyaları + + diff --git a/desktop/kde6/applications/minuet-kf6/actions.py b/desktop/kde6/applications/minuet-kf6/actions.py new file mode 100755 index 0000000000..676b7d139b --- /dev/null +++ b/desktop/kde6/applications/minuet-kf6/actions.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/copyleft/gpl.txt + +from pisi.actionsapi import kde6 +from pisi.actionsapi import pisitools + +def setup(): + kde6.configure() + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("COPYING*", "README*") diff --git a/desktop/kde6/applications/minuet-kf6/files/qtfix2.patch b/desktop/kde6/applications/minuet-kf6/files/qtfix2.patch new file mode 100755 index 0000000000..16b5dd116d --- /dev/null +++ b/desktop/kde6/applications/minuet-kf6/files/qtfix2.patch @@ -0,0 +1,13 @@ +--- qtfix.patch 2016-12-22 15:50:07.000000000 +0100 ++++ qtfix1.patch 2017-03-08 18:03:57.055106559 +0100 +@@ -5,8 +5,8 @@ + set (KDE_APPLICATIONS_VERSION "0.2.1") + + set(ECM_MIN_VERSION "5.15.0") +--set(QT_MIN_VERSION "5.7.0") +-+set(QT_MIN_VERSION "5.6.2") ++-set(QT_MIN_VERSION "5.7.1") +++set(QT_MIN_VERSION "5.7.1") + set(KF5_MIN_VERSION "5.15.0") + + find_package(ECM ${ECM_MIN_VERSION} CONFIG REQUIRED) diff --git a/desktop/kde6/applications/minuet-kf6/files/qtfixc.patch b/desktop/kde6/applications/minuet-kf6/files/qtfixc.patch new file mode 100755 index 0000000000..6f5ff7ce8c --- /dev/null +++ b/desktop/kde6/applications/minuet-kf6/files/qtfixc.patch @@ -0,0 +1,14 @@ +--- qtfix.patch 2016-12-22 15:50:07.000000000 +0100 ++++ qtfixb.patch 2016-12-23 13:00:31.000000000 +0100 +@@ -4,9 +4,9 @@ + @@ -10,7 +10,7 @@ + set (KDE_APPLICATIONS_VERSION "0.2.1") + +- set(ECM_MIN_VERSION "5.15.0") ++ set(ECM_MIN_VERSION "5.29.0") + -set(QT_MIN_VERSION "5.7.0") + +set(QT_MIN_VERSION "5.6.2") +- set(KF5_MIN_VERSION "5.15.0") ++ set(KF5_MIN_VERSION "5.29.0") + + find_package(ECM ${ECM_MIN_VERSION} CONFIG REQUIRED) diff --git a/desktop/kde6/applications/minuet-kf6/pspec.xml b/desktop/kde6/applications/minuet-kf6/pspec.xml new file mode 100755 index 0000000000..f8e65c4b17 --- /dev/null +++ b/desktop/kde6/applications/minuet-kf6/pspec.xml @@ -0,0 +1,91 @@ + + + + minuet-kf6 + https://minuet-kf6.kde.org + + Alihan Öztürk + alihan@pisilinux.org + + LGPLv2 + app:gui + A KDE Software for Music Education + Music education Free Software, thoughtfully designed to push your musical skills to the next level. Enhance your ability to recognize intervals, chords, rhythm, and scales while enjoying all the power of Free Software. + https://download.kde.org/stable/release-service/24.02.0/src/minuet-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-svg-devel + qt6-base-devel + qt6-declarative-devel + ki18n-kf6-devel + kxmlgui-kf6-devel + kio-kf6-devel + kcrash-kf6-devel + kdoctools-kf6-devel + alsa-lib-devel + drumstick-devel + fluidsynth-devel + + + + + + + + minuet-kf6 + A KDE Software for Music Education + + kio-kf6 + ki18n-kf6 + kcrash-kf6 + libgcc + kconfig-kf6 + kxmlgui-kf6 + alsa-lib + qt6-base + kcompletion-kf6 + kcoreaddons-kf6 + drumstick-libs + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + fluidsynth + qt6-svg + qt6-declarative + + + /usr/bin + /usr/share + /usr/share/appdata + /usr/share/applications + /usr/share/doc + /usr/share/icons + /usr/share/kxmlgui-kf65 + /usr/share/minuet-kf6 + /usr/lib + + + + + minuet-kf6-devel + Development files for minuet-kf6 + + qt6-base-devel + minuet-kf6 + + + /usr/include + /usr/lib/cmake + /usr/lib/pkgconfig + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/poxml-kf6/actions.py b/desktop/kde6/applications/poxml-kf6/actions.py new file mode 100755 index 0000000000..5c56bf7fb3 --- /dev/null +++ b/desktop/kde6/applications/poxml-kf6/actions.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import pisitools +from pisi.actionsapi import kde6 + +NoStrip=["/usr/share"] + +def setup(): + kde6.configure() + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("COPYING*") diff --git a/desktop/kde6/applications/poxml-kf6/pspec.xml b/desktop/kde6/applications/poxml-kf6/pspec.xml new file mode 100755 index 0000000000..9aa81c3c47 --- /dev/null +++ b/desktop/kde6/applications/poxml-kf6/pspec.xml @@ -0,0 +1,56 @@ + + + + + + poxml-kf6 + http://www.kde.org/ + + Mathias Freire + mathiasfreire45@gmail.com + + GPLv2 + app:gui + desktop.kde.sdk + Tools for translating DocBook XML files with Gettex + This is a collection of tools that facilitate translating DocBook XML files using Gettext message files (PO files). + https://download.kde.org/stable/release-service/24.02.0/src/poxml-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-base-devel + gettext-devel + kdoctools-kf6-devel + docbook-xsl + + + + + poxml-kf6 + + libgcc + gettext + qt6-base + + + kdesdk + + + kdesdk + + + /usr/bin + /usr/share/doc + /usr/share/man + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/poxml-kf6/translations.xml b/desktop/kde6/applications/poxml-kf6/translations.xml new file mode 100755 index 0000000000..f7bcb3faa3 --- /dev/null +++ b/desktop/kde6/applications/poxml-kf6/translations.xml @@ -0,0 +1,8 @@ + + + + poxml-kf6 + DocBook XML dosyalarını çevirme araçları. + poxml-kf6, DocBook XML dosyalarını (.po) Gettext yarımıyla çevirmeyi sağlayan bir programdır. + + diff --git a/desktop/kde6/applications/rocs-kf6/actions.py b/desktop/kde6/applications/rocs-kf6/actions.py new file mode 100755 index 0000000000..b29afbc032 --- /dev/null +++ b/desktop/kde6/applications/rocs-kf6/actions.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import pisitools +from pisi.actionsapi import kde6 + +def setup(): + kde6.configure() + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("LICENSES/*") diff --git a/desktop/kde6/applications/rocs-kf6/pspec.xml b/desktop/kde6/applications/rocs-kf6/pspec.xml new file mode 100755 index 0000000000..cf9366ac0c --- /dev/null +++ b/desktop/kde6/applications/rocs-kf6/pspec.xml @@ -0,0 +1,103 @@ + + + + + + rocs-kf6 + https://www.kde.org + + Pisi Linux Admins + admin@pisilinux.org + + LGPLv2 + app:gui + desktop.kde.edu + rocs-kf6 Graph Theory + rocs-kf6 aims to be a Graph Theory IDE for helping professors to show the results of a graph algorithm and also helping students to do the algorithms. rocs-kf6 has a scripting module, done in Qt Script, that interacts with the drawn graph and every change in the graph with the script is reflected on the drawn one.. + mirrors://kde/stable/release-service/24.02.0/src/rocs-24.02.0.tar.xz + + qt6-base-devel + qt6-declarative-devel + + + qt6-base-devel + + + extra-cmake-modules-kf6 + kdoctools-kf6-devel + kdeclarative-kf6-devel + ki18n-kf6-devel + gettext-devel + kitemviews-kf6-devel + ktexteditor-kf6-devel + kxmlgui-kf6-devel + kconfig-kf6-devel + karchive-kf6-devel + kcompletion-kf6-devel + kcoreaddons-kf6-devel + kconfigwidgets-kf6-devel + kwidgetsaddons-kf6-devel + cmake + qt6-location-devel + grantlee-qt6-devel + boost-devel + qt6-svg-devel + + + + + rocs-kf6 + + qt6-base + + qt6-declarative + + + qt6-svg + grantlee-qt6 + kdeclarative-kf6 + ktexteditor-kf6 + kparts-kf6 + libgcc + ki18n-kf6 + kconfig-kf6 + karchive-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + kxmlgui-kf6 + kitemviews-kf6 + + + /usr/bin + /usr/share + /usr/lib + /usr/lib/qt6 + /usr/share/doc + + + + + rocs-kf6-devel + Development files for rocs-kf6 + + rocs-kf6 + + + /usr/include + /usr/lib/cmake + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/signon-kwallet-extension-kf6/actions.py b/desktop/kde6/applications/signon-kwallet-extension-kf6/actions.py new file mode 100755 index 0000000000..e84c895080 --- /dev/null +++ b/desktop/kde6/applications/signon-kwallet-extension-kf6/actions.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/copyleft/gpl.txt + +from pisi.actionsapi import kde6 +from pisi.actionsapi import pisitools + +def setup(): + kde6.configure() + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("COPYING") diff --git a/desktop/kde6/applications/signon-kwallet-extension-kf6/pspec.xml b/desktop/kde6/applications/signon-kwallet-extension-kf6/pspec.xml new file mode 100755 index 0000000000..a742ef569e --- /dev/null +++ b/desktop/kde6/applications/signon-kwallet-extension-kf6/pspec.xml @@ -0,0 +1,48 @@ + + + + signon-kwallet-extension-kf6 + http://kde.org + + Alihan Öztürk + alihan@pisilinux.org + + LGPLv2 + app + desktop.kde.network + kwallet-kf6 signon extension + kwallet-kf6 signon extension + + extra-cmake-modules-kf6 + qt6-base-devel + kwallet-kf6-devel + signon-devel + + mirrors://kde/stable/release-service/24.02.0/src/signon-kwallet-extension-24.02.0.tar.xz + + + + signon-kwallet-extension-kf6 + kwallet-kf6 signon extension + + libgcc + signon + kwallet-kf6 + qt6-base + + + /usr/lib/signon + /usr/share/doc + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/step-kf6/actions.py b/desktop/kde6/applications/step-kf6/actions.py new file mode 100755 index 0000000000..d0ef227a16 --- /dev/null +++ b/desktop/kde6/applications/step-kf6/actions.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import pisitools +from pisi.actionsapi import kde6, shelltools + + +def setup(): + kde6.configure("-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3") + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("LICENSES/*", "ChangeLog", "AUTHORS", "README*", "DESIGN") diff --git a/desktop/kde6/applications/step-kf6/pspec.xml b/desktop/kde6/applications/step-kf6/pspec.xml new file mode 100755 index 0000000000..d0ac3809ae --- /dev/null +++ b/desktop/kde6/applications/step-kf6/pspec.xml @@ -0,0 +1,89 @@ + + + + + + step-kf6 + http://kde.org/applications/education/step/ + + Pisi Linux Admins + admin@pisilinux.org + + LGPLv2 + app:gui + desktop.kde.edu + Interactive Physical Simulator + step-kf6 is an interactive physical simulator. It allows you to explore the physical world through simulations. + mirrors://kde/stable/release-service/24.02.0/src/step-24.02.0.tar.xz + + qt6-base-devel + + qt6-svg-devel + qt6-declarative-devel + extra-cmake-modules-kf6 + kdoctools-kf6-devel + + mesa-devel + + kconfig-kf6-devel + knewstuff-kf6-devel + kplotting-kf6-devel + eigen3 + pkgconfig + libqalculate-devel + cln-devel + + + kitemmodels-kf6-devel + + kunitconversion-kf6-devel + qt6-linguist + gsl-devel + + + + + step-kf6 + + qt6-base + cln + gsl + + kcrash-kf6 + knewstuff-kf6 + kplotting-kf6 + libqalculate + kparts-kf6 + kio-kf6 + libgcc + + ki18n-kf6 + kconfig-kf6 + kxmlgui-kf6 + kjobwidgets-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + kiconthemes-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + kservice-kf6 + + + /etc/xdg + /usr/bin + /usr/share + /usr/share/doc + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/umbrello-kf6/actions.py b/desktop/kde6/applications/umbrello-kf6/actions.py new file mode 100755 index 0000000000..baf97623c5 --- /dev/null +++ b/desktop/kde6/applications/umbrello-kf6/actions.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Licensed under the GNU General Public License, version 3. +# See the file http://www.gnu.org/licenses/gpl.txt + +from pisi.actionsapi import shelltools +from pisi.actionsapi import pisitools +from pisi.actionsapi import kde6 +from pisi.actionsapi import get + +NoStrip=["/usr/share"] + +def setup(): + kde6.configure("-DBUILD_KF5=ON") + +def build(): + kde6.make() + +def install(): + kde6.install() + + pisitools.dodoc("COPYING*", "AUTHORS", "CODING-STYLE", "ChangeLog", "README", "THANKS", "TODO") diff --git a/desktop/kde6/applications/umbrello-kf6/files/upstream.patch b/desktop/kde6/applications/umbrello-kf6/files/upstream.patch new file mode 100755 index 0000000000..fa05851179 --- /dev/null +++ b/desktop/kde6/applications/umbrello-kf6/files/upstream.patch @@ -0,0 +1,77852 @@ +diff -Nuar umbrello-kf6-15.08.1.orig/CMakeLists.txt umbrello-kf6-15.08.1/CMakeLists.txt +--- umbrello-kf6-15.08.1.orig/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/CMakeLists.txt 2015-10-08 11:48:59.471089026 +0300 +@@ -6,8 +6,8 @@ + set (KDE_APPLICATIONS_VERSION_MICRO "1") + + set(umbrello-kf6_VERSION_MAJOR "2") +-set(umbrello-kf6_VERSION_MINOR "17") +-set(umbrello-kf6_VERSION_PATCH ${KDE_APPLICATIONS_VERSION_MICRO}) ++set(umbrello-kf6_VERSION_MINOR "18") ++set(umbrello-kf6_VERSION_PATCH "99") + + option(BUILD_KF5 "Build for KDE Frameworks 5" OFF) + +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/actor.cpp umbrello-kf6-15.08.1/umbrello/actor.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/actor.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/actor.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,67 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "actor.h" +- +-/** +- * Constructs an Actor. +- * +- * @param name The name of the Actor. +- * @param id The unique id to assign to this Actor. +- */ +-UMLActor::UMLActor(const QString & name, Uml::ID::Type id) +- : UMLCanvasObject(name, id) +-{ +- init(); +-} +- +-/** +- * Standard destructor. +- */ +-UMLActor::~UMLActor() +-{ +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLActor::init() +-{ +- m_BaseType = UMLObject::ot_Actor; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLActor::clone() const +-{ +- UMLActor *clone = new UMLActor(); +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLActor::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement actorElement = UMLObject::save(QLatin1String("UML:Actor"), qDoc); +- qElement.appendChild(actorElement); +-} +- +-/** +- * Loads the XMI element (empty). +- */ +-bool UMLActor::load(QDomElement& element) +-{ +- Q_UNUSED(element); +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/actor.h umbrello-kf6-15.08.1/umbrello/actor.h +--- umbrello-kf6-15.08.1.orig/umbrello/actor.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/actor.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,44 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ACTOR_H +-#define ACTOR_H +- +-#include "umlcanvasobject.h" +- +-/** +- * This class contains the non-graphical information required for a UML Actor. +- * This class inherits from @ref UMLCanvasObject which contains most of the +- * information. +- * The @ref UMLDoc class creates instances of this type. +- * +- * @short Information for a non-graphical UML Actor. +- * @author Paul Hensgen +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLActor : public UMLCanvasObject +-{ +- Q_OBJECT +-public: +- explicit UMLActor(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLActor(); +- +- virtual void init(); +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- bool load(QDomElement & element); +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/artifact.cpp umbrello-kf6-15.08.1/umbrello/artifact.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/artifact.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/artifact.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,90 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "artifact.h" +-#include "association.h" +-#include "clipboard/idchangelog.h" +- +-#include +- +-/** +- * Sets up an Artifact. +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLArtifact::UMLArtifact(const QString & name, Uml::ID::Type id) +- : UMLPackage(name, id), +- m_drawAsType(defaultDraw) +-{ +- m_BaseType = UMLObject::ot_Artifact; +-} +- +-/** +- * Standard deconstructor. +- */ +-UMLArtifact::~UMLArtifact() +-{ +-} +- +-/** +- * Make a clone of this object. +- * @return the cloned object +- */ +-UMLObject* UMLArtifact::clone() const +-{ +- UMLArtifact *clone = new UMLArtifact(); +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the UML:Artifact element including its operations, +- * attributes and templates +- * @param qDoc the xml document +- * @param qElement the xml element +- */ +-void UMLArtifact::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement artifactElement = UMLObject::save(QLatin1String("UML:Artifact"), qDoc); +- artifactElement.setAttribute(QLatin1String("drawas"), m_drawAsType); +- qElement.appendChild(artifactElement); +-} +- +-/** +- * Loads the UML:Artifact element including its operations, +- * attributes and templates. +- * @param element the xml element to load +- * @return the success status of the operation +- */ +-bool UMLArtifact::load(QDomElement& element) +-{ +- QString drawAs = element.attribute(QLatin1String("drawas"), QLatin1String("0")); +- m_drawAsType = (Draw_Type)drawAs.toInt(); +- return true; +-} +- +-/** +- * Sets m_drawAsType for which method to draw the artifact as. +- * @param type the draw type +- */ +-void UMLArtifact::setDrawAsType(Draw_Type type) +-{ +- m_drawAsType = type; +-} +- +-/** +- * Returns the value of m_drawAsType. +- * @return the value of the draw type attribute +- */ +-UMLArtifact::Draw_Type UMLArtifact::getDrawAsType() +-{ +- return m_drawAsType; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/artifact.h umbrello-kf6-15.08.1/umbrello/artifact.h +--- umbrello-kf6-15.08.1.orig/umbrello/artifact.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/artifact.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,66 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ARTIFACT_H +-#define ARTIFACT_H +- +-#include "package.h" +- +-/** +- * This class contains the non-graphical information required for a UML +- * Artifact. +- * This class inherits from @ref UMLCanvasObject which contains most of the +- * information. +- * +- * @short Non-graphical information for a Artifact. +- * @author Jonathan Riddell +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLArtifact : public UMLPackage +-{ +- Q_OBJECT +-public: +- +- /** +- * Artifacts can be drawn using one of several icons. +- */ +- enum Draw_Type { +- defaultDraw, +- file, +- library, +- table +- }; +- +- explicit UMLArtifact(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLArtifact(); +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- void setDrawAsType(Draw_Type type); +- +- Draw_Type getDrawAsType(); +- +-protected: +- +- bool load(QDomElement & element); +- +-private: +- +- /** +- * Artifacts can be drawn as one of several different icons, +- * this value choosing how to draw them. +- */ +- Draw_Type m_drawAsType; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/association.cpp umbrello-kf6-15.08.1/umbrello/association.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/association.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/association.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,742 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "association.h" +- +-// app includes +-#include "debug_utils.h" +-#include "classifier.h" +-#include "classpropertiesdialog.h" +-#include "folder.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlrole.h" +-#include "uniqueid.h" +-#include "model_utils.h" +-#include "cmds.h" +- +-// kde includes +-#include +- +-// qt includes +-#include +-#include +- +-using namespace Uml; +- +-DEBUG_REGISTER(UMLAssociation) +- +-/** +- * Sets up an association. +- * A new unique ID is assigned internally. +- * @param type The AssociationType::Enum to construct. +- * @param roleA Pointer to the UMLObject in role A. +- * @param roleB Pointer to the UMLObject in role B. +- */ +-UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type, +- UMLObject * roleA, UMLObject * roleB) +- : UMLObject(QString()) +-{ +- init(type, roleA, roleB); +- +- m_pRole[RoleType::A]->setID(UniqueID::gen()); +- m_pRole[RoleType::B]->setID(UniqueID::gen()); +-} +- +-/** +- * Constructs an association - for loading only. +- * This constructor should not normally be used as it constructs +- * an incomplete association (i.e. the role objects are missing.) +- * @param type The AssociationType::Enum to construct. +- * Default: Unknown. +- */ +-UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type) +- : UMLObject(QString(), Uml::ID::Reserved) +-{ +- init(type, NULL, NULL); +-} +- +-/** +- * Standard destructor. +- */ +-UMLAssociation::~UMLAssociation() +-{ +- if (m_pRole[RoleType::A] == NULL) { +- uError() << "UMLAssociation destructor: m_pRole[A] is NULL already"; +- } else { +- delete m_pRole[RoleType::A]; +- m_pRole[RoleType::A] = NULL; +- } +- if (m_pRole[RoleType::B] == NULL) { +- uError() << "UMLAssociation destructor: m_pRole[B] is NULL already"; +- } else { +- delete m_pRole[RoleType::B]; +- m_pRole[RoleType::B] = NULL; +- } +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLAssociation::operator==(const UMLAssociation &rhs) const +-{ +- if (this == &rhs) { +- return true; +- } +- return (UMLObject::operator== (rhs) && +- m_AssocType == rhs.m_AssocType && +- m_Name == rhs.m_Name && +- m_pRole[RoleType::A] == rhs.m_pRole[RoleType::A] && +- m_pRole[RoleType::B] == rhs.m_pRole[RoleType::B]); +-} +- +-/** +- * Returns the AssociationType::Enum of the UMLAssociation. +- * @return The AssociationType::Enum of the UMLAssociation. +- */ +-Uml::AssociationType::Enum UMLAssociation::getAssocType() const +-{ +- return m_AssocType; +-} +- +-/** +- * Returns a String representation of this UMLAssociation. +- */ +-QString UMLAssociation::toString() const +-{ +- QString string; +- if(m_pRole[RoleType::A]) +- { +- string += m_pRole[RoleType::A]->object()->name(); +- string += QLatin1Char(':'); +- string += m_pRole[RoleType::A]->name(); +- } +- string += QLatin1Char(':') + Uml::AssociationType::toStringI18n(m_AssocType) + QLatin1Char(':'); +- if(m_pRole[RoleType::B]) +- { +- string += m_pRole[RoleType::B]->object()->name(); +- string += QLatin1Char(':'); +- string += m_pRole[RoleType::B]->name(); +- } +- return string; +-} +- +-/** +- * Resolve types. Required when dealing with foreign XMI files. +- * Needs to be called after all UML objects are loaded from file. +- * Overrides the method from UMLObject. +- * Calls resolveRef() for each role. +- * @return True for success. +- */ +-bool UMLAssociation::resolveRef() +-{ +- bool successA = getUMLRole(RoleType::A)->resolveRef(); +- bool successB = getUMLRole(RoleType::B)->resolveRef(); +- if (successA && successB) { +- UMLObject *objA = getUMLRole(RoleType::A)->object(); +- UMLObject *objB = getUMLRole(RoleType::B)->object(); +- // Check if need to change the assoc type to Realization +- if (isRealization(objA, objB)) { +- m_AssocType = Uml::AssociationType::Realization; +- } +- m_pUMLPackage->addAssocToConcepts(this); +- return true; +- } +- return false; +-} +- +-/** +- * Creates the or XMI element +- * including its role objects. +- */ +-void UMLAssociation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- if (m_AssocType == Uml::AssociationType::Generalization) { +- QDomElement assocElement = UMLObject::save(QLatin1String("UML:Generalization"), qDoc); +- assocElement.setAttribute(QLatin1String("discriminator"), QString()); +- assocElement.setAttribute(QLatin1String("child"), Uml::ID::toString(getObjectId(RoleType::A))); +- assocElement.setAttribute(QLatin1String("parent"), Uml::ID::toString(getObjectId(RoleType::B))); +- qElement.appendChild(assocElement); +- return; +- } +- if (m_AssocType == Uml::AssociationType::Realization) { +- QDomElement assocElement = UMLObject::save(QLatin1String("UML:Abstraction"), qDoc); +- assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); +- assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); +- qElement.appendChild(assocElement); +- return; +- } +- if (m_AssocType == Uml::AssociationType::Dependency) { +- QDomElement assocElement = UMLObject::save(QLatin1String("UML:Dependency"), qDoc); +- assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); +- assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); +- qElement.appendChild(assocElement); +- return; +- } +- if (m_AssocType == Uml::AssociationType::Child2Category) { +- QDomElement assocElement = UMLObject::save(QLatin1String("UML:Child2Category"), qDoc); +- assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); +- assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); +- qElement.appendChild(assocElement); +- return; +- } +- if (m_AssocType == Uml::AssociationType::Category2Parent) { +- QDomElement assocElement = UMLObject::save(QLatin1String("UML:Category2Parent"), qDoc); +- assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); +- assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); +- qElement.appendChild(assocElement); +- return; +- } +- +- QDomElement associationElement = UMLObject::save(QLatin1String("UML:Association"), qDoc); +- QDomElement connElement = qDoc.createElement(QLatin1String("UML:Association.connection")); +- getUMLRole(RoleType::A)->saveToXMI (qDoc, connElement); +- getUMLRole(RoleType::B)->saveToXMI (qDoc, connElement); +- associationElement.appendChild (connElement); +- qElement.appendChild(associationElement); +-} +- +-bool UMLAssociation::showPropertiesDialog(QWidget *parent) +-{ +- QPointer dlg = new ClassPropertiesDialog(parent, this, true); +- bool modified = false; +- if (dlg->exec()) { +- modified = true; +- } +- dlg->close(); +- delete dlg; +- return modified; +-} +- +-/** +- * Creates the or XMI element +- * including its role objects. +- */ +-bool UMLAssociation::load(QDomElement & element) +-{ +- if (id() == Uml::ID::None) +- return false; // old style XMI file. No real info in this association. +- +- UMLDoc * doc = UMLApp::app()->document(); +- UMLObject * obj[2] = { NULL, NULL }; +- if (m_AssocType == Uml::AssociationType::Generalization || +- m_AssocType == Uml::AssociationType::Realization || +- m_AssocType == Uml::AssociationType::Dependency || +- m_AssocType == Uml::AssociationType::Child2Category || +- m_AssocType == Uml::AssociationType::Category2Parent) { +- QString general = element.attribute(QLatin1String("general")); +- if (!general.isEmpty()) { +- UMLClassifier *owningClassifier = dynamic_cast(m_pUMLPackage); +- if (owningClassifier == NULL){ +- uWarning() << "Cannot load UML2 generalization: m_pUMLPackage is expected " +- << "to be the owning classifier (=client)"; +- return false; +- } +- m_pRole[RoleType::A]->setObject(owningClassifier); +- m_pRole[RoleType::B]->setSecondaryId(general); // defer resolution to resolveRef() +- owningClassifier->addAssociationEnd(this); +- m_pUMLPackage = m_pUMLPackage->umlPackage(); // reparent +- m_pUMLPackage->addObject(this); +- return true; +- } +- for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { +- const QString fetch = (m_AssocType == Uml::AssociationType::Generalization ? +- r == RoleType::A ? QLatin1String("child") : QLatin1String("parent") +- : r == RoleType::A ? QLatin1String("client") : QLatin1String("supplier")); +- QString roleIdStr = element.attribute(fetch); +- if (roleIdStr.isEmpty()) { +- // Might be given as a child node instead - see below. +- continue; +- } +- +- // set umlobject of role if possible (else defer resolution) +- obj[r] = doc->findObjectById(Uml::ID::fromString(roleIdStr)); +- Uml::RoleType::Enum role = Uml::RoleType::fromInt(r); +- if (obj[r] == NULL) { +- m_pRole[role]->setSecondaryId(roleIdStr); // defer to resolveRef() +- } else { +- m_pRole[role]->setObject(obj[r]); +- if (m_pUMLPackage == NULL) { +- Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(obj[r]->baseType()); +- m_pUMLPackage = doc->rootFolder(mt); +- DEBUG(DBG_SRC) << "assoctype " << m_AssocType +- << ": setting model type " << Uml::ModelType::toString(mt); +- } +- } +- } +- if (obj[RoleType::A] == NULL || obj[RoleType::B] == NULL) { +- for (QDomNode node = element.firstChild(); !node.isNull(); +- node = node.nextSibling()) { +- if (node.isComment()) +- continue; +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (Model_Utils::isCommonXMIAttribute(tag)) +- continue; +- // Permitted tag names: +- // roleA: "child" "subtype" "client" +- // roleB: "parent" "supertype" "supplier" +- QString idStr = tempElement.attribute(QLatin1String("xmi.id")); +- if (idStr.isEmpty()) +- idStr = tempElement.attribute(QLatin1String("xmi.idref")); +- if (idStr.isEmpty()) { +- QDomNode inner = node.firstChild(); +- QDomElement tmpElem = inner.toElement(); +- idStr = tmpElem.attribute(QLatin1String("xmi.id")); +- if (idStr.isEmpty()) +- idStr = tmpElem.attribute(QLatin1String("xmi.idref")); +- } +- if (idStr.isEmpty()) { +- uError() << "type " << m_AssocType +- << ", id " << Uml::ID::toString(id()) << ": " +- << "xmi id not given for " << tag; +- continue; +- } +- // Since we know for sure that we're dealing with a non +- // umbrello-kf6 file, use deferred resolution unconditionally. +- if (UMLDoc::tagEq(tag, QLatin1String("child")) || +- UMLDoc::tagEq(tag, QLatin1String("subtype")) || +- UMLDoc::tagEq(tag, QLatin1String("client"))) { +- getUMLRole(RoleType::A)->setSecondaryId(idStr); +- } else { +- getUMLRole(RoleType::B)->setSecondaryId(idStr); +- } +- } +- } +- +- // it is a realization if either endpoint is an interface +- if (isRealization(obj[RoleType::A], obj[RoleType::B])) { +- m_AssocType = Uml::AssociationType::Realization; +- } +- return true; +- } +- +- for (QDomNode node = element.firstChild(); !node.isNull(); +- node = node.nextSibling()) { +- // uml13.dtd compliant format (new style) +- if (node.isComment()) +- continue; +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (Model_Utils::isCommonXMIAttribute(tag)) +- continue; +- if (!UMLDoc::tagEq(tag, QLatin1String("Association.connection")) && +- !UMLDoc::tagEq(tag, QLatin1String("Association.end")) && // Embarcadero's Describe +- !UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) && +- !UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { +- uWarning() << "unknown child node " << tag; +- continue; +- } +- // Load role A. +- QDomNode nodeA = tempElement.firstChild(); +- while (nodeA.isComment()) +- nodeA = nodeA.nextSibling(); +- tempElement = nodeA.toElement(); +- if (tempElement.isNull()) { +- uWarning() << "UML:Association : element (A) is Null"; +- return false; +- } +- tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe +- m_AssocType = Uml::AssociationType::UniAssociation; +- } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && +- !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { +- uWarning() << "unknown child (A) tag " << tag; +- return false; +- } +- if (! getUMLRole(RoleType::A)->loadFromXMI(tempElement)) +- return false; +- // Load role B. +- QDomNode nodeB = nodeA.nextSibling(); +- while (nodeB.isComment()) +- nodeB = nodeB.nextSibling(); +- tempElement = nodeB.toElement(); +- if (tempElement.isNull()) { +- uWarning() << "UML:Association : element (B) is Null"; +- return false; +- } +- tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe +- m_AssocType = Uml::AssociationType::UniAssociation; +- } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && +- !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { +- uWarning() << "unknown child (B) tag " << tag; +- return false; +- } +- if (! getUMLRole(RoleType::B)->loadFromXMI(tempElement)) +- return false; +- +- if (m_pUMLPackage == NULL) { +- Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(getObject(RoleType::B)->baseType()); +- m_pUMLPackage = doc->rootFolder(mt); +- DEBUG(DBG_SRC) << "setting model type " << Uml::ModelType::toString(mt); +- } +- +- // setting the association type: +- // +- // In the old days, we could just record this on the association, +- // and be done with it. But thats not how the UML13.dtd does things. +- // As a result, we are checking roleA for information about the +- // parent association (!) which by this point in the parse, should +- // be set. However, the information that the roles are allowed to have +- // is not complete, so we need to finish the analysis here. +- +- // find self-associations +- if (m_AssocType == Uml::AssociationType::Association && getObjectId(RoleType::A) == getObjectId(RoleType::B)) +- m_AssocType = Uml::AssociationType::Association_Self; +- +- // fall-back default type +- if (m_AssocType == Uml::AssociationType::Unknown) { +- m_AssocType = Uml::AssociationType::Association; +- } +- +- return true; +- } +- +- // From here on it's old-style stuff. +- QString assocTypeStr = element.attribute(QLatin1String("assoctype"), QLatin1String("-1")); +- Uml::AssociationType::Enum assocType = Uml::AssociationType::Unknown; +- if (assocTypeStr[0] >= QLatin1Char('a') && assocTypeStr[0] <= QLatin1Char('z')) { +- // In an earlier version, the natural assoctype names were saved. +- const char *assocTypeString[] = { +- "generalization", // Uml::AssociationType::Generalization +- "aggregation", // Uml::AssociationType::Aggregation +- "dependency", // Uml::AssociationType::Dependency +- "association", // Uml::AssociationType::Association +- "associationself", // Uml::AssociationType::Association_Self +- "collmessage", // Uml::AssociationType::Coll_Message +- "seqmessage", // Uml::AssociationType::Seq_Message +- "collmessageself", // Uml::AssociationType::Coll_Message_Self +- "seqmessageself", // Uml::AssociationType::Seq_Message_Self +- "implementation", // Uml::AssociationType::Implementation +- "composition", // Uml::AssociationType::Composition +- "realization", // Uml::AssociationType::Realization +- "uniassociation", // Uml::AssociationType::UniAssociation +- "anchor", // Uml::AssociationType::Anchor +- "state", // Uml::AssociationType::State +- "activity", // Uml::AssociationType::Activity +- "exception", // Uml::AssociationType::Exception +- "category2parent" // Uml::AssociationType::Category2Parent +- "child2category" // Uml::AssociationType::Child2Category +- "relationship" // Uml::AssociationType::Relationship +- }; +- const int arraySize = sizeof(assocTypeString) / sizeof(char*); +- DEBUG(DBG_SRC) << "AssociationType string array size = " << arraySize; +- +- int index; +- for (index = 0; index < arraySize; ++index) +- if (assocTypeStr == QString::fromLatin1(assocTypeString[index])) +- break; +- if (index < arraySize) +- assocType = Uml::AssociationType::fromInt(index); +- } else { +- int assocTypeNum = assocTypeStr.toInt(); +- if (assocTypeNum < (int)Uml::AssociationType::Generalization || // first enum +- assocTypeNum >= (int)Uml::AssociationType::Reserved) { // last enum +- uWarning() << "bad assoctype of UML:AssociationType::Enum " << Uml::ID::toString(id()); +- return false; +- } +- assocType = Uml::AssociationType::fromInt(assocTypeNum); +- } +- setAssociationType(assocType); +- +- Uml::ID::Type roleAObjID = Uml::ID::fromString(element.attribute(QLatin1String("rolea"), QLatin1String("-1"))); +- Uml::ID::Type roleBObjID = Uml::ID::fromString(element.attribute(QLatin1String("roleb"), QLatin1String("-1"))); +- if (assocType == Uml::AssociationType::Aggregation || +- assocType == Uml::AssociationType::Composition) { +- // Flip roles to compensate for changed diamond logic in AssociationLine. +- // For further explanations see AssociationWidget::loadFromXMI. +- Uml::ID::Type tmp = roleAObjID; +- roleAObjID = roleBObjID; +- roleBObjID = tmp; +- } +- +- UMLObject * objA = doc->findObjectById(roleAObjID); +- UMLObject * objB = doc->findObjectById(roleBObjID); +- +- if(objA) +- getUMLRole(RoleType::A)->setObject(objA); +- else +- return false; +- +- if(objB) +- getUMLRole(RoleType::B)->setObject(objB); +- else +- return false; +- +- setMultiplicity(element.attribute(QLatin1String("multia")), RoleType::A); +- setMultiplicity(element.attribute(QLatin1String("multib")), RoleType::B); +- +- setRoleName(element.attribute(QLatin1String("namea")), RoleType::A); +- setRoleName(element.attribute(QLatin1String("nameb")), RoleType::B); +- +- setRoleDoc(element.attribute(QLatin1String("doca")), RoleType::A); +- setRoleDoc(element.attribute(QLatin1String("docb")), RoleType::B); +- +- // Visibility defaults to Public if it cant set it here.. +- QString visibilityA = element.attribute(QLatin1String("visibilitya"), QLatin1String("0")); +- QString visibilityB = element.attribute(QLatin1String("visibilityb"), QLatin1String("0")); +- int vis = visibilityA.toInt(); +- if (vis >= 200) // bkwd compat. +- vis -= 200; +- setVisibility((Uml::Visibility::Enum)vis, RoleType::A); +- vis = visibilityB.toInt(); +- if (vis >= 200) // bkwd compat. +- vis -= 200; +- setVisibility((Uml::Visibility::Enum)vis, RoleType::B); +- +- // Changeability defaults to Changeable if it cant set it here.. +- QString changeabilityA = element.attribute(QLatin1String("changeabilitya"), QLatin1String("0")); +- QString changeabilityB = element.attribute(QLatin1String("changeabilityb"), QLatin1String("0")); +- if (changeabilityA.toInt() > 0) +- setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); +- if (changeabilityB.toInt() > 0) +- setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); +- +- return true; +-} +- +-/** +- * Returns the UMLObject assigned to the given role. +- * @return Pointer to the UMLObject in the given role. +- */ +-UMLObject* UMLAssociation::getObject(Uml::RoleType::Enum role) const +-{ +- if (m_pRole[role] == NULL) +- return NULL; +- return m_pRole[role]->object(); +-} +- +-/** +- * Returns the ID of the UMLObject assigned to the given role. +- * Shorthand for getObject(role)->ID(). +- * @return ID of the UMLObject in the given role. +- */ +-Uml::ID::Type UMLAssociation::getObjectId(Uml::RoleType::Enum role) const +-{ +- UMLRole *roleObj = m_pRole[role]; +- if (roleObj == NULL) +- return Uml::ID::None; +- UMLObject *o = roleObj->object(); +- if (o == NULL) { +- QString auxID = roleObj->secondaryId(); +- if (auxID.isEmpty()) { +- uError() << "role " << role << ": getObject returns NULL"; +- return Uml::ID::None; +- } else { +- DEBUG(DBG_SRC) << "role " << role << ": using secondary ID " << auxID; +- return Uml::ID::fromString(auxID); +- } +- } +- return o->id(); +-} +- +-/** +- * Returns the ID of the UMLObject assigned to the given role. +- * CURRENTLY UNUSED. +- * @return ID of the UMLObject of the given role. +- */ +-Uml::ID::Type UMLAssociation::getRoleId(RoleType::Enum role) const +-{ +- return m_pRole[role]->id(); +-} +- +-/** +- * Returns the changeability. +- */ +-Uml::Changeability::Enum UMLAssociation::changeability(Uml::RoleType::Enum role) const +-{ +- return m_pRole[role]->changeability(); +-} +- +-/** +- * Returns the Visibility of the given role. +- * @return Visibility of the given role. +- */ +-Uml::Visibility::Enum UMLAssociation::visibility(Uml::RoleType::Enum role) const +-{ +- return m_pRole[role]->visibility(); +-} +- +-/** +- * Returns the multiplicity assigned to the given role. +- * @return The multiplicity assigned to the given role. +- */ +-QString UMLAssociation::getMultiplicity(Uml::RoleType::Enum role) const +-{ +- return m_pRole[role]->multiplicity(); +-} +- +-/** +- * Returns the name assigned to the role A. +- * @return The name assigned to the given role. +- */ +-QString UMLAssociation::getRoleName(Uml::RoleType::Enum role) const +-{ +- return m_pRole[role]->name(); +-} +- +-/** +- * Returns the documentation assigned to the given role. +- * @return Documentation text of given role. +- */ +-QString UMLAssociation::getRoleDoc(Uml::RoleType::Enum role) const +-{ +- return m_pRole[role]->doc(); +-} +- +-/** +- * Get the underlying UMLRole object for the given role. +- * @return Pointer to the UMLRole object for the given role. +- */ +-UMLRole * UMLAssociation::getUMLRole(Uml::RoleType::Enum role) const +-{ +- return m_pRole[role]; +-} +- +-/** +- * Set the attribute m_bOldLoadMode. +- * @param value the new value to set +- */ +-void UMLAssociation::setOldLoadMode(bool value /* = true */) +-{ +- m_bOldLoadMode = value; +-} +- +-/** +- * Return the backward compatibility flag for loading files. +- */ +-bool UMLAssociation::getOldLoadMode() const +-{ +- return m_bOldLoadMode; +-} +- +-/** +- * Sets the assocType of the UMLAssociation. +- * @param assocType The AssociationType::Enum of the UMLAssociation. +- */ +-void UMLAssociation::setAssociationType(Uml::AssociationType::Enum assocType) +-{ +- m_AssocType = assocType; +- if (m_AssocType == Uml::AssociationType::UniAssociation) +- { +- // In this case we need to auto-set the multiplicity/rolenames +- // of the roles +-#ifdef VERBOSE_DEBUGGING +- DEBUG(DBG_SRC) << " A new uni-association has been created."; +-#endif +- } +- UMLObject::emitModified(); +-} +- +-/** +- * Sets the UMLObject playing the given role in the association. +- * @param obj Pointer to the UMLObject of the given role. +- * @param role The Uml::RoleType::Enum played by the association +- */ +-void UMLAssociation::setObject(UMLObject *obj, Uml::RoleType::Enum role) +-{ +- m_pRole[role]->setObject(obj); +-} +- +-/** +- * Sets the visibility of the given role of the UMLAssociation. +- * @param value Visibility of role. +- * @param role The Uml::RoleType::Enum to which the visibility is being applied +- */ +-void UMLAssociation::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) +-{ +- m_pRole[role]->setVisibility(value); +-} +- +-/** +- * Sets the changeability of the given role of the UMLAssociation. +- * @param value Changeability_Type of the given role. +- * @param role The Uml::RoleType::Enum to which the changeability is being set +- */ +-void UMLAssociation::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) +-{ +- m_pRole[role]->setChangeability(value); +-} +- +-/** +- * Sets the multiplicity of the given role of the UMLAssociation. +- * @param multi The multiplicity of the given role. +- * @param role The Uml::RoleType::Enum to which the multiplicity is being applied +- */ +-void UMLAssociation::setMultiplicity(const QString &multi, Uml::RoleType::Enum role) +-{ +- if (m_pRole[role]->multiplicity() != multi) { +- UMLApp::app()->executeCommand(new CmdChangeMultiplicity(m_pRole[role], multi)); +- } +-} +- +-/** +- * Sets the name of the given role of the UMLAssociation. +- * @param roleName The name to set for the given role. +- * @param role The Uml::RoleType::Enum for which to set the name. +- */ +-void UMLAssociation::setRoleName(const QString &roleName, Uml::RoleType::Enum role) +-{ +- m_pRole[role]->setName(roleName); +-} +- +-/** +- * Sets the documentation on the given role in the association. +- * @param doc The string with the documentation. +- * @param role The Uml::RoleType::Enum to which the documentation is being applied +- */ +-void UMLAssociation::setRoleDoc(const QString &doc, Uml::RoleType::Enum role) +-{ +- m_pRole[role]->setDoc(doc); +-} +- +-/** +- * When the association type is "Generalization" and at least one of the +- * given objects an interface, then it is a "Realization". +- * @param objA UML object as role A +- * @param objB UML object as role B +- * @return flag whether association is a realization +- */ +-bool UMLAssociation::isRealization(UMLObject* objA, UMLObject* objB) const +-{ +- bool aIsInterface = false; +- if (objA && (objA->baseType() == UMLObject::ot_Interface)) { +- aIsInterface = true; +- } +- bool bIsInterface = false; +- if (objB && (objB->baseType() == UMLObject::ot_Interface)) { +- bIsInterface = true; +- } +- return (m_AssocType == Uml::AssociationType::Generalization) && +- (aIsInterface || bIsInterface); +-} +- +-/** +- * Common initializations at construction time. +- * @param type The AssociationType::Enum to represent. +- * @param roleAObj Pointer to the role A UMLObject. +- * @param roleBObj Pointer to the role B UMLObject. +- */ +-void UMLAssociation::init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj) +-{ +- m_AssocType = type; +- m_BaseType = ot_Association; +- m_Name = QString(); +- m_bOldLoadMode = false; +- nrof_parent_widgets = -1; +- if (!UMLApp::app()->document()->loading()) { +- m_pUMLPackage = UMLApp::app()->document()->currentRoot(); +- } +- m_pRole[RoleType::A] = new UMLRole (this, roleAObj, RoleType::A); +- m_pRole[RoleType::B] = new UMLRole (this, roleBObj, RoleType::B); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/association.h umbrello-kf6-15.08.1/umbrello/association.h +--- umbrello-kf6-15.08.1.orig/umbrello/association.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/association.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,102 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ASSOCIATION_H +-#define ASSOCIATION_H +- +-#include "basictypes.h" +-#include "umlobject.h" +- +-#include +-#include +- +-class UMLRole; +- +-/** +- * This class contains the non-graphic representation of an association. +- * An association can be a generalization, realization, simple association, +- * directed association, aggregation, or composition. +- * +- * @short Sets up association information. +- * @author Oliver Kellogg +- * @see UMLObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLAssociation : public UMLObject +-{ +- Q_OBJECT +- friend class AssociationWidget; +- +-public: +- UMLAssociation(Uml::AssociationType::Enum type, UMLObject *roleA, UMLObject *roleB); +- explicit UMLAssociation(Uml::AssociationType::Enum type = Uml::AssociationType::Unknown); +- +- virtual ~UMLAssociation(); +- +- bool operator==(const UMLAssociation &rhs) const; +- +- QString toString() const; +- +- UMLRole * getUMLRole(Uml::RoleType::Enum role) const; +- Uml::ID::Type getObjectId(Uml::RoleType::Enum role) const; +- Uml::ID::Type getRoleId(Uml::RoleType::Enum role) const; +- +- void setAssociationType(Uml::AssociationType::Enum assocType); +- Uml::AssociationType::Enum getAssocType() const; +- +- void setObject(UMLObject *obj, Uml::RoleType::Enum role); +- UMLObject* getObject(Uml::RoleType::Enum role) const; +- +- void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); +- Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; +- +- void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); +- Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; +- +- void setMultiplicity(const QString &multi, Uml::RoleType::Enum role); +- QString getMultiplicity(Uml::RoleType::Enum role) const; +- +- void setRoleName(const QString &roleName, Uml::RoleType::Enum role); +- QString getRoleName(Uml::RoleType::Enum role) const; +- +- void setRoleDoc(const QString &doc, Uml::RoleType::Enum role); +- QString getRoleDoc(Uml::RoleType::Enum role) const; +- +- void setOldLoadMode(bool value = true); +- bool getOldLoadMode() const; +- +- virtual UMLObject* clone() const { return NULL; } +- +- virtual bool resolveRef(); +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual bool showPropertiesDialog(QWidget *parent = 0); +- +-protected: +- +- bool load(QDomElement& element); +- +- // keep track of number of parent widgets +- int nrof_parent_widgets; +- +- void init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj); +- +- UMLRole * m_pRole[2]; +- Uml::AssociationType::Enum m_AssocType; +- QString m_Name; +- bool m_bOldLoadMode; +- +-private: +- +- bool isRealization(UMLObject* objA, UMLObject* objB) const; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/attribute.cpp umbrello-kf6-15.08.1/umbrello/attribute.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/attribute.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/attribute.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,424 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "attribute.h" +- +-// app includes +-#include "debug_utils.h" +-#include "classifier.h" +-#include "operation.h" +-#include "umlobject.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "folder.h" +-#include "umlattributedialog.h" +-#include "object_factory.h" +- +-/** +- * Sets up an attribute. +- * +- * @param parent The parent of this UMLAttribute. +- * @param name The name of this UMLAttribute. +- * @param id The unique id given to this UMLAttribute. +- * @param s The visibility of the UMLAttribute. +- * @param type The type of this UMLAttribute. +- * @param iv The initial value of the attribute. +- */ +-UMLAttribute::UMLAttribute(UMLObject *parent, +- const QString& name, Uml::ID::Type id, +- Uml::Visibility::Enum s, +- UMLObject *type, const QString& iv) +- : UMLClassifierListItem(parent, name, id) +-{ +- m_InitialValue = iv; +- m_BaseType = UMLObject::ot_Attribute; +- m_visibility = s; +- m_ParmKind = Uml::ParameterDirection::In; +- /* CHECK: Do we need this: +- if (type == NULL) { +- type = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef"); +- } +- */ +- m_pSecondary = type; +-} +- +-/** +- * Sets up an attribute. +- * +- * @param parent The parent of this UMLAttribute. +- */ +-UMLAttribute::UMLAttribute(UMLObject *parent) : UMLClassifierListItem(parent) +-{ +- m_BaseType = UMLObject::ot_Attribute; +- m_visibility = Uml::Visibility::Private; +- m_ParmKind = Uml::ParameterDirection::In; +-} +- +-/** +- * Destructor. +- */ +-UMLAttribute::~UMLAttribute() +-{ +-} +- +-/** +- * Reimplementation of method from UMLObject is required as +- * an extra signal, attributeChanged(), is emitted. +- */ +-void UMLAttribute::setName(const QString &name) +-{ +- m_name = name; +- emit attributeChanged(); +- UMLObject::emitModified(); +-} +- +-/** +- * Reimplementation of method from UMLObject is required as +- * an extra signal, attributeChanged(), is emitted. +- */ +-void UMLAttribute::setVisibility(Uml::Visibility::Enum s) +-{ +- m_visibility = s; +- emit attributeChanged(); +- UMLObject::emitModified(); +-} +- +-/** +- * Returns The initial value of the UMLAttribute. +- * +- * @return The initial value of the Atrtibute. +- */ +-QString UMLAttribute::getInitialValue() const +-{ +- return m_InitialValue; +-} +- +-/** +- * Sets the initial value of the UMLAttribute. +- * +- * @param iv The initial value of the UMLAttribute. +- */ +-void UMLAttribute::setInitialValue(const QString &iv) +-{ +- if(m_InitialValue != iv) { +- m_InitialValue = iv; +- UMLObject::emitModified(); +- } +-} +- +-void UMLAttribute::setParmKind (Uml::ParameterDirection::Enum pk) +-{ +- m_ParmKind = pk; +-} +- +-Uml::ParameterDirection::Enum UMLAttribute::getParmKind() const +-{ +- return m_ParmKind; +-} +- +-/** +- * Returns a string representation of the UMLAttribute. +- * +- * @param sig If true will show the attribute type and initial value. +- * @return Returns a string representation of the UMLAttribute. +- */ +-QString UMLAttribute::toString(Uml::SignatureType::Enum sig) +-{ +- QString s; +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { +- s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); +- } +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { +- // Determine whether the type name needs to be scoped. +- UMLObject *owningObject = static_cast(parent()); +- if (owningObject->baseType() == UMLObject::ot_Operation) { +- // The immediate parent() is the UMLOperation but we want +- // the UMLClassifier: +- owningObject = static_cast(owningObject->parent()); +- } +- UMLClassifier *ownParent = dynamic_cast(owningObject); +- if (ownParent == NULL) { +- uError() << "parent " << owningObject->name() +- << " is not a UMLClassifier"; +- return QString(); +- } +- QString typeName; +- UMLClassifier *type = UMLClassifierListItem::getType(); +- if (type) { +- UMLPackage *typeScope = type->umlPackage(); +- if (typeScope != ownParent && typeScope != ownParent->umlPackage()) +- typeName = type->fullyQualifiedName(); +- else +- typeName = type->name(); +- } +- // The default direction, "in", is not mentioned. +- // Perhaps we should include a pd_Unspecified in +- // Uml::ParameterDirection::Enum to have better control over this. +- if (m_ParmKind == Uml::ParameterDirection::InOut) +- s += QLatin1String("inout "); +- else if (m_ParmKind == Uml::ParameterDirection::Out) +- s += QLatin1String("out "); +- // Construct the attribute text. +- QString string = s + name() + QLatin1String(" : ") + typeName; +- if (m_InitialValue.length() > 0) +- string += QLatin1String(" = ") + m_InitialValue; +- return string; +- } +- return s + name(); +-} +- +-/** +- * Reimplement method from UMLObject. +- */ +-QString UMLAttribute::getFullyQualifiedName(const QString& separator, +- bool includeRoot /* = false */) const +-{ +- UMLOperation *op = NULL; +- UMLObject *owningObject = static_cast(parent()); +- if (owningObject->baseType() == UMLObject::ot_Operation) { +- op = static_cast(owningObject); +- owningObject = static_cast(owningObject->parent()); +- } +- UMLClassifier *ownParent = dynamic_cast(owningObject); +- if (ownParent == NULL) { +- uError() << name() << ": parent " << owningObject->name() +- << " is not a UMLClassifier"; +- return QString(); +- } +- QString tempSeparator = separator; +- if (tempSeparator.isEmpty()) +- tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); +- QString fqn = ownParent->fullyQualifiedName(tempSeparator, includeRoot); +- if (op) +- fqn.append(tempSeparator + op->name()); +- fqn.append(tempSeparator + name()); +- return fqn; +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLAttribute::operator==(const UMLAttribute &rhs) const +-{ +- if(this == &rhs) +- return true; +- +- if(!UMLObject::operator==(rhs)) +- return false; +- +- // The type name is the only distinguishing criterion. +- // (Some programming languages might support more, but others don't.) +- if (m_pSecondary != rhs.m_pSecondary) +- return false; +- +- return true; +-} +- +-/** +- * Copy the internal presentation of this object into the UMLAttribute +- * object. +- */ +-void UMLAttribute::copyInto(UMLObject *lhs) const +-{ +- UMLAttribute *target = static_cast(lhs); +- // call the parent first. +- UMLClassifierListItem::copyInto(target); +- +- // Copy all datamembers +- target->m_pSecondary = m_pSecondary; +- target->m_SecondaryId = m_SecondaryId; +- target->m_InitialValue = m_InitialValue; +- target->m_ParmKind = m_ParmKind; +-} +- +-/** +- * Make a clone of the UMLAttribute. +- */ +-UMLObject* UMLAttribute::clone() const +-{ +- //FIXME: The new attribute should be slaved to the NEW parent not the old. +- UMLAttribute *clone = new UMLAttribute(static_cast(parent())); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement attributeElement = UMLObject::save(QLatin1String("UML:Attribute"), qDoc); +- if (m_pSecondary == NULL) { +- uDebug() << name() << ": m_pSecondary is NULL, m_SecondaryId is '" +- << m_SecondaryId << "'"; +- } else { +- attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); +- } +- if (! m_InitialValue.isEmpty()) +- attributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); +- qElement.appendChild(attributeElement); +-} +- +-/** +- * Loads the XMI element. +- */ +-bool UMLAttribute::load(QDomElement & element) +-{ +- m_SecondaryId = element.attribute(QLatin1String("type")); +- // We use the m_SecondaryId as a temporary store for the xmi.id +- // of the attribute type model object. +- // It is resolved later on, when all classes have been loaded. +- // This deferred resolution is required because the xmi.id may +- // be a forward reference, i.e. it may identify a model object +- // that has not yet been loaded. +- if (m_SecondaryId.isEmpty()) { +- // Perhaps the type is stored in a child node: +- QDomNode node = element.firstChild(); +- while (!node.isNull()) { +- if (node.isComment()) { +- node = node.nextSibling(); +- continue; +- } +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { +- node = node.nextSibling(); +- continue; +- } +- m_SecondaryId = Model_Utils::getXmiId(tempElement); +- if (m_SecondaryId.isEmpty()) +- m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); +- if (m_SecondaryId.isEmpty()) { +- QString href = tempElement.attribute(QLatin1String("href")); +- if (href.isEmpty()) { +- QDomNode inner = node.firstChild(); +- QDomElement tmpElem = inner.toElement(); +- m_SecondaryId = Model_Utils::getXmiId(tmpElem); +- if (m_SecondaryId.isEmpty()) +- m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); +- } else { +- int hashpos = href.lastIndexOf(QChar(QLatin1Char('#'))); +- if (hashpos < 0) { +- uDebug() << name() << ": cannot find type " << href; +- } else { +- QString typeName = href.mid(hashpos + 1); +- UMLFolder *dtFolder = UMLApp::app()->document()->datatypeFolder(); +- m_pSecondary = Model_Utils::findUMLObject(dtFolder->containedObjects(), +- typeName, UMLObject::ot_Datatype); +- if (!m_pSecondary) { +- m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, +- typeName, dtFolder); +- } +- } +- } +- } +- break; +- } +- if (m_SecondaryId.isEmpty()) { +- uDebug() << name() << ": cannot find type."; +- } +- } +- m_InitialValue = element.attribute(QLatin1String("initialValue")); +- if (m_InitialValue.isEmpty()) { +- // for backward compatibility +- m_InitialValue = element.attribute(QLatin1String("value")); +- } +- return true; +-} +- +-/** +- * Display the properties configuration dialog for the attribute. +- */ +-bool UMLAttribute::showPropertiesDialog(QWidget* parent) +-{ +- UMLAttributeDialog dialog(parent, this); +- return dialog.exec(); +-} +- +-/** +- * Puts in the param templateParamList all the template params that are in templateParam +- */ +-void UMLAttribute::setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList) +-{ +- if (templateParam.isEmpty()) +- return; +- QString type = templateParam.simplified(); +- +- int start = type.indexOf(QLatin1Char('<')); +- if (start >= 0) { +- int end = start; +- int count = 1; +- int len = type.length(); +- while (count != 0 && ++end < len) { +- QChar c = type.at(end); +- if (c == QLatin1Char('<')) { +- count++; +- } +- if (c == QLatin1Char('>')) { +- count--; +- } +- } +- if (count != 0) { +- //The template is ill-formated, let's quit +- return; +- } +- setTemplateParams(type.mid(start + 1, end - start - 1), templateParamList); +- setTemplateParams(type.left(start) + type.right(len - end - 1), templateParamList); +- } else { +- QStringList paramsList = type.split(QLatin1Char(',')); +- for (QStringList::Iterator it = paramsList.begin(); it != paramsList.end(); ++it) { +- QString param = *it; +- if (!param.isEmpty()) { +- UMLDoc *pDoc = UMLApp::app()->document(); +- UMLObject* obj = pDoc->findUMLObject(param); +- if (obj == NULL) { +- obj = pDoc->findUMLObject(param.remove(QLatin1Char(' '))); +- } +- if (obj != NULL) { +- //We want to list only the params that already exist in this document +- //If the param doesnt't already exist, we couldn't draw an association anyway +- UMLClassifier* tmpClassifier = static_cast(obj); +- if (templateParamList.indexOf(tmpClassifier) == -1) { +- templateParamList.append(tmpClassifier); +- } +- } +- } +- } +- } +-} +- +-/** +- * Returns all the template params (if any) that are in the type of this attribute +- */ +-UMLClassifierList UMLAttribute::getTemplateParams() +-{ +- UMLClassifierList templateParamList; +- QString type = getType()->name(); +- QString templateParam; +- // Handle C++/D/Java template/generic parameters +- const Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); +- if (pl == Uml::ProgrammingLanguage::Cpp || +- pl == Uml::ProgrammingLanguage::Java || pl == Uml::ProgrammingLanguage::D) { +- int start = type.indexOf(QLatin1Char('<')); +- if (start >= 0) { +- int end = type.lastIndexOf(QLatin1Char('>')); +- if (end > start) { +- templateParam = type.mid(start + 1, end - start - 1); +- setTemplateParams(templateParam, templateParamList); +- } +- } +- } +- return templateParamList; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/attribute.h umbrello-kf6-15.08.1/umbrello/attribute.h +--- umbrello-kf6-15.08.1.orig/umbrello/attribute.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/attribute.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,84 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ATTRIBUTE_H +-#define ATTRIBUTE_H +- +-#include "basictypes.h" +-#include "classifierlistitem.h" +-#include "umlclassifierlist.h" +- +-/** +- * This class is used to set up information for an attribute. This is like +- * a programming attribute. It has a type, name, visibility and initial value. +- * +- * @short Sets up attribute information. +- * @author Paul Hensgen +- * @see UMLObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLAttribute : public UMLClassifierListItem +-{ +- Q_OBJECT +-public: +- +- UMLAttribute(UMLObject *parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None, +- Uml::Visibility::Enum s = Uml::Visibility::Private, +- UMLObject *type = 0, const QString& iv = QString()); +- explicit UMLAttribute(UMLObject *parent); +- +- bool operator==(const UMLAttribute &rhs) const; +- +- virtual ~UMLAttribute(); +- +- virtual void copyInto(UMLObject *lhs) const; +- +- void setName(const QString &name); +- +- void setVisibility(Uml::Visibility::Enum s); +- +- virtual UMLObject* clone() const; +- +- QString getInitialValue() const; +- void setInitialValue(const QString &iv); +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- QString getFullyQualifiedName(const QString& separator = QString(), +- bool includeRoot = false) const; +- +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +- void setParmKind(Uml::ParameterDirection::Enum pk); +- Uml::ParameterDirection::Enum getParmKind() const; +- +- virtual UMLClassifierList getTemplateParams(); +- +-signals: +- +- void attributeChanged(); +- +-protected: +- +- bool load(QDomElement & element); +- +- QString m_InitialValue; ///< text for the attribute's initial value. +- Uml::ParameterDirection::Enum m_ParmKind; +- +-private: +- +- void setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/category.cpp umbrello-kf6-15.08.1/umbrello/category.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/category.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/category.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,101 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "category.h" +- +-/** +- * Constructs a Category. +- * +- * @param name The name of the Category. +- * @param id The unique id to assign to this Category. +- */ +-UMLCategory::UMLCategory(const QString & name, Uml::ID::Type id) +- : UMLCanvasObject(name, id) +-{ +- init(); +-} +- +-/** +- * Standard destructor. +- */ +-UMLCategory::~UMLCategory() +-{ +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLCategory::init() +-{ +- m_BaseType = UMLObject::ot_Category; +- m_CategoryType = ct_Disjoint_Specialisation; +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLCategory::copyInto(UMLObject *lhs) const +-{ +- UMLCategory *target = static_cast(lhs); +- +- // call the parent first +- UMLCanvasObject::copyInto(target); +- +- target->m_CategoryType = m_CategoryType; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLCategory::clone() const +-{ +- UMLCategory *clone = new UMLCategory(); +- copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLCategory::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement categoryElement = UMLObject::save(QLatin1String("UML:Category"), qDoc); +- categoryElement.setAttribute(QLatin1String("categoryType"), (int)m_CategoryType); +- qElement.appendChild(categoryElement); +-} +- +-/** +- * Loads the XMI element (empty.) +- */ +-bool UMLCategory::load(QDomElement& element) +-{ +- m_CategoryType = (Category_Type)element.attribute(QLatin1String("categoryType"), +- QLatin1String("0")).toInt(); +- return true; +-} +- +-/** +- * Get the category type +- */ +-UMLCategory::Category_Type UMLCategory::getType() +-{ +- return m_CategoryType; +-} +- +-/** +- * Set the category type +- */ +-void UMLCategory::setType(Category_Type type) +-{ +- m_CategoryType = type; +- emitModified(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/category.h umbrello-kf6-15.08.1/umbrello/category.h +--- umbrello-kf6-15.08.1.orig/umbrello/category.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/category.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,62 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef CATEGORY_H +-#define CATEGORY_H +- +-#include "umlcanvasobject.h" +- +-/** +- * This class contains the non-graphical information required for a UML Category. +- * This class inherits from @ref UMLCanvasObject which contains most of the +- * information. +- * The @ref UMLDoc class creates instances of this type. +- * +- * @short Information for a non-graphical UML Category. +- * @author Sharan Rao +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLCategory : public UMLCanvasObject { +- Q_OBJECT +-public: +- +- enum Category_Type { +- ct_Disjoint_Specialisation, +- ct_Overlapping_Specialisation, +- ct_Union +- }; +- +- explicit UMLCategory(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- ~UMLCategory(); +- +- virtual void init(); +- +- void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- UMLCategory::Category_Type getType(); +- +- void setType(Category_Type type); +- +-protected: +- +- bool load(QDomElement & element); +- +-private: +- +- Category_Type m_CategoryType; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.cpp umbrello-kf6-15.08.1/umbrello/checkconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/checkconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,160 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-//own header +-#include "checkconstraint.h" +- +-// app includes +-#include "debug_utils.h" +-#include "umlcheckconstraintdialog.h" +- +-/** +- * Sets up a constraint. +- * +- * @param parent The parent of this UMLCheckConstraint. +- * @param name The name of this UMLCheckConstraint. +- * @param id The unique id given to this UMLCheckConstraint. +- */ +-UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent, +- const QString& name, Uml::ID::Type id) +- : UMLEntityConstraint(parent, name, id) +-{ +- init(); +-} +- +-/** +- * Sets up a constraint. +- * +- * @param parent The parent of this UMLCheckConstraint. +- */ +-UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent) +- : UMLEntityConstraint(parent) +-{ +- init(); +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLCheckConstraint::operator==(const UMLCheckConstraint &rhs) const +-{ +- if (this == &rhs) +- return true; +- +- if (!UMLObject::operator==(rhs)) +- return false; +- +- return true; +-} +- +-/** +- * Destructor. +- */ +-UMLCheckConstraint::~UMLCheckConstraint() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the UMLCheckConstraint +- * object. +- */ +-void UMLCheckConstraint::copyInto(UMLObject *lhs) const +-{ +- UMLCheckConstraint *target = static_cast(lhs); +- +- // call the parent first. +- UMLEntityConstraint::copyInto(target); +- +- // Copy all datamembers +- target->m_CheckCondition = m_CheckCondition; +-} +- +-/** +- * Make a clone of the UMLCheckConstraint. +- */ +-UMLObject* UMLCheckConstraint::clone() const +-{ +- //FIXME: The new attribute should be slaved to the NEW parent not the old. +- UMLCheckConstraint *clone = new UMLCheckConstraint(static_cast(parent())); +- copyInto(clone); +- return clone; +-} +- +-/** +- * Returns a string representation of the UMLCheckConstraint. +- * +- * @param sig If true will show the attribute type and initial value. +- * @return Returns a string representation of the UMLAttribute. +- */ +-QString UMLCheckConstraint::toString(Uml::SignatureType::Enum sig) +-{ +- QString s; +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { +- s = name() ; +- } +- +- return s; +-} +- +-QString UMLCheckConstraint::getFullyQualifiedName(const QString& separator, +- bool includeRoot) const +-{ +- Q_UNUSED(separator); Q_UNUSED(includeRoot); +- return this->name(); +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLCheckConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement checkConstraintElement = UMLObject::save(QLatin1String("UML:CheckConstraint"), qDoc); +- +- QDomNode checkCondition = qDoc.createTextNode(m_CheckCondition); +- checkConstraintElement.appendChild(checkCondition); +- +- qElement.appendChild(checkConstraintElement); +-} +- +-/** +- * Display the properties configuration dialog for the attribute. +- */ +-bool UMLCheckConstraint::showPropertiesDialog(QWidget* parent) +-{ +- UMLCheckConstraintDialog dialog(parent, this); +- return dialog.exec(); +-} +- +-/** +- * Loads the XMI element. +- */ +-bool UMLCheckConstraint::load(QDomElement & element) +-{ +- QDomNode node = element.firstChild(); +- +- QDomText checkConstraintText = node.toText(); +- if (checkConstraintText.isNull()) +- m_CheckCondition = QString(); +- else +- m_CheckCondition = checkConstraintText.data(); +- +- return true; +-} +- +-/** +- * Initialises Check Constraint +- */ +-void UMLCheckConstraint::init() +-{ +- m_BaseType = UMLObject::ot_CheckConstraint; +- m_CheckCondition.clear(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.h umbrello-kf6-15.08.1/umbrello/checkconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/checkconstraint.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,71 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef CHECKCONSTRAINT_H +-#define CHECKCONSTRAINT_H +- +-#include "basictypes.h" +-#include "entityconstraint.h" +- +-/** +- * This class is used to set up information for a unique entity constraint. +- * +- * @short Sets up Check Constraint information for UMLEntities. +- * @author Sharan Rao +- * @see UMLObject UMLClassifierListItem UMLEntityConstraint +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLCheckConstraint : public UMLEntityConstraint +-{ +- Q_OBJECT +-public: +- +- UMLCheckConstraint(UMLObject *parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None); +- explicit UMLCheckConstraint(UMLObject *parent); +- +- bool operator==(const UMLCheckConstraint &rhs) const; +- +- virtual ~UMLCheckConstraint(); +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- QString getFullyQualifiedName(const QString& separator = QString(), +- bool includeRoot = false) const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +- QString getCheckCondition() const { +- return m_CheckCondition; +- } +- +- void setCheckCondition(const QString& condition) { +- m_CheckCondition = condition.trimmed(); +- } +- +-protected: +- +- bool load(QDomElement & element); +- +-private: +- +- void init(); +- +- QString m_CheckCondition; ///< the check condition +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifier.cpp umbrello-kf6-15.08.1/umbrello/classifier.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/classifier.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/classifier.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1631 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +-#include "classifier.h" +- +-// app includes +-#include "association.h" +-#include "debug_utils.h" +-#include "umlassociationlist.h" +-#include "operation.h" +-#include "attribute.h" +-#include "template.h" +-#include "enumliteral.h" +-#include "entityattribute.h" +-#include "enum.h" +-#include "entity.h" +-#include "stereotype.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "uniqueid.h" +-#include "object_factory.h" +-#include "model_utils.h" +-#include "idchangelog.h" +-#include "umloperationdialog.h" +-#include "umlattributedialog.h" +-#include "umltemplatedialog.h" +-#include "optionstate.h" +-#include "icon_utils.h" +- +-// kde includes +-#include +-#include +- +-// qt includes +-#include +- +-using namespace Uml; +- +-/** +- * @brief holds set of classifiers for recursive loop detection +- */ +-class UMLClassifierSet: public QSet { +-public: +- UMLClassifierSet() : level(0) +- { +- } +- int level; +-}; +- +-/** +- * Sets up a Classifier. +- * +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLClassifier::UMLClassifier(const QString & name, Uml::ID::Type id) +- : UMLPackage(name, id) +-{ +- m_BaseType = UMLObject::ot_Class; // default value +- m_pClassAssoc = NULL; +- m_isRef = false; +-} +- +-/** +- * Standard deconstructor. +- */ +-UMLClassifier::~UMLClassifier() +-{ +-} +- +-/** +- * Reimplementation of method from class UMLObject for controlling the +- * exact type of this classifier: class, interface, or datatype. +- * @param ot the base type to set +- */ +-void UMLClassifier::setBaseType(UMLObject::ObjectType ot) +-{ +- m_BaseType = ot; +- Icon_Utils::IconType newIcon; +- switch (ot) { +- case ot_Interface: +- UMLObject::setStereotypeCmd(QLatin1String("interface")); +- UMLObject::m_bAbstract = true; +- newIcon = Icon_Utils::it_Interface; +- break; +- case ot_Class: +- UMLObject::setStereotypeCmd(QString()); +- UMLObject::m_bAbstract = false; +- newIcon = Icon_Utils::it_Class; +- break; +- case ot_Datatype: +- UMLObject::setStereotypeCmd(QLatin1String("datatype")); +- UMLObject::m_bAbstract = false; +- newIcon = Icon_Utils::it_Datatype; +- break; +- case ot_Package: +- UMLObject::setStereotypeCmd(QLatin1String("package")); +- UMLObject::m_bAbstract = false; +- newIcon = Icon_Utils::it_Package; +- break; +- default: +- uError() << "cannot set to type " << ot; +- return; +- } +- Model_Utils::treeViewChangeIcon(this, newIcon); +-} +- +-/** +- * Returns true if this classifier represents an interface. +- */ +-bool UMLClassifier::isInterface() const +-{ +- return (m_BaseType == ot_Interface); +-} +- +-/** +- * Returns true if this classifier represents a datatype. +- */ +-bool UMLClassifier::isDatatype() const +-{ +- return (m_BaseType == ot_Datatype); +-} +- +-/** +- * Checks whether an operation is valid based on its signature - +- * An operation is "valid" if the operation's name and parameter list +- * are unique in the classifier. +- * +- * @param name Name of the operation to check. +- * @param opParams The operation's argument list. +- * @param exemptOp Pointer to the exempt method (optional.) +- * @return NULL if the signature is valid (ok), else return a pointer +- * to the existing UMLOperation that causes the conflict. +- */ +-UMLOperation * UMLClassifier::checkOperationSignature( +- const QString& name, +- UMLAttributeList opParams, +- UMLOperation *exemptOp) +-{ +- UMLOperationList list = findOperations(name); +- if (list.count() == 0) { +- return NULL; +- } +- const int inputParmCount = opParams.count(); +- +- // there is at least one operation with the same name... compare the parameter list +- foreach (UMLOperation* test, list) { +- if (test == exemptOp) { +- continue; +- } +- UMLAttributeList testParams = test->getParmList(); +- const int pCount = testParams.count(); +- if (pCount != inputParmCount) { +- continue; +- } +- int i = 0; +- while (i < pCount) { +- // The only criterion for equivalence is the parameter types. +- // (Default values are not considered.) +- if(testParams.at(i)->getTypeName() != opParams.at(i)->getTypeName()) +- break; +- i++; +- } +- if (i == pCount) { // all parameters matched->the signature is not unique +- return test; +- } +- } +- // we did not find an exact match, so the signature is unique (acceptable) +- return NULL; +-} +- +-/** +- * Find an operation of the given name and parameter signature. +- * +- * @param name The name of the operation to find. +- * @param params The parameter descriptors of the operation to find. +- * +- * @return The operation found. Will return 0 if none found. +- */ +-UMLOperation* UMLClassifier::findOperation(const QString& name, +- Model_Utils::NameAndType_List params) +-{ +- UMLOperationList list = findOperations(name); +- if (list.count() == 0) { +- return NULL; +- } +- // if there are operation(s) with the same name then compare the parameter list +- const int inputParmCount = params.count(); +- +- foreach (UMLOperation* test, list) { +- UMLAttributeList testParams = test->getParmList(); +- const int pCount = testParams.count(); +- if (inputParmCount == 0 && pCount == 0) +- return test; +- if (inputParmCount != pCount) +- continue; +- int i = 0; +- for (; i < pCount; ++i) { +- Model_Utils::NameAndType_ListIt nt(params.begin() + i); +- UMLClassifier *type = dynamic_cast((*nt).m_type); +- UMLClassifier *testType = testParams.at(i)->getType(); +- if (type == NULL && testType == NULL) { //no parameter type +- continue; +- } else if (type == NULL) { //template parameter +- if (testType->name() != QLatin1String("class")) +- break; +- } else if (type != testType) +- break; +- } +- if (i == pCount) +- return test; // all parameters matched +- } +- return 0; +-} +- +-/** +- * Creates an operation in the current document. +- * The new operation is initialized with name, id, etc. +- * If a method with the given profile already exists in the classifier, +- * no new method is created and the existing operation is returned. +- * If no name is provided, or if the params are NULL, an Operation +- * Dialog is shown to ask the user for a name and parameters. +- * The operation's signature is checked for validity within the parent +- * classifier. +- * +- * @param name The operation name (will be chosen internally if +- * none given.) +- * @param isExistingOp Optional pointer to bool. If supplied, the bool is +- * set to true if an existing operation is returned. +- * @param params Optional list of parameter names and types. +- * If supplied, new operation parameters are +- * constructed using this list. +- * @return The new operation, or NULL if the operation could not be +- * created because for example, the user canceled the dialog +- * or no appropriate name can be found. +- */ +-UMLOperation* UMLClassifier::createOperation( +- const QString &name /*=QString()*/, +- bool *isExistingOp /*=NULL*/, +- Model_Utils::NameAndType_List *params /*=NULL*/) +-{ +- bool nameNotSet = (name.isNull() || name.isEmpty()); +- if (! nameNotSet) { +- Model_Utils::NameAndType_List parList; +- if (params) +- parList = *params; +- UMLOperation* existingOp = findOperation(name, parList); +- if (existingOp != NULL) { +- if (isExistingOp != NULL) +- *isExistingOp = true; +- return existingOp; +- } +- } +- // we did not find an exact match, so the signature is unique +- UMLOperation *op = new UMLOperation(this, name); +- if (params) { +- for (Model_Utils::NameAndType_ListIt it = params->begin(); it != params->end(); ++it) { +- const Model_Utils::NameAndType &nt = *it; +- UMLAttribute *par = new UMLAttribute(op, nt.m_name, Uml::ID::None, Uml::Visibility::Private, +- nt.m_type, nt.m_initialValue); +- par->setParmKind(nt.m_direction); +- op->addParm(par); +- } +- } +- +- // Only show the operation dialog if no name was provided (allows quick-create +- // from listview) +- if (nameNotSet) { +- op->setName(uniqChildName(UMLObject::ot_Operation)); +- +- while (true) { +- QPointer operationDialog = new UMLOperationDialog(0, op); +- if(operationDialog->exec() != QDialog::Accepted) { +- delete op; +- delete operationDialog; +- return NULL; +- } else if (checkOperationSignature(op->name(), op->getParmList())) { +- KMessageBox::information(0, +- i18n("An operation with the same name and signature already exists. You cannot add it again.")); +- } else { +- break; +- } +- delete operationDialog; +- } +- } +- +- // operation name is ok, formally add it to the classifier +- if (! addOperation(op)) { +- delete op; +- return NULL; +- } +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(op); +- return op; +-} +- +-/** +- * Appends an operation to the classifier. +- * This function is mainly intended for the clipboard. +- * +- * @param op Pointer to the UMLOperation to add. +- * @param position Inserted at the given position. +- * @return True if the operation was added successfully. +- */ +-bool UMLClassifier::addOperation(UMLOperation* op, int position) +-{ +- Q_ASSERT(op); +- if (m_List.indexOf(op) != -1) { +- uDebug() << "findRef(" << op->name() << ") finds op (bad)"; +- return false; +- } +- if (checkOperationSignature(op->name(), op->getParmList())) { +- uDebug() << "checkOperationSignature(" << op->name() << ") op is non-unique"; +- return false; +- } +- +- if (position >= 0 && position <= m_List.count()) { +- uDebug() << op->name() << ": inserting at position " << position; +- m_List.insert(position, op); +- UMLClassifierListItemList itemList = getFilteredList(UMLObject::ot_Operation); +- QString buf; +- foreach (UMLClassifierListItem* currentAtt, itemList) { +- buf.append(QLatin1Char(' ') + currentAtt->name()); +- } +- uDebug() << " list after change: " << buf; +- } +- else { +- m_List.append(op); +- } +- emit operationAdded(op); +- UMLObject::emitModified(); +- connect(op, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +-} +- +-/** +- * Appends an operation to the classifier. +- * @see bool addOperation(UMLOperation* Op, int position = -1) +- * This function is mainly intended for the clipboard. +- * +- * @param op Pointer to the UMLOperation to add. +- * @param log Pointer to the IDChangeLog. +- * @return True if the operation was added successfully. +- */ +-bool UMLClassifier::addOperation(UMLOperation* op, IDChangeLog* log) +-{ +- if (addOperation(op, -1)) { +- return true; +- } +- else if (log) { +- log->removeChangeByNewID(op->id()); +- } +- return false; +-} +- +-/** +- * Remove an operation from the Classifier. +- * The operation is not deleted so the caller is responsible for what +- * happens to it after this. +- * +- * @param op The operation to remove. +- * @return Count of the remaining operations after removal, or +- * -1 if the given operation was not found. +- */ +-int UMLClassifier::removeOperation(UMLOperation *op) +-{ +- if (op == NULL) { +- uDebug() << "called on NULL op"; +- return -1; +- } +- if (!m_List.removeAll(op)) { +- uDebug() << "cannot find op " << op->name() << " in list"; +- return -1; +- } +- // disconnection needed. +- // note that we don't delete the operation, just remove it from the Classifier +- disconnect(op, SIGNAL(modified()), this, SIGNAL(modified())); +- emit operationRemoved(op); +- UMLObject::emitModified(); +- return m_List.count(); +-} +- +-/** +- * Create and add a just created template. +- * @param currentName the name of the template +- * @return the template or NULL +- */ +-UMLObject* UMLClassifier::createTemplate(const QString& currentName /*= QString()*/) +-{ +- QString name = currentName; +- bool goodName = !name.isEmpty(); +- if (!goodName) { +- name = uniqChildName(UMLObject::ot_Template); +- } +- UMLTemplate* newTemplate = new UMLTemplate(this, name); +- +- int button = QDialog::Accepted; +- +- while (button == QDialog::Accepted && !goodName) { +- QPointer templateDialog = new UMLTemplateDialog(0, newTemplate); +- button = templateDialog->exec(); +- name = newTemplate->name(); +- +- if (name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } +- else if (findChildObject(name) != NULL) { +- KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); +- } +- else { +- goodName = true; +- } +- delete templateDialog; +- } +- +- if (button != QDialog::Accepted) { +- return NULL; +- } +- +- addTemplate(newTemplate); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newTemplate); +- return newTemplate; +-} +- +-/** +- * Returns the number of attributes for the class. +- * +- * @return The number of attributes for the class. +- */ +-int UMLClassifier::attributes() +-{ +- UMLClassifierListItemList atts = getFilteredList(UMLObject::ot_Attribute); +- return atts.count(); +-} +- +-/** +- * Returns the attributes for the specified scope. +- * @return List of true attributes for the class. +- */ +-UMLAttributeList UMLClassifier::getAttributeList() const +-{ +- UMLAttributeList attributeList; +- foreach (UMLObject* listItem, m_List) { +- uIgnoreZeroPointer(listItem); +- if (listItem->baseType() == UMLObject::ot_Attribute) { +- attributeList.append(static_cast(listItem)); +- } +- } +- return attributeList; +-} +- +-/** +- * Returns the attributes for the specified scope. +- * @param scope The scope of the attribute. +- * @return List of true attributes for the class. +- */ +-UMLAttributeList UMLClassifier::getAttributeList(Visibility::Enum scope) const +-{ +- UMLAttributeList list; +- if (!isInterface()) +- { +- UMLAttributeList atl = getAttributeList(); +- foreach(UMLAttribute* at, atl) +- { +- uIgnoreZeroPointer(at); +- if (! at->isStatic()) +- { +- if (scope == Uml::Visibility::Private) +- { +- if ((at->visibility() == Uml::Visibility::Private) || +- (at->visibility() == Uml::Visibility::Implementation)) +- { +- list.append(at); +- } +- } +- else if (scope == at->visibility()) +- { +- list.append(at); +- } +- } +- } +- } +- return list; +-} +- +-/** +- * Returns the static attributes for the specified scope. +- * +- * @param scope The scope of the attribute. +- * @return List of true attributes for the class. +- */ +-UMLAttributeList UMLClassifier::getAttributeListStatic(Visibility::Enum scope) const +-{ +- UMLAttributeList list; +- if (!isInterface()) +- { +- UMLAttributeList atl = getAttributeList(); +- foreach(UMLAttribute* at, atl) +- { +- uIgnoreZeroPointer(at); +- if (at->isStatic()) +- { +- if (scope == Uml::Visibility::Private) +- { +- if ((at->visibility() == Uml::Visibility::Private) || +- (at->visibility() == Uml::Visibility::Implementation)) +- { +- list.append(at); +- } +- } +- else if (scope == at->visibility()) +- { +- list.append(at); +- } +- } +- } +- } +- return list; +-} +- +-/** +- * Find a list of operations with the given name. +- * +- * @param n The name of the operation to find. +- * @return The list of objects found; will be empty if none found. +- */ +-UMLOperationList UMLClassifier::findOperations(const QString &n) +-{ +- const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); +- UMLOperationList list; +- foreach (UMLObject* obj, m_List) { +- uIgnoreZeroPointer(obj); +- if (obj->baseType() != UMLObject::ot_Operation) +- continue; +- UMLOperation *op = static_cast(obj); +- if (caseSensitive) { +- if (obj->name() == n) +- list.append(op); +- } else if (obj->name().toLower() == n.toLower()) { +- list.append(op); +- } +- } +- return list; +-} +- +-/** +- * Find the child object by the given id. +- * @param id the id of the child object +- * @param considerAncestors flag whether the ancestors should be considered during search +- * @return the found child object or NULL +- */ +-UMLObject* UMLClassifier::findChildObjectById(Uml::ID::Type id, bool considerAncestors /* =false */) +-{ +- UMLObject *o = UMLCanvasObject::findChildObjectById(id); +- if (o) { +- return o; +- } +- if (considerAncestors) { +- UMLClassifierList ancestors = findSuperClassConcepts(); +- foreach (UMLClassifier *anc, ancestors) { +- UMLObject *o = anc->findChildObjectById(id); +- if (o) { +- return o; +- } +- } +- } +- return NULL; +-} +- +-/** +- * Returns a list of concepts which inherit from this concept. +- * +- * @param type The ClassifierType to seek. +- * @return List of UMLClassifiers that inherit from us. +- */ +-UMLClassifierList UMLClassifier::findSubClassConcepts (ClassifierType type) +-{ +- UMLClassifierList list = getSubClasses(); +- UMLAssociationList rlist = getRealizations(); +- +- UMLClassifierList inheritingConcepts; +- Uml::ID::Type myID = id(); +- foreach(UMLClassifier *c, list) { +- uIgnoreZeroPointer(c); +- if (type == ALL || (!c->isInterface() && type == CLASS) +- || (c->isInterface() && type == INTERFACE)) { +- inheritingConcepts.append(c); +- } +- } +- +- foreach (UMLAssociation *a, rlist) { +- uIgnoreZeroPointer(a); +- if (a->getObjectId(RoleType::A) != myID) +- { +- UMLObject* obj = a->getObject(RoleType::A); +- UMLClassifier *concept = dynamic_cast(obj); +- if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) +- || (concept->isInterface() && type == INTERFACE)) +- && (inheritingConcepts.indexOf(concept) == -1)) +- { +- inheritingConcepts.append(concept); +- } +- } +- } +- +- return inheritingConcepts; +-} +- +-/** +- * Returns a list of concepts which this concept inherits from. +- * +- * @param type The ClassifierType to seek. +- * @return List of UMLClassifiers we inherit from. +- */ +-UMLClassifierList UMLClassifier::findSuperClassConcepts (ClassifierType type) +-{ +- UMLClassifierList list = getSuperClasses(); +- UMLAssociationList rlist = getRealizations(); +- +- UMLClassifierList parentConcepts; +- Uml::ID::Type myID = id(); +- foreach (UMLClassifier *concept, list) { +- uIgnoreZeroPointer(concept); +- if (type == ALL || (!concept->isInterface() && type == CLASS) +- || (concept->isInterface() && type == INTERFACE)) +- parentConcepts.append(concept); +- } +- +- foreach (UMLAssociation *a, rlist) { +- if (a->getObjectId(RoleType::A) == myID) +- { +- UMLObject* obj = a->getObject(RoleType::B); +- UMLClassifier *concept = dynamic_cast(obj); +- if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) +- || (concept->isInterface() && type == INTERFACE)) +- && (parentConcepts.indexOf(concept) == -1)) +- parentConcepts.append(concept); +- } +- } +- +- return parentConcepts; +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLClassifier::operator==(const UMLClassifier & rhs) const +-{ +- return UMLCanvasObject::operator==(rhs); +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLClassifier::copyInto(UMLObject *lhs) const +-{ +- UMLClassifier *target = static_cast(lhs); +- UMLCanvasObject::copyInto(target); +- target->setBaseType(m_BaseType); +- // CHECK: association property m_pClassAssoc is not copied +- m_List.copyInto(&(target->m_List)); +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLClassifier::clone() const +-{ +- UMLClassifier *clone = new UMLClassifier(); +- copyInto(clone); +- return clone; +-} +- +-/** +- * Needs to be called after all UML objects are loaded from file. +- * Calls the parent resolveRef(), and calls resolveRef() on all +- * UMLClassifierListItems. +- * Overrides the method from UMLObject. +- * +- * @return true for success. +- */ +-bool UMLClassifier::resolveRef() +-{ +- bool success = UMLPackage::resolveRef(); +- // Using reentrant iteration is a bare necessity here: +- foreach (UMLObject* obj, m_List) { +- uIgnoreZeroPointer(obj); +- /**** For reference, here is the non-reentrant iteration scheme - +- DO NOT USE THIS ! +- for (UMLObject *obj = m_List.first(); obj; obj = m_List.next()) +- { .... } +- ****/ +- if (obj->resolveRef()) { +- UMLClassifierListItem *cli = static_cast(obj); +- switch (cli->baseType()) { +- case UMLObject::ot_Attribute: +- emit attributeAdded(cli); +- break; +- case UMLObject::ot_Operation: +- emit operationAdded(cli); +- break; +- case UMLObject::ot_Template: +- emit templateAdded(cli); +- break; +- default: +- break; +- } +- } +- } +- return success; +-} +- +-/** +- * Reimplemented from UMLObject. +- */ +-bool UMLClassifier::acceptAssociationType(AssociationType::Enum type) +-{ +- switch(type) +- { +- case AssociationType::Generalization: +- case AssociationType::Aggregation: +- case AssociationType::Relationship: +- case AssociationType::Dependency: +- case AssociationType::Association: +- case AssociationType::Association_Self: +- case AssociationType::Containment: +- case AssociationType::Composition: +- case AssociationType::Realization: +- case AssociationType::UniAssociation: +- return true; +- default: +- return false; +- } +- return false; //shutup compiler warning +-} +- +-/** +- * Creates an attribute for the class. +- * +- * @param name An optional name, used by when creating through UMLListView +- * @param type An optional type, used by when creating through UMLListView +- * @param vis An optional visibility, used by when creating through UMLListView +- * @param init An optional initial value, used by when creating through UMLListView +- * @return The UMLAttribute created +- */ +-UMLAttribute* UMLClassifier::createAttribute(const QString &name, +- UMLObject *type, +- Visibility::Enum vis, +- const QString &init) +-{ +- Uml::ID::Type id = UniqueID::gen(); +- QString currentName; +- if (name.isNull()) { +- currentName = uniqChildName(UMLObject::ot_Attribute); +- } else { +- currentName = name; +- } +- UMLAttribute* newAttribute = new UMLAttribute(this, currentName, id, vis, type, init); +- +- int button = QDialog::Accepted; +- bool goodName = false; +- +- //check for name.isNull() stops dialog being shown +- //when creating attribute via list view +- while (button == QDialog::Accepted && !goodName && name.isNull()) { +- QPointer attributeDialog = new UMLAttributeDialog(0, newAttribute); +- button = attributeDialog->exec(); +- QString name = newAttribute->name(); +- +- if(name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } else if (findChildObject(name) != NULL) { +- KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); +- } else { +- goodName = true; +- } +- delete attributeDialog; +- } +- +- if (button != QDialog::Accepted) { +- delete newAttribute; +- return NULL; +- } +- +- addAttribute(newAttribute); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newAttribute); +- return newAttribute; +-} +- +-/** +- * Creates and adds an attribute for the class. +- * +- * @param name an optional name, used by when creating through UMLListView +- * @param id an optional id +- * @return the UMLAttribute created and added +- */ +- +-UMLAttribute* UMLClassifier::addAttribute(const QString &name, Uml::ID::Type id /* = Uml::id_None */) +-{ +- foreach (UMLObject* obj, m_List) { +- uIgnoreZeroPointer(obj); +- if (obj->baseType() == UMLObject::ot_Attribute && obj->name() == name) +- return static_cast(obj); +- } +- Uml::Visibility::Enum scope = Settings::optionState().classState.defaultAttributeScope; +- UMLAttribute *a = new UMLAttribute(this, name, id, scope); +- m_List.append(a); +- emit attributeAdded(a); +- UMLObject::emitModified(); +- connect(a, SIGNAL(modified()), this, SIGNAL(modified())); +- return a; +-} +- +-/** +- * Adds an already created attribute. +- * The attribute object must not belong to any other concept. +- * +- * @param name the name of the attribute +- * @param type the type of the attribute +- * @param scope the visibility of the attribute +- * @return the just created and added attribute +- */ +-UMLAttribute* UMLClassifier::addAttribute(const QString &name, UMLObject *type, Visibility::Enum scope) +-{ +- UMLAttribute *a = new UMLAttribute(this); +- a->setName(name); +- a->setVisibility(scope); +- a->setID(UniqueID::gen()); +- if (type) { +- a->setType(type); +- } +- m_List.append(a); +- emit attributeAdded(a); +- UMLObject::emitModified(); +- connect(a, SIGNAL(modified()), this, SIGNAL(modified())); +- return a; +-} +- +-/** +- * Adds an already created attribute. +- * The attribute object must not belong to any other concept. +- * +- * @param att Pointer to the UMLAttribute. +- * @param log Pointer to the IDChangeLog (optional.) +- * @param position Position index for the insertion (optional.) +- * If the position is omitted, or if it is +- * negative or too large, the attribute is added +- * to the end of the list. +- * @return True if the attribute was successfully added. +- */ +-bool UMLClassifier::addAttribute(UMLAttribute* att, IDChangeLog* log /* = 0 */, +- int position /* = -1 */) +-{ +- Q_ASSERT(att); +- if (findChildObject(att->name()) == NULL) { +- att->setParent(this); +- if (position >= 0 && position < (int)m_List.count()) { +- m_List.insert(position, att); +- } +- else { +- m_List.append(att); +- } +- emit attributeAdded(att); +- UMLObject::emitModified(); +- connect(att, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } else if (log) { +- log->removeChangeByNewID(att->id()); +- delete att; +- } +- return false; +-} +- +-/** +- * Removes an attribute from the class. +- * +- * @param att The attribute to remove. +- * @return Count of the remaining attributes after removal. +- * Returns -1 if the given attribute was not found. +- */ +-int UMLClassifier::removeAttribute(UMLAttribute* att) +-{ +- if (!m_List.removeAll(att)) { +- uDebug() << "cannot find att given in list"; +- return -1; +- } +- emit attributeRemoved(att); +- UMLObject::emitModified(); +- // If we are deleting the object, then we don't need to disconnect..this is done auto-magically +- // for us by QObject. -b.t. +- // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); +- delete att; +- return m_List.count(); +-} +- +-/** +- * Sets the UMLAssociation for which this class shall act as an +- * association class. +- */ +-void UMLClassifier::setClassAssoc(UMLAssociation *assoc) +-{ +- m_pClassAssoc = assoc; +-} +- +-/** +- * Returns the UMLAssociation for which this class acts as an +- * association class. Returns NULL if this class does not act +- * as an association class. +- */ +-UMLAssociation *UMLClassifier::getClassAssoc() const +-{ +- return m_pClassAssoc; +-} +- +-/** +- * Return true if this classifier has abstract operations. +- */ +-bool UMLClassifier::hasAbstractOps () +-{ +- UMLOperationList opl(getOpList()); +- foreach(UMLOperation *op, opl) { +- uIgnoreZeroPointer(op); +- if (op->isAbstract()) { +- return true; +- } +- } +- return false; +-} +- +-/** +- * Counts the number of operations in the Classifier. +- * +- * @return The number of operations for the Classifier. +- */ +-int UMLClassifier::operations() +-{ +- return getOpList().count(); +-} +- +- +-/** +- * Return a list of operations for the Classifier. +- * +- * @param includeInherited Includes operations from superclasses. +- * @param alreadyTraversed internal used object to avoid recursive loops +- * @return The list of operations for the Classifier. +- */ +-UMLOperationList UMLClassifier::getOpList(bool includeInherited, UMLClassifierSet *alreadyTraversed) +-{ +- UMLOperationList ops; +- foreach (UMLObject* li, m_List) { +- uIgnoreZeroPointer(li); +- if (li->baseType() == ot_Operation) { +- ops.append(static_cast(li)); +- } +- } +- if (includeInherited) { +- if (!alreadyTraversed) { +- alreadyTraversed = new UMLClassifierSet; +- } +- else +- alreadyTraversed->level++; +- +- if (!alreadyTraversed->contains(this)) +- *alreadyTraversed << this; +- +- // get a list of parents of this class +- UMLClassifierList parents = findSuperClassConcepts(); +- foreach(UMLClassifier *c, parents) { +- if (alreadyTraversed->contains(c)) { +- uError() << "class " << c->name() << " is starting a dependency loop!"; +- continue; +- } +- // get operations for each parent by recursive call +- UMLOperationList pops = c->getOpList(true, alreadyTraversed); +- // add these operations to operation list, but only if unique. +- foreach (UMLOperation *po, pops) { +- QString po_as_string(po->toString(Uml::SignatureType::SigNoVis)); +- bool breakFlag = false; +- foreach (UMLOperation* o, ops) { +- if (o->toString(Uml::SignatureType::SigNoVis) == po_as_string) { +- breakFlag = true; +- break; +- } +- } +- if (breakFlag == false) +- ops.append(po); +- } +- // remember this node +- *alreadyTraversed << c; +- } +- if (alreadyTraversed->level-- == 0) { +- delete alreadyTraversed; +- alreadyTraversed = 0; +- } +- } +- return ops; +-} +- +-/** +- * Returns the entries in m_List that are of the requested type. +- * If the requested type is UMLObject::ot_UMLObject then all entries +- * are returned. +- * @param ot the requested object type +- * @return The list of true operations for the Concept. +- */ +-UMLClassifierListItemList UMLClassifier::getFilteredList(UMLObject::ObjectType ot) const +-{ +- UMLClassifierListItemList resultList; +- foreach (UMLObject* o, m_List) { +- uIgnoreZeroPointer(o); +- if (!o || o->baseType() == UMLObject::ot_Association) { +- continue; +- } +- UMLClassifierListItem *listItem = static_cast(o); +- if (ot == UMLObject::ot_UMLObject || listItem->baseType() == ot) { +- resultList.append(listItem); +- } +- } +- return resultList; +-} +- +-/** +- * Adds an already created template. +- * The template object must not belong to any other concept. +- * +- * @param name the name of the template +- * @param id the id of the template +- * @return the added template +- */ +-UMLTemplate* UMLClassifier::addTemplate(const QString &name, Uml::ID::Type id) +-{ +- UMLTemplate *templt = findTemplate(name); +- if (templt) { +- return templt; +- } +- templt = new UMLTemplate(this, name, id); +- m_List.append(templt); +- emit templateAdded(templt); +- UMLObject::emitModified(); +- connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); +- return templt; +-} +- +-/** +- * Adds an already created template. +- * The template object must not belong to any other concept. +- * +- * @param newTemplate Pointer to the UMLTemplate object to add. +- * @param log Pointer to the IDChangeLog. +- * @return True if the template was successfully added. +- */ +-bool UMLClassifier::addTemplate(UMLTemplate* newTemplate, IDChangeLog* log /* = 0*/) +-{ +- QString name = newTemplate->name(); +- if (findChildObject(name) == NULL) { +- newTemplate->setParent(this); +- m_List.append(newTemplate); +- emit templateAdded(newTemplate); +- UMLObject::emitModified(); +- connect(newTemplate, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } +- else if (log) { +- log->removeChangeByNewID(newTemplate->id()); +- delete newTemplate; +- } +- return false; +-} +- +-/** +- * Adds an template to the class. +- * The template object must not belong to any other class. +- * TODO: If the param IDChangeLog from the method above is not being used, +- * give position a default value of -1 and the method can replace the above one. +- * @param templt Pointer to the UMLTemplate to add. +- * @param position The position of the template in the list. +- * A value of -1 will add the template at the end. +- * @return True if the template was successfully added. +- */ +-bool UMLClassifier::addTemplate(UMLTemplate* templt, int position) +-{ +- Q_ASSERT(templt); +- QString name = templt->name(); +- if (findChildObject(name) == NULL) { +- templt->setParent(this); +- if (position >= 0 && position <= (int)m_List.count()) { +- m_List.insert(position, templt); +- } +- else { +- m_List.append(templt); +- } +- emit templateAdded(templt); +- UMLObject::emitModified(); +- connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } +- //else +- return false; +-} +- +-/** +- * Removes a template from the class. +- * +- * @param umltemplate The template to remove. +- * @return Count of the remaining templates after removal. +- * Returns -1 if the given template was not found. +- */ +-int UMLClassifier::removeTemplate(UMLTemplate* umltemplate) +-{ +- if (!m_List.removeAll(umltemplate)) { +- uWarning() << "cannot find att given in list"; +- return -1; +- } +- emit templateRemoved(umltemplate); +- UMLObject::emitModified(); +- disconnect(umltemplate, SIGNAL(modified()), this, SIGNAL(modified())); +- return m_List.count(); +-} +- +-/** +- * Seeks the template parameter of the given name. +- * @param name the template name +- * @return the found template or 0 +- */ +-UMLTemplate *UMLClassifier::findTemplate(const QString& name) +-{ +- UMLTemplateList templParams = getTemplateList(); +- foreach (UMLTemplate *templt, templParams) { +- if (templt->name() == name) { +- return templt; +- } +- } +- return 0; +-} +- +-/** +- * Returns the number of templates for the class. +- * +- * @return The number of templates for the class. +- */ +-int UMLClassifier::templates() +-{ +- UMLClassifierListItemList tempList = getFilteredList(UMLObject::ot_Template); +- return tempList.count(); +-} +- +-/** +- * Returns the templates. +- * Same as UMLClassifier::getFilteredList(ot_Template) but +- * return type is a true UMLTemplateList. +- * +- * @return Pointer to the list of true templates for the class. +- */ +-UMLTemplateList UMLClassifier::getTemplateList() const +-{ +- UMLTemplateList templateList; +- foreach (UMLObject* listItem, m_List) { +- uIgnoreZeroPointer(listItem); +- if (listItem->baseType() == UMLObject::ot_Template) { +- templateList.append(static_cast(listItem)); +- } +- } +- return templateList; +-} +- +-/** +- * Take and return a subordinate item from this classifier. +- * Ownership of the item is passed to the caller. +- * +- * @param item Subordinate item to take. +- * @return Index in m_List of the item taken. +- * Return -1 if the item is not found in m_List. +- */ +-int UMLClassifier::takeItem(UMLClassifierListItem *item) +-{ +- QString buf; +- foreach (UMLObject* currentAtt, m_List) { +- uIgnoreZeroPointer(currentAtt); +- QString txt = currentAtt->name(); +- if (txt.isEmpty()) { +- txt = QLatin1String("Type-") + QString::number((int) currentAtt->baseType()); +- } +- buf.append(QLatin1Char(' ') + currentAtt->name()); +- } +- uDebug() << " UMLClassifier::takeItem (before): m_List is " << buf; +- +- int index = m_List.indexOf(item); +- if (index == -1) { +- return -1; +- } +- switch (item->baseType()) { +- case UMLObject::ot_Operation: { +- if (removeOperation(dynamic_cast(item)) < 0) { +- index = -1; +- } +- break; +- } +- case UMLObject::ot_Attribute: { +- UMLAttribute *retval = dynamic_cast(m_List.takeAt(index).data()); +- if (retval) { +- emit attributeRemoved(retval); +- UMLObject::emitModified(); +- } else { +- index = -1; +- } +- break; +- } +- case UMLObject::ot_Template: { +- UMLTemplate *templt = dynamic_cast(m_List.takeAt(index).data()); +- if (templt) { +- emit templateRemoved(templt); +- UMLObject::emitModified(); +- } else { +- index = -1; +- } +- break; +- } +- case UMLObject::ot_EnumLiteral: { +- UMLEnumLiteral *el = dynamic_cast(m_List.takeAt(index).data()); +- if (el) { +- UMLEnum *e = static_cast(this); +- e->signalEnumLiteralRemoved(el); +- UMLObject::emitModified(); +- } else { +- index = -1; +- } +- break; +- } +- case UMLObject::ot_EntityAttribute: { +- UMLEntityAttribute* el = dynamic_cast(m_List.takeAt(index).data()); +- if (el) { +- UMLEntity *e = static_cast(this); +- e->signalEntityAttributeRemoved(el); +- UMLObject::emitModified(); +- } else { +- index = -1; +- } +- break; +- } +- default: +- index = -1; +- break; +- } +- return index; +-} +- +-/** +- * Set the origin type (in case of e.g. typedef) +- * @param origType the origin type to set +- */ +-void UMLClassifier::setOriginType(UMLClassifier *origType) +-{ +- m_pSecondary = origType; +-} +- +-/** +- * Get the origin type (in case of e.g. typedef) +- * @return the origin type +- */ +-UMLClassifier * UMLClassifier::originType() const +-{ +- return dynamic_cast(m_pSecondary.data()); +-} +- +-/** +- * Set the m_isRef flag (true when dealing with a pointer type) +- * @param isRef the flag to set +- */ +-void UMLClassifier::setIsReference(bool isRef) +-{ +- m_isRef = isRef; +-} +- +-/** +- * Get the m_isRef flag. +- * @return true if is reference, otherwise false +- */ +-bool UMLClassifier::isReference() const +-{ +- return m_isRef; +-} +- +-/** +- * Return true if this classifier has associations. +- * @return true if classifier has associations +- */ +-bool UMLClassifier::hasAssociations() +-{ +- return getSpecificAssocs(AssociationType::Association).count() > 0 +- || getAggregations().count() > 0 +- || getCompositions().count() > 0 +- || getUniAssociationToBeImplemented().count() > 0; +-} +- +-/** +- * Return true if this classifier has attributes. +- */ +-bool UMLClassifier::hasAttributes() +-{ +- return getAttributeList(Uml::Visibility::Public).count() > 0 +- || getAttributeList(Uml::Visibility::Protected).count() > 0 +- || getAttributeList(Uml::Visibility::Private).count() > 0 +- || getAttributeListStatic(Uml::Visibility::Public).count() > 0 +- || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 +- || getAttributeListStatic(Uml::Visibility::Private).count() > 0; +-} +- +-/** +- * Return true if this classifier has static attributes. +- */ +-bool UMLClassifier::hasStaticAttributes() +-{ +- return getAttributeListStatic(Uml::Visibility::Public).count() > 0 +- || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 +- || getAttributeListStatic(Uml::Visibility::Private).count() > 0; +-} +- +-/** +- * Return true if this classifier has accessor methods. +- */ +-bool UMLClassifier::hasAccessorMethods() +-{ +- return hasAttributes() || hasAssociations(); +-} +- +-/** +- * Return true if this classifier has operation methods. +- */ +-bool UMLClassifier::hasOperationMethods() +-{ +- return getOpList().last() ? true : false; +-} +- +-/** +- * Return true if this classifier has methods. +- */ +-bool UMLClassifier::hasMethods() +-{ +- return hasOperationMethods() || hasAccessorMethods(); +-} +- +-// this is a bit too simplistic..some associations are for +-// SINGLE objects, and WONT be declared as Vectors, so this +-// is a bit overly inclusive (I guess that's better than the other way around) +- +-/** +- * Return true if this classifier has vector fields. +- */ +-bool UMLClassifier::hasVectorFields() +-{ +- return hasAssociations(); +-} +- +-/** +- * Return the list of unidirectional association that should show up in the code +- */ +-UMLAssociationList UMLClassifier::getUniAssociationToBeImplemented() +-{ +- UMLAssociationList associations = getSpecificAssocs(AssociationType::UniAssociation); +- UMLAssociationList uniAssocListToBeImplemented; +- +- foreach (UMLAssociation *a, associations) { +- uIgnoreZeroPointer(a); +- if (a->getObjectId(RoleType::B) == id()) { +- continue; // we need to be at the A side +- } +- QString roleNameB = a->getRoleName(RoleType::B); +- if (!roleNameB.isEmpty()) { +- UMLAttributeList atl = getAttributeList(); +- bool found = false; +- //make sure that an attribute with the same name doesn't already exist +- foreach (UMLAttribute *at, atl) { +- uIgnoreZeroPointer(a); +- if (at->name() == roleNameB) { +- found = true; +- break; +- } +- } +- if (!found) { +- uniAssocListToBeImplemented.append(a); +- } +- } +- } +- return uniAssocListToBeImplemented; +-} +- +-/** +- * Creates XML tag , , or +- * depending on m_BaseType. +- * Saves possible template parameters, generalizations, attributes, +- * operations, and contained objects to the given QDomElement. +- */ +-void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QString tag; +- switch (m_BaseType) { +- case UMLObject::ot_Class: +- tag = QLatin1String("UML:Class"); +- break; +- case UMLObject::ot_Interface: +- tag = QLatin1String("UML:Interface"); +- break; +- case UMLObject::ot_Datatype: +- tag = QLatin1String("UML:DataType"); +- break; +- case UMLObject::ot_Package: +- UMLPackage::saveToXMI(qDoc, qElement); +- return; +- break; +- default: +- uError() << "internal error: basetype is " << m_BaseType; +- return; +- } +- QDomElement classifierElement = UMLObject::save(tag, qDoc); +- if (m_BaseType == UMLObject::ot_Datatype && m_pSecondary != NULL) +- classifierElement.setAttribute(QLatin1String("elementReference"), +- Uml::ID::toString(m_pSecondary->id())); +- +- //save templates +- UMLClassifierListItemList list = getFilteredList(UMLObject::ot_Template); +- if (list.count()) { +- QDomElement tmplElement = qDoc.createElement(QLatin1String("UML:ModelElement.templateParameter")); +- foreach (UMLClassifierListItem *tmpl, list) { +- tmpl->saveToXMI(qDoc, tmplElement); +- } +- classifierElement.appendChild(tmplElement); +- } +- +- //save generalizations (we are the subclass, the other end is the superclass) +- UMLAssociationList generalizations = getSpecificAssocs(AssociationType::Generalization); +- if (generalizations.count()) { +- QDomElement genElement = qDoc.createElement(QLatin1String("UML:GeneralizableElement.generalization")); +- foreach (UMLAssociation *a, generalizations) { +- // We are the subclass if we are at the role A end. +- if (m_nId != a->getObjectId(RoleType::A)) { +- continue; +- } +- QDomElement gElem = qDoc.createElement(QLatin1String("UML:Generalization")); +- gElem.setAttribute(QLatin1String("xmi.idref"), Uml::ID::toString(a->id())); +- genElement.appendChild(gElem); +- } +- if (genElement.hasChildNodes()) { +- classifierElement.appendChild(genElement); +- } +- } +- +- // save attributes +- QDomElement featureElement = qDoc.createElement(QLatin1String("UML:Classifier.feature")); +- UMLClassifierListItemList attList = getFilteredList(UMLObject::ot_Attribute); +- foreach (UMLClassifierListItem *pAtt, attList) { +- pAtt->saveToXMI(qDoc, featureElement); +- } +- +- // save operations +- UMLOperationList opList = getOpList(); +- foreach (UMLOperation *pOp, opList) { +- pOp->saveToXMI(qDoc, featureElement); +- } +- if (featureElement.hasChildNodes()) { +- classifierElement.appendChild(featureElement); +- } +- +- // save contained objects +- if (m_objects.count()) { +- QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); +- foreach (UMLObject* obj, m_objects) { +- uIgnoreZeroPointer(obj); +- obj->saveToXMI (qDoc, ownedElement); +- } +- classifierElement.appendChild(ownedElement); +- } +- qElement.appendChild(classifierElement); +-} +- +-/** +- * Create a new ClassifierListObject (attribute, operation, template) +- * according to the given XMI tag. +- * Returns NULL if the string given does not contain one of the tags +- * , , or . +- * Used by the clipboard for paste operation. +- */ +-UMLClassifierListItem* UMLClassifier::makeChildObject(const QString& xmiTag) +-{ +- UMLClassifierListItem* pObject = NULL; +- if (UMLDoc::tagEq(xmiTag, QLatin1String("Operation")) || +- UMLDoc::tagEq(xmiTag, QLatin1String("ownedOperation"))) { +- pObject = new UMLOperation(this); +- } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Attribute")) || +- UMLDoc::tagEq(xmiTag, QLatin1String("ownedAttribute"))) { +- if (baseType() != UMLObject::ot_Class) +- return NULL; +- pObject = new UMLAttribute(this); +- } else if (UMLDoc::tagEq(xmiTag, QLatin1String("TemplateParameter"))) { +- pObject = new UMLTemplate(this); +- } +- return pObject; +-} +- +-/** +- * Auxiliary to loadFromXMI: +- * The loading of operations is implemented here. +- * Calls loadSpecialized() for any other tag. +- * Child classes can override the loadSpecialized method +- * to load its additional tags. +- */ +-bool UMLClassifier::load(QDomElement& element) +-{ +- UMLClassifierListItem *child = NULL; +- m_SecondaryId = element.attribute(QLatin1String("elementReference")); +- if (!m_SecondaryId.isEmpty()) { +- // @todo We do not currently support composition. +- m_isRef = true; +- } +- bool totalSuccess = true; +- for (QDomNode node = element.firstChild(); !node.isNull(); +- node = node.nextSibling()) { +- if (node.isComment()) +- continue; +- element = node.toElement(); +- QString tag = element.tagName(); +- QString stereotype = element.attribute(QLatin1String("stereotype")); +- if (UMLDoc::tagEq(tag, QLatin1String("ModelElement.templateParameter")) || +- UMLDoc::tagEq(tag, QLatin1String("Classifier.feature")) || +- UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) || +- UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe +- UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { +- load(element); +- // Not evaluating the return value from load() +- // because we want a best effort. +- +- } else if ((child = makeChildObject(tag)) != NULL) { +- if (child->loadFromXMI(element)) { +- switch (child->baseType()) { +- case UMLObject::ot_Template: +- addTemplate(static_cast(child)); +- break; +- case UMLObject::ot_Operation: +- if (! addOperation(static_cast(child))) { +- uError() << "error from addOperation(op)"; +- delete child; +- totalSuccess = false; +- } +- break; +- case UMLObject::ot_Attribute: +- addAttribute(static_cast(child)); +- break; +- default: +- break; +- } +- } else { +- uWarning() << "failed to load " << tag; +- delete child; +- totalSuccess = false; +- } +- } else if (!Model_Utils::isCommonXMIAttribute(tag)) { +- UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag, stereotype); +- if (pObject == NULL) { +- // Not setting totalSuccess to false +- // because we want a best effort. +- continue; +- } +- pObject->setUMLPackage(this); +- if (! pObject->loadFromXMI(element)) { +- removeObject(pObject); +- delete pObject; +- totalSuccess = false; +- } +- } +- } +- return totalSuccess; +-} +- +-/* +-UMLClassifierList UMLClassifier::getPlainAssocChildClassifierList() +-{ +- UMLAssociationList plainAssociations = getSpecificAssocs(Uml::AssociationType::Association); +- return findAssocClassifierObjsInRoles(&plainAssociations); +-} +- +-UMLClassifierList UMLClassifier::getAggregateChildClassifierList() +-{ +- UMLAssociationList aggregations = getAggregations(); +- return findAssocClassifierObjsInRoles(&aggregations); +-} +- +-UMLClassifierList UMLClassifier::getCompositionChildClassifierList() +-{ +- UMLAssociationList compositions = getCompositions(); +- return findAssocClassifierObjsInRoles(&compositions); +-} +- +-UMLClassifierList UMLClassifier::findAssocClassifierObjsInRoles (UMLAssociationList * list) +-{ +- UMLClassifierList classifiers; +- +- for (UMLAssociationListIt alit(*list); alit.hasNext(); ) { +- UMLAssociation* a = alit.next(); +- // DON'T accept a classifier IF the association role is empty, by +- // convention, that means to ignore the classifier on that end of +- // the association. +- // We also ignore classifiers which are the same as the current one +- // (e.g. id matches), we only want the "other" classifiers +- if (a->getObjectId(RoleType::A) == id() && !a->getRoleName(RoleType::B).isEmpty()) { +- UMLClassifier *c = dynamic_cast(a->getObject(RoleType::B)); +- if(c) +- classifiers.append(c); +- } else if (a->getObjectId(RoleType::B) == id() && !a->getRoleName(RoleType::A).isEmpty()) { +- UMLClassifier *c = dynamic_cast(a->getObject(RoleType::A)); +- if(c) +- classifiers.append(c); +- } +- } +- +- return classifiers; +-} +-*/ +- +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifier.h umbrello-kf6-15.08.1/umbrello/classifier.h +--- umbrello-kf6-15.08.1.orig/umbrello/classifier.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/classifier.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,199 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +-#ifndef CLASSIFIER_H +-#define CLASSIFIER_H +- +-#include "package.h" +-#include "umlattributelist.h" +-#include "umloperationlist.h" +-#include "umlclassifierlistitemlist.h" +-#include "classifierlistitem.h" +-#include "umltemplatelist.h" +-#include "model_utils.h" +- +-// forward declarations +-class UMLAssociation; +-class IDChangeLog; +-class UMLClassifierSet; +- +-/** +- * This class defines the non-graphical information required for a +- * UML Classifier (ie a class or interface). +- * This class inherits from @ref UMLPackage which allows classifiers +- * to also act as namespaces, i.e. it allows classifiers to nest. +- * +- * NOTE: There is a unit test available for this class. +- * Please, use and adapt it when necessary. +- * +- * @short Information for a non-graphical Concept/Class. +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLClassifier : public UMLPackage +-{ +- Q_OBJECT +-public: +- +- /** +- * Enumeration identifying the type of classifier. +- */ +- enum ClassifierType { ALL = 0, CLASS, INTERFACE, DATATYPE }; +- +- explicit UMLClassifier(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLClassifier(); +- +- bool operator==(const UMLClassifier & rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- UMLObject* clone() const; +- +- virtual UMLAttribute* createAttribute(const QString &name = QString(), +- UMLObject *type = 0, +- Uml::Visibility::Enum vis = Uml::Visibility::Private, +- const QString &init = QString()); +- +- UMLAttribute* addAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); +- UMLAttribute* addAttribute(const QString &name, UMLObject *type, Uml::Visibility::Enum scope); +- +- bool addAttribute(UMLAttribute* att, IDChangeLog* log = 0, +- int position = -1); +- +- int removeAttribute(UMLAttribute *att); +- +- int attributes() ; +- +- UMLAttributeList getAttributeList() const; +- UMLAttributeList getAttributeList(Uml::Visibility::Enum scope) const; +- UMLAttributeList getAttributeListStatic(Uml::Visibility::Enum scope) const; +- +- UMLOperation* createOperation(const QString &name = QString(), +- bool *isExistingOp = NULL, +- Model_Utils::NameAndType_List *params = NULL); +- +- bool addOperation(UMLOperation* op, int position = -1); +- bool addOperation(UMLOperation* op, IDChangeLog* log); +- +- UMLOperation * checkOperationSignature(const QString& name, +- UMLAttributeList opParams, +- UMLOperation *exemptOp = NULL); +- +- int removeOperation(UMLOperation *op); +- +- int operations(); +- +- UMLOperationList getOpList(bool includeInherited = false, UMLClassifierSet *alreadyTraversed = 0); +- +- UMLObject* createTemplate(const QString& name = QString()); +- +- UMLTemplate* addTemplate(const QString &name, Uml::ID::Type id = Uml::ID::None); +- +- bool addTemplate(UMLTemplate* newTemplate, IDChangeLog* log = 0); +- bool addTemplate(UMLTemplate* templt, int position); +- +- int removeTemplate(UMLTemplate* umltemplate); +- +- UMLTemplate *findTemplate(const QString& name); +- +- int templates(); +- +- UMLTemplateList getTemplateList() const; +- +- int takeItem(UMLClassifierListItem* item); +- +- virtual UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; +- +- virtual bool resolveRef(); +- +- UMLOperationList findOperations(const QString &n); +- +- virtual UMLObject* findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); +- +- UMLOperation* findOperation(const QString& name, +- Model_Utils::NameAndType_List params); +- +- UMLClassifierList findSuperClassConcepts(ClassifierType type = ALL); +- +- UMLClassifierList findSubClassConcepts(ClassifierType type = ALL); +- +- virtual bool acceptAssociationType(Uml::AssociationType::Enum type); +- +- void setClassAssoc(UMLAssociation *assoc); +- UMLAssociation *getClassAssoc() const; +- +- void setBaseType(UMLObject::ObjectType ot); +- +- bool isInterface() const; +- +- bool isDatatype() const; +- +- void setOriginType(UMLClassifier *origType); +- UMLClassifier * originType() const; +- +- void setIsReference(bool isRef = true); +- bool isReference() const; +- +- bool hasAbstractOps(); +- bool hasAssociations(); +- bool hasAttributes(); +- bool hasStaticAttributes(); +- bool hasMethods(); +- bool hasAccessorMethods(); +- bool hasOperationMethods(); +- bool hasVectorFields(); +- +- /** +- * utility functions to allow easy determination of what classifiers +- * are "owned" by the current one via named association type (e.g. +- * plain, aggregate or compositions). +- */ +-// UMLClassifierList getPlainAssocChildClassifierList(); +-// UMLClassifierList getAggregateChildClassifierList(); +-// UMLClassifierList getCompositionChildClassifierList(); +- +- virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); +- +- virtual UMLAssociationList getUniAssociationToBeImplemented(); +- +-signals: +- +- void operationAdded(UMLClassifierListItem *); +- void operationRemoved(UMLClassifierListItem *); +- +- void templateAdded(UMLClassifierListItem*); +- void templateRemoved(UMLClassifierListItem*); +- +- // only applies when (m_Type == ot_Class) +- void attributeAdded(UMLClassifierListItem*); +- void attributeRemoved(UMLClassifierListItem*); +- +-private: +- +- UMLAssociation *m_pClassAssoc; +- +- bool m_isRef; +- +- /** +- * Utility method called by "get*ChildClassfierList()" methods. It basically +- * finds all the classifiers named in each association in the given association list +- * which aren't the current one. Useful for finding which classifiers are "owned" by the +- * current one via declared associations such as in aggregations/compositions. +- */ +-// UMLClassifierList findAssocClassifierObjsInRoles (UMLAssociationList * list); +- +-protected: +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual bool load(QDomElement& element); +- +-}; +- +-#endif // CLASSIFIER_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.cpp umbrello-kf6-15.08.1/umbrello/classifierlistitem.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/classifierlistitem.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,159 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "classifierlistitem.h" +- +-// local includes +-#include "debug_utils.h" +-#include "classifier.h" +-#include "model_utils.h" +-#include "object_factory.h" +-#include "uml.h" +-#include "umldoc.h" +- +-// kde includes +-#include +- +-/** +- * Constructor. +- * +- * @param parent The parent to this operation. +- * At first sight it would appear that the type of the +- * parent should be UMLClassifier. However, the class +- * UMLAttribute is also used for the parameters of +- * operations, and in this case the UMLOperation is the +- * parent. +- * @param name The name of the operation. +- * @param id The id of the operation. +- */ +-UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent, +- const QString& name, Uml::ID::Type id) +- : UMLObject(parent, name, id) +-{ +- UMLObject *parentObj = const_cast(parent); +- UMLClassifier *pc = dynamic_cast(parentObj); +- if (pc) +- UMLObject::setUMLPackage(pc); +-} +- +-/** +- * Constructor. +- * +- * @param parent The parent to this operation. +- * At first sight it would appear that the type of the +- * parent should be UMLClassifier. However, the class +- * UMLAttribute is also used for the parameters of +- * operations, and in this case the UMLOperation is the +- * parent. +- */ +-UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent) +- : UMLObject(parent) +-{ +- UMLObject *parentObj = const_cast(parent); +- UMLClassifier *pc = dynamic_cast(parentObj); +- if (pc) +- UMLObject::setUMLPackage(pc); +-} +- +-/** +- * Destructor. Empty. +- */ +-UMLClassifierListItem::~UMLClassifierListItem() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLClassifierListItem::copyInto(UMLObject *lhs) const +-{ +- // Call the parent. +- UMLObject::copyInto(lhs); +-} +- +-/** +- * Returns a string representation of the list item. +- * +- * @param sig What type of operation string to show. +- * @return The string representation of the operation. +- */ +-QString UMLClassifierListItem::toString(Uml::SignatureType::Enum sig) +-{ +- Q_UNUSED(sig); +- return name(); +-} +- +-/** +- * Returns the type of the UMLClassifierListItem. +- * +- * @return The type of the UMLClassifierListItem. +- */ +-UMLClassifier * UMLClassifierListItem::getType() const +-{ +- return dynamic_cast(m_pSecondary.data()); +-} +- +-/** +- * Returns the type name of the UMLClassifierListItem. +- * +- * @return The type name of the UMLClassifierListItem. +- */ +-QString UMLClassifierListItem::getTypeName() const +-{ +- if (m_pSecondary == NULL) +- return m_SecondaryId; +- const UMLPackage *typePkg = m_pSecondary->umlPackage(); +- if (typePkg != NULL && typePkg != m_pUMLPackage) +- return m_pSecondary->fullyQualifiedName(); +- return m_pSecondary->name(); +-} +- +-/** +- * Sets the type of the UMLAttribute. +- * +- * @param type Pointer to the UMLObject of the type. +- */ +-void UMLClassifierListItem::setType(UMLObject *type) +-{ +- if (m_pSecondary != type) { +- m_pSecondary = type; +- UMLObject::emitModified(); +- } +-} +- +-/** +- * Sets the type name of the UMLClassifierListItem. +- * DEPRECATED - use setType() instead. +- * +- * @param type The type name of the UMLClassifierListItem. +- */ +-void UMLClassifierListItem::setTypeName(const QString &type) +-{ +- if (type.isEmpty() || type == QLatin1String("void")) { +- m_pSecondary = NULL; +- m_SecondaryId.clear(); +- return; +- } +- UMLDoc *pDoc = UMLApp::app()->document(); +- m_pSecondary = pDoc->findUMLObject(type); +- if (m_pSecondary == NULL) { +- // Make data type for easily identified cases +- if (Model_Utils::isCommonDataType(type) || type.contains(QLatin1Char('*'))) { +- m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, type); +- uDebug() << "created datatype for " << type; +- } else { +- m_SecondaryId = type; +- } +- } +- UMLObject::emitModified(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.h umbrello-kf6-15.08.1/umbrello/classifierlistitem.h +--- umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/classifierlistitem.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,58 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef CLASSIFIERLISTITEM_H +-#define CLASSIFIERLISTITEM_H +- +-#include "umlobject.h" +- +-// forward declaration +-class UMLClassifier; +- +-/** +- * Classifiers (classes, interfaces) have lists of operations, +- * attributes, templates and others. This is a base class for +- * the items in this list. This abstraction should remove +- * duplication of dialogs and allow for stereotypes in lists. +- * +- * @short A base class for classifier list items (e.g. attributes) +- * @author Jonathan Riddell +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLClassifierListItem : public UMLObject +-{ +- Q_OBJECT +-public: +- +- UMLClassifierListItem(UMLObject *parent, +- const QString& name, +- Uml::ID::Type id = Uml::ID::None); +- explicit UMLClassifierListItem(UMLObject *parent); +- virtual ~UMLClassifierListItem(); +- +- virtual void setType(UMLObject *type); +- UMLClassifier * getType() const; +- +- void setTypeName(const QString &type); +- virtual QString getTypeName() const; +- +- virtual QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- virtual void copyInto(UMLObject *lhs) const; +- +- /** +- * The abstract method UMLObject::clone() must be implemented +- * by the classes inheriting from UMLClassifierListItem. +- */ +- virtual UMLObject* clone() const = 0; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/CMakeLists.txt umbrello-kf6-15.08.1/umbrello/CMakeLists.txt +--- umbrello-kf6-15.08.1.orig/umbrello/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/CMakeLists.txt 2015-10-08 11:48:59.486089026 +0300 +@@ -56,7 +56,8 @@ + ${CMAKE_CURRENT_SOURCE_DIR}/docgenerators/ + ${CMAKE_CURRENT_SOURCE_DIR}/finder/ + ${CMAKE_CURRENT_SOURCE_DIR}/refactoring/ +- ${CMAKE_CURRENT_SOURCE_DIR}/widgets/ ++ ${CMAKE_CURRENT_SOURCE_DIR}/umlmodel/ ++ ${CMAKE_CURRENT_SOURCE_DIR}/umlwidgets/ + ${CMAKE_SOURCE_DIR}/lib/cppparser/ + ${CMAKE_SOURCE_DIR}/lib/interfaces/ + ) +@@ -343,47 +344,47 @@ + cmds/widget/cmd_setTxt.cpp + ) + +-set(libwidgets_SRCS +- widgets/activitywidget.cpp +- widgets/actorwidget.cpp +- widgets/artifactwidget.cpp +- widgets/associationline.cpp +- widgets/associationwidget.cpp +- widgets/boxwidget.cpp +- widgets/categorywidget.cpp +- widgets/classifierwidget.cpp +- widgets/combinedfragmentwidget.cpp +- widgets/componentwidget.cpp +- widgets/datatypewidget.cpp +- widgets/entitywidget.cpp +- widgets/enumwidget.cpp +- widgets/floatingdashlinewidget.cpp +- widgets/floatingtextwidget.cpp +- widgets/forkjoinwidget.cpp +- widgets/layoutgrid.cpp +- widgets/linkwidget.cpp +- widgets/messagewidget.cpp +- widgets/nodewidget.cpp +- widgets/notewidget.cpp +- widgets/objectnodewidget.cpp +- widgets/objectwidget.cpp +- widgets/packagewidget.cpp +- widgets/pinportbase.cpp +- widgets/pinwidget.cpp +- widgets/portwidget.cpp +- widgets/preconditionwidget.cpp +- widgets/regionwidget.cpp +- widgets/seqlinewidget.cpp +- widgets/signalwidget.cpp +- widgets/statewidget.cpp +- widgets/toolbarstateonewidget.cpp +- widgets/umlwidget.cpp +- widgets/usecasewidget.cpp +- widgets/widget_factory.cpp +- widgets/widget_utils.cpp +- widgets/widgetbase.cpp +- widgets/widgetlist_utils.cpp +- widgets/statusbartoolbutton.cpp ++set(libumlwidgets_SRCS ++ umlwidgets/activitywidget.cpp ++ umlwidgets/actorwidget.cpp ++ umlwidgets/artifactwidget.cpp ++ umlwidgets/associationline.cpp ++ umlwidgets/associationwidget.cpp ++ umlwidgets/boxwidget.cpp ++ umlwidgets/categorywidget.cpp ++ umlwidgets/classifierwidget.cpp ++ umlwidgets/combinedfragmentwidget.cpp ++ umlwidgets/componentwidget.cpp ++ umlwidgets/datatypewidget.cpp ++ umlwidgets/entitywidget.cpp ++ umlwidgets/enumwidget.cpp ++ umlwidgets/floatingdashlinewidget.cpp ++ umlwidgets/floatingtextwidget.cpp ++ umlwidgets/forkjoinwidget.cpp ++ umlwidgets/layoutgrid.cpp ++ umlwidgets/linkwidget.cpp ++ umlwidgets/messagewidget.cpp ++ umlwidgets/nodewidget.cpp ++ umlwidgets/notewidget.cpp ++ umlwidgets/objectnodewidget.cpp ++ umlwidgets/objectwidget.cpp ++ umlwidgets/packagewidget.cpp ++ umlwidgets/pinportbase.cpp ++ umlwidgets/pinwidget.cpp ++ umlwidgets/portwidget.cpp ++ umlwidgets/preconditionwidget.cpp ++ umlwidgets/regionwidget.cpp ++ umlwidgets/seqlinewidget.cpp ++ umlwidgets/signalwidget.cpp ++ umlwidgets/statewidget.cpp ++ umlwidgets/toolbarstateonewidget.cpp ++ umlwidgets/umlwidget.cpp ++ umlwidgets/usecasewidget.cpp ++ umlwidgets/widget_factory.cpp ++ umlwidgets/widget_utils.cpp ++ umlwidgets/widgetbase.cpp ++ umlwidgets/widgetlist_utils.cpp ++ umlwidgets/statusbartoolbutton.cpp + ) + + set(libfinder_SRCS +@@ -394,47 +395,60 @@ + finder/umlscenefinder.cpp + ) + +-########### next target ############### ++set(libuml_SRCS ++ umlmodel/actor.cpp ++ umlmodel/artifact.cpp ++ umlmodel/association.cpp ++ umlmodel/attribute.cpp ++ umlmodel/category.cpp ++ umlmodel/checkconstraint.cpp ++ umlmodel/classifier.cpp ++ umlmodel/classifierlistitem.cpp ++ umlmodel/component.cpp ++ umlmodel/entity.cpp ++ umlmodel/entityattribute.cpp ++ umlmodel/entityconstraint.cpp ++ umlmodel/enum.cpp ++ umlmodel/enumliteral.cpp ++ umlmodel/folder.cpp ++ umlmodel/foreignkeyconstraint.cpp ++ umlmodel/node.cpp ++ umlmodel/operation.cpp ++ umlmodel/package.cpp ++ umlmodel/port.cpp ++ umlmodel/stereotype.cpp ++ umlmodel/template.cpp ++ umlmodel/umlattributelist.cpp ++ umlmodel/umlcanvasobject.cpp ++ umlmodel/umlclassifierlistitemlist.cpp ++ umlmodel/umlentityattributelist.cpp ++ umlmodel/umlentityconstraintlist.cpp ++ umlmodel/umlobject.cpp ++ umlmodel/umlobjectlist.cpp ++ umlmodel/umlrole.cpp ++ umlmodel/usecase.cpp ++ umlmodel/uniqueconstraint.cpp ++) + + set(umbrello-kf6base_SRCS +- actor.cpp +- artifact.cpp +- association.cpp + assocrules.cpp +- attribute.cpp + basictypes.cpp + birdview.cpp +- category.cpp +- checkconstraint.cpp +- classifier.cpp +- classifierlistitem.cpp + cmdlineexportallviewsevent.cpp +- component.cpp + docwindow.cpp + dotgenerator.cpp +- entity.cpp +- entityattribute.cpp +- entityconstraint.cpp +- enum.cpp +- enumliteral.cpp +- folder.cpp +- foreignkeyconstraint.cpp + icon_utils.cpp + import_argo.cpp + import_rose.cpp + layoutgenerator.cpp + listpopupmenu.cpp + model_utils.cpp +- node.cpp + object_factory.cpp +- operation.cpp + optionstate.cpp +- package.cpp + petalnode.cpp + petaltree2uml.cpp +- port.cpp +- stereotype.cpp +- template.cpp ++ stereotypeswindow.cpp ++ stereotypesmodel.cpp + toolbarstatearrow.cpp + toolbarstateassociation.cpp + toolbarstate.cpp +@@ -443,26 +457,16 @@ + toolbarstateother.cpp + toolbarstatepool.cpp + umlappprivate.cpp +- umlattributelist.cpp +- umlcanvasobject.cpp +- umlclassifierlistitemlist.cpp + uml.cpp + umldoc.cpp +- umlentityattributelist.cpp +- umlentityconstraintlist.cpp + umllistview.cpp + umllistviewitem.cpp +- umlobject.cpp +- umlobjectlist.cpp +- umlrole.cpp + umlscene.cpp + umlview.cpp + umlviewimageexporterall.cpp + umlviewimageexporter.cpp + umlviewimageexportermodel.cpp +- uniqueconstraint.cpp + uniqueid.cpp +- usecase.cpp + worktoolbar.cpp + ) + +@@ -482,7 +486,8 @@ + ${libcodegenerator_SRCS} + ${libdocgenerator_SRCS} + ${libcmds_SRCS} +- ${libwidgets_SRCS} ++ ${libuml_SRCS} ++ ${libumlwidgets_SRCS} + ${umbrello-kf6base_SRCS} + ) + +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/component.cpp umbrello-kf6-15.08.1/umbrello/component.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/component.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/component.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,127 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "component.h" +-// app includes +-#include "association.h" +-#include "debug_utils.h" +-#include "object_factory.h" +-#include "model_utils.h" +-#include "clipboard/idchangelog.h" +-#include "umldoc.h" +-// kde includes +-#include +- +-/** +- * Sets up a Component. +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLComponent::UMLComponent(const QString & name, Uml::ID::Type id) +- : UMLPackage(name, id), +- m_executable(false) +-{ +- m_BaseType = UMLObject::ot_Component; +-} +- +-/** +- * Destructor. +- */ +-UMLComponent::~UMLComponent() +-{ +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLComponent::clone() const +-{ +- UMLComponent *clone = new UMLComponent(); +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the UML:Component element including its operations, +- * attributes and templates +- */ +-void UMLComponent::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement componentElement = UMLObject::save(QLatin1String("UML:Component"), qDoc); +- componentElement.setAttribute(QLatin1String("executable"), m_executable); +- // Save contained components if any. +- if (m_objects.count()) { +- QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); +- for (UMLObjectListIt objectsIt(m_objects); objectsIt.hasNext();) { +- UMLObject* obj = objectsIt.next(); +- uIgnoreZeroPointer(obj); +- obj->saveToXMI (qDoc, ownedElement); +- } +- componentElement.appendChild(ownedElement); +- } +- qElement.appendChild(componentElement); +-} +- +-/** +- * Loads the UML:Component element including its ports et al. +- */ +-bool UMLComponent::load(QDomElement& element) +-{ +- QString executable = element.attribute(QLatin1String("executable"), QLatin1String("0")); +- m_executable = (bool)executable.toInt(); +- 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::isCommonXMIAttribute(type)) +- continue; +- if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || +- UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { +- //CHECK: umbrello-kf6 currently assumes that nested elements +- // are ownedElements anyway. +- // Therefore these tags are not further interpreted. +- if (! load(tempElement)) +- return false; +- continue; +- } +- UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); +- if (!pObject) { +- uWarning() << "Unknown type of umlobject to create: " << type; +- continue; +- } +- pObject->setUMLPackage(this); +- if (pObject->loadFromXMI(tempElement)) { +- addObject(pObject); +- } else { +- delete pObject; +- } +- } +- return true; +-} +- +-/** +- * Sets m_executable. +- */ +-void UMLComponent::setExecutable(bool executable) +-{ +- m_executable = executable; +-} +- +-/** +- * Returns the value of m_executable. +- */ +-bool UMLComponent::getExecutable() +-{ +- return m_executable; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/component.h umbrello-kf6-15.08.1/umbrello/component.h +--- umbrello-kf6-15.08.1.orig/umbrello/component.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/component.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,48 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef COMPONENT_H +-#define COMPONENT_H +- +-#include "package.h" +- +-/** +- * This class contains the non-graphical information required for a +- * UML Component. +- * This class inherits from @ref UMLPackage which contains most +- * of the information. +- * +- * @short Non-graphical information for a Component. +- * @author Jonathan Riddell +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLComponent : public UMLPackage +-{ +- Q_OBJECT +-public: +- explicit UMLComponent(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLComponent(); +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- void setExecutable(bool executable); +- bool getExecutable(); +- +-protected: +- bool load(QDomElement & element); +- +-private: +- bool m_executable; ///< holds whether this is an executable component or not +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/dialogs/notedialog.cpp umbrello-kf6-15.08.1/umbrello/dialogs/notedialog.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/dialogs/notedialog.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/dialogs/notedialog.cpp 2015-10-08 11:48:59.497089026 +0300 +@@ -36,6 +36,7 @@ + QVBoxLayout *layout = new QVBoxLayout(frame); + layout->addWidget(m_docWidget, 10); + setMinimumSize(600, 250); ++ m_docWidget->setFocus(); + } + + /** +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/dialogs/widgets/documentationwidget.cpp umbrello-kf6-15.08.1/umbrello/dialogs/widgets/documentationwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/dialogs/widgets/documentationwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/dialogs/widgets/documentationwidget.cpp 2015-10-08 11:48:59.499089026 +0300 +@@ -67,6 +67,8 @@ + m_editField->setLineWrapMode(QTextEdit::WidgetWidth); + m_editField->setWordWrapMode(QTextOption::WordWrap); + m_editField->setText(text); ++ setFocusProxy(m_editField); ++ + QHBoxLayout *layout = new QHBoxLayout(m_box); + layout->addWidget(m_editField); + layout->setMargin(fontMetrics().height()); +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/docwindow.cpp umbrello-kf6-15.08.1/umbrello/docwindow.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/docwindow.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/docwindow.cpp 2015-10-08 11:48:59.499089026 +0300 +@@ -91,6 +91,7 @@ + statusLayout->addWidget(m_modifiedWidget, 0, 5, 1, 1); + m_docTE = new KTextEdit(this); + m_docTE->setText(QString()); ++ setFocusProxy(m_docTE); + //m_docTE->setWordWrapMode(QTextEdit::WidgetWidth); + QVBoxLayout* docLayout = new QVBoxLayout(this); + docLayout->addLayout(statusLayout); +@@ -461,5 +462,6 @@ + tab->setCurrentIndex(i); + } + } ++ m_docTE->setFocus(); + } + +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityattribute.cpp umbrello-kf6-15.08.1/umbrello/entityattribute.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/entityattribute.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/entityattribute.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,280 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "entityattribute.h" +- +-// app includes +-#include "debug_utils.h" +-//#include "umlcanvasobject.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "umlentityattributedialog.h" +-#include "object_factory.h" +- +-// qt includes +-#include +- +-/** +- * Sets up an entityattribute. +- * @param parent The parent of this UMLEntityAttribute. +- * @param name The name of this UMLEntityAttribute. +- * @param id The unique id given to this UMLEntityAttribute. +- * @param s The visibility of the UMLEntityAttribute. +- * @param type The type of this UMLEntityAttribute. +- * @param iv The initial value of the entityattribute. +- */ +-UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent, const QString& name, +- Uml::ID::Type id, Uml::Visibility::Enum s, +- UMLObject *type, const QString& iv) +- : UMLAttribute(parent, name, id, s, type, iv) +-{ +- init(); +- if (m_pSecondary) { +- m_pSecondary->setBaseType(UMLObject::ot_Entity); +- } +-} +- +-/** +- * Sets up an entityattribute. +- * @param parent The parent of this UMLEntityAttribute. +- */ +-UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent) +- : UMLAttribute(parent) +-{ +- init(); +-} +- +-/** +- * Destructor. +- */ +-UMLEntityAttribute::~UMLEntityAttribute() +-{ +-} +- +-/** +- * Initialize members of this class. +- * Auxiliary method used by constructors. +- */ +-void UMLEntityAttribute::init() +-{ +- m_BaseType = UMLObject::ot_EntityAttribute; +- m_indexType = UMLEntityAttribute::None; +- m_autoIncrement = false; +- m_null = false; +-} +- +-/** +- * Returns the value of the UMLEntityAttribute's attributes property. +- * @return The value of the UMLEntityAttribute's attributes property. +- */ +-QString UMLEntityAttribute::getAttributes() const +-{ +- return m_attributes; +-} +- +-/** +- * Sets the UMLEntityAttribute's attributes property. +- * @param attributes The new value for the attributes property. +- */ +-void UMLEntityAttribute::setAttributes(const QString& attributes) +-{ +- m_attributes = attributes; +-} +- +-/** +- * Returns the UMLEntityAttribute's length/values property. +- * @return The new value of the length/values property. +- */ +-QString UMLEntityAttribute::getValues() const +-{ +- return m_values; +-} +- +-/** +- * Sets the UMLEntityAttribute's length/values property. +- * @param values The new value of the length/values property. +- */ +-void UMLEntityAttribute::setValues(const QString& values) +-{ +- m_values = values; +-} +- +-/** +- * Returns the UMLEntityAttribute's auto_increment boolean +- * @return The UMLEntityAttribute's auto_increment boolean +- */ +-bool UMLEntityAttribute::getAutoIncrement() const +-{ +- return m_autoIncrement; +-} +- +-/** +- * Sets the UMLEntityAttribute's auto_increment boolean +- * @param autoIncrement The UMLEntityAttribute's auto_increment boolean +- */ +-void UMLEntityAttribute::setAutoIncrement(const bool autoIncrement) +-{ +- m_autoIncrement = autoIncrement; +-} +- +-/** +- * Returns the UMLEntityAttribute's index type property. +- * @return The value of the UMLEntityAttribute's index type property. +- */ +-UMLEntityAttribute::DBIndex_Type UMLEntityAttribute::indexType() const +-{ +- return m_indexType; +-} +- +-/** +- * Sets the initial value of the UMLEntityAttribute's index type property. +- * @param indexType The initial value of the UMLEntityAttribute's index type property. +- */ +-void UMLEntityAttribute::setIndexType(const UMLEntityAttribute::DBIndex_Type indexType) +-{ +- m_indexType = indexType; +-} +- +-/** +- * Returns the UMLEntityAttribute's allow null value. +- * @return The UMLEntityAttribute's allow null value. +- */ +-bool UMLEntityAttribute::getNull() const +-{ +- return m_null; +-} +- +-/** +- * Sets the initial value of the UMLEntityAttribute's allow null value. +- * @param nullIn The initial value of the UMLEntityAttribute's allow null value. +- */ +-void UMLEntityAttribute::setNull(const bool nullIn) +-{ +- m_null = nullIn; +-} +- +-/** +- * Returns a string representation of the UMLEntityAttribute. +- * @param sig If true will show the entityattribute type and initial value. +- * @return Returns a string representation of the UMLEntityAttribute. +- */ +-QString UMLEntityAttribute::toString(Uml::SignatureType::Enum sig) +-{ +- QString s; +- //FIXME +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { +- s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); +- } +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { +- QString string = s + name() + QLatin1String(" : ") + getTypeName(); +- if(m_InitialValue.length() > 0) +- string += QLatin1String(" = ") + m_InitialValue; +- return string; +- } else +- return s + name(); +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLEntityAttribute::operator==(const UMLEntityAttribute &rhs) const +-{ +- if(this == &rhs) +- return true; +- +- if(!UMLObject::operator==(rhs)) +- return false; +- +- // The type name is the only distinguishing criterion. +- // (Some programming languages might support more, but others don't.) +- if (m_pSecondary != rhs.m_pSecondary) +- return false; +- +- return true; +-} +- +-/** +- * Copy the internal presentation of this object into the UMLEntityAttribute +- * object. +- */ +-void UMLEntityAttribute::copyInto(UMLObject *lhs) const +-{ +- UMLEntityAttribute *target = static_cast(lhs); +- +- // call the parent first. +- UMLClassifierListItem::copyInto(target); +- +- // Copy all datamembers +- target->m_pSecondary = m_pSecondary; +- target->m_SecondaryId = m_SecondaryId; +- target->m_InitialValue = m_InitialValue; +- target->m_ParmKind = m_ParmKind; +-} +- +-/** +- * Make a clone of the UMLEntityAttribute. +- */ +-UMLObject* UMLEntityAttribute::clone() const +-{ +- UMLEntityAttribute* clone = new UMLEntityAttribute((UMLEntityAttribute*)parent()); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLEntityAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement entityattributeElement = UMLObject::save(QLatin1String("UML:EntityAttribute"), qDoc); +- if (m_pSecondary == NULL) { +- uDebug() << name() << ": m_pSecondary is NULL, using local name " << m_SecondaryId; +- entityattributeElement.setAttribute(QLatin1String("type"), m_SecondaryId); +- } else { +- entityattributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); +- } +- entityattributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); +- entityattributeElement.setAttribute(QLatin1String("dbindex_type"), m_indexType); +- entityattributeElement.setAttribute(QLatin1String("values"), m_values); +- entityattributeElement.setAttribute(QLatin1String("attributes"), m_attributes); +- entityattributeElement.setAttribute(QLatin1String("auto_increment"), m_autoIncrement); +- entityattributeElement.setAttribute(QLatin1String("allow_null"), m_null); +- qElement.appendChild(entityattributeElement); +-} +- +-/** +- * Loads the XMI element. +- */ +-bool UMLEntityAttribute::load(QDomElement & element) +-{ +- if (! UMLAttribute::load(element)) +- return false; +- int indexType = element.attribute(QLatin1String("dbindex_type"), QLatin1String("1100")).toInt(); +- m_indexType = (UMLEntityAttribute::DBIndex_Type)indexType; +- m_values = element.attribute(QLatin1String("values")); +- m_attributes = element.attribute(QLatin1String("attributes")); +- m_autoIncrement = (bool)element.attribute(QLatin1String("auto_increment")).toInt(); +- m_null = (bool)element.attribute(QLatin1String("allow_null")).toInt(); +- return true; +-} +- +-/** +- * Display the properties configuration dialog for the entityattribute. +- */ +-bool UMLEntityAttribute::showPropertiesDialog(QWidget* parent) +-{ +- UMLEntityAttributeDialog dialog(parent, this); +- return dialog.exec(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityattribute.h umbrello-kf6-15.08.1/umbrello/entityattribute.h +--- umbrello-kf6-15.08.1.orig/umbrello/entityattribute.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/entityattribute.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,85 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENTITYATTRIBUTE_H +-#define ENTITYATTRIBUTE_H +- +-#include "attribute.h" +-#include "basictypes.h" +- +-/** +- * This class is used to set up information for an entityattribute. This is a database field +- * It has a type, name, index type and default value. +- * +- * @short Sets up entityattribute information. +- * @author Jonathan Riddell +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLEntityAttribute : public UMLAttribute +-{ +- Q_OBJECT +- Q_ENUMS(DBIndex_Type) +-public: +- enum DBIndex_Type +- { +- None = 1100, +- Primary, +- Index, +- Unique +- }; +- +- UMLEntityAttribute(UMLObject* parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None, +- Uml::Visibility::Enum s = Uml::Visibility::Private, +- UMLObject *type = 0, const QString& iv = QString()); +- explicit UMLEntityAttribute(UMLObject* parent); +- virtual ~UMLEntityAttribute(); +- +- bool operator==(const UMLEntityAttribute& rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- void setAttributes(const QString& attributes); +- QString getAttributes() const; +- +- void setIndexType(const DBIndex_Type indexType); +- DBIndex_Type indexType() const; +- +- void setValues(const QString& values); +- QString getValues() const; +- +- void setAutoIncrement(const bool autoIncrement); +- bool getAutoIncrement() const; +- +- void setNull(const bool null); +- bool getNull() const; +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +-protected: +- void init(); +- +- bool load(QDomElement& element); +- +-private: +- DBIndex_Type m_indexType; +- QString m_values; +- QString m_attributes; +- bool m_autoIncrement; +- bool m_null; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.cpp umbrello-kf6-15.08.1/umbrello/entityconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/entityconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,76 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-//own header +-#include "entityconstraint.h" +- +-// app includes +-#include "umlobject.h" +-#include "umldoc.h" +-#include "uml.h" +- +-// qt includes +-#include +- +-/** +- * Sets up a constraint. +- * @param parent The parent of this UMLEntityConstraint. +- * @param name The name of this UMLEntityConstraint. +- * @param id The unique id given to this UMLEntityConstraint. +- */ +-UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent, +- const QString& name, Uml::ID::Type id) +- : UMLClassifierListItem(parent, name, id) +-{ +- m_BaseType = UMLObject::ot_EntityConstraint; +-} +- +-/** +- * Sets up a constraint. +- * @param parent The parent of this UMLEntityConstraint. +- */ +-UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent) +- : UMLClassifierListItem(parent) +-{ +- m_BaseType = UMLObject::ot_EntityConstraint; +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLEntityConstraint::operator==(const UMLEntityConstraint &rhs) const +-{ +- if(this == &rhs) +- return true; +- +- if(!UMLObject::operator==(rhs)) +- return false; +- +- return true; +-} +- +-/** +- * destructor. +- */ +-UMLEntityConstraint::~UMLEntityConstraint() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the UMLEntityConstraint +- * object. +- */ +-void UMLEntityConstraint::copyInto(UMLObject *lhs) const +-{ +- // call the parent first. +- UMLClassifierListItem::copyInto(lhs); +-} +- +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.h umbrello-kf6-15.08.1/umbrello/entityconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/entityconstraint.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,49 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENTITYCONSTRAINT_H +-#define ENTITYCONSTRAINT_H +- +-#include "basictypes.h" +-#include "classifierlistitem.h" +-#include "umlclassifierlist.h" +- +-/** +- * This class is used to set up information for a entity constraint. +- * +- * @short Sets up entity constraint information. +- * @author Sharan Rao +- * @see UMLObject UMLClassifierListItem +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLEntityConstraint : public UMLClassifierListItem +-{ +- Q_OBJECT +- +-public: +- UMLEntityConstraint(UMLObject *parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None); +- +- explicit UMLEntityConstraint(UMLObject *parent); +- +- bool operator==(const UMLEntityConstraint &rhs) const; +- +- virtual ~UMLEntityConstraint(); +- +- virtual void copyInto(UMLObject *lhs) const; +- +- /** +- * Make a clone of the UMLEntityConstraint. +- */ +- virtual UMLObject* clone() const = 0; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entity.cpp umbrello-kf6-15.08.1/umbrello/entity.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/entity.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/entity.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,719 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "entity.h" +- +-// app includes +-#include "debug_utils.h" +-#include "entityattribute.h" +-#include "uniqueconstraint.h" +-#include "foreignkeyconstraint.h" +-#include "checkconstraint.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "uniqueid.h" +-#include "umlentityattributelist.h" +-#include "umlentityconstraintlist.h" +-#include "idchangelog.h" +-#include "umlentityattributedialog.h" +-#include "umluniqueconstraintdialog.h" +-#include "umlforeignkeyconstraintdialog.h" +-#include "umlcheckconstraintdialog.h" +- +-// kde includes +-#include +-#include +- +-// qt includes +-#include +- +-/** +- * Constructor. +- */ +-UMLEntity::UMLEntity(const QString& name, Uml::ID::Type id) +- : UMLClassifier(name, id), +- m_PrimaryKey(0) +-{ +- m_BaseType = UMLObject::ot_Entity; +- connect(this, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), +- this, SLOT(slotEntityAttributeRemoved(UMLClassifierListItem*))); +-} +- +-/** +- * Standard destructor. +- */ +-UMLEntity::~UMLEntity() +-{ +- m_List.clear(); +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLEntity::operator==(const UMLEntity& rhs) const +-{ +- return UMLClassifier::operator==(rhs); +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLEntity::copyInto(UMLObject *lhs) const +-{ +- UMLEntity *target = static_cast(lhs); +- +- // call base class copy function +- UMLClassifier::copyInto(target); +- +- // copy local data items +- target->m_PrimaryKey = m_PrimaryKey; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLEntity::clone() const +-{ +- UMLEntity* clone = new UMLEntity(); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Create an UMLAttribute. +- * @param name an optional name for the attribute +- * @param type an optional type object for the attribute +- * @param vis the visibility of the attribute +- * @param iv the initial value for the attribute +- * @return the just created attribute or null +- */ +-UMLAttribute* UMLEntity::createAttribute(const QString &name /*= QString()*/, UMLObject *type /*= 0*/, +- Uml::Visibility::Enum vis /* = Uml::Visibility::Private*/, +- const QString& iv /* = QString()*/) +-{ +- Uml::ID::Type id = UniqueID::gen(); +- QString currentName; +- if (name.isNull()) { +- currentName = uniqChildName(UMLObject::ot_EntityAttribute); +- } else { +- currentName = name; +- } +- +- UMLEntityAttribute* newAttribute = new UMLEntityAttribute(this, currentName, id, vis, type, iv); +- +- int button = QDialog::Accepted; +- bool goodName = false; +- +- //check for name.isNull() stops dialog being shown +- //when creating attribute via list view +- while (button == QDialog::Accepted && !goodName && name.isNull()) { +- QPointer dialog = new UMLEntityAttributeDialog(0, newAttribute); +- button = dialog->exec(); +- QString name = newAttribute->name(); +- +- if (name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } else if (findChildObject(name) != NULL) { +- KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); +- } else { +- goodName = true; +- } +- delete dialog; +- } +- +- if (button != QDialog::Accepted) { +- delete newAttribute; +- return 0; +- } +- +- addEntityAttribute(newAttribute); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newAttribute); +- return newAttribute; +-} +- +-/** +- * Creates a Unique Constraint for this Entity. +- * @param name an optional name +- * @return the UniqueConstraint created +- */ +-UMLUniqueConstraint* UMLEntity::createUniqueConstraint(const QString &name) +-{ +- Uml::ID::Type id = UniqueID::gen(); +- QString currentName; +- if (name.isNull()) { +- +- /** +- * @todo check parameter +- */ +- currentName = uniqChildName(UMLObject::ot_UniqueConstraint); +- } else { +- currentName = name; +- } +- +- UMLUniqueConstraint* newUniqueConstraint = new UMLUniqueConstraint(this, currentName, id); +- +- int button = QDialog::Accepted; +- bool goodName = false; +- +- //check for name.isNull() stops dialog being shown +- //when creating attribute via list view +- while (button == QDialog::Accepted && !goodName && name.isNull()) { +- QPointer dialog = new UMLUniqueConstraintDialog(0, newUniqueConstraint); +- button = dialog->exec(); +- QString name = newUniqueConstraint->name(); +- +- if (name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } else if (findChildObject(name) != NULL) { +- KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); +- } else { +- goodName = true; +- } +- delete dialog; +- } +- +- if (button != QDialog::Accepted) { +- delete newUniqueConstraint; +- return NULL; +- } +- +- addConstraint(newUniqueConstraint); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newUniqueConstraint); +- emitModified(); +- return newUniqueConstraint; +-} +- +-/** +- * Creates a Foreign Key Constraint for this Entity. +- * @param name an optional name +- * @return the ForeignKeyConstraint created +- */ +-UMLForeignKeyConstraint* UMLEntity::createForeignKeyConstraint(const QString &name) +-{ +- Uml::ID::Type id = UniqueID::gen(); +- QString currentName; +- if (name.isNull()) { +- currentName = uniqChildName(UMLObject::ot_ForeignKeyConstraint); +- } else { +- currentName = name; +- } +- +- UMLForeignKeyConstraint* newForeignKeyConstraint = new UMLForeignKeyConstraint(this, currentName, id); +- +- int button = QDialog::Accepted; +- bool goodName = false; +- +- //check for name.isNull() stops dialog being shown +- //when creating attribute via list view +- while (button == QDialog::Accepted && !goodName && name.isNull()) { +- QPointer dialog = new UMLForeignKeyConstraintDialog(0, newForeignKeyConstraint); +- button = dialog->exec(); +- QString name = newForeignKeyConstraint->name(); +- +- if (name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } else if (findChildObject(name) != NULL) { +- KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); +- } else { +- goodName = true; +- } +- delete dialog; +- } +- +- if (button != QDialog::Accepted) { +- return NULL; +- } +- +- addConstraint(newForeignKeyConstraint); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newForeignKeyConstraint); +- emitModified(); +- return newForeignKeyConstraint; +-} +- +-/** +- * Creates a Check Constraint for this Entity. +- * @param name an optional name +- * @return the CheckConstraint created +- */ +-UMLCheckConstraint* UMLEntity::createCheckConstraint(const QString &name) +-{ +- Uml::ID::Type id = UniqueID::gen(); +- QString currentName; +- if (name.isNull()) { +- currentName = uniqChildName(UMLObject::ot_CheckConstraint); +- } else { +- currentName = name; +- } +- +- UMLCheckConstraint* newCheckConstraint = new UMLCheckConstraint(this, currentName, id); +- +- int button = QDialog::Accepted; +- bool goodName = false; +- +- //check for name.isNull() stops dialog being shown +- //when creating attribute via list view +- while (button == QDialog::Accepted && !goodName && name.isNull()) { +- QPointer dialog = new UMLCheckConstraintDialog(0, newCheckConstraint); +- button = dialog->exec(); +- QString name = newCheckConstraint->name(); +- +- if (name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } else if (findChildObject(name) != NULL) { +- KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); +- } else { +- goodName = true; +- } +- delete dialog; +- } +- +- if (button != QDialog::Accepted) { +- return NULL; +- } +- +- addConstraint(newCheckConstraint); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newCheckConstraint); +- emitModified(); +- return newCheckConstraint; +-} +- +-/** +- * Adds an entityAttribute. +- * The entityAttribute object must not belong to any other concept. +- * @param name name of the UMLEntityAttribute +- * @param id id of the UMLEntityAttribute +- * @return True if the entityAttribute was successfully added. +- */ +-UMLObject* UMLEntity::addEntityAttribute(const QString& name, Uml::ID::Type id) +-{ +- UMLEntityAttribute* literal = new UMLEntityAttribute(this, name, id); +- m_List.append(literal); +- emit entityAttributeAdded(literal); +- UMLObject::emitModified(); +- connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); +- return literal; +-} +- +-/** +- * Adds an already created entityAttribute. +- * The entityAttribute object must not belong to any other concept. +- * @param att Pointer to the UMLEntityAttribute. +- * @param log Pointer to the IDChangeLog. +- * @return True if the entityAttribute was successfully added. +- */ +-bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log /* = 0*/) +-{ +- QString name = (QString)att->name(); +- if (findChildObject(name) == NULL) { +- att->setParent(this); +- m_List.append(att); +- emit entityAttributeAdded(att); +- UMLObject::emitModified(); +- connect(att, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } else if (log) { +- log->removeChangeByNewID(att->id()); +- delete att; +- } +- return false; +-} +- +-/** +- * Adds an entityAttribute to the entity, at the given position. +- * If position is negative or too large, the entityAttribute is added +- * to the end of the list. +- * TODO: give default value -1 to position (append) - now it conflicts with the method above.. +- * @param att Pointer to the UMLEntityAttribute. +- * @param position Position index for the insertion. +- * @return True if the entityAttribute was successfully added. +- */ +-bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, int position) +-{ +- Q_ASSERT(att); +- QString name = (QString)att->name(); +- if (findChildObject(name) == NULL) { +- att->setParent(this); +- if (position >= 0 && position <= (int)m_List.count()) { +- m_List.insert(position, att); +- } else { +- m_List.append(att); +- } +- emit entityAttributeAdded(att); +- UMLObject::emitModified(); +- connect(att, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } +- return false; +-} +- +-/** +- * Removes an entityAttribute from the class. +- * @param att The entityAttribute to remove. +- * @return Count of the remaining entityAttributes after removal. +- * Returns -1 if the given entityAttribute was not found. +- */ +-int UMLEntity::removeEntityAttribute(UMLClassifierListItem* att) +-{ +- if (!m_List.removeAll((UMLEntityAttribute*)att)) { +- uDebug() << "cannot find att given in list"; +- return -1; +- } +- emit entityAttributeRemoved(att); +- UMLObject::emitModified(); +- // If we are deleting the object, then we don't need to disconnect..this is done auto-magically +- // for us by QObject. -b.t. +- // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); +- delete att; +- return m_List.count(); +-} +- +-/** +- * Returns the number of entityAttributes for the class. +- * @return The number of entityAttributes for the class. +- */ +-int UMLEntity::entityAttributes() +-{ +- UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); +- return entityAttributes.count(); +-} +- +-/** +- * Emit the entityAttributeRemoved signal. +- */ +-void UMLEntity::signalEntityAttributeRemoved(UMLClassifierListItem *eattr) +-{ +- emit entityAttributeRemoved(eattr); +-} +- +-/** +- * Resolve the types referenced by our UMLEntityAttributes. +- * Reimplements the method from UMLClassifier. +- */ +-bool UMLEntity::resolveRef() +-{ +- bool success = UMLClassifier::resolveRef(); +- for (UMLObjectListIt oit(m_List); oit.hasNext();) { +- UMLObject* obj = oit.next(); +- if (obj->resolveRef()) { +- UMLClassifierListItem *cli = static_cast(obj); +- switch (cli->baseType()) { +- case UMLObject::ot_EntityAttribute: +- emit entityAttributeAdded(cli); +- break; +- case UMLObject::ot_UniqueConstraint: +- case UMLObject::ot_ForeignKeyConstraint: +- emit entityConstraintAdded(cli); +- break; +- default: +- break; +- } +- } +- } +- return success; +-} +- +-/** +- * Creates the element including its entityliterals. +- */ +-void UMLEntity::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement entityElement = UMLObject::save(QLatin1String("UML:Entity"), qDoc); +- //save operations +- UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); +- UMLClassifierListItem* pEntityAttribute = 0; +- foreach (pEntityAttribute, entityAttributes) { +- pEntityAttribute->saveToXMI(qDoc, entityElement); +- } +- +- UMLClassifierListItemList entityConstraints = getFilteredList(UMLObject::ot_EntityConstraint); +- foreach(UMLClassifierListItem* cli, entityConstraints) { +- cli->saveToXMI(qDoc, entityElement); +- } +- +- qElement.appendChild(entityElement); +-} +- +-/** +- * Loads the element including its entityAttributes. +- */ +-bool UMLEntity::load(QDomElement& element) +-{ +- QDomNode node = element.firstChild(); +- while(!node.isNull()) { +- if (node.isComment()) { +- node = node.nextSibling(); +- continue; +- } +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { // for backward compatibility +- UMLEntityAttribute* pEntityAttribute = new UMLEntityAttribute(this); +- if(!pEntityAttribute->loadFromXMI(tempElement)) { +- return false; +- } +- m_List.append(pEntityAttribute); +- } else if (UMLDoc::tagEq(tag, QLatin1String("UniqueConstraint"))) { +- UMLUniqueConstraint* pUniqueConstraint = new UMLUniqueConstraint(this); +- if (!pUniqueConstraint->loadFromXMI(tempElement)) { +- return false; +- } +- addConstraint(pUniqueConstraint); +- } else if (UMLDoc::tagEq(tag, QLatin1String("ForeignKeyConstraint"))) { +- UMLForeignKeyConstraint* pForeignKeyConstraint = new UMLForeignKeyConstraint(this); +- if (!pForeignKeyConstraint->loadFromXMI(tempElement)) { +- return false; +- } +- +- addConstraint(pForeignKeyConstraint); +- } else if (UMLDoc::tagEq(tag, QLatin1String("CheckConstraint"))) { +- +- UMLCheckConstraint* pCheckConstraint = new UMLCheckConstraint(this); +- if (!pCheckConstraint->loadFromXMI(tempElement)) { +- return false; +- } +- +- addConstraint(pCheckConstraint); +- } else if (tag == QLatin1String("stereotype")) { +- uDebug() << name() << ": losing old-format stereotype."; +- } else { +- uWarning() << "unknown child type in UMLEntity::load"; +- } +- node = node.nextSibling(); +- }//end while +- return true; +-} +- +-/** +- * Sets the UniqueConstraint passed as the Primary Key of this Entity +- * If the UniqueConstraint exists, then it is made a primary key +- * Else the UniqueConstraint is added and set as PrimaryKey +- * @param uconstr The Unique Constraint that is to be set as Primary Key +- * @return true if Primary key could be set successfully +- */ +-bool UMLEntity::setAsPrimaryKey(UMLUniqueConstraint* uconstr) +-{ +- if (uconstr == NULL) { +- uDebug() << "NULL value passed. To unset a Primary Key use " +- << "unsetPrimaryKey()"; +- return false; +- } +- +- if (static_cast(uconstr->parent()) != this) { +- +- uDebug() << "Parent of " << uconstr->name() +- << " does not match with current entity"; +- return false; +- } +- +- // check if this constraint already exists as a unique constraint for this entity +- UMLUniqueConstraint* uuc = static_cast(findChildObjectById(uconstr->id())); +- if (uuc == NULL) { +- addConstraint(uconstr); +- uuc = uconstr; +- } +- +- UMLUniqueConstraint* oldPrimaryKey = m_PrimaryKey; +- +- m_PrimaryKey = uuc; +- +- if (oldPrimaryKey != NULL) +- oldPrimaryKey->emitModified(); +- +- uuc->emitModified(); +- emitModified(); +- return true; +-} +- +-/** +- * Unset a Primary Key Constraint if it exists, else does nothing +- * This function will make the primary key into just another UniqueConstraint +- * if it exists +- */ +-void UMLEntity::unsetPrimaryKey() +-{ +- m_PrimaryKey = 0; +-} +- +-/** +- * Checks if This UMLEntity has a primary key set. +- * @return true if a Primary Key Exists for this UMLEntity +- */ +-bool UMLEntity::hasPrimaryKey() const +-{ +- if (m_PrimaryKey) { +- return true; +- } +- +- return false; +-} +- +-/** +- * Adds a Constraint to this UMLEntity. +- * To set a UMLUniqueConstraint as Primary Key use setAsPrimaryKey. +- * @param constr The UMLEntityConstraint that is to be added +- * @return true if the constraint could be added successfully +- */ +-bool UMLEntity::addConstraint(UMLEntityConstraint* constr) +-{ +- if (findChildObjectById(constr->id()) != NULL) { +- uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) +- << " already exists "; +- return false; +- } +- +- m_List.append(constr); +- +- emit entityConstraintAdded(constr); +- UMLObject::emitModified(); +- connect(constr, SIGNAL(modified()), this, SIGNAL(modified())); +- +- return true; +-} +- +-/** +- * Removes an existing constraint from this UMLEntity. +- * If the Contraint is a Primary Key, this Entity will no longer have a PrimaryKey. +- * @param constr the constraint to be removed +- * @return true if the constraint could be removed successfully +- */ +-bool UMLEntity::removeConstraint(UMLEntityConstraint* constr) +-{ +- if (findChildObjectById(constr->id()) == NULL) { +- uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) +- << " does not exist "; +- return false; +- } +- +- if (m_PrimaryKey == constr) { +- unsetPrimaryKey(); +- } +- +- m_List.removeAll(constr); +- +- emit entityConstraintRemoved(constr); +- UMLObject::emitModified(); +- +- delete constr; +- return true; +-} +- +-/** +- * Slot for entity attribute removed. +- */ +-void UMLEntity::slotEntityAttributeRemoved(UMLClassifierListItem* cli) +-{ +- // this function does some cleanjobs related to this entity when the attribute is +- // removed, like, removing the attribute from all constraints +- +- UMLEntityAttribute* entAtt = static_cast(cli); +- if (cli) { +- UMLClassifierListItemList ual = this->getFilteredList(UMLObject::ot_UniqueConstraint); +- +- foreach(UMLClassifierListItem* ucli, ual) { +- UMLUniqueConstraint* uuc = static_cast(ucli); +- if (uuc->hasEntityAttribute(entAtt)) { +- uuc->removeEntityAttribute(entAtt); +- } +- } +- } +- +-} +- +-/** +- * Reimplementation of getFilteredList to support ot=UMLObject::ot_EntityConstraint. +- */ +-UMLClassifierListItemList UMLEntity::getFilteredList(UMLObject::ObjectType ot) const +-{ +- if (ot == UMLObject::ot_EntityConstraint) { +- UMLClassifierListItemList ucList, fcList, ccList, rcList; +- ucList = UMLClassifier::getFilteredList(UMLObject::ot_UniqueConstraint); +- fcList = UMLClassifier::getFilteredList(UMLObject::ot_ForeignKeyConstraint); +- ccList = UMLClassifier::getFilteredList(UMLObject::ot_CheckConstraint); +- +- // append the lists to rcList +- // first the Unique Constraints +- foreach(UMLClassifierListItem* ucli, ucList) { +- rcList.append(ucli); +- } +- +- // then the Foreign Key Constraints +- foreach(UMLClassifierListItem* ucli, fcList) { +- rcList.append(ucli); +- } +- +- foreach(UMLClassifierListItem* ucli, ccList) { +- rcList.append(ucli); +- } +- +- return rcList; +- } else { +- return UMLClassifier::getFilteredList(ot); +- } +-} +- +-/** +- * Checks if a given Unique Constraint is primary key of this entity +- * @param uConstr a Unique Constraint +- * @return bool true if passed parameter is a primary key of this entity +- */ +-bool UMLEntity::isPrimaryKey(UMLUniqueConstraint* uConstr) const +-{ +- if (uConstr == m_PrimaryKey) { +- return true; +- } +- +- return false; +-} +- +-/** +- * Returns the Entity Attributes. +- * Same as getFilteredList(UMLObject::ot_EntityAttribute). +- */ +-UMLEntityAttributeList UMLEntity::getEntityAttributes() const +-{ +- UMLEntityAttributeList entityAttributeList; +- for (UMLObjectListIt lit(m_List); lit.hasNext();) { +- UMLObject *listItem = lit.next(); +- if (listItem->baseType() == UMLObject::ot_EntityAttribute) { +- entityAttributeList.append(static_cast(listItem)); +- } +- } +- return entityAttributeList; +-} +- +- +-/** +- * Create a new ClassifierListObject (entityattribute) +- * according to the given XMI tag. +- * Returns NULL if the string given does not contain one of the tags +- * +- * Used by the clipboard for paste operation. +- * Reimplemented from UMLClassifier for UMLEntity +- */ +-UMLClassifierListItem* UMLEntity::makeChildObject(const QString& xmiTag) +-{ +- UMLClassifierListItem* pObject = NULL; +- if (UMLDoc::tagEq(xmiTag, QLatin1String("EntityAttribute"))) { +- pObject = new UMLEntityAttribute(this); +- } +- return pObject; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entity.h umbrello-kf6-15.08.1/umbrello/entity.h +--- umbrello-kf6-15.08.1.orig/umbrello/entity.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/entity.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,108 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENTITY_H +-#define ENTITY_H +- +-#include "classifier.h" +- +-// forward declarations +-class UMLEntityAttribute; +-class UMLEntityConstraint; +-class UMLUniqueConstraint; +-class UMLForeignKeyConstraint; +-class UMLCheckConstraint; +-class UMLEntityAttributeList; +- +-/** +- * This class contains the non-graphical information required for a UML +- * Entity. +- * This class inherits from @ref UMLClassifier which contains most of the +- * information. +- * +- * @short Non-graphical Information for an Entity. +- * @author Jonathan Riddell +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLEntity : public UMLClassifier +-{ +- Q_OBJECT +-public: +- explicit UMLEntity(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLEntity(); +- +- bool operator==(const UMLEntity& rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- virtual UMLAttribute* createAttribute(const QString &name = QString(), +- UMLObject *type = 0, Uml::Visibility::Enum vis = Uml::Visibility::Private, +- const QString &init = QString()); +- +- UMLUniqueConstraint* createUniqueConstraint(const QString &name = QString()); +- UMLForeignKeyConstraint* createForeignKeyConstraint(const QString &name = QString()); +- UMLCheckConstraint* createCheckConstraint(const QString &name = QString()); +- +- UMLObject* addEntityAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); +- bool addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log = 0); +- bool addEntityAttribute(UMLEntityAttribute* att, int position); +- +- int removeEntityAttribute(UMLClassifierListItem* att); +- +- void signalEntityAttributeRemoved(UMLClassifierListItem *eattr); +- +- int entityAttributes() ; +- +- bool setAsPrimaryKey(UMLUniqueConstraint* uconstr); +- void unsetPrimaryKey(); +- bool hasPrimaryKey() const; +- bool isPrimaryKey(UMLUniqueConstraint* uConstr) const; +- +- bool addConstraint(UMLEntityConstraint* constr); +- bool removeConstraint(UMLEntityConstraint* constr); +- +- virtual bool resolveRef(); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; +- +- UMLEntityAttributeList getEntityAttributes() const; +- +- virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); +- +-private slots: +- void slotEntityAttributeRemoved(UMLClassifierListItem*); +- +-signals: +- void entityAttributeAdded(UMLClassifierListItem*); +- void entityAttributeRemoved(UMLClassifierListItem*); +- void entityConstraintAdded(UMLClassifierListItem*); +- void entityConstraintRemoved(UMLClassifierListItem*); +- +-protected: +- bool load(QDomElement& element); +- +-private: +- +- /** +- * Primary Key of this Entity +- * This is a pointer kept for easy access to the primary key, and to distinguish it +- * from all other UniqueConstraints. It is also there in m_List (inherited from +- * UMLCanvasObject) +- */ +- UMLUniqueConstraint* m_PrimaryKey; +- +-}; +- +-#endif // ENTITY_H +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enum.cpp umbrello-kf6-15.08.1/umbrello/enum.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/enum.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/enum.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,302 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "enum.h" +- +-// app includes +-#include "debug_utils.h" +-#include "enumliteral.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "uniqueid.h" +-#include "idchangelog.h" +- +-// kde includes +-#include +-#include +- +-/** +- * Sets up an enum. +- * @param name The name of the Enum. +- * @param id The unique id of the Enum. +- */ +-UMLEnum::UMLEnum(const QString& name, Uml::ID::Type id) : UMLClassifier(name, id) +-{ +- init(); +-} +- +-/** +- * Standard destructor. +- */ +-UMLEnum::~UMLEnum() +-{ +- m_List.clear(); +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLEnum::operator==(const UMLEnum & rhs) const +-{ +- return UMLClassifier::operator==(rhs); +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLEnum::copyInto(UMLObject *lhs) const +-{ +- UMLClassifier::copyInto(lhs); +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLEnum::clone() const +-{ +- UMLEnum *clone = new UMLEnum(); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLEnum::init() +-{ +- m_BaseType = UMLObject::ot_Enum; +- setStereotypeCmd(QLatin1String("enum")); +-} +- +-/** +- * Creates a literal for the enum. +- * @return The UMLEnum created +- */ +-UMLObject* UMLEnum::createEnumLiteral(const QString& name) +-{ +- Uml::ID::Type id = UniqueID::gen(); +- QString currentName; +- if (name.isNull()) { +- currentName = uniqChildName(UMLObject::ot_EnumLiteral); +- } else { +- currentName = name; +- } +- +- UMLEnumLiteral* newEnumLiteral = new UMLEnumLiteral(this, currentName); +- +- bool ok = true; +- bool goodName = false; +- +- //check for name.isNull() stops dialog being shown +- //when creating enum literal via list view +- while (ok && !goodName && name.isNull()) { +- ok = newEnumLiteral->showPropertiesDialog(UMLApp::app()); +- QString name = newEnumLiteral->name(); +- +- if(name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); +- } else { +- goodName = true; +- } +- } +- +- if (!ok) { +- delete newEnumLiteral; +- return NULL; +- } +- +- addEnumLiteral(newEnumLiteral); +- +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(newEnumLiteral); +- return newEnumLiteral; +-} +- +-/** +- * Adds an enumliteral to the enum. +- * @param name The name of the enumliteral. +- * @param id The id of the enumliteral (optional.) +- * If omitted a new ID is assigned internally. +- * @return Pointer to the UMLEnumliteral created. +- */ +-UMLObject* UMLEnum::addEnumLiteral(const QString &name, Uml::ID::Type id) +-{ +- UMLObject *el = UMLCanvasObject::findChildObject(name); +- if (el != NULL) { +- uDebug() << name << " is already present"; +- return el; +- } +- UMLEnumLiteral* literal = new UMLEnumLiteral(this, name, id); +- m_List.append(literal); +- UMLObject::emitModified(); +- emit enumLiteralAdded(literal); +- connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); +- return literal; +-} +- +-/** +- * Adds an already created enumliteral. +- * The enumliteral object must not belong to any other concept. +- * @param literal Pointer to the UMLEnumLiteral. +- * @param Log Pointer to the IDChangeLog. +- * @return True if the enumliteral was successfully added. +- */ +-bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log /* = 0*/) +-{ +- QString name = (QString)literal->name(); +- if (findChildObject(name) == NULL) { +- literal->setParent(this); +- m_List.append(literal); +- UMLObject::emitModified(); +- emit enumLiteralAdded(literal); +- connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } else if (Log) { +- Log->removeChangeByNewID(literal->id()); +- delete literal; +- } +- return false; +-} +- +-/** +- * Adds an enumliteral to the enum, at the given position. +- * If position is negative or too large, the enumliteral is added +- * to the end of the list. +- * TODO: give default value -1 to position (append) - now it conflicts with the method above.. +- * @param literal Pointer to the UMLEnumLiteral. +- * @param position Position index for the insertion. +- * @return True if the enumliteral was successfully added. +- */ +-bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, int position) +-{ +- Q_ASSERT(literal); +- QString name = (QString)literal->name(); +- if (findChildObject(name) == NULL) { +- literal->setParent(this); +- if (position >= 0 && position <= (int)m_List.count()) { +- m_List.insert(position, literal); +- } else { +- m_List.append(literal); +- } +- UMLObject::emitModified(); +- emit enumLiteralAdded(literal); +- connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); +- return true; +- } +- return false; +-} +- +-/** +- * Removes an enumliteral from the class. +- * @param literal The enumliteral to remove. +- * @return Count of the remaining enumliterals after removal. +- * Returns -1 if the given enumliteral was not found. +- */ +-int UMLEnum::removeEnumLiteral(UMLEnumLiteral* literal) +-{ +- if (!m_List.removeAll(literal)) { +- uDebug() << "cannot find att given in list"; +- return -1; +- } +- emit enumLiteralRemoved(literal); +- UMLObject::emitModified(); +- // If we are deleting the object, then we don't need to disconnect..this is done auto-magically +- // for us by QObject. -b.t. +- // disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); +- delete literal; +- return m_List.count(); +-} +- +-/** +- * Returns the number of enumliterals for the class. +- * @return The number of enumliterals for the class. +- */ +-int UMLEnum::enumLiterals() +-{ +- return m_List.count(); +-} +- +-/** +- * Emit the enumLiteralRemoved signal. +- */ +-void UMLEnum::signalEnumLiteralRemoved(UMLClassifierListItem *elit) +-{ +- emit enumLiteralRemoved(elit); +-} +- +-/** +- * Creates the element including its enumliterals. +- */ +-void UMLEnum::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement enumElement = UMLObject::save(QLatin1String("UML:Enumeration"), qDoc); +- // save enum literals +- UMLClassifierListItemList enumLiterals = getFilteredList(UMLObject::ot_EnumLiteral); +- foreach (UMLClassifierListItem* pEnumLiteral, enumLiterals) { +- pEnumLiteral->saveToXMI(qDoc, enumElement); +- } +- qElement.appendChild(enumElement); +-} +- +-/** +- * Loads the element including its enumliterals. +- */ +-bool UMLEnum::load(QDomElement& element) +-{ +- QDomNode node = element.firstChild(); +- while(!node.isNull()) { +- if (node.isComment()) { +- node = node.nextSibling(); +- continue; +- } +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("EnumerationLiteral")) || +- UMLDoc::tagEq(tag, QLatin1String("ownedLiteral")) || +- UMLDoc::tagEq(tag, QLatin1String("EnumLiteral"))) { // for backward compatibility +- UMLEnumLiteral* pEnumLiteral = new UMLEnumLiteral(this); +- if(!pEnumLiteral->loadFromXMI(tempElement)) { +- return false; +- } +- m_List.append(pEnumLiteral); +- } else if (UMLDoc::tagEq(tag, QLatin1String("Enumeration.literal"))) { // Embarcadero's Describe +- if (! load(tempElement)) +- return false; +- } else if (tag == QLatin1String("stereotype")) { +- uDebug() << name() << ": losing old-format stereotype."; +- } else { +- uWarning() << "unknown child type: " << tag; +- } +- node = node.nextSibling(); +- }//end while +- return true; +-} +- +-/** +- * Create a new ClassifierListObject (enumLiteral) +- * according to the given XMI tag. +- * Returns NULL if the string given does not contain one of the tags +- * +- * Used by the clipboard for paste operation. +- * Reimplemented from UMLClassifier for UMLEnum +- */ +-UMLClassifierListItem* UMLEnum::makeChildObject(const QString& xmiTag) +-{ +- UMLClassifierListItem* pObject = NULL; +- if (UMLDoc::tagEq(xmiTag, QLatin1String("EnumerationLiteral")) || +- UMLDoc::tagEq(xmiTag, QLatin1String("EnumLiteral"))) { +- pObject = new UMLEnumLiteral(this); +- } +- return pObject; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enum.h umbrello-kf6-15.08.1/umbrello/enum.h +--- umbrello-kf6-15.08.1.orig/umbrello/enum.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/enum.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,72 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENUM_H +-#define ENUM_H +- +-#include "classifier.h" +- +-class UMLEnumLiteral; +- +-/** +- * This class contains the non-graphical information required for a UML +- * Enum. +- * This class inherits from @ref UMLClassifier which contains most of the +- * information. +- * +- * @short Non-graphical Information for an Enum. +- * @author Jonathan Riddell +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLEnum : public UMLClassifier +-{ +- Q_OBJECT +-public: +- explicit UMLEnum(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); +- +- virtual ~UMLEnum(); +- +- bool operator==(const UMLEnum& rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- UMLObject* createEnumLiteral(const QString& name = QString()); +- +- UMLObject* addEnumLiteral(const QString &name, Uml::ID::Type id = Uml::ID::None); +- +- bool addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log = 0); +- bool addEnumLiteral(UMLEnumLiteral* literal, int position); +- +- int removeEnumLiteral(UMLEnumLiteral* literal); +- +- int enumLiterals(); +- +- void signalEnumLiteralRemoved(UMLClassifierListItem *elit); +- +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); +- +-signals: +- void enumLiteralAdded(UMLClassifierListItem*); +- void enumLiteralRemoved(UMLClassifierListItem*); +- +-protected: +- bool load(QDomElement & element); +- +-private: +- void init(); +- +-}; +- +-#endif // ENUM_H +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enumliteral.cpp umbrello-kf6-15.08.1/umbrello/enumliteral.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/enumliteral.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/enumliteral.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,126 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "enumliteral.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +- +-/** +- * Sets up an enum literal. +- * @param parent The parent of this UMLEnumLiteral. +- * @param name The name of this UMLEnumLiteral. +- * @param id The unique id given to this UMLEnumLiteral. +- */ +-UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent, +- const QString& name, Uml::ID::Type id) +- : UMLClassifierListItem(parent, name, id) +-{ +- m_BaseType = UMLObject::ot_EnumLiteral; +-} +- +-/** +- * Sets up an enum literal. +- * @param parent The parent of this UMLEnumLiteral. +- */ +-UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent) +- : UMLClassifierListItem(parent) +-{ +- m_BaseType = UMLObject::ot_EnumLiteral; +-} +- +-/** +- * Destructor. +- */ +-UMLEnumLiteral::~UMLEnumLiteral() +-{ +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLEnumLiteral::operator==(const UMLEnumLiteral& 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 UMLEnumLiteral::copyInto(UMLObject *lhs) const +-{ +- UMLClassifierListItem::copyInto(lhs); +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLEnumLiteral::clone() const +-{ +- UMLEnumLiteral *clone = new UMLEnumLiteral((UMLObject *) parent()); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLEnumLiteral::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement attributeElement = UMLObject::save(QLatin1String("UML:EnumerationLiteral"), qDoc); +- qElement.appendChild(attributeElement); +-} +- +-/** +- * Loads the XMI element (empty.) +- */ +-bool UMLEnumLiteral::load(QDomElement& element) +-{ +- Q_UNUSED(element); +- return true; +-} +- +-/** +- * Display the properties configuration dialog for the enum literal. +- */ +-bool UMLEnumLiteral::showPropertiesDialog(QWidget* parent) +-{ +- bool ok; +-#if QT_VERSION >= 0x050000 +- QString enumName = QInputDialog::getText(parent, +- i18nc("enum name", "Name"), i18n("Enter name:"), +- QLineEdit::Normal, +- name(), &ok); +-#else +- QString enumName = KInputDialog::getText(i18nc("enum name", "Name"), i18n("Enter name:"), name(), &ok, parent); +-#endif +- if (ok && !enumName.isEmpty()) { +- setName(enumName); +- return true; +- } else { +- return false; +- } +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enumliteral.h umbrello-kf6-15.08.1/umbrello/enumliteral.h +--- umbrello-kf6-15.08.1.orig/umbrello/enumliteral.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/enumliteral.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,49 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENUMLITERAL_H +-#define ENUMLITERAL_H +- +-#include "classifierlistitem.h" +- +-/** +- * This class is used to set up information for an enum literal. Enum +- * literals are the values that enums can be set to. +- * +- * @short Sets up attribute information. +- * @author Paul Hensgen +- * @see UMLObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLEnumLiteral : public UMLClassifierListItem +-{ +-public: +- UMLEnumLiteral(UMLObject* parent, +- const QString& name, Uml::ID::Type id = Uml::ID::None); +- explicit UMLEnumLiteral(UMLObject* parent); +- +- bool operator==(const UMLEnumLiteral &rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- virtual ~UMLEnumLiteral(); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +-protected: +- bool load(QDomElement& element); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/folder.cpp umbrello-kf6-15.08.1/umbrello/folder.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/folder.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/folder.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,558 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "folder.h" +- +-// app includes +-#include "debug_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); +- delete 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 = static_cast(o); +- 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 = static_cast(o); +- 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->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 = static_cast(o); +- 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 = static_cast(o); +- 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 = static_cast(o); +- 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 saveToXMI(): 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::saveContents(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->saveToXMI (qDoc, ownedElement); +- } +- // Save asscociations if any. +- for (UMLObjectListIt ait(m_List); ait.hasNext();) { +- obj = ait.next(); +- obj->saveToXMI (qDoc, ownedElement); +- } +- qElement.appendChild(ownedElement); +- // Save diagrams to `extension'. +- if (m_diagrams.count()) { +- QDomElement diagramsElement = qDoc.createElement(QLatin1String("diagrams")); +- +- foreach (UMLView* pView, m_diagrams) { +- pView->umlScene()->saveToXMI(qDoc, diagramsElement); +- } +- QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); +- extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); +- extension.appendChild(diagramsElement); +- qElement.appendChild(extension); +- } +-} +- +-/** +- * Auxiliary to saveToXMI(): 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::save(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::save(elementName, qDoc); +- saveContents(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::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- if (m_folderFile.isEmpty()) { +- save(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(); +- save(qDoc, qElement); +- return; +- } +- // Okay, external file is writable. Wrap up main file. +- QDomElement folderElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); +- QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); +- extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); +- 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(m_pUMLPackage->id())); +- folderRoot.setAttribute(QLatin1String("parent"), m_pUMLPackage->fullyQualifiedName(QLatin1String("::"), true)); +- saveContents(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::loadDiagramsFromXMI(QDomNode& diagrams) +-{ +- 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()->loadFromXMI(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 load(element); +-} +- +-/** +- * Loads the owned elements of the . +- */ +-bool UMLFolder::load(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::isCommonXMIAttribute(type)) +- continue; +- if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || +- UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { +- //CHECK: umbrello-kf6 currently assumes that nested elements +- // are ownedElements anyway. +- // Therefore these tags are not further interpreted. +- if (! load(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")) { +- QDomNode diagramNode = xtnode.firstChild(); +- if (!loadDiagramsFromXMI(diagramNode)) +- totalSuccess = false; +- } 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->loadFromXMI(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; +- } +- } +- pObject->setUMLPackage(this); +- if (!pObject->loadFromXMI(tempElement)) { +- removeObject(pObject); +- delete pObject; +- totalSuccess = false; +- } +- } +- return totalSuccess; +-} +- +-/** +- * 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/folder.h umbrello-kf6-15.08.1/umbrello/folder.h +--- umbrello-kf6-15.08.1.orig/umbrello/folder.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/folder.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,92 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLFOLDER_H +-#define UMLFOLDER_H +- +-#include "package.h" +-#include "umlviewlist.h" +-#include "optionstate.h" +- +-/** +- * This class manages the UMLObjects and UMLViews of a Folder. +- * This class inherits from UMLPackage which contains most +- * of the information. +- * +- * The UMLDoc class allocates a fixed instance of this class for +- * each of the predefined Logical, UseCase, Component, Deployment, and +- * Entity-Relationship folders. Further instances are created on demand +- * for user folders. +- * +- * @short Non-graphical management of objects and diagrams of a Folder +- * @author Oliver Kellogg +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- * +- * TODO: This whole class needs a relook regarding view/scene. +- */ +-class UMLFolder : public UMLPackage +-{ +- Q_OBJECT +-public: +- explicit UMLFolder(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLFolder(); +- +- virtual UMLObject* clone() const; +- +- void setLocalName(const QString& localName); +- QString localName() const; +- +- void addView(UMLView *view); +- +- void removeView(UMLView *view); +- +- void appendViews(UMLViewList& viewList, bool includeNested = true); +- +- void activateViews(); +- +- UMLView* findView(Uml::ID::Type id); +- UMLView* findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes = true); +- +- void setViewOptions(const Settings::OptionState& optionState); +- +- void removeAllViews(); +- +- void setFolderFile(const QString& fileName); +- QString folderFile() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- friend QDebug operator<<(QDebug out, const UMLFolder& item); +- +-protected: +- void saveContents(QDomDocument& qDoc, QDomElement& qElement); +- +- void save(QDomDocument& qDoc, QDomElement& qElement); +- +- bool loadDiagramsFromXMI(QDomNode& diagrams); +- +- bool loadFolderFile(const QString& path); +- +- bool load(QDomElement & element); +- +-private: +- QString m_localName; ///< i18n name, only used for predefined root folders +- /** +- * If m_folderFile is not empty then it contains a file name to which +- * this folder is saved. +- * In this case the folder file acts as a physically separate submodel. +- * What is saved in the main model is not the folder contents but a +- * reference to the folder file. +- */ +- QString m_folderFile; +- UMLViewList m_diagrams; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.cpp umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,444 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-//own header +-#include "foreignkeyconstraint.h" +- +-// app includes +-#include "debug_utils.h" +-#include "entity.h" +-#include "entityattribute.h" +-#include "umlobject.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "umlforeignkeyconstraintdialog.h" +-#include "object_factory.h" +- +-/** +- * Sets up a constraint. +- * @param parent The parent of this UMLForeignKeyConstraint. +- * @param name The name of this UMLForeignKeyConstraint. +- * @param id The unique id given to this UMLForeignKeyConstraint. +- */ +-UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent, +- const QString& name, Uml::ID::Type id) +- : UMLEntityConstraint(parent, name, id) +-{ +- init(); +-} +- +-/** +- * Sets up a constraint. +- * @param parent The parent of this UMLForeignKeyConstraint. +- */ +-UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent) +- : UMLEntityConstraint(parent) +-{ +- init(); +-} +- +-/** +- * Initialisation of common variables +- */ +-void UMLForeignKeyConstraint::init() +-{ +- // initialise attributes +- m_BaseType = UMLObject::ot_ForeignKeyConstraint; +- +- // should be NULL actually +- // self referencing assigned to protect default behaviour +- m_ReferencedEntity = static_cast(parent()); +- +- m_UpdateAction = uda_NoAction; +- m_DeleteAction = uda_NoAction; +- +- // connecte signals and slots +- connect(this, SIGNAL(sigReferencedEntityChanged()), this, SLOT(slotReferencedEntityChanged())); +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLForeignKeyConstraint::operator==(const UMLForeignKeyConstraint &rhs) const +-{ +- if(this == &rhs) +- return true; +- +- if(!UMLObject::operator==(rhs)) +- return false; +- +- return true; +-} +- +-/** +- * Destructor. +- */ +-UMLForeignKeyConstraint::~UMLForeignKeyConstraint() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the UMLForeignKeyConstraint +- * object. +- */ +-void UMLForeignKeyConstraint::copyInto(UMLObject *lhs) const +-{ +- UMLForeignKeyConstraint *target = static_cast(lhs); +- +- // call the parent first. +- UMLEntityConstraint::copyInto(target); +- +- // Copy all datamembers +- target->m_ReferencedEntity = m_ReferencedEntity; +- target->m_AttributeMap = m_AttributeMap; +- target->m_DeleteAction = m_DeleteAction; +- target->m_UpdateAction = m_UpdateAction; +-} +- +-/** +- * Make a clone of the UMLForeignKeyConstraint. +- */ +-UMLObject* UMLForeignKeyConstraint::clone() const +-{ +- //FIXME: The new attribute should be slaved to the NEW parent not the old. +- UMLForeignKeyConstraint *clone = new UMLForeignKeyConstraint(static_cast(parent())); +- copyInto(clone); +- return clone; +-} +- +-/** +- * Returns a string representation of the UMLForeignKeyConstraint. +- * @param sig If true will show the attribute type and initial value. +- * @return Returns a string representation of the UMLAttribute. +- */ +-QString UMLForeignKeyConstraint::toString(Uml::SignatureType::Enum sig) +-{ +- QString s; +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { +- s = name() + QLatin1Char(':'); +- s += QLatin1String(" Foreign Key ("); +- QList keys = m_AttributeMap.keys(); +- bool first = true; +- foreach(UMLEntityAttribute* key, keys) { +- if (first) { +- first = false; +- } else +- s += QLatin1Char(','); +- s += key->name(); +- } +- s += QLatin1Char(')'); +- } +- +- return s; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLForeignKeyConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement foreignKeyConstraintElement = UMLObject::save(QLatin1String("UML:ForeignKeyConstraint"), qDoc); +- +- foreignKeyConstraintElement.setAttribute(QLatin1String("referencedEntity"), Uml::ID::toString(m_ReferencedEntity->id())); +- +- int updateAction = (int)m_UpdateAction; +- int deleteAction = (int)m_DeleteAction; +- +- foreignKeyConstraintElement.setAttribute(QLatin1String("updateAction"), updateAction); +- foreignKeyConstraintElement.setAttribute(QLatin1String("deleteAction"), deleteAction); +- +- QMap::iterator i; +- for (i = m_AttributeMap.begin(); i!= m_AttributeMap.end() ; ++i) { +- QDomElement mapElement = qDoc.createElement(QLatin1String("AttributeMap")); +- mapElement.setAttribute(QLatin1String("key"), Uml::ID::toString((i.key())->id())); +- mapElement.setAttribute(QLatin1String("value"), Uml::ID::toString((i.value())->id())); +- foreignKeyConstraintElement.appendChild(mapElement); +- } +- +- qElement.appendChild(foreignKeyConstraintElement); +-} +- +-/** +- * Display the properties configuration dialog for the attribute. +- */ +-bool UMLForeignKeyConstraint::showPropertiesDialog(QWidget* parent) +-{ +- UMLForeignKeyConstraintDialog dialog(parent, this); +- return dialog.exec(); +-} +- +-/** +- * Adds the attribute pair to the attributeMap +- * @param pAttr The Attribute of the Parent Entity +- * @param rAttr The Attribute of the Referenced Entity +- * @return true if the attribute pair could be added successfully +- */ +-bool UMLForeignKeyConstraint::addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) +-{ +- UMLEntity *owningParent = dynamic_cast(parent()); +- +- if (pAttr == NULL || rAttr == NULL) { +- uError() << "null values passed to function"; +- return false; +- } +- // check for sanity of pAttr (parent entity attribute) +- if (owningParent == NULL) { +- uError() << name() << ": parent is not a UMLEntity"; +- return false; +- } +- +- if (owningParent->findChildObjectById(pAttr->id()) == NULL) { +- uError() << " parent " << owningParent->name() +- << " does not contain attribute " << pAttr->name(); +- return false; +- } +- +- //check for sanity of rAttr (referenced entity attribute) +- if (m_ReferencedEntity != NULL) { +- if (m_ReferencedEntity->findChildObjectById(rAttr->id()) == NULL) { +- uError() << " parent " << m_ReferencedEntity->name() +- << " does not contain attribute " << rAttr->name(); +- return false; +- } +- } else { +- uError() << "Referenced Table Not set. Not Adding Pair "; +- return false; +- } +- +- // check if key takes part in some mapping +- if (m_AttributeMap.contains(pAttr) == true) +- return false; +- +- // check if value takes part in some mapping (no direct function) +- foreach(UMLEntityAttribute* attr, m_AttributeMap.values()) { +- if (rAttr == attr) +- return false; +- } +- +- // passed all checks, insert now +- m_AttributeMap.insert(pAttr, rAttr); +- +- QMap::iterator i; +- for (i = m_AttributeMap.begin(); i != m_AttributeMap.end(); ++i) +- uDebug() << i.key()->name() << QLatin1String(" ") << i.key()->baseType() +- << QLatin1String(" ") << i.value()->name() << QLatin1String(" ") << i.value()->baseType(); +- +- return true; +-} +- +-/** +- * Removes an Attribute pair +- * @param pAttr The Attribute of the Parent Entity in the map. This attribute is the +- key of the map. +- * @return true of the attribute pair could be removed successfully +- */ +-bool UMLForeignKeyConstraint::removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr) +-{ +- bool state = m_AttributeMap.remove(pAttr); +- +- return state; +-} +- +-/** +- * Check if a attribute pair already exists +- * @param pAttr The Attribute of the Parent Entity +- * @param rAttr The Attribute of the Referenced Entity +- * @return true if the attribute pair could be found. +- */ +-bool UMLForeignKeyConstraint::hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const +-{ +- if (m_AttributeMap.contains(pAttr)) { +- if (m_AttributeMap.value(pAttr) == rAttr) { +- return true; +- } +- } +- +- return false; +-} +- +-/** +- * Loads the XMI element. +- */ +-bool UMLForeignKeyConstraint::load(QDomElement & element) +-{ +- UMLDoc* doc = UMLApp::app()->document(); +- +- Uml::ID::Type referencedEntityId = Uml::ID::fromString(element.attribute(QLatin1String("referencedEntity"))); +- +- UMLObject* obj = doc->findObjectById(referencedEntityId); +- m_ReferencedEntity = static_cast(obj); +- +- if (m_ReferencedEntity == NULL) { +- // save for resolving later +- m_pReferencedEntityID = referencedEntityId; +- } +- +- m_UpdateAction = (UpdateDeleteAction)element.attribute(QLatin1String("updateAction")).toInt(); +- m_DeleteAction = (UpdateDeleteAction)element.attribute(QLatin1String("deleteAction")).toInt(); +- +- QDomNode node = element.firstChild(); +- while (!node.isNull()) { +- if (node.isComment()) { +- node = node.nextSibling(); +- continue; +- } +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("AttributeMap"))) { +- +- QString xmiKey = tempElement.attribute(QLatin1String("key")); +- QString xmiValue = tempElement.attribute(QLatin1String("value")); +- Uml::ID::Type keyId = Uml::ID::fromString(xmiKey); +- Uml::ID::Type valueId = Uml::ID::fromString(xmiValue); +- +- UMLEntity* parentEntity = static_cast(parent()); +- UMLObject* keyObj = parentEntity->findChildObjectById(keyId); +- UMLEntityAttribute* key = static_cast(keyObj); +- +- if (keyObj == NULL) { +- uWarning() << "unable to resolve foreign key referencing attribute " << xmiKey; +- } else if (m_ReferencedEntity == NULL) { +- // if referenced entity is null, then we won't find its attributes even +- // save for resolving later +- m_pEntityAttributeIDMap.insert(key, valueId); +- } else { +- UMLObject* valueObj = m_ReferencedEntity->findChildObjectById(valueId); +- if (valueObj == NULL) { +- uWarning() << "unable to resolve foreign key referenced attribute" << xmiValue; +- } else { +- m_AttributeMap[key] = static_cast(valueObj); +- } +- } +- +- } else { +- uWarning() << "unknown child type in UMLForeignKeyConstraint::load"; +- } +- +- node = node.nextSibling(); +- } +- +- return true; +-} +- +-/** +- * Set the Referenced Entity. +- * @param ent The Entity to Reference +- */ +-void UMLForeignKeyConstraint::setReferencedEntity(UMLEntity* ent) +-{ +- if (ent == m_ReferencedEntity) +- return; +- +- m_ReferencedEntity = ent; +- +- emit sigReferencedEntityChanged(); +-} +- +-/** +- * Get the Referenced Entity. +- * @return the UML entity object +- */ +-UMLEntity* UMLForeignKeyConstraint::getReferencedEntity() const +-{ +- return m_ReferencedEntity; +-} +- +-/** +- * Slot for referenced entity changed. +- */ +-void UMLForeignKeyConstraint::slotReferencedEntityChanged() +-{ +- // clear all mappings +- m_AttributeMap.clear(); +-} +- +-/** +- * Clears all mappings between local and referenced attributes +- */ +-void UMLForeignKeyConstraint::clearMappings() +-{ +- m_AttributeMap.clear(); +-} +- +-/** +- * Remimplementation from base classes +- * Used to resolve forward references to referenced entities in xmi +- */ +-bool UMLForeignKeyConstraint::resolveRef() +-{ +- // resolve referenced entity first +- UMLDoc* doc = UMLApp::app()->document(); +- +- bool success = true; +- +- //resolve the referenced entity +- if (!Uml::ID::toString(m_pReferencedEntityID).isEmpty()) { +- UMLObject* obj = doc->findObjectById(m_pReferencedEntityID); +- m_ReferencedEntity = static_cast(obj); +- if (m_ReferencedEntity == NULL) { +- success = false; +- } +- } +- +- QMap::iterator i; +- for (i = m_pEntityAttributeIDMap.begin(); i!= m_pEntityAttributeIDMap.end() ; ++i) { +- if (!Uml::ID::toString(i.value()).isEmpty()) { +- UMLObject* obj = doc->findObjectById(i.value()); +- m_AttributeMap[i.key()] = static_cast(obj); +- if (m_AttributeMap[i.key()] == NULL) { +- success = false; +- } +- } +- } +- +- return success; +-} +- +-/** +- * Retrieve all Pairs of Attributes. +- */ +-QMap UMLForeignKeyConstraint::getEntityAttributePairs() +-{ +- return m_AttributeMap; +-} +- +-/** +- * Get the Delete Action. +- */ +-UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getDeleteAction() const +-{ +- return m_DeleteAction; +-} +- +-/** +- * Get the Update Action. +- */ +-UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getUpdateAction() const +-{ +- return m_UpdateAction; +-} +- +-/** +- * Set the Delete Action to the specified UpdateDeleteAction. +- */ +-void UMLForeignKeyConstraint::setDeleteAction(UpdateDeleteAction uda) +-{ +- m_DeleteAction = uda; +-} +- +-/** +- * Set the Update Action to the specified UpdateDeleteAction +- */ +-void UMLForeignKeyConstraint::setUpdateAction(UpdateDeleteAction uda) +-{ +- m_UpdateAction = uda; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.h umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,120 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef FOREIGNKEYCONSTRAINT_H +-#define FOREIGNKEYCONSTRAINT_H +- +-// appl includes +-#include "basictypes.h" +-#include "entityconstraint.h" +- +-// qt includes +-#include +- +-//forward declarations +-class UMLEntityAttribute; +-class UMLEntity; +- +-/** +- * This class is used to set up information for a foreign key entity constraint. +- * @short Sets up Foreign Key entity constraint information. +- * @author Sharan Rao +- * @see UMLObject UMLClassifierListItem UMLEntityConstraint +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLForeignKeyConstraint : public UMLEntityConstraint +-{ +- Q_OBJECT +- +-public: +- +- /** +- * Update/Delete Action: Action to be taken on Update or Delete of a referenced attribute +- * is either, No Action, Restrict, Cascade, Set NULL, Set Default. +- */ +- enum UpdateDeleteAction { uda_NoAction = 0, +- uda_Restrict, +- uda_Cascade, +- uda_SetNull, +- uda_SetDefault }; +- +- UMLForeignKeyConstraint(UMLObject *parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None); +- explicit UMLForeignKeyConstraint(UMLObject *parent); +- +- bool operator==(const UMLForeignKeyConstraint &rhs) const; +- +- virtual ~UMLForeignKeyConstraint(); +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- void setReferencedEntity(UMLEntity* ent); +- UMLEntity* getReferencedEntity() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +- bool addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr); +- +- bool removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr); +- +- bool hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const; +- +- QMap getEntityAttributePairs(); +- +- void setDeleteAction(UpdateDeleteAction uda); +- UpdateDeleteAction getDeleteAction() const; +- +- void setUpdateAction(UpdateDeleteAction uda); +- UpdateDeleteAction getUpdateAction() const; +- +- void clearMappings(); +- +- bool resolveRef(); +- +-signals: +- void sigReferencedEntityChanged(); +- +-private slots: +- void slotReferencedEntityChanged(); +- +-protected: +- bool load(QDomElement & element); +- +-private: +- +- Uml::ID::Type m_pReferencedEntityID; ///< Used to resolve forward references to UMLEntity. +- +- /** +- * Used to resolve forward references to UMLEntityAttributes +- * Key -> The local attribute +- * Value -> Id of the attribute it is mapping to +- */ +- QMap m_pEntityAttributeIDMap; +- +- void init(); +- +- UMLEntity* m_ReferencedEntity; ///< The UMLEntity that this foreign key references. +- +- /** +- * Stores the Mapping of attributes between parent table and referenced table +- */ +- QMap m_AttributeMap; +- +- UpdateDeleteAction m_UpdateAction; ///< What to do on Update of referenced attributes. +- UpdateDeleteAction m_DeleteAction; ///< What to do on Deletion of referenced attributes. +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/listpopupmenu.cpp umbrello-kf6-15.08.1/umbrello/listpopupmenu.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/listpopupmenu.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/listpopupmenu.cpp 2015-10-08 11:48:59.500089026 +0300 +@@ -1195,7 +1195,6 @@ + void ListPopupMenu::makeClassifierShowPopup(ClassifierWidget *c) + { + WidgetBase::WidgetType type = c->baseType(); +- ClassifierWidget *cls = NULL; + + #if QT_VERSION >= 0x050000 + QMenu* show = new QMenu(i18n("Show"), this); +@@ -1208,9 +1207,8 @@ + setActionChecked(mt_Show_Documentation, c->visualProperty(ClassifierWidget::ShowDocumentation)); + #endif + if (type == WidgetBase::wt_Class) { +- cls = static_cast(c); + insert(mt_Show_Attributes, show, i18n("Attributes"), CHECKABLE); +- setActionChecked(mt_Show_Attributes, cls->visualProperty(ClassifierWidget::ShowAttributes)); ++ setActionChecked(mt_Show_Attributes, c->visualProperty(ClassifierWidget::ShowAttributes)); + } + insert(mt_Show_Operations, show, i18n("Operations"), CHECKABLE); + setActionChecked(mt_Show_Operations, c->visualProperty(ClassifierWidget::ShowOperations)); +@@ -1224,16 +1222,14 @@ + setActionChecked(mt_Show_Operation_Signature, sig); + if (type == WidgetBase::wt_Class) { + insert(mt_Show_Attribute_Signature, show, i18n("Attribute Signature"), CHECKABLE); +- sig = (cls->attributeSignature() == Uml::SignatureType::SigNoVis || +- cls->attributeSignature() == Uml::SignatureType::ShowSig); ++ sig = (c->attributeSignature() == Uml::SignatureType::SigNoVis || ++ c->attributeSignature() == Uml::SignatureType::ShowSig); + setActionChecked(mt_Show_Attribute_Signature, sig); + } + insert(mt_Show_Packages, show, i18n("Package"), CHECKABLE); + setActionChecked(mt_Show_Packages, c->visualProperty(ClassifierWidget::ShowPackage)); +- if (type == WidgetBase::wt_Class) { +- insert(mt_Show_Stereotypes, show, i18n("Stereotype"), CHECKABLE); +- setActionChecked(mt_Show_Stereotypes, cls->visualProperty(ClassifierWidget::ShowStereotype)); +- } ++ insert(mt_Show_Stereotypes, show, i18n("Stereotype"), CHECKABLE); ++ setActionChecked(mt_Show_Stereotypes, c->visualProperty(ClassifierWidget::ShowStereotype)); + addMenu(show); + } + +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/node.cpp umbrello-kf6-15.08.1/umbrello/node.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/node.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/node.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,68 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "node.h" +- +-#include +- +-/** +- * Sets up a Node. +- * +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLNode::UMLNode(const QString & name, Uml::ID::Type id) +- : UMLCanvasObject(name, id) +-{ +- init(); +-} +- +-/** +- * Destructor. +- */ +-UMLNode::~UMLNode() +-{ +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLNode::init() +-{ +- m_BaseType = UMLObject::ot_Node; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLNode::clone() const +-{ +- UMLNode *clone = new UMLNode(); +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLNode::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement nodeElement = UMLObject::save(QLatin1String("UML:Node"), qDoc); +- qElement.appendChild(nodeElement); +-} +- +-/** +- * Loads the XMI element (empty.) +- */ +-bool UMLNode::load(QDomElement&) +-{ +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/node.h umbrello-kf6-15.08.1/umbrello/node.h +--- umbrello-kf6-15.08.1.orig/umbrello/node.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/node.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,46 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef NODE_H +-#define NODE_H +- +-#include "umlcanvasobject.h" +- +-/** +- * This class contains the non-graphical information required for a UML Node. +- * This class inherits from @ref UMLCanvasObject which contains most of the +- * information. +- * +- * @short Non-graphical information for a Node. +- * @author Jonathan Riddell +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLNode : public UMLCanvasObject +-{ +- Q_OBJECT +-public: +- +- explicit UMLNode(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLNode(); +- +- virtual void init(); +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- +- bool load(QDomElement & element); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/operation.cpp umbrello-kf6-15.08.1/umbrello/operation.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/operation.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/operation.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,611 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "operation.h" +- +-// app includes +-#include "attribute.h" +-#include "classifier.h" +-#include "model_utils.h" +-#include "debug_utils.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "uniqueid.h" +-#include "umloperationdialog.h" +-#include "codegenerator.h" +-#include "codedocument.h" +-#include "codeblock.h" +- +-// kde includes +-#include +- +-// qt includes +-#include +- +-/** +- * Constructs an UMLOperation. +- * Not intended for general use: The operation is not tied in with +- * umbrello-kf6's Qt signalling for object creation. +- * If you want to create an Operation use the method in UMLDoc instead. +- * +- * @param parent the parent to this operation +- * @param name the name of the operation +- * @param id the id of the operation +- * @param s the visibility of the operation +- * @param rt the return type of the operation +- */ +-UMLOperation::UMLOperation(UMLClassifier *parent, const QString& name, +- Uml::ID::Type id, Uml::Visibility::Enum s, UMLObject *rt) +- : UMLClassifierListItem(parent, name, id) +-{ +- if (rt) +- m_returnId = UniqueID::gen(); +- else +- m_returnId = Uml::ID::None; +- m_pSecondary = rt; +- m_visibility = s; +- m_BaseType = UMLObject::ot_Operation; +- m_bConst = false; +- m_Code.clear(); +-} +- +-/** +- * Constructs an UMLOperation. +- * Not intended for general use: The operation is not tied in with +- * umbrello-kf6's Qt signalling for object creation. +- * If you want to create an Operation use the method in UMLDoc instead. +- * +- * @param parent the parent to this operation +- */ +-UMLOperation::UMLOperation(UMLClassifier * parent) +- : UMLClassifierListItem (parent) +-{ +- m_BaseType = UMLObject::ot_Operation; +- m_bConst = false; +- m_Code.clear(); +-} +- +-/** +- * Destructor. +- */ +-UMLOperation::~UMLOperation() +-{ +-} +- +-/** +- * Reimplement method from UMLClassifierListItem. +- * +- * @param type pointer to the type object +- */ +-void UMLOperation::setType(UMLObject* type) +-{ +- UMLClassifierListItem::setType(type); +- if (m_returnId == Uml::ID::None) +- m_returnId = UniqueID::gen(); +-} +- +-/** +- * Move a parameter one position to the left. +- * +- * @param a the parameter to move +- */ +-void UMLOperation::moveParmLeft(UMLAttribute * a) +-{ +- if (a == NULL) { +- uDebug() << "called on NULL attribute"; +- return; +- } +- uDebug() << "called for " << a->name(); +- disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); +- int idx; +- if ((idx=m_List.indexOf(a)) == -1) { +- uDebug() << "Error move parm left " << a->name(); +- return; +- } +- if (idx == 0) +- return; +- m_List.removeAll(a); +- m_List.insert(idx-1, a); +-} +- +-/** +- * Move a parameter one position to the right. +- * +- * @param a the parameter to move +- */ +-void UMLOperation::moveParmRight(UMLAttribute * a) +-{ +- if (a == NULL) { +- uDebug() << "called on NULL attribute"; +- return; +- } +- uDebug() << "called for " << a->name(); +- disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); +- int idx; +- if ((idx=m_List.indexOf(a)) == -1) { +- uDebug() << "Error move parm right " << a->name(); +- return; +- } +- int count = m_List.count(); +- if (idx == count-1) +- return; +- m_List.removeAll(a); +- m_List.insert(idx+1, a); +-} +- +-/** +- * Remove a parameter from the operation. +- * +- * @param a the parameter to remove +- * @param emitModifiedSignal whether to emit the "modified" signal +- * which creates an entry in the Undo stack for the +- * removal, default: true +- */ +-void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) +-{ +- if (a == NULL) { +- uDebug() << "called on NULL attribute"; +- return; +- } +- uDebug() << "called for " << a->name(); +- disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); +- if(!m_List.removeAll(a)) +- uDebug() << "Error removing parm " << a->name(); +- +- if (emitModifiedSignal) +- emit modified(); +-} +- +-/** +- * Returns a list of parameters. +- * +- * @return a list of the parameters in the operation +- */ +-UMLAttributeList UMLOperation::getParmList() const +-{ +- return m_List; +-} +- +-/** +- * Finds a parameter of the operation. +- * +- * @param name the parameter name to search for +- * @return the found parameter, 0 if not found +- */ +-UMLAttribute* UMLOperation::findParm(const QString &name) +-{ +- UMLAttribute * obj=0; +- foreach (obj, m_List) { +- if (obj->name() == name) +- return obj; +- } +- return 0; +-} +- +-/** +- * Returns a string representation of the operation. +- * +- * @param sig what type of operation string to show +- * @return the string representation of the operation +- */ +-QString UMLOperation::toString(Uml::SignatureType::Enum sig) +-{ +- QString s; +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) +- s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); +- +- s += name(); +- Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); +- bool parameterlessOpNeedsParentheses = +- (pl != Uml::ProgrammingLanguage::Pascal && pl != Uml::ProgrammingLanguage::Ada); +- +- if (sig == Uml::SignatureType::NoSig || sig == Uml::SignatureType::NoSigNoVis) { +- if (parameterlessOpNeedsParentheses) +- s.append(QLatin1String("()")); +- return s; +- } +- int last = m_List.count(); +- if (last) { +- s.append(QLatin1String("(")); +- int i = 0; +- foreach (UMLAttribute *param, m_List) { +- i++; +- s.append(param->toString(Uml::SignatureType::SigNoVis)); +- if (i < last) +- s.append(QLatin1String(", ")); +- } +- s.append(QLatin1String(")")); +- } else if (parameterlessOpNeedsParentheses) { +- s.append(QLatin1String("()")); +- } +- UMLClassifier *ownParent = static_cast(parent()); +- QString returnType; +- UMLClassifier *retType = UMLClassifierListItem::getType(); +- if (retType) { +- UMLPackage *retVisibility = retType->umlPackage(); +- if (retVisibility != ownParent && retVisibility != ownParent->umlPackage()) +- returnType = retType->fullyQualifiedName(); +- else +- returnType = retType->name(); +- } +- if (returnType.length() > 0 && returnType != QLatin1String("void")) { +- s.append(QLatin1String(" : ")); +- +- if (returnType.startsWith(QLatin1String(QLatin1String("virtual ")))) { +- s += returnType.mid(8); +- } else { +- s += returnType; +- } +- } +- return s; +-} +- +-/** +- * Add a parameter to the operation. +- * +- * @param parameter the parameter to add +- * @param position the position in the parameter list. +- * If position = -1 the parameter will be +- * appended to the list. +- */ +-void UMLOperation::addParm(UMLAttribute *parameter, int position) +-{ +- if(position >= 0 && position <= (int)m_List.count()) +- m_List.insert(position, parameter); +- else +- m_List.append(parameter); +- UMLObject::emitModified(); +- connect(parameter, SIGNAL(modified()), this, SIGNAL(modified())); +-} +- +-/** +- * Returns an unused parameter name for a new parameter. +- */ +-QString UMLOperation::getUniqueParameterName() +-{ +- QString currentName = i18n("new_parameter"); +- QString name = currentName; +- for (int number = 1; findParm(name); ++number) { +- name = currentName + QLatin1Char('_') + QString::number(number); +- } +- return name; +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLOperation::operator==(const UMLOperation & rhs) const +-{ +- if (this == &rhs) +- return true; +- +- if (!UMLObject::operator==(rhs)) +- return false; +- +- if (getTypeName() != rhs.getTypeName()) +- return false; +- +- if (m_List.count() != rhs.m_List.count()) +- return false; +- +- if (!(m_List == rhs.m_List)) +- return false; +- +- return true; +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLOperation::copyInto(UMLObject *lhs) const +-{ +- UMLOperation *target = static_cast(lhs); +- +- UMLClassifierListItem::copyInto(target); +- +- m_List.copyInto(&(target->m_List)); +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLOperation::clone() const +-{ +- //FIXME: The new operation should be slaved to the NEW parent not the old. +- UMLOperation *clone = new UMLOperation(static_cast(parent())); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Calls resolveRef() on all parameters. +- * Needs to be called after all UML objects are loaded from file. +- * +- * @return true for success +- */ +-bool UMLOperation::resolveRef() +-{ +- bool overallSuccess = UMLObject::resolveRef(); +- // See remark on iteration style in UMLClassifier::resolveRef() +- foreach (UMLAttribute* pAtt, m_List) { +- if (! pAtt->resolveRef()) +- overallSuccess = false; +- } +- return overallSuccess; +-} +- +-/** +- * Returns whether this operation is a constructor. +- * +- * @return true if this operation is a constructor +- */ +-bool UMLOperation::isConstructorOperation() +-{ +- // if an operation has the stereotype constructor +- // return true +- if (stereotype() == QLatin1String("constructor")) +- return true; +- +- UMLClassifier * c = static_cast(this->parent()); +- QString cName = c->name(); +- QString opName = name(); +- // It's a constructor operation if the operation name +- // matches that of the parent classifier. +- return (cName == opName); +-} +- +-/** +- * Returns whether this operation is a destructor. +- * +- * @return true if this operation is a destructor +- */ +-bool UMLOperation::isDestructorOperation() +-{ +- if (stereotype() == QLatin1String("destructor")) +- return true; +- UMLClassifier * c = static_cast(this->parent()); +- +- QString cName = c->name(); +- QString opName = name(); +- // Special support for C++ syntax: +- // It's a destructor operation if the operation name begins +- // with "~" followed by the name of the parent classifier. +- if (! opName.startsWith(QLatin1Char('~'))) +- return false; +- opName.remove(QRegExp(QLatin1String("^~\\s*"))); +- return (cName == opName); +-} +- +-/** +- * Shortcut for (isConstructorOperation() || isDestructorOperation()). +- * +- * @return true if this operation is a constructor or destructor +- */ +-bool UMLOperation::isLifeOperation() +-{ +- return (isConstructorOperation() || isDestructorOperation()); +-} +- +-/** +- * Sets whether this operation is a query (C++ "const"). +- */ +-void UMLOperation::setConst(bool b) +-{ +- m_bConst = b; +-} +- +-/** +- * Returns whether this operation is a query (C++ "const"). +- */ +-bool UMLOperation::getConst() const +-{ +- return m_bConst; +-} +- +-/** +- * Display the properties configuration dialog for the template. +- * +- * @param parent the parent for the dialog +- */ +-bool UMLOperation::showPropertiesDialog(QWidget* parent) +-{ +- UMLOperationDialog dialog(parent, this); +- return dialog.exec(); +-} +- +-/** +- * Sets the source code for this operation. +- * +- * @param code the body of this operation +- */ +-void UMLOperation::setSourceCode(const QString& code) +-{ +- m_Code = code; +-} +- +-/** +- * Returns the source code for this operation. +- */ +-QString UMLOperation::getSourceCode() const +-{ +- return m_Code; +-} +- +-/** +- * Saves to the XMI element. +- */ +-void UMLOperation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement operationElement = UMLObject::save(QLatin1String("UML:Operation"), qDoc); +- operationElement.setAttribute(QLatin1String("isQuery"), m_bConst ? QLatin1String("true") : QLatin1String("false")); +- QDomElement featureElement = qDoc.createElement(QLatin1String("UML:BehavioralFeature.parameter")); +- if (m_pSecondary) { +- QDomElement retElement = qDoc.createElement(QLatin1String("UML:Parameter")); +- if (m_returnId == Uml::ID::None) { +- uDebug() << name() << ": m_returnId is not set, setting it now."; +- m_returnId = UniqueID::gen(); +- } +- retElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_returnId)); +- retElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); +- retElement.setAttribute(QLatin1String("kind"), QLatin1String("return")); +- featureElement.appendChild(retElement); +- } else { +- uDebug() << "m_SecondaryId is " << m_SecondaryId; +- } +- +- //save each attribute here, type different +- foreach(UMLAttribute* pAtt, m_List) { +- QDomElement attElement = pAtt->UMLObject::save(QLatin1String("UML:Parameter"), qDoc); +- UMLClassifier *attrType = pAtt->getType(); +- if (attrType) { +- attElement.setAttribute(QLatin1String("type"), Uml::ID::toString(attrType->id())); +- } else { +- attElement.setAttribute(QLatin1String("type"), pAtt->getTypeName()); +- } +- attElement.setAttribute(QLatin1String("value"), pAtt->getInitialValue()); +- +- Uml::ParameterDirection::Enum kind = pAtt->getParmKind(); +- if (kind == Uml::ParameterDirection::Out) +- attElement.setAttribute(QLatin1String("kind"), QLatin1String("out")); +- else if (kind == Uml::ParameterDirection::InOut) +- attElement.setAttribute(QLatin1String("kind"), QLatin1String("inout")); +- // The default for the parameter kind is "in". +- +- featureElement.appendChild(attElement); +- } +- if (featureElement.hasChildNodes()) { +- operationElement.appendChild(featureElement); +- } +- qElement.appendChild(operationElement); +-} +- +-/** +- * Loads a XMI element. +- */ +-bool UMLOperation::load(QDomElement & element) +-{ +- m_SecondaryId = element.attribute(QLatin1String("type")); +- QString isQuery = element.attribute(QLatin1String("isQuery")); +- if (!isQuery.isEmpty()) { +- // We need this extra test for isEmpty() because load() might have been +- // called again by the processing for BehavioralFeature.parameter (see below) +- m_bConst = (isQuery == QLatin1String("true")); +- } +- QDomNode node = element.firstChild(); +- if (node.isComment()) +- node = node.nextSibling(); +- QDomElement attElement = node.toElement(); +- while (!attElement.isNull()) { +- QString tag = attElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("BehavioralFeature.parameter")) || +- UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement"))) { // Embarcadero's Describe +- if (! load(attElement)) +- return false; +- } else if (UMLDoc::tagEq(tag, QLatin1String("Parameter"))) { +- QString kind = attElement.attribute(QLatin1String("kind")); +- if (kind.isEmpty()) { +- kind = attElement.attribute(QLatin1String("direction")); // Embarcadero's Describe +- if (kind.isEmpty()) { +- // Perhaps the kind is stored in a child node: +- for (QDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) { +- if (n.isComment()) +- continue; +- QDomElement tempElement = n.toElement(); +- QString tag = tempElement.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("kind"))) +- continue; +- kind = tempElement.attribute(QLatin1String("xmi.value")); +- break; +- } +- } +- if (kind.isEmpty()) { +- kind = QLatin1String("in"); +- } +- } +- if (kind == QLatin1String("return") || +- kind == QLatin1String("result")) { // Embarcadero's Describe +- QString returnId = Model_Utils::getXmiId(attElement); +- if (!returnId.isEmpty()) +- m_returnId = Uml::ID::fromString(returnId); +- m_SecondaryId = attElement.attribute(QLatin1String("type")); +- if (m_SecondaryId.isEmpty()) { +- // Perhaps the type is stored in a child node: +- QDomNode node = attElement.firstChild(); +- while (!node.isNull()) { +- if (node.isComment()) { +- node = node.nextSibling(); +- continue; +- } +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { +- node = node.nextSibling(); +- continue; +- } +- m_SecondaryId = Model_Utils::getXmiId(tempElement); +- if (m_SecondaryId.isEmpty()) +- m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); +- if (m_SecondaryId.isEmpty()) { +- QDomNode inner = node.firstChild(); +- QDomElement tmpElem = inner.toElement(); +- m_SecondaryId = Model_Utils::getXmiId(tmpElem); +- if (m_SecondaryId.isEmpty()) +- m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); +- } +- break; +- } +- if (m_SecondaryId.isEmpty()) { +- uError() << name() << ": cannot find return type."; +- } +- } +- // Use deferred xmi.id resolution. +- m_pSecondary = NULL; +- } else { +- UMLAttribute * pAtt = new UMLAttribute(this); +- if(!pAtt->loadFromXMI(attElement)) { +- delete pAtt; +- return false; +- } +- if (kind == QLatin1String("out")) +- pAtt->setParmKind(Uml::ParameterDirection::Out); +- else if (kind == QLatin1String("inout")) +- pAtt->setParmKind(Uml::ParameterDirection::InOut); +- else +- pAtt->setParmKind(Uml::ParameterDirection::In); +- m_List.append(pAtt); +- } +- } +- node = node.nextSibling(); +- if (node.isComment()) +- node = node.nextSibling(); +- attElement = node.toElement(); +- +- // loading the source code which was entered in the 'classpropdlg' dialog is not done +- // with the following code, because there is no CodeDocument. +- /* +- CodeGenerator* codegen = UMLApp::app()->getGenerator(); +- if (codegen) { +- uDebug() << "CodeDocument searching with id=" << Uml::ID::toString(UMLObject::ID()); +- CodeDocument* codeDoc = codegen->findCodeDocumentByID(Uml::ID::toString(UMLObject::ID())); +- if (codeDoc) { +- uDebug() << "CodeDocument found:\n" << codeDoc; +- } +- } +- */ +- // it is done in the code generators by calling CodeGenerator::loadFromXMI(...). +- +- }//end while +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/operation.h umbrello-kf6-15.08.1/umbrello/operation.h +--- umbrello-kf6-15.08.1.orig/umbrello/operation.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/operation.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,84 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef OPERATION_H +-#define OPERATION_H +- +-#include "umlattributelist.h" +-#include "classifierlistitem.h" +- +-class UMLClassifier; +- +-/** +- * This class represents an operation in the UML model. +- * +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLOperation : public UMLClassifierListItem +-{ +- Q_OBJECT +-public: +- UMLOperation(UMLClassifier * parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None, +- Uml::Visibility::Enum s = Uml::Visibility::Public, +- UMLObject *rt = 0); +- explicit UMLOperation(UMLClassifier * parent); +- virtual ~UMLOperation(); +- +- bool operator==(const UMLOperation & rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- void setType(UMLObject* type); +- +- void moveParmLeft(UMLAttribute *a); +- void moveParmRight(UMLAttribute *a); +- +- void removeParm(UMLAttribute *a, bool emitModifiedSignal = true); +- +- UMLAttributeList getParmList() const; +- +- UMLAttribute * findParm(const QString &name); +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- void addParm(UMLAttribute *parameter, int position = -1); +- +- bool resolveRef(); +- +- QString getUniqueParameterName(); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +- bool isConstructorOperation(); +- bool isDestructorOperation(); +- bool isLifeOperation(); +- +- void setConst(bool b); +- bool getConst() const; +- +- void setSourceCode(const QString& code); +- QString getSourceCode() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- bool load(QDomElement & element); +- +-private: +- Uml::ID::Type m_returnId; ///< Holds the xmi.id of the +- UMLAttributeList m_List; ///< Parameter list +- bool m_bConst; ///< Holds the isQuery attribute of the +- QString m_Code; ///< Holds the entered source code +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/org.kde.umbrello-kf6.appdata.xml umbrello-kf6-15.08.1/umbrello/org.kde.umbrello-kf6.appdata.xml +--- umbrello-kf6-15.08.1.orig/umbrello/org.kde.umbrello-kf6.appdata.xml 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/org.kde.umbrello-kf6.appdata.xml 2015-10-08 11:48:59.501089026 +0300 +@@ -0,0 +1,136 @@ ++ ++ ++ org.kde.umbrello-kf6.desktop ++ CC0-1.0 ++ GPL-2.0+ ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ umbrello-kf6 ++ xxumbrello-kf6xx ++ UML Modeller ++ Modelador UML ++ UML modelář ++ UML-Modeller ++ UML Modeller ++ Modelador UML ++ UML-i modelleerimise rakendus ++ UML-mallinnusohjelma ++ Modelador de UML ++ Modellatore UML ++ UML-modeller ++ Program do modelowania UML ++ Modelador de UML ++ Modelador de UML ++ Modelár UML ++ Modelirnik UML ++ UML-modellering ++ Засіб моделювання UML ++ xxUML Modellerxx ++ ++

++ umbrello-kf6 is a Unified Modelling Language (UML) modelling tool and code generator. ++ It can create diagrams of software and other systems in the industry-standard UML format, and can also generate code from UML diagrams ++ in a variety of programming languages. ++

++

L'umbrello-kf6 és una eina de modelatge de Llenguatge Unificat de Modelatge (UML) i generador de codi. Pot crear diagrames de programari i altres sistemes en el format UML estàndard de la indústria, i també pot generar codi des de diagrames UML en diversos llenguatges de programació.

++

umbrello-kf6 is a Unified Modelling Language (UML) modelling tool and code generator. It can create diagrams of software and other systems in the industry-standard UML format, and can also generate code from UML diagrams in a variety of programming languages.

++

umbrello-kf6 es una herramienta de modelado y de generación de código para el lenguaje unificado de modelado (UML). Puede crear diagramas de software y de otros sistemas en el formato estándar de la industria UML, además de generar código a partir de diagramas UML en diversos lenguajes de programación.

++

umbrello-kf6 on unifitseeritud modelleerimiskeele UML modelleerimistööriist ja koodi genereerija. See võib luua tarkvara ja muude süsteemide skeeme standardses UML-vormingus, samuti genereerida UML-skeemide põhjal koodi mitmes programmeerimiskeeles.

++

umbrello-kf6 on UML-mallinnusohjelma. umbrello-kf6lla voi luoda kaavioita ohjelmistoista ja muista järjestelmistä käyttäen standardia UML-muotoa. Sillä voi myös luoda koodin UML-kaavioiden perusteella useille ohjelmointikielille.

++

umbrello-kf6 é unha ferramenta de modelaxe e xerador de código baseado na linguaxe de modelaxe UML. Pode crear diagramas de software e doutros sistemas usando o formato estándar da industria, UML, e pode tamén xerar código a partir de diagramas UML en varios linguaxes de programación.

++

umbrello-kf6 è uno strumento per diagrammi UML e un generatore di codice. Può creare diagrammi di software e altri sistemi nello standard industriale UML, e può anche generare codice partendo dai diagrammi UML in diversi linguaggi di programmazione.

++

umbrello-kf6 is een Unified Modelling Language (UML) hulpmiddel voor modellering en generator van code. Het kan diagrammen van software en andere systemen maken in het industrie-standaard UML-formaat en kan ook code genereren uit UML diagrammen in een verscheidenheid van programmeertalen.

++

umbrello-kf6 jest Unified Modelling Language (UML) (z ang. Językiem do Jednolitego Modelowania) i generatorem kodu. Może tworzyć diagramy oprogramowania i innych systemów w formacie standardu przemysłowego UML, a także generować kod z diagramów UML w wielu językach programowania.

++

O umbrello-kf6 é uma ferramenta de modelação em UML (Unified Modelling Language) e gerador de código. Poderá criar diagramas de aplicações e outros sistemas, usando o formato-padrão da indústria UML, podendo também gerar código a partir de diagramas UML, numa grande variedade de linguagens de programação.

++

umbrello-kf6 é uma ferramenta de modelação de UML (Unified Modelling Language) e gerador de código. Ele pode criar diagramas de softwares e outros sistemas, usando o formato de UML padrão da indústria, assim como gerar código a partir de diagramas UML, em uma grande variedade de linguagens de programação.

++

umbrello-kf6 je nástroj na modelovania v UML a generátor kódu. Dokáže vytvárať diagramy softvéru a iných systémov v priemyselnom štandarde UML a tiež generovať kód z UML diagramov v množstve programovacích jazykov.

++

umbrello-kf6 je orodje za modeliranje v poenotenem jeziku za modeliranje (UML) in ustvarjalnik kode. Ustvari lahko diagrame programov in drugih sistemov v industrijski standardizirani obliki UML, iz diagramov UML pa lahko ustvari tudi kodo v različnih programskih jezikih.

++

umbrello-kf6 är ett modelleringsverktyg för Unified Modelling Language och kodgenerator. Det kan skapa diagram av programvara och andra system med industristandardformatet UML, och kan också skapa kod från UML-diagram på ett antal olika programspråk.

++

umbrello-kf6 — засіб моделювання уніфікованою мовою моделювання (UML) та інструмент для створення шаблонів коду. Програма здатна створювати діаграми систем програмного забезпечення та інших систем у стандартному форматі UML та реалізовувати діаграми UML у програмному коді багатьма мовами програмування.

++

xxumbrello-kf6 is a Unified Modelling Language (UML) modelling tool and code generator. It can create diagrams of software and other systems in the industry-standard UML format, and can also generate code from UML diagrams in a variety of programming languages.xx

++

Features:

++

Característiques:

++

Vlastnosti:

++

Funktionen:

++

Features:

++

Funciones:

++

Omadused:

++

Ominaisuuksia:

++

Funcionalidades:

++

Funzionalità:

++

Kenmerken:

++

Możliwości:

++

Funcionalidades:

++

Funcionalidades:

++

Funkcie:

++

Zmožnosti:

++

Funktioner:

++

Можливості:

++

xxFeatures:xx

++
    ++
  • Supported formats: XMI
  • ++
  • Formats acceptats: XMI
  • ++
  • Podporované formáty: XMI
  • ++
  • Unterstützte Formate: XMI
  • ++
  • Supported formats: XMI
  • ++
  • Formatos permitidos: XMI
  • ++
  • Toetatud vormingud: XMI
  • ++
  • Tukee XMI-tiedostomuotoa
  • ++
  • Formatos compatíbeis: XMI.
  • ++
  • Formati supportati: XMI
  • ++
  • Ondersteunde formaten: XMI
  • ++
  • Obsługiwane formaty: XMI
  • ++
  • Formatos suportados: XMI
  • ++
  • Formatos suportados: XMI
  • ++
  • Podporované formáty: XMI
  • ++
  • Podprte oblike: XMI
  • ++
  • Format som stöds: XMI
  • ++
  • Підтримувані формати: XMI
  • ++
  • xxSupported formats: XMIxx
  • ++
  • Several type of diagrams supported: use case, class, sequence, collaboration, state, activity, component, deployment, entity relationship
  • ++
  • Es permeten diversos tipus de diagrames: cas d'ús, classe, seqüència, col·laboració, estat, activitat, component, desplegament, entitat relació
  • ++
  • Several type of diagrams supported: use case, class, sequence, collaboration, state, activity, component, deployment, entity relationship
  • ++
  • Permite usar varios tipos de diagramas: casos de uso, clase, secuencia, colaboración, estado, actividad, componente, despliegue y relación de entidades
  • ++
  • Toetatud on mitut tüüpi skeemid: kasutus, klass, järgnevus, koostöö, olek, tegevus, komponent, evitus, olem-seos
  • ++
  • Tukee monenlaisia kaavioita: käyttötapauskaavio, luokkakaavio, sekvenssikaavio, yhteistyökaavio, tilakaavio, aktiviteettikaavio, komponenttikaavio, sijoittelukaavio, käsitekaavio
  • ++
  • Permite traballar con varios tipos de diagramas: caso de uso, clase, secuencia, colaboración, estado, actividade, compoñente, distribución, e entidade-relación.
  • ++
  • Diversi tipi di diagrammi supportati: casi d'uso, classe, sequenza, collaborazione, stato, attività, componente, dispiegamento, relazione tra entità
  • ++
  • Verschillende typen diagrammen worden ondersteund: use case, klassen, volgorde, samenwerking, status, activiteit, component, deployment, relaties tussen eenheden
  • ++
  • Kilka obsługiwanych rodzajów diagramów: przypadki użycia, klasy, sekwencje, kolaboracje, stany, aktywności, składniki, zastosowanie, współzależności obiektów
  • ++
  • Diversos tipos de diagramas suportados: casos de uso, classe, sequência, colaboração, estado, actividade, componente, entrada em produção, entidade-associação
  • ++
  • Há suporte para diversos tipos de diagramas: casos de uso, classe, sequência, colaboração, estado, atividade, componente, distribuição, relacionamento de entidade
  • ++
  • Podporovaných je niekoľko typov diagramov: prípady použitia, triedy, sekvencie, stavy, aktivity, nasadenie, vzžahy entít
  • ++
  • Podprte so številne vrste diagramov: primer uporabe, razred, zaporedje, sodelovanje, stanje, dejavnost, sestavni del, namestitev, odvisnost entitete
  • ++
  • Flera diagramtyper stöds: användningsfall, klass, sekvens, samarbete, tillstånd, aktivitet, komponent, utplacering, objektsamband
  • ++
  • Підтримка декількох типів діаграм: випадків використання, класів, послідовності, співпраці, станів, компонент, розміщення та взаємозв’язку компонентів.
  • ++
  • xxSeveral type of diagrams supported: use case, class, sequence, collaboration, state, activity, component, deployment, entity relationshipxx
  • ++
++
++ http://umbrello-kf6.kde.org ++ https://bugs.kde.org/enter_bug.cgi?format=guided&product=umbrello-kf6 ++ http://docs.kde.org/stable/en/kdesdk/umbrello/index.html ++ ++ ++ http://kde.org/images/screenshots/umbrello-kf6.png ++ ++ ++ KDE ++ ++ umbrello-kf6 ++ ++
+diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/package.cpp umbrello-kf6-15.08.1/umbrello/package.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/package.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/package.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,461 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header file +-#include "package.h" +- +-// local includes +-#include "debug_utils.h" +-#include "dialog_utils.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "classifier.h" +-#include "association.h" +-#include "entity.h" +-#include "object_factory.h" +-#include "model_utils.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +- +-using namespace Uml; +- +-/** +- * Sets up a Package. +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLPackage::UMLPackage(const QString & name, Uml::ID::Type id) +- : UMLCanvasObject(name, id) +-{ +- m_BaseType = ot_Package; +-} +- +-/** +- * Destructor. +- */ +-UMLPackage::~UMLPackage() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new object. +- */ +-void UMLPackage::copyInto(UMLObject *lhs) const +-{ +- UMLPackage *target = static_cast(lhs); +- +- UMLCanvasObject::copyInto(target); +- +- m_objects.copyInto(&(target->m_objects)); +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLPackage::clone() const +-{ +- UMLPackage *clone = new UMLPackage(); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Adds an existing association to the matching concept in the list of concepts. +- * The selection of the matching concept depends on the association type: +- * For generalizations, the assoc is added to the concept that matches role A. +- * For aggregations and compositions, the assoc is added to the concept +- * that matches role B. +- * @param assoc the association to add +- */ +-void UMLPackage::addAssocToConcepts(UMLAssociation* assoc) +-{ +- if (! AssociationType::hasUMLRepresentation(assoc->getAssocType())) +- return; +- Uml::ID::Type AId = assoc->getObjectId(Uml::RoleType::A); +- Uml::ID::Type BId = assoc->getObjectId(Uml::RoleType::B); +- UMLObject *o = NULL; +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- o = oit.next(); +- UMLCanvasObject *c = dynamic_cast(o); +- if (c == NULL) +- continue; +- if (AId == c->id() || (BId == c->id())) { +- if (c->hasAssociation(assoc)) +- uDebug() << c->name() << " already has association id=" << Uml::ID::toString(assoc->id()); +- else +- c->addAssociationEnd(assoc); +- } +- UMLPackage *pkg = dynamic_cast(c); +- if (pkg) +- pkg->addAssocToConcepts(assoc); +- } +-} +- +-/** +- * Remove the association from the participating concepts. +- * @param assoc the association to remove +- */ +-void UMLPackage::removeAssocFromConcepts(UMLAssociation *assoc) +-{ +- UMLObject *o = 0; +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- o = oit.next(); +- UMLCanvasObject *c = dynamic_cast(o); +- if (c) { +- if (c->hasAssociation(assoc)) +- c->removeAssociationEnd(assoc); +- UMLPackage *pkg = dynamic_cast(c); +- if (pkg) +- pkg->removeAssocFromConcepts(assoc); +- } +- } +-} +- +-/** +- * Adds an object in this package. +- * +- * @param pObject Pointer to the UMLObject to add. +- * @return True if the object was actually added. +- */ +-bool UMLPackage::addObject(UMLObject *pObject) +-{ +- if (pObject == NULL) { +- uError() << "is called with a NULL object"; +- return false; +- } +- if (pObject == this) { +- uError() << "adding myself as child is not allowed"; +- return false; +- } +- +- if (m_objects.indexOf(pObject) != -1) { +- uDebug() << pObject->name() << " is already there"; +- return false; +- } +- if (pObject->baseType() == UMLObject::ot_Association) { +- UMLAssociation *assoc = static_cast(pObject); +- // Adding the UMLAssociation at the participating concepts is done +- // again later (in UMLAssociation::resolveRef()) if they are not yet +- // known right here. +- if (assoc->getObject(Uml::RoleType::A) && assoc->getObject(Uml::RoleType::B)) { +- UMLPackage *pkg = pObject->umlPackage(); +- if (pkg != this) { +- uError() << "UMLPackage " << name() << " addObject: " +- << "assoc's UMLPackage is " << pkg->name(); +- } +- addAssocToConcepts(assoc); +- } +- } +- else { +- QString name = pObject->name(); +- QString oldName = name; +- while (findObject(name) != NULL) { +- QString prevName = name; +- name = Model_Utils::uniqObjectName(pObject->baseType(), this); +- bool ok = Dialog_Utils::askName(i18nc("object name", "Name"), +- i18n("An object with the name %1\nalready exists in the package %2.\nPlease enter a new name:", prevName, this->name()), +- name); +- if (!ok) { +- name = oldName; +- continue; +- } +- if (name.length() == 0) { +- KMessageBox::error(0, i18n("That is an invalid name."), +- i18n("Invalid Name")); +- continue; +- } +- } +- if (oldName != name) { +- pObject->setName(name); +- } +- } +- m_objects.append(pObject); +- return true; +-} +- +-/** +- * Removes an object from this package. +- * Does not physically delete the object. +- * +- * @param pObject Pointer to the UMLObject to be removed. +- */ +-void UMLPackage::removeObject(UMLObject *pObject) +-{ +- if (pObject->baseType() == UMLObject::ot_Association) { +- UMLObject *o = const_cast(pObject); +- UMLAssociation *assoc = static_cast(o); +- removeAssocFromConcepts(assoc); +- } +- if (m_objects.indexOf(pObject) == -1) +- uDebug() << name() << " removeObject: object with id=" +- << Uml::ID::toString(pObject->id()) << "not found."; +- else +- m_objects.removeAll(pObject); +-} +- +-/** +- * Removes all objects from this package. +- * Inner containers (e.g. nested packages) are removed recursively. +- */ +-void UMLPackage::removeAllObjects() +-{ +- UMLCanvasObject::removeAllChildObjects(); +- UMLObject *o = NULL; +- +- while (!m_objects.isEmpty() && (o = m_objects.first()) != NULL) { +- UMLPackage *pkg = dynamic_cast(o); +- if (pkg) +- pkg->removeAllObjects(); +- removeObject(o); +- delete o; +- } +-} +- +-/** +- * Returns the list of objects contained in this package. +- */ +-UMLObjectList UMLPackage::containedObjects() +-{ +- return m_objects; +-} +- +-/** +- * Find the object of the given name in the list of contained objects. +- * +- * @param name The name to seek. +- * @return Pointer to the UMLObject found or NULL if not found. +- */ +-UMLObject * UMLPackage::findObject(const QString &name) +-{ +- const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- UMLObject *obj = oit.next(); +- if (!obj) +- continue; +- if (caseSensitive) { +- if (obj->name() == name) +- return obj; +- } else if (obj->name().toLower() == name.toLower()) { +- return obj; +- } +- } +- return NULL; +-} +- +-/** +- * Find the object of the given ID in the list of contained objects. +- * +- * @param id The ID to seek. +- * @return Pointer to the UMLObject found or NULL if not found. +- */ +-UMLObject * UMLPackage::findObjectById(Uml::ID::Type id) +-{ +- return Model_Utils::findObjectInList(id, m_objects); +-} +- +-/** +- * Append all packages from this package (and those from nested packages) +- * to the given UMLPackageList. +- * +- * @param packages The list to append to +- * @param includeNested Whether to include the packages from nested packages +- * (default:true) +- */ +-void UMLPackage::appendPackages(UMLPackageList& packages, bool includeNested) +-{ +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- UMLObject *o = oit.next(); +- uIgnoreZeroPointer(o); +- ObjectType ot = o->baseType(); +- if (ot == ot_Package || ot == ot_Folder) { +- packages.append(static_cast(o)); +- if (includeNested) { +- UMLPackage *inner = static_cast(o); +- inner->appendPackages(packages); +- } +- } +- } +-} +- +-/** +- * Append all classifiers from this package (and those from +- * nested packages) to the given UMLClassifierList. +- * +- * @param classifiers The list to append to. +- * @param includeNested Whether to include the classifiers from +- * nested packages (default: true.) +- */ +-void UMLPackage::appendClassifiers(UMLClassifierList& classifiers, +- bool includeNested /* = true */) +-{ +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- UMLObject *o = oit.next(); +- uIgnoreZeroPointer(o); +- ObjectType ot = o->baseType(); +- if (ot == ot_Class || ot == ot_Interface || +- ot == ot_Datatype || ot == ot_Enum || ot == ot_Entity) { +- classifiers.append((UMLClassifier *)o); +- } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { +- UMLPackage *inner = static_cast(o); +- inner->appendClassifiers(classifiers); +- } +- } +-} +- +-/** +- * Append all entities from this package (and those +- * from nested packages) to the given UMLEntityList. +- * +- * @param entities The list to append to. +- * @param includeNested Whether to include the entities from +- * nested packages (default: true.) +- */ +-void UMLPackage::appendEntities(UMLEntityList& entities, +- bool includeNested /* = true */) +-{ +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- UMLObject *o = oit.next(); +- uIgnoreZeroPointer(o); +- ObjectType ot = o->baseType(); +- if (ot == ot_Entity) { +- UMLEntity *c = static_cast(o); +- entities.append(c); +- } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { +- UMLPackage *inner = static_cast(o); +- inner->appendEntities(entities); +- } +- } +-} +- +-/** +- * Append all classes and interfaces from this package (and those +- * from nested packages) to the given UMLClassifierList. +- * +- * @param classifiers The list to append to. +- * @param includeNested Whether to include the classifiers from +- * nested packages (default: true.) +- */ +-void UMLPackage::appendClassesAndInterfaces(UMLClassifierList& classifiers, +- bool includeNested /* = true */) +-{ +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- UMLObject *o = oit.next(); +- uIgnoreZeroPointer(o); +- ObjectType ot = o->baseType(); +- if (ot == ot_Class || ot == ot_Interface) { +- UMLClassifier *c = static_cast(o); +- classifiers.append(c); +- } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { +- UMLPackage *inner = static_cast(o); +- inner->appendClassesAndInterfaces(classifiers); +- } +- } +-} +- +-/** +- * Resolve types. Required when dealing with foreign XMI files. +- * Needs to be called after all UML objects are loaded from file. +- * Overrides the method from UMLObject. +- * Calls resolveRef() on each contained object. +- * +- * @return True for overall success. +- */ +-bool UMLPackage::resolveRef() +-{ +- bool overallSuccess = UMLCanvasObject::resolveRef(); +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- UMLObject *obj = oit.next(); +- uIgnoreZeroPointer(obj); +- if (! obj->resolveRef()) { +- UMLObject::ObjectType ot = obj->baseType(); +- if (ot != UMLObject::ot_Package && ot != UMLObject::ot_Folder) +- m_objects.removeAll(obj); +- overallSuccess = false; +- } +- } +- return overallSuccess; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLPackage::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement packageElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); +- QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); +- UMLObject *obj = NULL; +- // save classifiers etc. +- for (UMLObjectListIt oit(m_objects); oit.hasNext();) { +- obj = oit.next(); +- uIgnoreZeroPointer(obj); +- obj->saveToXMI (qDoc, ownedElement); +- } +- // save associations +- for (UMLObjectListIt ait(m_List); ait.hasNext();) { +- obj = ait.next(); +- obj->saveToXMI (qDoc, ownedElement); +- } +- +- packageElement.appendChild(ownedElement); +- qElement.appendChild(packageElement); +-} +- +-/** +- * Loads the XMI element. +- * Auxiliary to UMLObject::loadFromXMI. +- */ +-bool UMLPackage::load(QDomElement& element) +-{ +- 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::isCommonXMIAttribute(type)) +- continue; +- if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || +- UMLDoc::tagEq(type, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe +- UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { +- //CHECK: umbrello-kf6 currently assumes that nested elements +- // are ownedElements anyway. +- // Therefore these tags are not further interpreted. +- if (! load(tempElement)) +- return false; +- continue; +- } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || +- UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { +- type = tempElement.attribute(QLatin1String("xmi:type")); +- } +- UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); +- if(!pObject) { +- uWarning() << "Unknown type of umlobject to create: " << type; +- continue; +- } +- pObject->setUMLPackage(this); +- if (!pObject->loadFromXMI(tempElement)) { +- removeObject(pObject); +- delete pObject; +- } +- } +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/package.h umbrello-kf6-15.08.1/umbrello/package.h +--- umbrello-kf6-15.08.1.orig/umbrello/package.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/package.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,79 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PACKAGE_H +-#define PACKAGE_H +- +-#include "umlcanvasobject.h" +-#include "umlclassifierlist.h" +-#include "umlentitylist.h" +- +-// forward declarations +-class UMLAssociation; +- +-/** +- * This class contains the non-graphical information required for a UML +- * Package. +- * This class inherits from @ref UMLCanvasObject which contains most of the +- * information. +- * +- * @short Non-graphical information for a Package. +- * @author Jonathan Riddell +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLPackage : public UMLCanvasObject +-{ +- Q_OBJECT +-public: +- explicit UMLPackage(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLPackage(); +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- bool addObject(UMLObject *pObject); +- void removeObject(UMLObject *pObject); +- +- virtual void removeAllObjects(); +- +- UMLObjectList containedObjects(); +- +- void addAssocToConcepts(UMLAssociation* assoc); +- void removeAssocFromConcepts(UMLAssociation *assoc); +- +- UMLObject * findObject(const QString &name); +- UMLObject * findObjectById(Uml::ID::Type id); +- +- void appendPackages(UMLPackageList& packages, bool includeNested = true); +- void appendClassifiers(UMLClassifierList& classifiers, +- bool includeNested = true); +- void appendClassesAndInterfaces(UMLClassifierList& classifiers, +- bool includeNested = true); +- void appendEntities(UMLEntityList& entities, +- bool includeNested = true); +- +- virtual bool resolveRef(); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-protected: +- virtual bool load(QDomElement& element); +- +- /** +- * References to the objects contained in this package. +- * The UMLPackage is the owner of the objects. +- */ +- UMLObjectList m_objects; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/port.cpp umbrello-kf6-15.08.1/umbrello/port.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/port.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/port.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,68 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "port.h" +- +-#include +- +-/** +- * Sets up a Port. +- * +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLPort::UMLPort(const QString & name, Uml::ID::Type id) +- : UMLCanvasObject(name, id) +-{ +- init(); +-} +- +-/** +- * Destructor. +- */ +-UMLPort::~UMLPort() +-{ +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLPort::init() +-{ +- m_BaseType = UMLObject::ot_Port; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLPort::clone() const +-{ +- UMLPort *clone = new UMLPort(); +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLPort::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement portElement = UMLObject::save(QLatin1String("UML:Port"), qDoc); +- qElement.appendChild(portElement); +-} +- +-/** +- * Loads the XMI element (empty.) +- */ +-bool UMLPort::load(QDomElement&) +-{ +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/port.h umbrello-kf6-15.08.1/umbrello/port.h +--- umbrello-kf6-15.08.1.orig/umbrello/port.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/port.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,46 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PORT_H +-#define PORT_H +- +-#include "umlcanvasobject.h" +- +-/** +- * This class contains the non-graphical information required for a UML Port. +- * This class inherits from @ref UMLCanvasObject which contains most of the +- * information. +- * +- * @short Non-graphical information for a Port. +- * @author Oliver Kellogg +- * @see UMLCanvasObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLPort : public UMLCanvasObject +-{ +- Q_OBJECT +-public: +- +- explicit UMLPort(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLPort(); +- +- virtual void init(); +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- +- bool load(QDomElement & element); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotype.cpp umbrello-kf6-15.08.1/umbrello/stereotype.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/stereotype.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/stereotype.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,164 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "stereotype.h" +- +-// local includes +-#include "debug_utils.h" +-#include "umldoc.h" +-#include "uml.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +- +-/** +- * 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() +-{ +-} +- +-/** +- * 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::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- //FIXME: uml13.dtd compliance +- QDomElement stereotypeElement = UMLObject::save(QLatin1String("UML:Stereotype"), qDoc); +- qElement.appendChild(stereotypeElement); +-} +- +-/** +- * Display the properties configuration dialog for the stereotype +- * (just a line edit). +- */ +-bool UMLStereotype::showPropertiesDialog(QWidget* parent) +-{ +- bool ok; +-#if QT_VERSION >= 0x050000 +- QString stereoTypeName = QInputDialog::getText(parent, +- i18n("Stereotype"), i18n("Enter name:"), +- QLineEdit::Normal, +- name(), &ok); +-#else +- QString stereoTypeName = KInputDialog::getText(i18n("Stereotype"), i18n("Enter name:"), name(), &ok, parent); +-#endif +- 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotype.h umbrello-kf6-15.08.1/umbrello/stereotype.h +--- umbrello-kf6-15.08.1.orig/umbrello/stereotype.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/stereotype.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,71 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef STEREOTYPE_H +-#define STEREOTYPE_H +- +-#include "umlobject.h" +- +-/** +- * This class is used to set up information for a stereotype. +- * Stereotypes are used essentially as properties of +- * attributes and operations etc. +- * +- * Each stereotype object is reference counted, i.e. client code +- * manages it such that it comes into existence as soon as there is +- * at least one user, and ceases existing when the number of users +- * drops to 0. +- * m_refCount reflects the number of users. It is externally managed, +- * i.e. client code must take care to call incrRefCount() and +- * decrRefCount() as appropriate. +- * +- * The one and only owner of all stereotypes is the UMLDoc, and the +- * ownership is specially managed (umlPackage() returns NULL for a +- * UMLStereotype.) The reason for this special treatment is that +- * class UMLDoc does not inherit from class UMLPackage, and therefore +- * setUMLPackage() cannot be used for stereotypes. +- * +- * @short Sets up stereotype information. +- * @author Jonathan Riddell +- * @author Oliver Kellogg +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLStereotype : public UMLObject +-{ +- Q_OBJECT +-public: +- explicit UMLStereotype(const QString &name, Uml::ID::Type id = Uml::ID::None); +- UMLStereotype(); +- +- virtual ~UMLStereotype(); +- +- bool operator==(const UMLStereotype &rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- void incrRefCount(); +- void decrRefCount(); +- +- int refCount() const; +- +- QString name(bool includeAdornments=false) const; +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent); +- +-protected: +- int m_refCount; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.cpp umbrello-kf6-15.08.1/umbrello/stereotypesmodel.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/stereotypesmodel.cpp 2015-10-08 11:48:59.505089026 +0300 +@@ -0,0 +1,121 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "stereotypesmodel.h" ++ ++// app includes ++#include "stereotype.h" ++#include "uml.h" ++#include "umldoc.h" ++ ++// kde includes ++#include ++ ++// qt includes ++#include ++ ++StereotypesModel::StereotypesModel(UMLStereotypeList *stereotypes) ++ : m_count(0), ++ m_stereotypes(stereotypes) ++{ ++} ++ ++int StereotypesModel::rowCount(const QModelIndex &parent) const ++{ ++ Q_UNUSED(parent); ++ ++ int count = m_stereotypes->count(); ++ return count; ++} ++ ++int StereotypesModel::columnCount(const QModelIndex &parent) const ++{ ++ Q_UNUSED(parent); ++ ++ return 2; ++} ++ ++QVariant StereotypesModel::headerData(int section, Qt::Orientation orientation, int role) const ++{ ++ if (section < 0) ++ return QVariant(); ++ ++ if (role != Qt::DisplayRole) ++ return QVariant(); ++ ++ if (orientation == Qt::Vertical) ++ return section + 1; ++ if (section == 0) ++ return QVariant(i18n("Name")); ++ else if (section == 1) ++ return QVariant(i18n("Usage")); ++ else return QVariant(); ++} ++ ++QVariant StereotypesModel::data(const QModelIndex & index, int role) const ++{ ++ if (role == Qt::UserRole && index.column() == 0) { ++ QVariant v; ++ v.setValue(m_stereotypes->at(index.row())); ++ return v; ++ } ++ ++ if (role != Qt::DisplayRole) ++ return QVariant(); ++ ++ int cCount = columnCount(index); ++ if (index.column() >= cCount) ++ return QVariant(); ++ ++ UMLStereotype *s = m_stereotypes->at(index.row()); ++ if (cCount == 1) { ++ QString a = s->name() + QString(QLatin1String(" (%1)")).arg(s->refCount()); ++ return a; ++ } ++ ++ // table view ++ if (index.column() == 0) ++ return s->name(); ++ else ++ return s->refCount(); ++} ++ ++bool StereotypesModel::addStereotype(UMLStereotype *stereotype) ++{ ++ if (m_stereotypes->contains(stereotype)) ++ return false; ++ int index = m_stereotypes->count(); ++ beginInsertRows(QModelIndex(), index, index); ++ m_stereotypes->append(stereotype); ++ endInsertRows(); ++ return true; ++} ++ ++bool StereotypesModel::removeStereotype(UMLStereotype *stereotype) ++{ ++ if (!m_stereotypes->contains(stereotype)) ++ return false; ++ int index = m_stereotypes->indexOf(stereotype); ++ beginRemoveRows(QModelIndex(), index, index); ++ m_stereotypes->removeAll(stereotype); ++ endRemoveRows(); ++ return true; ++} ++ ++void StereotypesModel::emitDataChanged(const QModelIndex &index) ++{ ++ emit dataChanged(index, index); ++} ++ ++void StereotypesModel::emitDataChanged(int index) ++{ ++ QModelIndex mi = createIndex(index,0); ++ emit dataChanged(mi, mi); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.h umbrello-kf6-15.08.1/umbrello/stereotypesmodel.h +--- umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/stereotypesmodel.h 2015-10-08 11:48:59.505089026 +0300 +@@ -0,0 +1,47 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef STEREOTYPESMODEL_H ++#define STEREOTYPESMODEL_H ++ ++// app includes ++#include "umlstereotypelist.h" ++ ++// qt includes ++#include ++ ++class UMLStereotype; ++ ++Q_DECLARE_METATYPE(UMLStereotype*); ++ ++class StereotypesModel : public QAbstractTableModel ++{ ++ Q_OBJECT ++public: ++ StereotypesModel(UMLStereotypeList *stereotypes); ++ ++ int rowCount(const QModelIndex &parent) const; ++ int columnCount(const QModelIndex &parent) const; ++ ++ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; ++ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; ++ ++ bool addStereotype(UMLStereotype *stereotype); ++ bool removeStereotype(UMLStereotype *stereotype); ++ ++ void emitDataChanged(const QModelIndex &index); ++ void emitDataChanged(int index); ++ ++protected: ++ int m_count; ++ UMLStereotypeList *m_stereotypes; ++}; ++ ++#endif // STEREOTYPESMODEL_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.cpp umbrello-kf6-15.08.1/umbrello/stereotypeswindow.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/stereotypeswindow.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,72 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "stereotypeswindow.h" ++ ++// app includes ++#include "stereotype.h" ++#include "stereotypesmodel.h" ++#include "uml.h" ++#include "umldoc.h" ++ ++// kde includes ++#include ++ ++// qt includes ++#include ++#include ++#include ++#include ++ ++StereotypesWindow::StereotypesWindow(QWidget *parent) ++ : QDockWidget(i18n("&Stereotypes"), 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() ++{ ++ delete m_stereotypesTree; ++} ++ ++void StereotypesWindow::modified() ++{ ++ UMLStereotype *o = static_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 = UMLApp::app()->document()->stereotypesModel()->data(index, Qt::UserRole); ++ if (v.canConvert()) { ++ UMLStereotype *s = v.value(); ++ s->showPropertiesDialog(this); ++ } ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.h umbrello-kf6-15.08.1/umbrello/stereotypeswindow.h +--- umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/stereotypeswindow.h 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,38 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef STEREOTYPESWINDOW_H ++#define STEREOTYPESWINDOW_H ++ ++#include ++#include ++ ++class QTableView; ++ ++class StereotypesWindow : public QDockWidget ++{ ++ Q_OBJECT ++public: ++ explicit StereotypesWindow(QWidget *parent = 0); ++ ~StereotypesWindow(); ++ ++signals: ++ ++public slots: ++ void modified(); ++ ++protected slots: ++ void slotStereotypesDoubleClicked(QModelIndex index); ++ ++protected: ++ QTableView *m_stereotypesTree; ++}; ++ ++#endif // STEREOTYPESWINDOW_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/template.cpp umbrello-kf6-15.08.1/umbrello/template.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/template.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/template.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,146 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "template.h" +- +-// app includes +-#include "debug_utils.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umltemplatedialog.h" +- +-/** +- * Sets up a template. +- * +- * @param parent The parent of this UMLTemplate (i.e. its concept). +- * @param name The name of this UMLTemplate. +- * @param id The unique id given to this UMLTemplate. +- * @param type The type of this UMLTemplate. +- */ +-UMLTemplate::UMLTemplate(UMLObject *parent, const QString& name, +- Uml::ID::Type id, const QString& type) +- : UMLClassifierListItem(parent, name, id) +-{ +- setTypeName(type); +- m_BaseType = UMLObject::ot_Template; +-} +- +-/** +- * Sets up a template. +- * +- * @param parent The parent of this UMLTemplate (i.e. its concept). +- */ +-UMLTemplate::UMLTemplate(UMLObject *parent) +- : UMLClassifierListItem(parent) +-{ +- m_BaseType = UMLObject::ot_Template; +-} +- +-/** +- * Destructor. +- */ +-UMLTemplate::~UMLTemplate() +-{ +-} +- +-QString UMLTemplate::toString(Uml::SignatureType::Enum sig) +-{ +- Q_UNUSED(sig); +- if (m_pSecondary == NULL || m_pSecondary->name() == QLatin1String("class")) { +- return name(); +- } else { +- return name() + QLatin1String(" : ") + m_pSecondary->name(); +- } +-} +- +-/** +- * Overrides method from UMLClassifierListItem. +- * Returns the type name of the UMLTemplate. +- * If the template parameter is a class, there is no separate +- * type object. In this case, getTypeName() returns "class". +- * +- * @return The type name of the UMLClassifierListItem. +- */ +-QString UMLTemplate::getTypeName() const +-{ +- if (m_pSecondary == NULL) +- return QLatin1String("class"); +- return m_pSecondary->name(); +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLTemplate::operator==(const UMLTemplate &rhs) const +-{ +- if (this == &rhs) { +- return true; +- } +- if (!UMLObject::operator==(rhs)) { +- return false; +- } +- if (m_pSecondary != rhs.m_pSecondary) { +- return false; +- } +- return true; +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLTemplate::copyInto(UMLObject *lhs) const +-{ +- UMLClassifierListItem::copyInto(lhs); +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLTemplate::clone() const +-{ +- UMLTemplate *clone = new UMLTemplate((UMLTemplate*) parent()); +- copyInto(clone); +- +- return clone; +-} +- +-/** +- * Writes the XMI element. +- */ +-void UMLTemplate::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- //FIXME: uml13.dtd compliance +- QDomElement attributeElement = UMLObject::save(QLatin1String("UML:TemplateParameter"), qDoc); +- if (m_pSecondary) +- attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); +- qElement.appendChild(attributeElement); +-} +- +-/** +- * Loads the XMI element. +- */ +-bool UMLTemplate::load(QDomElement& element) +-{ +- m_SecondaryId = element.attribute(QLatin1String("type")); +- return true; +-} +- +-/** +- * Display the properties configuration dialog for the template. +- * +- * @return Success status. +- */ +-bool UMLTemplate::showPropertiesDialog(QWidget* parent) +-{ +- UMLTemplateDialog dialog(parent, this); +- return dialog.exec(); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/template.h umbrello-kf6-15.08.1/umbrello/template.h +--- umbrello-kf6-15.08.1.orig/umbrello/template.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/template.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,57 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef TEMPLATE_H +-#define TEMPLATE_H +- +-#include "classifierlistitem.h" +- +-/** +- * This class holds information used by template classes, called +- * paramaterised class in UML and a generic in Java. It has a +- * type (usually just "class") and name. +- * +- * @short Sets up template information. +- * @author Jonathan Riddell +- * @see UMLObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLTemplate : public UMLClassifierListItem +-{ +-public: +- +- UMLTemplate(UMLObject *parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None, const QString& type = QLatin1String("class")); +- +- explicit UMLTemplate(UMLObject *parent); +- +- bool operator==(const UMLTemplate &rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- virtual ~UMLTemplate(); +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- virtual QString getTypeName() const; +- +- virtual bool showPropertiesDialog(QWidget* parent); +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- +- bool load(QDomElement & element); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umbrello-kf6ui.rc umbrello-kf6-15.08.1/umbrello/umbrello-kf6ui.rc +--- umbrello-kf6-15.08.1.orig/umbrello/umbrello-kf6ui.rc 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umbrello-kf6ui.rc 2015-10-08 11:48:59.506089026 +0300 +@@ -85,6 +85,7 @@ + + + ++ + + + +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlappprivate.h umbrello-kf6-15.08.1/umbrello/umlappprivate.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlappprivate.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlappprivate.h 2015-10-08 11:48:59.506089026 +0300 +@@ -15,8 +15,11 @@ + #include "finddialog.h" + #include "findresults.h" + #include "uml.h" ++#include "stereotypeswindow.h" + + // kde includes ++#include ++#include + #include + #include + #include +@@ -43,16 +46,18 @@ + { + Q_OBJECT + public: +- QWidget *parent; ++ UMLApp *parent; + FindDialog findDialog; + FindResults findResults; + QListWidget *logWindow; ///< Logging window. ++ KToggleAction *viewStereotypesWindow; ++ StereotypesWindow *stereotypesWindow; + + ktexteditor-kf6::Editor *editor; + ktexteditor-kf6::View *view; + ktexteditor-kf6::Document *document; + +- explicit UMLAppPrivate(QWidget *_parent) ++ explicit UMLAppPrivate(UMLApp *_parent) + : parent(_parent), + findDialog(_parent), + view(0), +@@ -101,6 +106,18 @@ + delete dialog; + delete document; + } ++ ++ void createStereotypesWindow() ++ { ++ // create the tree viewer ++ stereotypesWindow = new StereotypesWindow(parent); ++ parent->addDockWidget(Qt::LeftDockWidgetArea, stereotypesWindow); ++ ++ viewStereotypesWindow = parent->actionCollection()->add(QLatin1String("view_stereotypes_window")); ++ viewStereotypesWindow->setText(i18n("Stereotypes")); ++ connect(viewStereotypesWindow, SIGNAL(triggered(bool)), stereotypesWindow, SLOT(setVisible(bool))); ++ } ++ + }; + + #endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlassociationlist.h umbrello-kf6-15.08.1/umbrello/umlassociationlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlassociationlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlassociationlist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,23 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-2007 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLASSOCIATIONLIST_H +-#define UMLASSOCIATIONLIST_H +- +-#include +- +-// forward declaration +-class UMLAssociation; +- +-typedef QList UMLAssociationList; +-typedef QListIterator UMLAssociationListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlattributelist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,61 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "umlattributelist.h" +- +-#include "attribute.h" +- +-#include +- +-UMLAttributeList::UMLAttributeList() +-{ +-} +- +-UMLAttributeList::UMLAttributeList(const UMLAttributeList& other) +- : QList(other) +-{ +-} +- +-UMLAttributeList::~UMLAttributeList() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLAttributeList::copyInto(UMLAttributeList *rhs) const +-{ +- // Don't copy yourself. +- if (rhs == this) return; +- +- rhs->clear(); +- +- // Suffering from const; we shall not modify our object. +- UMLAttributeList *tmp = new UMLAttributeList(*this); +- +- UMLAttribute *item; +- for (UMLAttributeListIt ait(*tmp); ait.hasNext() ;) +- { +- item = ait.next(); +- rhs->append((UMLAttribute*)item->clone()); +- } +- delete tmp; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLAttributeList* UMLAttributeList::clone() const +-{ +- UMLAttributeList *clone = new UMLAttributeList(); +- copyInto(clone); +- return clone; +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.h umbrello-kf6-15.08.1/umbrello/umlattributelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlattributelist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,42 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLATTRIBUTELIST_H +-#define UMLATTRIBUTELIST_H +- +-#include +- +-#include "attribute.h" +- +-//typedef QPtrList UMLAttributeList; +-typedef QListIterator UMLAttributeListIt; +- +-/** +- * This sub-class adds copyInto and clone to the QPtrList +- * base class. +- */ +-class UMLAttributeList : public QList +-{ +-public: +- +- UMLAttributeList(); +- +- UMLAttributeList(const UMLAttributeList&); +- +- virtual ~UMLAttributeList(); +- +- virtual void copyInto(UMLAttributeList *rhs) const; +- +- virtual UMLAttributeList* clone() const; +-}; +- +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.cpp umbrello-kf6-15.08.1/umbrello/umlcanvasobject.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlcanvasobject.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,464 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "umlcanvasobject.h" +- +-// local includes +-#include "debug_utils.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "classifier.h" +-#include "association.h" +-#include "attribute.h" +-#include "operation.h" +-#include "template.h" +-#include "stereotype.h" +-#include "idchangelog.h" +- +-// kde includes +-#include +- +-DEBUG_REGISTER_DISABLED(UMLCanvasObject) +- +-/** +- * Sets up a UMLCanvasObject. +- * +- * @param name The name of the Concept. +- * @param id The unique id of the Concept. +- */ +-UMLCanvasObject::UMLCanvasObject(const QString & name, Uml::ID::Type id) +- : UMLObject(name, id) +-{ +-} +- +-/** +- * Standard deconstructor. +- */ +-UMLCanvasObject::~UMLCanvasObject() +-{ +- //removeAllAssociations(); +- // No! This is way too late to do that. +- // It should have been called explicitly before destructing the +- // UMLCanvasObject. +- if (associations()) +- DEBUG(DBG_SRC) << "UMLCanvasObject destructor: FIXME: there are still associations()"; +-} +- +-/** +- * Return the subset of m_List that matches the given type. +- * +- * @param assocType The AssociationType::Enum to match. +- * @return The list of associations that match assocType. +- */ +-UMLAssociationList UMLCanvasObject::getSpecificAssocs(Uml::AssociationType::Enum assocType) +-{ +- UMLAssociationList list; +- UMLObject *o = NULL; +- for (UMLObjectListIt oit(m_List); oit.hasNext();) { +- o = oit.next(); +- uIgnoreZeroPointer(o); +- if (o->baseType() != UMLObject::ot_Association) +- continue; +- UMLAssociation *a = static_cast(o); +- if (a->getAssocType() == assocType) +- list.append(a); +- } +- return list; +-} +- +-/** +- * Adds an association end to m_List. +- * +- * @param assoc The association to add. +- * @todo change param type to UMLRole +- */ +-bool UMLCanvasObject::addAssociationEnd(UMLAssociation* assoc) +-{ +- Q_ASSERT(assoc); +- // add association only if not already present in list +- if (!hasAssociation(assoc)) +- { +- m_List.append(assoc); +- +- // Don't emit signals during load from XMI +- UMLObject::emitModified(); +- emit sigAssociationEndAdded(assoc); +- return true; +- } +- return false; +-} +- +-/** +- * Determine if this canvasobject has the given association. +- * +- * @param assoc The association to check. +- */ +-bool UMLCanvasObject::hasAssociation(UMLAssociation* assoc) +-{ +- uint cnt = m_List.count(assoc); +- DEBUG(DBG_SRC) << "count is " << cnt; +- return (cnt > 0); +-} +- +-/** +- * Remove an association end from the CanvasObject. +- * +- * @param assoc The association to remove. +- * @todo change param type to UMLRole +- */ +-int UMLCanvasObject::removeAssociationEnd(UMLAssociation * assoc) +-{ +- if (!hasAssociation(assoc) || !m_List.removeAll(assoc)) { +- DEBUG(DBG_SRC) << "cannot find given assoc " << assoc << " in list"; +- return -1; +- } +- UMLApp::app()->document()->removeAssociation(assoc, false); +- UMLObject::emitModified(); +- emit sigAssociationEndRemoved(assoc); +- return m_List.count(); +-} +- +-/** +- * Remove all association ends from the CanvasObject. +- */ +-void UMLCanvasObject::removeAllAssociationEnds() +-{ +- for (int i = 0; i < m_List.count(); i++) { +- UMLObject *o = m_List.at(i); +- uIgnoreZeroPointer(o); +- if (o->baseType() != UMLObject::ot_Association) { +- continue; +- } +- UMLAssociation *assoc = static_cast(o); +- //umldoc->slotRemoveUMLObject(assoc); +- UMLObject* objA = assoc->getObject(Uml::RoleType::A); +- UMLObject* objB = assoc->getObject(Uml::RoleType::B); +- UMLCanvasObject *roleAObj = dynamic_cast(objA); +- if (roleAObj) { +- roleAObj->removeAssociationEnd(assoc); +- } else if (objA) { +- DEBUG(DBG_SRC) << name() << ": objA " << objA->name() << " is not a UMLCanvasObject"; +- } else +- DEBUG(DBG_SRC) << name() << "): objA is NULL"; +- UMLCanvasObject *roleBObj = dynamic_cast(objB); +- if (roleBObj) { +- roleBObj->removeAssociationEnd(assoc); +- } else if (objB) { +- DEBUG(DBG_SRC) << name() << "): objB " << objB->name() << " is not a UMLCanvasObject"; +- } else +- DEBUG(DBG_SRC) << name() << "): objB is NULL"; +- } +-} +- +-/** +- * Remove all child objects. +- * Just clear list, objects must be deleted where they were created +- * (or we have bad crashes). +- */ +-void UMLCanvasObject::removeAllChildObjects() +-{ +- if (!m_List.isEmpty()) { +- removeAllAssociationEnds(); +- m_List.clear(); +- } +-} +- +-/** +- * Returns a name for the new association, operation, template +- * or attribute appended with a number if the default name is +- * taken e.g. new_association, new_association_1 etc. +- * +- * @param type The object type for which to make a name. +- * @param prefix Optional prefix to use for the name. +- * If not given then uniqChildName() will choose the prefix +- * internally based on the object type. +- * @return Unique name string for the ObjectType given. +- */ +-QString UMLCanvasObject::uniqChildName(const UMLObject::ObjectType type, +- const QString &prefix /* = QString() */) +-{ +- QString currentName; +- currentName = prefix; +- if (currentName.isEmpty()) { +- switch (type) { +- case UMLObject::ot_Association: +- currentName = i18n("new_association"); +- break; +- case UMLObject::ot_Attribute: +- currentName = i18n("new_attribute"); +- break; +- case UMLObject::ot_Template: +- currentName = i18n("new_template"); +- break; +- case UMLObject::ot_Operation: +- currentName = i18n("new_operation"); +- break; +- case UMLObject::ot_EnumLiteral: +- currentName = i18n("new_literal"); +- break; +- case UMLObject::ot_EntityAttribute: +- currentName = i18n("new_field"); +- break; +- case UMLObject::ot_UniqueConstraint: +- currentName = i18n("new_unique_constraint"); +- break; +- case UMLObject::ot_ForeignKeyConstraint: +- currentName = i18n("new_fkey_constraint"); +- break; +- case UMLObject::ot_CheckConstraint: +- currentName = i18n("new_check_constraint"); +- break; +- default: +- uWarning() << "uniqChildName() called for unknown child type " << UMLObject::toString(type); +- return QLatin1String("ERROR_in_UMLCanvasObject_uniqChildName"); +- } +- } +- +- QString name = currentName; +- for (int number = 1; findChildObject(name); ++number) { +- name = currentName + QLatin1Char('_') + QString::number(number); +- } +- return name; +-} +- +-/** +- * Find a child object with the given name. +- * +- * @param n The name of the object to find. +- * @param t The type to find (optional.) If not given then +- * any object type will match. +- * @return Pointer to the object found; NULL if none found. +- */ +-UMLObject * UMLCanvasObject::findChildObject(const QString &n, UMLObject::ObjectType t) +-{ +- const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); +- UMLObject *obj = NULL; +- for (UMLObjectListIt oit(m_List); oit.hasNext();) { +- obj = oit.next(); +- uIgnoreZeroPointer(obj); +- if (t != UMLObject::ot_UMLObject && obj->baseType() != t) +- continue; +- if (caseSensitive) { +- if (obj->name() == n) +- return obj; +- } else if (obj->name().toLower() == n.toLower()) { +- return obj; +- } +- } +- return NULL; +-} +- +-/** +- * Find an association. +- * +- * @param id The id of the object to find. +- * @param considerAncestors boolean switch to consider ancestors while searching +- * @return Pointer to the object found (NULL if not found.) +- */ +-UMLObject* UMLCanvasObject::findChildObjectById(Uml::ID::Type id, bool considerAncestors) +-{ +- Q_UNUSED(considerAncestors); +- UMLObject *o = NULL; +- for (UMLObjectListIt oit(m_List); oit.hasNext();) { +- o = oit.next(); +- uIgnoreZeroPointer(o); +- if (o->id() == id) +- return o; +- } +- return 0; +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLCanvasObject::operator==(const UMLCanvasObject& rhs) const +-{ +- if (this == &rhs) { +- return true; +- } +- if (!UMLObject::operator==(rhs)) { +- return false; +- } +- if (m_List.count() != rhs.m_List.count()) { +- return false; +- } +- if (&m_List != &(rhs.m_List)) { +- return false; +- } +- return true; +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLCanvasObject::copyInto(UMLObject *lhs) const +-{ +- UMLObject::copyInto(lhs); +- +- // TODO Associations are not copied at the moment. This because +- // the duplicate function (on umlwidgets) do not copy the associations. +- // +- //target->m_List = m_List; +-} +- +-/** +- * Returns the number of associations for the CanvasObject. +- * This is the sum of the aggregations and compositions. +- * +- * @return The number of associations for the Concept. +- */ +-int UMLCanvasObject::associations() +-{ +- int count = 0; +- UMLObject *obj = NULL; +- for (UMLObjectListIt oit(m_List); oit.hasNext();) { +- obj = oit.next(); +- uIgnoreZeroPointer(obj); +- if (obj->baseType() == UMLObject::ot_Association) +- count++; +- } +- return count; +-} +- +-/** +- * Return the list of associations for the CanvasObject. +- * +- * @return The list of associations for the CanvasObject. +- */ +-UMLAssociationList UMLCanvasObject::getAssociations() +-{ +- UMLAssociationList assocs; +- UMLObject *o = NULL; +- for (UMLObjectListIt oit(m_List); oit.hasNext() ;) { +- o = oit.next(); +- uIgnoreZeroPointer(o); +- if (o->baseType() != UMLObject::ot_Association) +- continue; +- UMLAssociation *assoc = static_cast(o); +- assocs.append(assoc); +- } +- return assocs; +-} +- +-/** +- * Return a list of the superclasses of this concept. +- * TODO: This overlaps with UMLClassifier::findSuperClassConcepts(), +- * see if we can merge the two. +- * +- * @param withRealizations include realizations in the returned list (default=yes) +- * @return The list of superclasses for the concept. +- */ +-UMLClassifierList UMLCanvasObject::getSuperClasses(bool withRealizations) +-{ +- UMLClassifierList list; +- UMLAssociationList assocs = getAssociations(); +- foreach (UMLAssociation* a, assocs) { +- uIgnoreZeroPointer(a); +- if ((a->getAssocType() != Uml::AssociationType::Generalization && +- a->getAssocType() != Uml::AssociationType::Realization) || +- (!withRealizations && a->getAssocType() == Uml::AssociationType::Realization) || +- a->getObjectId(Uml::RoleType::A) != id()) +- continue; +- UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::B)); +- if (c) +- list.append(c); +- else +- DEBUG(DBG_SRC) << name() << ": generalization's other end is not a " +- << "UMLClassifier (id= " << Uml::ID::toString(a->getObjectId(Uml::RoleType::B)) << ")"; +- } +- return list; +-} +- +-/** +- * Return a list of the classes that inherit from this concept. +- * TODO: This overlaps with UMLClassifier::findSubClassConcepts(), +- * see if we can merge the two. +- * +- * @return The list of classes inheriting from the concept. +- */ +-UMLClassifierList UMLCanvasObject::getSubClasses() +-{ +- UMLClassifierList list; +- UMLAssociationList assocs = getAssociations(); +- foreach (UMLAssociation* a, assocs) { +- uIgnoreZeroPointer(a); +- if ((a->getAssocType() != Uml::AssociationType::Generalization && +- a->getAssocType() != Uml::AssociationType::Realization) || +- a->getObjectId(Uml::RoleType::B) != id()) +- continue; +- UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::A)); +- if (c) +- list.append(c); +- else +- DEBUG(DBG_SRC) << "specialization's other end is not a UMLClassifier" +- << " (id=" << Uml::ID::toString(a->getObjectId(Uml::RoleType::A)) << ")"; +- } +- return list; +-} +- +-/** +- * Shorthand for getSpecificAssocs(Uml::at_Realization) +- * +- * @return The list of realizations for the Concept. +- */ +-UMLAssociationList UMLCanvasObject::getRealizations() +-{ +- return getSpecificAssocs(Uml::AssociationType::Realization); +-} +- +-/** +- * Shorthand for getSpecificAssocs(Uml::at_Aggregation) +- * +- * @return The list of aggregations for the Concept. +- */ +-UMLAssociationList UMLCanvasObject::getAggregations() +-{ +- return getSpecificAssocs(Uml::AssociationType::Aggregation); +-} +- +-/** +- * Shorthand for getSpecificAssocs(Uml::at_Composition) +- * +- * @return The list of compositions for the Concept. +- */ +-UMLAssociationList UMLCanvasObject::getCompositions() +-{ +- return getSpecificAssocs(Uml::AssociationType::Composition); +-} +- +-/** +- * Shorthand for getSpecificAssocs(Uml::at_Relationship) +- * +- * @return The list of relationships for the entity. +- */ +-UMLAssociationList UMLCanvasObject::getRelationships() +-{ +- return getSpecificAssocs(Uml::AssociationType::Relationship); +-} +- +-/** +- * Reimplementation of UMLObject method. +- */ +-bool UMLCanvasObject::resolveRef() +-{ +- bool overallSuccess = UMLObject::resolveRef(); +- for (UMLObjectListIt ait(m_List); ait.hasNext();) { +- UMLObject *obj = ait.next(); +- uIgnoreZeroPointer(obj); +- if (! obj->resolveRef()) { +- m_List.removeAll(obj); +- overallSuccess = false; +- } +- } +- return overallSuccess; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.h umbrello-kf6-15.08.1/umbrello/umlcanvasobject.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlcanvasobject.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,108 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef CANVASOBJECT_H +-#define CANVASOBJECT_H +- +-#include "umlobject.h" +-#include "umlobjectlist.h" +-#include "umlclassifierlist.h" +-#include "umlassociationlist.h" +- +-/** +- * This class contains the non-graphical information required for UMLObjects +- * which appear as moveable widgets on the scene. +- * +- * This class inherits from @ref UMLObject which contains most of the +- * information. +- * It is not instantiated itself, it's just used as a super class for +- * actual model objects. +- * +- * @short Non-graphical information for a UMLCanvasObject. +- * @author Jonathan Riddell +- * @see UMLObject +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLCanvasObject : public UMLObject +-{ +- Q_OBJECT +- +-public: +- explicit UMLCanvasObject(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLCanvasObject(); +- +- bool operator==(const UMLCanvasObject& rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- // The abstract method UMLObject::clone() is implemented +- // in the classes inheriting from UMLCanvasObject. +- +- bool addAssociationEnd(UMLAssociation* assoc); +- +- bool hasAssociation(UMLAssociation* assoc); +- +- int removeAssociationEnd(UMLAssociation *assoc); +- +- void removeAllAssociationEnds(); +- +- int associations(); +- +- UMLAssociationList getAssociations(); +- +- UMLAssociationList getSpecificAssocs(Uml::AssociationType::Enum assocType); +- +- UMLClassifierList getSuperClasses(bool withRealizations = true); +- UMLClassifierList getSubClasses(); +- +- virtual UMLAssociationList getRealizations(); +- +- UMLAssociationList getAggregations(); +- UMLAssociationList getCompositions(); +- UMLAssociationList getRelationships(); +- +- virtual UMLObject *findChildObject(const QString &n, +- UMLObject::ObjectType t = UMLObject::ot_UMLObject); +- virtual UMLObject *findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); +- +- virtual QString uniqChildName(const UMLObject::ObjectType type, +- const QString &prefix = QString()); +- +- virtual void removeAllChildObjects(); +- +- UMLObjectList subordinates() const { +- return m_List; +- } +- +- virtual bool resolveRef(); +- +- // The abstract method UMLObject::saveToXMI() is implemented +- // in the classes inheriting from UMLCanvasObject. +- +-protected: +- +- /** +- * List of all the associations in this object. +- * Inheriting classes add more types of objects that are possible in this list; +- * for example, UMLClassifier adds operations, attributes, and templates. +- * +- * @todo Only a pointer to the appropriate assocation end object +- * (UMLRole) should be saved here, not the entire UMLAssociation. +- */ +- UMLObjectList m_List; +- +-signals: +- +- void sigAssociationEndAdded(UMLAssociation * assoc); +- void sigAssociationEndRemoved(UMLAssociation * assoc); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlist.h umbrello-kf6-15.08.1/umbrello/umlclassifierlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlclassifierlist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,22 +0,0 @@ +-/*************************************************************************** +- * 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-2010 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLCLASSIFIERLIST_H +-#define UMLCLASSIFIERLIST_H +- +-#include +- +-// forward declaration +-class UMLClassifier; +- +-typedef QList UMLClassifierList; +-typedef QListIterator UMLClassifierListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.cpp umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,60 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "umlclassifierlistitemlist.h" +- +-#include "classifierlistitem.h" +- +-#include +- +-UMLClassifierListItemList::UMLClassifierListItemList() +-{ +-} +- +-UMLClassifierListItemList::UMLClassifierListItemList(const UMLClassifierListItemList& other) +- : QList(other) +-{ +-} +- +-UMLClassifierListItemList::~UMLClassifierListItemList() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLClassifierListItemList::copyInto(UMLClassifierListItemList *rhs) const +-{ +- // Prevent copying to yourself. (Can cause serious injuries) +- if (rhs == this) return; +- +- rhs->clear(); +- +- // Suffering from const; we shall not modify our object. +- UMLClassifierListItemList *tmp = new UMLClassifierListItemList(*this); +- +- UMLClassifierListItem *item; +- for (UMLClassifierListItemListIt clit(*tmp); clit.hasNext() ;) { +- item = clit.next(); +- rhs->append((UMLClassifierListItem*)item->clone()); +- } +- delete tmp; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLClassifierListItemList* UMLClassifierListItemList::clone() const +-{ +- UMLClassifierListItemList *clone = new UMLClassifierListItemList(); +- copyInto(clone); +- return clone; +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.h umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,41 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLCLASSIFIERLISTITEMLIST_H +-#define UMLCLASSIFIERLISTITEMLIST_H +- +-#include +- +-// forward declaration +-class UMLClassifierListItem; +- +-//typedef QPtrList UMLClassifierListItemList; +-typedef QListIterator UMLClassifierListItemListIt; +- +-/** +- * This sub-class adds copyInto and clone to the QPtrList +- * base class. +- */ +-class UMLClassifierListItemList : public QList +-{ +-public: +- +- UMLClassifierListItemList(); +- UMLClassifierListItemList(const UMLClassifierListItemList& other); +- +- virtual ~UMLClassifierListItemList(); +- +- virtual void copyInto (UMLClassifierListItemList *rhs) const; +- +- virtual UMLClassifierListItemList* clone() const; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/uml.cpp umbrello-kf6-15.08.1/umbrello/uml.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/uml.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/uml.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -240,15 +240,15 @@ + delete m_clipTimer; + delete m_copyTimer; + delete m_commoncodegenpolicy; +- delete m_d; +- delete m_doc; + delete m_imageExporterAll; +- delete m_listView; + delete m_printer; + delete m_policyext; + delete m_pUndoStack; + delete m_refactoringAssist; + delete m_xhtmlGenerator; ++ delete m_listView; ++ delete m_doc; ++ delete m_d; + } + + /** +@@ -918,6 +918,8 @@ + widget->setLayout(m_layout); + setCentralWidget(widget); + ++ m_d->createStereotypesWindow(); ++ + // create the tree viewer + m_listDock = new QDockWidget(i18n("&Tree View"), this); + m_listDock->setObjectName(QLatin1String("TreeViewDock")); +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umldoc.cpp umbrello-kf6-15.08.1/umbrello/umldoc.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umldoc.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umldoc.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -44,6 +44,7 @@ + #include "umlscene.h" + #include "version.h" + #include "worktoolbar.h" ++#include "stereotypesmodel.h" + + // kde includes + #include +@@ -113,7 +114,8 @@ + m_nViewID(Uml::ID::None), + m_bTypesAreResolved(true), + m_pCurrentRoot(0), +- m_bClosing(false) ++ m_bClosing(false), ++ m_stereotypesModel(new StereotypesModel(&m_stereoList)) + { + for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) + m_root[i] = 0; +@@ -190,6 +192,7 @@ + } + delete m_pChangeLog; + qDeleteAll(m_stereoList); ++ delete m_stereotypesModel; + } + + /** +@@ -402,18 +405,19 @@ + // @fixme With advanced code generation enabled, this crashes. + removeAllObjects(); + ++ // Remove any stereotypes. ++ if (stereotypes().count() > 0) { ++ foreach(UMLStereotype *s, stereotypes()) { ++ m_stereotypesModel->removeStereotype(s); ++ delete s; ++ } ++ m_stereoList.clear(); ++ } ++ + // Restore the datatype folder, it has been deleted above. + createDatatypeFolder(); + // this creates to much items only Logical View should be created + listView->init(); +- /* Remove any stereotypes. +- if (m_stereoList.count() > 0) { +- UMLStereotype *s; +- for (UMLStereotypeListIt sit(m_stereoList); (s = sit.current()) != 0; ++sit) +- delete s; +- m_stereoList.clear(); +- } +- */ + } + m_bClosing = false; + } +@@ -1268,9 +1272,8 @@ + */ + void UMLDoc::addStereotype(UMLStereotype *s) + { +- if (! m_stereoList.contains(s)) { +- m_stereoList.append(s); +- } ++ if (m_stereotypesModel->addStereotype(s)) ++ emit sigObjectCreated(s); + } + + /** +@@ -1279,9 +1282,8 @@ + */ + void UMLDoc::removeStereotype(UMLStereotype *s) + { +- if (m_stereoList.contains(s)) { +- m_stereoList.removeAll(s); +- } ++ if (m_stereotypesModel->removeStereotype(s)) ++ emit sigObjectRemoved(s); + } + + /** +@@ -2444,6 +2446,11 @@ + qApp->processEvents(); // give UI events a chance + } + ++StereotypesModel *UMLDoc::stereotypesModel() ++{ ++ return m_stereotypesModel; ++} ++ + /** + * Ensures the XMI file is a valid UML file. + * Currently only checks for metamodel=UML. +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umldoc.h umbrello-kf6-15.08.1/umbrello/umldoc.h +--- umbrello-kf6-15.08.1.orig/umbrello/umldoc.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umldoc.h 2015-10-08 11:48:59.506089026 +0300 +@@ -48,6 +48,7 @@ + class QPrinter; + + class IDChangeLog; ++class StereotypesModel; + class UMLPackage; + class UMLFolder; + class DiagramPrintPage; +@@ -233,6 +234,8 @@ + + void resolveTypes(); + ++ StereotypesModel *stereotypesModel(); ++ + private: + void initSaveTimer(); + void createDatatypeFolder(); +@@ -308,6 +311,8 @@ + */ + bool m_bClosing; + ++ StereotypesModel *m_stereotypesModel; ++ + public slots: + void slotRemoveUMLObject(UMLObject*o); + void slotAutoSave(); +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlentityattributelist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlentityattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,60 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "umlentityattributelist.h" +- +-#include "entityattribute.h" +- +-#include +- +-UMLEntityAttributeList::UMLEntityAttributeList() +-{ +-} +- +-UMLEntityAttributeList::UMLEntityAttributeList(const UMLEntityAttributeList& other) +- : QList(other) +-{ +-} +- +-UMLEntityAttributeList::~UMLEntityAttributeList() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLEntityAttributeList::copyInto(UMLEntityAttributeList* rhs) const +-{ +- // Don't copy yourself. +- if (rhs == this) return; +- +- rhs->clear(); +- +- // Suffering from const; we shall not modify our object. +- UMLEntityAttributeList* tmp = new UMLEntityAttributeList(*this); +- +- UMLEntityAttribute* item; +- for (UMLEntityAttributeListIt eait(*tmp); eait.hasNext() ;) { +- item = eait.next(); +- rhs->append((UMLEntityAttribute*)item->clone()); +- } +- delete tmp; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLEntityAttributeList* UMLEntityAttributeList::clone() const +-{ +- UMLEntityAttributeList *clone = new UMLEntityAttributeList(); +- copyInto(clone); +- return clone; +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.h umbrello-kf6-15.08.1/umbrello/umlentityattributelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlentityattributelist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,41 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLENTITYATTRIBUTELIST_H +-#define UMLENTITYATTRIBUTELIST_H +- +-#include +-#include "entityattribute.h" +- +-//typedef QPtrList UMLEntityAttributeList; +-typedef QListIterator UMLEntityAttributeListIt; +- +-/** +- * This sub-class adds copyInto and clone to the QPtrList +- * base class. +- */ +-class UMLEntityAttributeList : public QList +-{ +-public: +- +- UMLEntityAttributeList(); +- +- UMLEntityAttributeList(const UMLEntityAttributeList&); +- +- virtual ~UMLEntityAttributeList(); +- +- virtual void copyInto (UMLEntityAttributeList* rhs) const; +- +- virtual UMLEntityAttributeList* clone() const; +-}; +- +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.cpp umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,60 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "umlentityconstraintlist.h" +- +-#include "entityconstraint.h" +- +-#include +- +-UMLEntityConstraintList::UMLEntityConstraintList() +-{ +-} +- +-UMLEntityConstraintList::UMLEntityConstraintList(const UMLEntityConstraintList& other) +- : QList(other) +-{ +-} +- +-UMLEntityConstraintList::~UMLEntityConstraintList() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLEntityConstraintList::copyInto(UMLEntityConstraintList* rhs) const +-{ +- // Don't copy yourself. +- if (rhs == this) return; +- +- rhs->clear(); +- +- // Suffering from const; we shall not modify our object. +- UMLEntityConstraintList* tmp = new UMLEntityConstraintList(*this); +- +- UMLEntityConstraint* item; +- for (UMLEntityConstraintListIt ecit(*tmp); ecit.hasNext() ;) { +- item = ecit.next(); +- rhs->append((UMLEntityConstraint*)item->clone()); +- } +- delete tmp; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLEntityConstraintList* UMLEntityConstraintList::clone() const +-{ +- UMLEntityConstraintList *clone = new UMLEntityConstraintList(); +- copyInto(clone); +- return clone; +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.h umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,43 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLENTITYCONSTRAINTLIST_H +-#define UMLENTITYCONSTRAINTLIST_H +- +-#include +- +-// forward declaration +-class UMLEntityConstraint; +- +- +-typedef QListIterator UMLEntityConstraintListIt; +- +-/** +- * This sub-class adds copyInto and clone to the QPtrList +- * base class. +- */ +-class UMLEntityConstraintList : public QList +-{ +-public: +- +- UMLEntityConstraintList(); +- +- UMLEntityConstraintList(const UMLEntityConstraintList&); +- +- virtual ~UMLEntityConstraintList(); +- +- virtual void copyInto (UMLEntityConstraintList* rhs) const; +- +- virtual UMLEntityConstraintList* clone() const; +-}; +- +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentitylist.h umbrello-kf6-15.08.1/umbrello/umlentitylist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlentitylist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlentitylist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,22 +0,0 @@ +-/*************************************************************************** +- * 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-2010 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLENTITYLIST_H +-#define UMLENTITYLIST_H +- +-#include +- +-// forward declaration +-class UMLEntity; +- +-typedef QList UMLEntityList; +-typedef QListIterator UMLEntityListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlenumliterallist.h umbrello-kf6-15.08.1/umbrello/umlenumliterallist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlenumliterallist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlenumliterallist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,23 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-2007 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLENUMLITERALLIST_H +-#define UMLENUMLITERALLIST_H +- +-#include +- +-// forward declaration +-class UMLEnumLiteral; +- +-typedef QList UMLEnumLiteralList; +-typedef QListIterator UMLEnumLiteralListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umllistview.cpp umbrello-kf6-15.08.1/umbrello/umllistview.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umllistview.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umllistview.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -2161,6 +2161,11 @@ + QString name = classifier->uniqChildName(objectType); + UMLObject* object = Object_Factory::createChildObject(classifier, objectType, name); + ++ if (object == 0) { ++ // creation was cancelled by the user ++ return; ++ } ++ + // Handle primary key constraints (mark the unique constraint as PK on + // the parent entity) + if (type == UMLListViewItem::lvt_PrimaryKeyConstraint) { +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/actor.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/actor.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,67 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "actor.h" ++ ++/** ++ * Constructs an Actor. ++ * ++ * @param name The name of the Actor. ++ * @param id The unique id to assign to this Actor. ++ */ ++UMLActor::UMLActor(const QString & name, Uml::ID::Type id) ++ : UMLCanvasObject(name, id) ++{ ++ init(); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLActor::~UMLActor() ++{ ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLActor::init() ++{ ++ m_BaseType = UMLObject::ot_Actor; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLActor::clone() const ++{ ++ UMLActor *clone = new UMLActor(); ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLActor::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement actorElement = UMLObject::save(QLatin1String("UML:Actor"), qDoc); ++ qElement.appendChild(actorElement); ++} ++ ++/** ++ * Loads the XMI element (empty). ++ */ ++bool UMLActor::load(QDomElement& element) ++{ ++ Q_UNUSED(element); ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.h umbrello-kf6-15.08.1/umbrello/umlmodel/actor.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/actor.h 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,44 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ACTOR_H ++#define ACTOR_H ++ ++#include "umlcanvasobject.h" ++ ++/** ++ * This class contains the non-graphical information required for a UML Actor. ++ * This class inherits from @ref UMLCanvasObject which contains most of the ++ * information. ++ * The @ref UMLDoc class creates instances of this type. ++ * ++ * @short Information for a non-graphical UML Actor. ++ * @author Paul Hensgen ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLActor : public UMLCanvasObject ++{ ++ Q_OBJECT ++public: ++ explicit UMLActor(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLActor(); ++ ++ virtual void init(); ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ bool load(QDomElement & element); ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,90 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "artifact.h" ++#include "association.h" ++#include "clipboard/idchangelog.h" ++ ++#include ++ ++/** ++ * Sets up an Artifact. ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLArtifact::UMLArtifact(const QString & name, Uml::ID::Type id) ++ : UMLPackage(name, id), ++ m_drawAsType(defaultDraw) ++{ ++ m_BaseType = UMLObject::ot_Artifact; ++} ++ ++/** ++ * Standard deconstructor. ++ */ ++UMLArtifact::~UMLArtifact() ++{ ++} ++ ++/** ++ * Make a clone of this object. ++ * @return the cloned object ++ */ ++UMLObject* UMLArtifact::clone() const ++{ ++ UMLArtifact *clone = new UMLArtifact(); ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the UML:Artifact element including its operations, ++ * attributes and templates ++ * @param qDoc the xml document ++ * @param qElement the xml element ++ */ ++void UMLArtifact::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement artifactElement = UMLObject::save(QLatin1String("UML:Artifact"), qDoc); ++ artifactElement.setAttribute(QLatin1String("drawas"), m_drawAsType); ++ qElement.appendChild(artifactElement); ++} ++ ++/** ++ * Loads the UML:Artifact element including its operations, ++ * attributes and templates. ++ * @param element the xml element to load ++ * @return the success status of the operation ++ */ ++bool UMLArtifact::load(QDomElement& element) ++{ ++ QString drawAs = element.attribute(QLatin1String("drawas"), QLatin1String("0")); ++ m_drawAsType = (Draw_Type)drawAs.toInt(); ++ return true; ++} ++ ++/** ++ * Sets m_drawAsType for which method to draw the artifact as. ++ * @param type the draw type ++ */ ++void UMLArtifact::setDrawAsType(Draw_Type type) ++{ ++ m_drawAsType = type; ++} ++ ++/** ++ * Returns the value of m_drawAsType. ++ * @return the value of the draw type attribute ++ */ ++UMLArtifact::Draw_Type UMLArtifact::getDrawAsType() ++{ ++ return m_drawAsType; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.h umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.h 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,66 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ARTIFACT_H ++#define ARTIFACT_H ++ ++#include "package.h" ++ ++/** ++ * This class contains the non-graphical information required for a UML ++ * Artifact. ++ * This class inherits from @ref UMLCanvasObject which contains most of the ++ * information. ++ * ++ * @short Non-graphical information for a Artifact. ++ * @author Jonathan Riddell ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLArtifact : public UMLPackage ++{ ++ Q_OBJECT ++public: ++ ++ /** ++ * Artifacts can be drawn using one of several icons. ++ */ ++ enum Draw_Type { ++ defaultDraw, ++ file, ++ library, ++ table ++ }; ++ ++ explicit UMLArtifact(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLArtifact(); ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ void setDrawAsType(Draw_Type type); ++ ++ Draw_Type getDrawAsType(); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++private: ++ ++ /** ++ * Artifacts can be drawn as one of several different icons, ++ * this value choosing how to draw them. ++ */ ++ Draw_Type m_drawAsType; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/association.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/association.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,742 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "association.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "classifier.h" ++#include "classpropertiesdialog.h" ++#include "folder.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlrole.h" ++#include "uniqueid.h" ++#include "model_utils.h" ++#include "cmds.h" ++ ++// kde includes ++#include ++ ++// qt includes ++#include ++#include ++ ++using namespace Uml; ++ ++DEBUG_REGISTER(UMLAssociation) ++ ++/** ++ * Sets up an association. ++ * A new unique ID is assigned internally. ++ * @param type The AssociationType::Enum to construct. ++ * @param roleA Pointer to the UMLObject in role A. ++ * @param roleB Pointer to the UMLObject in role B. ++ */ ++UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type, ++ UMLObject * roleA, UMLObject * roleB) ++ : UMLObject(QString()) ++{ ++ init(type, roleA, roleB); ++ ++ m_pRole[RoleType::A]->setID(UniqueID::gen()); ++ m_pRole[RoleType::B]->setID(UniqueID::gen()); ++} ++ ++/** ++ * Constructs an association - for loading only. ++ * This constructor should not normally be used as it constructs ++ * an incomplete association (i.e. the role objects are missing.) ++ * @param type The AssociationType::Enum to construct. ++ * Default: Unknown. ++ */ ++UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type) ++ : UMLObject(QString(), Uml::ID::Reserved) ++{ ++ init(type, NULL, NULL); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLAssociation::~UMLAssociation() ++{ ++ if (m_pRole[RoleType::A] == NULL) { ++ uError() << "UMLAssociation destructor: m_pRole[A] is NULL already"; ++ } else { ++ delete m_pRole[RoleType::A]; ++ m_pRole[RoleType::A] = NULL; ++ } ++ if (m_pRole[RoleType::B] == NULL) { ++ uError() << "UMLAssociation destructor: m_pRole[B] is NULL already"; ++ } else { ++ delete m_pRole[RoleType::B]; ++ m_pRole[RoleType::B] = NULL; ++ } ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLAssociation::operator==(const UMLAssociation &rhs) const ++{ ++ if (this == &rhs) { ++ return true; ++ } ++ return (UMLObject::operator== (rhs) && ++ m_AssocType == rhs.m_AssocType && ++ m_Name == rhs.m_Name && ++ m_pRole[RoleType::A] == rhs.m_pRole[RoleType::A] && ++ m_pRole[RoleType::B] == rhs.m_pRole[RoleType::B]); ++} ++ ++/** ++ * Returns the AssociationType::Enum of the UMLAssociation. ++ * @return The AssociationType::Enum of the UMLAssociation. ++ */ ++Uml::AssociationType::Enum UMLAssociation::getAssocType() const ++{ ++ return m_AssocType; ++} ++ ++/** ++ * Returns a String representation of this UMLAssociation. ++ */ ++QString UMLAssociation::toString() const ++{ ++ QString string; ++ if(m_pRole[RoleType::A]) ++ { ++ string += m_pRole[RoleType::A]->object()->name(); ++ string += QLatin1Char(':'); ++ string += m_pRole[RoleType::A]->name(); ++ } ++ string += QLatin1Char(':') + Uml::AssociationType::toStringI18n(m_AssocType) + QLatin1Char(':'); ++ if(m_pRole[RoleType::B]) ++ { ++ string += m_pRole[RoleType::B]->object()->name(); ++ string += QLatin1Char(':'); ++ string += m_pRole[RoleType::B]->name(); ++ } ++ return string; ++} ++ ++/** ++ * Resolve types. Required when dealing with foreign XMI files. ++ * Needs to be called after all UML objects are loaded from file. ++ * Overrides the method from UMLObject. ++ * Calls resolveRef() for each role. ++ * @return True for success. ++ */ ++bool UMLAssociation::resolveRef() ++{ ++ bool successA = getUMLRole(RoleType::A)->resolveRef(); ++ bool successB = getUMLRole(RoleType::B)->resolveRef(); ++ if (successA && successB) { ++ UMLObject *objA = getUMLRole(RoleType::A)->object(); ++ UMLObject *objB = getUMLRole(RoleType::B)->object(); ++ // Check if need to change the assoc type to Realization ++ if (isRealization(objA, objB)) { ++ m_AssocType = Uml::AssociationType::Realization; ++ } ++ m_pUMLPackage->addAssocToConcepts(this); ++ return true; ++ } ++ return false; ++} ++ ++/** ++ * Creates the or XMI element ++ * including its role objects. ++ */ ++void UMLAssociation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ if (m_AssocType == Uml::AssociationType::Generalization) { ++ QDomElement assocElement = UMLObject::save(QLatin1String("UML:Generalization"), qDoc); ++ assocElement.setAttribute(QLatin1String("discriminator"), QString()); ++ assocElement.setAttribute(QLatin1String("child"), Uml::ID::toString(getObjectId(RoleType::A))); ++ assocElement.setAttribute(QLatin1String("parent"), Uml::ID::toString(getObjectId(RoleType::B))); ++ qElement.appendChild(assocElement); ++ return; ++ } ++ if (m_AssocType == Uml::AssociationType::Realization) { ++ QDomElement assocElement = UMLObject::save(QLatin1String("UML:Abstraction"), qDoc); ++ assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); ++ assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); ++ qElement.appendChild(assocElement); ++ return; ++ } ++ if (m_AssocType == Uml::AssociationType::Dependency) { ++ QDomElement assocElement = UMLObject::save(QLatin1String("UML:Dependency"), qDoc); ++ assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); ++ assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); ++ qElement.appendChild(assocElement); ++ return; ++ } ++ if (m_AssocType == Uml::AssociationType::Child2Category) { ++ QDomElement assocElement = UMLObject::save(QLatin1String("UML:Child2Category"), qDoc); ++ assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); ++ assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); ++ qElement.appendChild(assocElement); ++ return; ++ } ++ if (m_AssocType == Uml::AssociationType::Category2Parent) { ++ QDomElement assocElement = UMLObject::save(QLatin1String("UML:Category2Parent"), qDoc); ++ assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); ++ assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); ++ qElement.appendChild(assocElement); ++ return; ++ } ++ ++ QDomElement associationElement = UMLObject::save(QLatin1String("UML:Association"), qDoc); ++ QDomElement connElement = qDoc.createElement(QLatin1String("UML:Association.connection")); ++ getUMLRole(RoleType::A)->saveToXMI (qDoc, connElement); ++ getUMLRole(RoleType::B)->saveToXMI (qDoc, connElement); ++ associationElement.appendChild (connElement); ++ qElement.appendChild(associationElement); ++} ++ ++bool UMLAssociation::showPropertiesDialog(QWidget *parent) ++{ ++ QPointer dlg = new ClassPropertiesDialog(parent, this, true); ++ bool modified = false; ++ if (dlg->exec()) { ++ modified = true; ++ } ++ dlg->close(); ++ delete dlg; ++ return modified; ++} ++ ++/** ++ * Creates the or XMI element ++ * including its role objects. ++ */ ++bool UMLAssociation::load(QDomElement & element) ++{ ++ if (id() == Uml::ID::None) ++ return false; // old style XMI file. No real info in this association. ++ ++ UMLDoc * doc = UMLApp::app()->document(); ++ UMLObject * obj[2] = { NULL, NULL }; ++ if (m_AssocType == Uml::AssociationType::Generalization || ++ m_AssocType == Uml::AssociationType::Realization || ++ m_AssocType == Uml::AssociationType::Dependency || ++ m_AssocType == Uml::AssociationType::Child2Category || ++ m_AssocType == Uml::AssociationType::Category2Parent) { ++ QString general = element.attribute(QLatin1String("general")); ++ if (!general.isEmpty()) { ++ UMLClassifier *owningClassifier = dynamic_cast(m_pUMLPackage); ++ if (owningClassifier == NULL){ ++ uWarning() << "Cannot load UML2 generalization: m_pUMLPackage is expected " ++ << "to be the owning classifier (=client)"; ++ return false; ++ } ++ m_pRole[RoleType::A]->setObject(owningClassifier); ++ m_pRole[RoleType::B]->setSecondaryId(general); // defer resolution to resolveRef() ++ owningClassifier->addAssociationEnd(this); ++ m_pUMLPackage = m_pUMLPackage->umlPackage(); // reparent ++ m_pUMLPackage->addObject(this); ++ return true; ++ } ++ for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { ++ const QString fetch = (m_AssocType == Uml::AssociationType::Generalization ? ++ r == RoleType::A ? QLatin1String("child") : QLatin1String("parent") ++ : r == RoleType::A ? QLatin1String("client") : QLatin1String("supplier")); ++ QString roleIdStr = element.attribute(fetch); ++ if (roleIdStr.isEmpty()) { ++ // Might be given as a child node instead - see below. ++ continue; ++ } ++ ++ // set umlobject of role if possible (else defer resolution) ++ obj[r] = doc->findObjectById(Uml::ID::fromString(roleIdStr)); ++ Uml::RoleType::Enum role = Uml::RoleType::fromInt(r); ++ if (obj[r] == NULL) { ++ m_pRole[role]->setSecondaryId(roleIdStr); // defer to resolveRef() ++ } else { ++ m_pRole[role]->setObject(obj[r]); ++ if (m_pUMLPackage == NULL) { ++ Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(obj[r]->baseType()); ++ m_pUMLPackage = doc->rootFolder(mt); ++ DEBUG(DBG_SRC) << "assoctype " << m_AssocType ++ << ": setting model type " << Uml::ModelType::toString(mt); ++ } ++ } ++ } ++ if (obj[RoleType::A] == NULL || obj[RoleType::B] == NULL) { ++ for (QDomNode node = element.firstChild(); !node.isNull(); ++ node = node.nextSibling()) { ++ if (node.isComment()) ++ continue; ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (Model_Utils::isCommonXMIAttribute(tag)) ++ continue; ++ // Permitted tag names: ++ // roleA: "child" "subtype" "client" ++ // roleB: "parent" "supertype" "supplier" ++ QString idStr = tempElement.attribute(QLatin1String("xmi.id")); ++ if (idStr.isEmpty()) ++ idStr = tempElement.attribute(QLatin1String("xmi.idref")); ++ if (idStr.isEmpty()) { ++ QDomNode inner = node.firstChild(); ++ QDomElement tmpElem = inner.toElement(); ++ idStr = tmpElem.attribute(QLatin1String("xmi.id")); ++ if (idStr.isEmpty()) ++ idStr = tmpElem.attribute(QLatin1String("xmi.idref")); ++ } ++ if (idStr.isEmpty()) { ++ uError() << "type " << m_AssocType ++ << ", id " << Uml::ID::toString(id()) << ": " ++ << "xmi id not given for " << tag; ++ continue; ++ } ++ // Since we know for sure that we're dealing with a non ++ // umbrello-kf6 file, use deferred resolution unconditionally. ++ if (UMLDoc::tagEq(tag, QLatin1String("child")) || ++ UMLDoc::tagEq(tag, QLatin1String("subtype")) || ++ UMLDoc::tagEq(tag, QLatin1String("client"))) { ++ getUMLRole(RoleType::A)->setSecondaryId(idStr); ++ } else { ++ getUMLRole(RoleType::B)->setSecondaryId(idStr); ++ } ++ } ++ } ++ ++ // it is a realization if either endpoint is an interface ++ if (isRealization(obj[RoleType::A], obj[RoleType::B])) { ++ m_AssocType = Uml::AssociationType::Realization; ++ } ++ return true; ++ } ++ ++ for (QDomNode node = element.firstChild(); !node.isNull(); ++ node = node.nextSibling()) { ++ // uml13.dtd compliant format (new style) ++ if (node.isComment()) ++ continue; ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (Model_Utils::isCommonXMIAttribute(tag)) ++ continue; ++ if (!UMLDoc::tagEq(tag, QLatin1String("Association.connection")) && ++ !UMLDoc::tagEq(tag, QLatin1String("Association.end")) && // Embarcadero's Describe ++ !UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) && ++ !UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { ++ uWarning() << "unknown child node " << tag; ++ continue; ++ } ++ // Load role A. ++ QDomNode nodeA = tempElement.firstChild(); ++ while (nodeA.isComment()) ++ nodeA = nodeA.nextSibling(); ++ tempElement = nodeA.toElement(); ++ if (tempElement.isNull()) { ++ uWarning() << "UML:Association : element (A) is Null"; ++ return false; ++ } ++ tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe ++ m_AssocType = Uml::AssociationType::UniAssociation; ++ } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && ++ !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { ++ uWarning() << "unknown child (A) tag " << tag; ++ return false; ++ } ++ if (! getUMLRole(RoleType::A)->loadFromXMI(tempElement)) ++ return false; ++ // Load role B. ++ QDomNode nodeB = nodeA.nextSibling(); ++ while (nodeB.isComment()) ++ nodeB = nodeB.nextSibling(); ++ tempElement = nodeB.toElement(); ++ if (tempElement.isNull()) { ++ uWarning() << "UML:Association : element (B) is Null"; ++ return false; ++ } ++ tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe ++ m_AssocType = Uml::AssociationType::UniAssociation; ++ } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && ++ !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { ++ uWarning() << "unknown child (B) tag " << tag; ++ return false; ++ } ++ if (! getUMLRole(RoleType::B)->loadFromXMI(tempElement)) ++ return false; ++ ++ if (m_pUMLPackage == NULL) { ++ Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(getObject(RoleType::B)->baseType()); ++ m_pUMLPackage = doc->rootFolder(mt); ++ DEBUG(DBG_SRC) << "setting model type " << Uml::ModelType::toString(mt); ++ } ++ ++ // setting the association type: ++ // ++ // In the old days, we could just record this on the association, ++ // and be done with it. But thats not how the UML13.dtd does things. ++ // As a result, we are checking roleA for information about the ++ // parent association (!) which by this point in the parse, should ++ // be set. However, the information that the roles are allowed to have ++ // is not complete, so we need to finish the analysis here. ++ ++ // find self-associations ++ if (m_AssocType == Uml::AssociationType::Association && getObjectId(RoleType::A) == getObjectId(RoleType::B)) ++ m_AssocType = Uml::AssociationType::Association_Self; ++ ++ // fall-back default type ++ if (m_AssocType == Uml::AssociationType::Unknown) { ++ m_AssocType = Uml::AssociationType::Association; ++ } ++ ++ return true; ++ } ++ ++ // From here on it's old-style stuff. ++ QString assocTypeStr = element.attribute(QLatin1String("assoctype"), QLatin1String("-1")); ++ Uml::AssociationType::Enum assocType = Uml::AssociationType::Unknown; ++ if (assocTypeStr[0] >= QLatin1Char('a') && assocTypeStr[0] <= QLatin1Char('z')) { ++ // In an earlier version, the natural assoctype names were saved. ++ const char *assocTypeString[] = { ++ "generalization", // Uml::AssociationType::Generalization ++ "aggregation", // Uml::AssociationType::Aggregation ++ "dependency", // Uml::AssociationType::Dependency ++ "association", // Uml::AssociationType::Association ++ "associationself", // Uml::AssociationType::Association_Self ++ "collmessage", // Uml::AssociationType::Coll_Message ++ "seqmessage", // Uml::AssociationType::Seq_Message ++ "collmessageself", // Uml::AssociationType::Coll_Message_Self ++ "seqmessageself", // Uml::AssociationType::Seq_Message_Self ++ "implementation", // Uml::AssociationType::Implementation ++ "composition", // Uml::AssociationType::Composition ++ "realization", // Uml::AssociationType::Realization ++ "uniassociation", // Uml::AssociationType::UniAssociation ++ "anchor", // Uml::AssociationType::Anchor ++ "state", // Uml::AssociationType::State ++ "activity", // Uml::AssociationType::Activity ++ "exception", // Uml::AssociationType::Exception ++ "category2parent" // Uml::AssociationType::Category2Parent ++ "child2category" // Uml::AssociationType::Child2Category ++ "relationship" // Uml::AssociationType::Relationship ++ }; ++ const int arraySize = sizeof(assocTypeString) / sizeof(char*); ++ DEBUG(DBG_SRC) << "AssociationType string array size = " << arraySize; ++ ++ int index; ++ for (index = 0; index < arraySize; ++index) ++ if (assocTypeStr == QString::fromLatin1(assocTypeString[index])) ++ break; ++ if (index < arraySize) ++ assocType = Uml::AssociationType::fromInt(index); ++ } else { ++ int assocTypeNum = assocTypeStr.toInt(); ++ if (assocTypeNum < (int)Uml::AssociationType::Generalization || // first enum ++ assocTypeNum >= (int)Uml::AssociationType::Reserved) { // last enum ++ uWarning() << "bad assoctype of UML:AssociationType::Enum " << Uml::ID::toString(id()); ++ return false; ++ } ++ assocType = Uml::AssociationType::fromInt(assocTypeNum); ++ } ++ setAssociationType(assocType); ++ ++ Uml::ID::Type roleAObjID = Uml::ID::fromString(element.attribute(QLatin1String("rolea"), QLatin1String("-1"))); ++ Uml::ID::Type roleBObjID = Uml::ID::fromString(element.attribute(QLatin1String("roleb"), QLatin1String("-1"))); ++ if (assocType == Uml::AssociationType::Aggregation || ++ assocType == Uml::AssociationType::Composition) { ++ // Flip roles to compensate for changed diamond logic in AssociationLine. ++ // For further explanations see AssociationWidget::loadFromXMI. ++ Uml::ID::Type tmp = roleAObjID; ++ roleAObjID = roleBObjID; ++ roleBObjID = tmp; ++ } ++ ++ UMLObject * objA = doc->findObjectById(roleAObjID); ++ UMLObject * objB = doc->findObjectById(roleBObjID); ++ ++ if(objA) ++ getUMLRole(RoleType::A)->setObject(objA); ++ else ++ return false; ++ ++ if(objB) ++ getUMLRole(RoleType::B)->setObject(objB); ++ else ++ return false; ++ ++ setMultiplicity(element.attribute(QLatin1String("multia")), RoleType::A); ++ setMultiplicity(element.attribute(QLatin1String("multib")), RoleType::B); ++ ++ setRoleName(element.attribute(QLatin1String("namea")), RoleType::A); ++ setRoleName(element.attribute(QLatin1String("nameb")), RoleType::B); ++ ++ setRoleDoc(element.attribute(QLatin1String("doca")), RoleType::A); ++ setRoleDoc(element.attribute(QLatin1String("docb")), RoleType::B); ++ ++ // Visibility defaults to Public if it cant set it here.. ++ QString visibilityA = element.attribute(QLatin1String("visibilitya"), QLatin1String("0")); ++ QString visibilityB = element.attribute(QLatin1String("visibilityb"), QLatin1String("0")); ++ int vis = visibilityA.toInt(); ++ if (vis >= 200) // bkwd compat. ++ vis -= 200; ++ setVisibility((Uml::Visibility::Enum)vis, RoleType::A); ++ vis = visibilityB.toInt(); ++ if (vis >= 200) // bkwd compat. ++ vis -= 200; ++ setVisibility((Uml::Visibility::Enum)vis, RoleType::B); ++ ++ // Changeability defaults to Changeable if it cant set it here.. ++ QString changeabilityA = element.attribute(QLatin1String("changeabilitya"), QLatin1String("0")); ++ QString changeabilityB = element.attribute(QLatin1String("changeabilityb"), QLatin1String("0")); ++ if (changeabilityA.toInt() > 0) ++ setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); ++ if (changeabilityB.toInt() > 0) ++ setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); ++ ++ return true; ++} ++ ++/** ++ * Returns the UMLObject assigned to the given role. ++ * @return Pointer to the UMLObject in the given role. ++ */ ++UMLObject* UMLAssociation::getObject(Uml::RoleType::Enum role) const ++{ ++ if (m_pRole[role] == NULL) ++ return NULL; ++ return m_pRole[role]->object(); ++} ++ ++/** ++ * Returns the ID of the UMLObject assigned to the given role. ++ * Shorthand for getObject(role)->ID(). ++ * @return ID of the UMLObject in the given role. ++ */ ++Uml::ID::Type UMLAssociation::getObjectId(Uml::RoleType::Enum role) const ++{ ++ UMLRole *roleObj = m_pRole[role]; ++ if (roleObj == NULL) ++ return Uml::ID::None; ++ UMLObject *o = roleObj->object(); ++ if (o == NULL) { ++ QString auxID = roleObj->secondaryId(); ++ if (auxID.isEmpty()) { ++ uError() << "role " << role << ": getObject returns NULL"; ++ return Uml::ID::None; ++ } else { ++ DEBUG(DBG_SRC) << "role " << role << ": using secondary ID " << auxID; ++ return Uml::ID::fromString(auxID); ++ } ++ } ++ return o->id(); ++} ++ ++/** ++ * Returns the ID of the UMLObject assigned to the given role. ++ * CURRENTLY UNUSED. ++ * @return ID of the UMLObject of the given role. ++ */ ++Uml::ID::Type UMLAssociation::getRoleId(RoleType::Enum role) const ++{ ++ return m_pRole[role]->id(); ++} ++ ++/** ++ * Returns the changeability. ++ */ ++Uml::Changeability::Enum UMLAssociation::changeability(Uml::RoleType::Enum role) const ++{ ++ return m_pRole[role]->changeability(); ++} ++ ++/** ++ * Returns the Visibility of the given role. ++ * @return Visibility of the given role. ++ */ ++Uml::Visibility::Enum UMLAssociation::visibility(Uml::RoleType::Enum role) const ++{ ++ return m_pRole[role]->visibility(); ++} ++ ++/** ++ * Returns the multiplicity assigned to the given role. ++ * @return The multiplicity assigned to the given role. ++ */ ++QString UMLAssociation::getMultiplicity(Uml::RoleType::Enum role) const ++{ ++ return m_pRole[role]->multiplicity(); ++} ++ ++/** ++ * Returns the name assigned to the role A. ++ * @return The name assigned to the given role. ++ */ ++QString UMLAssociation::getRoleName(Uml::RoleType::Enum role) const ++{ ++ return m_pRole[role]->name(); ++} ++ ++/** ++ * Returns the documentation assigned to the given role. ++ * @return Documentation text of given role. ++ */ ++QString UMLAssociation::getRoleDoc(Uml::RoleType::Enum role) const ++{ ++ return m_pRole[role]->doc(); ++} ++ ++/** ++ * Get the underlying UMLRole object for the given role. ++ * @return Pointer to the UMLRole object for the given role. ++ */ ++UMLRole * UMLAssociation::getUMLRole(Uml::RoleType::Enum role) const ++{ ++ return m_pRole[role]; ++} ++ ++/** ++ * Set the attribute m_bOldLoadMode. ++ * @param value the new value to set ++ */ ++void UMLAssociation::setOldLoadMode(bool value /* = true */) ++{ ++ m_bOldLoadMode = value; ++} ++ ++/** ++ * Return the backward compatibility flag for loading files. ++ */ ++bool UMLAssociation::getOldLoadMode() const ++{ ++ return m_bOldLoadMode; ++} ++ ++/** ++ * Sets the assocType of the UMLAssociation. ++ * @param assocType The AssociationType::Enum of the UMLAssociation. ++ */ ++void UMLAssociation::setAssociationType(Uml::AssociationType::Enum assocType) ++{ ++ m_AssocType = assocType; ++ if (m_AssocType == Uml::AssociationType::UniAssociation) ++ { ++ // In this case we need to auto-set the multiplicity/rolenames ++ // of the roles ++#ifdef VERBOSE_DEBUGGING ++ DEBUG(DBG_SRC) << " A new uni-association has been created."; ++#endif ++ } ++ UMLObject::emitModified(); ++} ++ ++/** ++ * Sets the UMLObject playing the given role in the association. ++ * @param obj Pointer to the UMLObject of the given role. ++ * @param role The Uml::RoleType::Enum played by the association ++ */ ++void UMLAssociation::setObject(UMLObject *obj, Uml::RoleType::Enum role) ++{ ++ m_pRole[role]->setObject(obj); ++} ++ ++/** ++ * Sets the visibility of the given role of the UMLAssociation. ++ * @param value Visibility of role. ++ * @param role The Uml::RoleType::Enum to which the visibility is being applied ++ */ ++void UMLAssociation::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) ++{ ++ m_pRole[role]->setVisibility(value); ++} ++ ++/** ++ * Sets the changeability of the given role of the UMLAssociation. ++ * @param value Changeability_Type of the given role. ++ * @param role The Uml::RoleType::Enum to which the changeability is being set ++ */ ++void UMLAssociation::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) ++{ ++ m_pRole[role]->setChangeability(value); ++} ++ ++/** ++ * Sets the multiplicity of the given role of the UMLAssociation. ++ * @param multi The multiplicity of the given role. ++ * @param role The Uml::RoleType::Enum to which the multiplicity is being applied ++ */ ++void UMLAssociation::setMultiplicity(const QString &multi, Uml::RoleType::Enum role) ++{ ++ if (m_pRole[role]->multiplicity() != multi) { ++ UMLApp::app()->executeCommand(new CmdChangeMultiplicity(m_pRole[role], multi)); ++ } ++} ++ ++/** ++ * Sets the name of the given role of the UMLAssociation. ++ * @param roleName The name to set for the given role. ++ * @param role The Uml::RoleType::Enum for which to set the name. ++ */ ++void UMLAssociation::setRoleName(const QString &roleName, Uml::RoleType::Enum role) ++{ ++ m_pRole[role]->setName(roleName); ++} ++ ++/** ++ * Sets the documentation on the given role in the association. ++ * @param doc The string with the documentation. ++ * @param role The Uml::RoleType::Enum to which the documentation is being applied ++ */ ++void UMLAssociation::setRoleDoc(const QString &doc, Uml::RoleType::Enum role) ++{ ++ m_pRole[role]->setDoc(doc); ++} ++ ++/** ++ * When the association type is "Generalization" and at least one of the ++ * given objects an interface, then it is a "Realization". ++ * @param objA UML object as role A ++ * @param objB UML object as role B ++ * @return flag whether association is a realization ++ */ ++bool UMLAssociation::isRealization(UMLObject* objA, UMLObject* objB) const ++{ ++ bool aIsInterface = false; ++ if (objA && (objA->baseType() == UMLObject::ot_Interface)) { ++ aIsInterface = true; ++ } ++ bool bIsInterface = false; ++ if (objB && (objB->baseType() == UMLObject::ot_Interface)) { ++ bIsInterface = true; ++ } ++ return (m_AssocType == Uml::AssociationType::Generalization) && ++ (aIsInterface || bIsInterface); ++} ++ ++/** ++ * Common initializations at construction time. ++ * @param type The AssociationType::Enum to represent. ++ * @param roleAObj Pointer to the role A UMLObject. ++ * @param roleBObj Pointer to the role B UMLObject. ++ */ ++void UMLAssociation::init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj) ++{ ++ m_AssocType = type; ++ m_BaseType = ot_Association; ++ m_Name = QString(); ++ m_bOldLoadMode = false; ++ nrof_parent_widgets = -1; ++ if (!UMLApp::app()->document()->loading()) { ++ m_pUMLPackage = UMLApp::app()->document()->currentRoot(); ++ } ++ m_pRole[RoleType::A] = new UMLRole (this, roleAObj, RoleType::A); ++ m_pRole[RoleType::B] = new UMLRole (this, roleBObj, RoleType::B); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.h umbrello-kf6-15.08.1/umbrello/umlmodel/association.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/association.h 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,102 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ASSOCIATION_H ++#define ASSOCIATION_H ++ ++#include "basictypes.h" ++#include "umlobject.h" ++ ++#include ++#include ++ ++class UMLRole; ++ ++/** ++ * This class contains the non-graphic representation of an association. ++ * An association can be a generalization, realization, simple association, ++ * directed association, aggregation, or composition. ++ * ++ * @short Sets up association information. ++ * @author Oliver Kellogg ++ * @see UMLObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLAssociation : public UMLObject ++{ ++ Q_OBJECT ++ friend class AssociationWidget; ++ ++public: ++ UMLAssociation(Uml::AssociationType::Enum type, UMLObject *roleA, UMLObject *roleB); ++ explicit UMLAssociation(Uml::AssociationType::Enum type = Uml::AssociationType::Unknown); ++ ++ virtual ~UMLAssociation(); ++ ++ bool operator==(const UMLAssociation &rhs) const; ++ ++ QString toString() const; ++ ++ UMLRole * getUMLRole(Uml::RoleType::Enum role) const; ++ Uml::ID::Type getObjectId(Uml::RoleType::Enum role) const; ++ Uml::ID::Type getRoleId(Uml::RoleType::Enum role) const; ++ ++ void setAssociationType(Uml::AssociationType::Enum assocType); ++ Uml::AssociationType::Enum getAssocType() const; ++ ++ void setObject(UMLObject *obj, Uml::RoleType::Enum role); ++ UMLObject* getObject(Uml::RoleType::Enum role) const; ++ ++ void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); ++ Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; ++ ++ void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); ++ Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; ++ ++ void setMultiplicity(const QString &multi, Uml::RoleType::Enum role); ++ QString getMultiplicity(Uml::RoleType::Enum role) const; ++ ++ void setRoleName(const QString &roleName, Uml::RoleType::Enum role); ++ QString getRoleName(Uml::RoleType::Enum role) const; ++ ++ void setRoleDoc(const QString &doc, Uml::RoleType::Enum role); ++ QString getRoleDoc(Uml::RoleType::Enum role) const; ++ ++ void setOldLoadMode(bool value = true); ++ bool getOldLoadMode() const; ++ ++ virtual UMLObject* clone() const { return NULL; } ++ ++ virtual bool resolveRef(); ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual bool showPropertiesDialog(QWidget *parent = 0); ++ ++protected: ++ ++ bool load(QDomElement& element); ++ ++ // keep track of number of parent widgets ++ int nrof_parent_widgets; ++ ++ void init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj); ++ ++ UMLRole * m_pRole[2]; ++ Uml::AssociationType::Enum m_AssocType; ++ QString m_Name; ++ bool m_bOldLoadMode; ++ ++private: ++ ++ bool isRealization(UMLObject* objA, UMLObject* objB) const; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.cpp 2015-10-08 11:48:59.506089026 +0300 +@@ -0,0 +1,424 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "attribute.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "classifier.h" ++#include "operation.h" ++#include "umlobject.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "folder.h" ++#include "umlattributedialog.h" ++#include "object_factory.h" ++ ++/** ++ * Sets up an attribute. ++ * ++ * @param parent The parent of this UMLAttribute. ++ * @param name The name of this UMLAttribute. ++ * @param id The unique id given to this UMLAttribute. ++ * @param s The visibility of the UMLAttribute. ++ * @param type The type of this UMLAttribute. ++ * @param iv The initial value of the attribute. ++ */ ++UMLAttribute::UMLAttribute(UMLObject *parent, ++ const QString& name, Uml::ID::Type id, ++ Uml::Visibility::Enum s, ++ UMLObject *type, const QString& iv) ++ : UMLClassifierListItem(parent, name, id) ++{ ++ m_InitialValue = iv; ++ m_BaseType = UMLObject::ot_Attribute; ++ m_visibility = s; ++ m_ParmKind = Uml::ParameterDirection::In; ++ /* CHECK: Do we need this: ++ if (type == NULL) { ++ type = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef"); ++ } ++ */ ++ m_pSecondary = type; ++} ++ ++/** ++ * Sets up an attribute. ++ * ++ * @param parent The parent of this UMLAttribute. ++ */ ++UMLAttribute::UMLAttribute(UMLObject *parent) : UMLClassifierListItem(parent) ++{ ++ m_BaseType = UMLObject::ot_Attribute; ++ m_visibility = Uml::Visibility::Private; ++ m_ParmKind = Uml::ParameterDirection::In; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLAttribute::~UMLAttribute() ++{ ++} ++ ++/** ++ * Reimplementation of method from UMLObject is required as ++ * an extra signal, attributeChanged(), is emitted. ++ */ ++void UMLAttribute::setName(const QString &name) ++{ ++ m_name = name; ++ emit attributeChanged(); ++ UMLObject::emitModified(); ++} ++ ++/** ++ * Reimplementation of method from UMLObject is required as ++ * an extra signal, attributeChanged(), is emitted. ++ */ ++void UMLAttribute::setVisibility(Uml::Visibility::Enum s) ++{ ++ m_visibility = s; ++ emit attributeChanged(); ++ UMLObject::emitModified(); ++} ++ ++/** ++ * Returns The initial value of the UMLAttribute. ++ * ++ * @return The initial value of the Atrtibute. ++ */ ++QString UMLAttribute::getInitialValue() const ++{ ++ return m_InitialValue; ++} ++ ++/** ++ * Sets the initial value of the UMLAttribute. ++ * ++ * @param iv The initial value of the UMLAttribute. ++ */ ++void UMLAttribute::setInitialValue(const QString &iv) ++{ ++ if(m_InitialValue != iv) { ++ m_InitialValue = iv; ++ UMLObject::emitModified(); ++ } ++} ++ ++void UMLAttribute::setParmKind (Uml::ParameterDirection::Enum pk) ++{ ++ m_ParmKind = pk; ++} ++ ++Uml::ParameterDirection::Enum UMLAttribute::getParmKind() const ++{ ++ return m_ParmKind; ++} ++ ++/** ++ * Returns a string representation of the UMLAttribute. ++ * ++ * @param sig If true will show the attribute type and initial value. ++ * @return Returns a string representation of the UMLAttribute. ++ */ ++QString UMLAttribute::toString(Uml::SignatureType::Enum sig) ++{ ++ QString s; ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { ++ s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); ++ } ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { ++ // Determine whether the type name needs to be scoped. ++ UMLObject *owningObject = static_cast(parent()); ++ if (owningObject->baseType() == UMLObject::ot_Operation) { ++ // The immediate parent() is the UMLOperation but we want ++ // the UMLClassifier: ++ owningObject = static_cast(owningObject->parent()); ++ } ++ UMLClassifier *ownParent = dynamic_cast(owningObject); ++ if (ownParent == NULL) { ++ uError() << "parent " << owningObject->name() ++ << " is not a UMLClassifier"; ++ return QString(); ++ } ++ QString typeName; ++ UMLClassifier *type = UMLClassifierListItem::getType(); ++ if (type) { ++ UMLPackage *typeScope = type->umlPackage(); ++ if (typeScope != ownParent && typeScope != ownParent->umlPackage()) ++ typeName = type->fullyQualifiedName(); ++ else ++ typeName = type->name(); ++ } ++ // The default direction, "in", is not mentioned. ++ // Perhaps we should include a pd_Unspecified in ++ // Uml::ParameterDirection::Enum to have better control over this. ++ if (m_ParmKind == Uml::ParameterDirection::InOut) ++ s += QLatin1String("inout "); ++ else if (m_ParmKind == Uml::ParameterDirection::Out) ++ s += QLatin1String("out "); ++ // Construct the attribute text. ++ QString string = s + name() + QLatin1String(" : ") + typeName; ++ if (m_InitialValue.length() > 0) ++ string += QLatin1String(" = ") + m_InitialValue; ++ return string; ++ } ++ return s + name(); ++} ++ ++/** ++ * Reimplement method from UMLObject. ++ */ ++QString UMLAttribute::getFullyQualifiedName(const QString& separator, ++ bool includeRoot /* = false */) const ++{ ++ UMLOperation *op = NULL; ++ UMLObject *owningObject = static_cast(parent()); ++ if (owningObject->baseType() == UMLObject::ot_Operation) { ++ op = static_cast(owningObject); ++ owningObject = static_cast(owningObject->parent()); ++ } ++ UMLClassifier *ownParent = dynamic_cast(owningObject); ++ if (ownParent == NULL) { ++ uError() << name() << ": parent " << owningObject->name() ++ << " is not a UMLClassifier"; ++ return QString(); ++ } ++ QString tempSeparator = separator; ++ if (tempSeparator.isEmpty()) ++ tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); ++ QString fqn = ownParent->fullyQualifiedName(tempSeparator, includeRoot); ++ if (op) ++ fqn.append(tempSeparator + op->name()); ++ fqn.append(tempSeparator + name()); ++ return fqn; ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLAttribute::operator==(const UMLAttribute &rhs) const ++{ ++ if(this == &rhs) ++ return true; ++ ++ if(!UMLObject::operator==(rhs)) ++ return false; ++ ++ // The type name is the only distinguishing criterion. ++ // (Some programming languages might support more, but others don't.) ++ if (m_pSecondary != rhs.m_pSecondary) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * Copy the internal presentation of this object into the UMLAttribute ++ * object. ++ */ ++void UMLAttribute::copyInto(UMLObject *lhs) const ++{ ++ UMLAttribute *target = static_cast(lhs); ++ // call the parent first. ++ UMLClassifierListItem::copyInto(target); ++ ++ // Copy all datamembers ++ target->m_pSecondary = m_pSecondary; ++ target->m_SecondaryId = m_SecondaryId; ++ target->m_InitialValue = m_InitialValue; ++ target->m_ParmKind = m_ParmKind; ++} ++ ++/** ++ * Make a clone of the UMLAttribute. ++ */ ++UMLObject* UMLAttribute::clone() const ++{ ++ //FIXME: The new attribute should be slaved to the NEW parent not the old. ++ UMLAttribute *clone = new UMLAttribute(static_cast(parent())); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement attributeElement = UMLObject::save(QLatin1String("UML:Attribute"), qDoc); ++ if (m_pSecondary == NULL) { ++ uDebug() << name() << ": m_pSecondary is NULL, m_SecondaryId is '" ++ << m_SecondaryId << "'"; ++ } else { ++ attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); ++ } ++ if (! m_InitialValue.isEmpty()) ++ attributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); ++ qElement.appendChild(attributeElement); ++} ++ ++/** ++ * Loads the XMI element. ++ */ ++bool UMLAttribute::load(QDomElement & element) ++{ ++ m_SecondaryId = element.attribute(QLatin1String("type")); ++ // We use the m_SecondaryId as a temporary store for the xmi.id ++ // of the attribute type model object. ++ // It is resolved later on, when all classes have been loaded. ++ // This deferred resolution is required because the xmi.id may ++ // be a forward reference, i.e. it may identify a model object ++ // that has not yet been loaded. ++ if (m_SecondaryId.isEmpty()) { ++ // Perhaps the type is stored in a child node: ++ QDomNode node = element.firstChild(); ++ while (!node.isNull()) { ++ if (node.isComment()) { ++ node = node.nextSibling(); ++ continue; ++ } ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { ++ node = node.nextSibling(); ++ continue; ++ } ++ m_SecondaryId = Model_Utils::getXmiId(tempElement); ++ if (m_SecondaryId.isEmpty()) ++ m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); ++ if (m_SecondaryId.isEmpty()) { ++ QString href = tempElement.attribute(QLatin1String("href")); ++ if (href.isEmpty()) { ++ QDomNode inner = node.firstChild(); ++ QDomElement tmpElem = inner.toElement(); ++ m_SecondaryId = Model_Utils::getXmiId(tmpElem); ++ if (m_SecondaryId.isEmpty()) ++ m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); ++ } else { ++ int hashpos = href.lastIndexOf(QChar(QLatin1Char('#'))); ++ if (hashpos < 0) { ++ uDebug() << name() << ": cannot find type " << href; ++ } else { ++ QString typeName = href.mid(hashpos + 1); ++ UMLFolder *dtFolder = UMLApp::app()->document()->datatypeFolder(); ++ m_pSecondary = Model_Utils::findUMLObject(dtFolder->containedObjects(), ++ typeName, UMLObject::ot_Datatype); ++ if (!m_pSecondary) { ++ m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, ++ typeName, dtFolder); ++ } ++ } ++ } ++ } ++ break; ++ } ++ if (m_SecondaryId.isEmpty()) { ++ uDebug() << name() << ": cannot find type."; ++ } ++ } ++ m_InitialValue = element.attribute(QLatin1String("initialValue")); ++ if (m_InitialValue.isEmpty()) { ++ // for backward compatibility ++ m_InitialValue = element.attribute(QLatin1String("value")); ++ } ++ return true; ++} ++ ++/** ++ * Display the properties configuration dialog for the attribute. ++ */ ++bool UMLAttribute::showPropertiesDialog(QWidget* parent) ++{ ++ UMLAttributeDialog dialog(parent, this); ++ return dialog.exec(); ++} ++ ++/** ++ * Puts in the param templateParamList all the template params that are in templateParam ++ */ ++void UMLAttribute::setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList) ++{ ++ if (templateParam.isEmpty()) ++ return; ++ QString type = templateParam.simplified(); ++ ++ int start = type.indexOf(QLatin1Char('<')); ++ if (start >= 0) { ++ int end = start; ++ int count = 1; ++ int len = type.length(); ++ while (count != 0 && ++end < len) { ++ QChar c = type.at(end); ++ if (c == QLatin1Char('<')) { ++ count++; ++ } ++ if (c == QLatin1Char('>')) { ++ count--; ++ } ++ } ++ if (count != 0) { ++ //The template is ill-formated, let's quit ++ return; ++ } ++ setTemplateParams(type.mid(start + 1, end - start - 1), templateParamList); ++ setTemplateParams(type.left(start) + type.right(len - end - 1), templateParamList); ++ } else { ++ QStringList paramsList = type.split(QLatin1Char(',')); ++ for (QStringList::Iterator it = paramsList.begin(); it != paramsList.end(); ++it) { ++ QString param = *it; ++ if (!param.isEmpty()) { ++ UMLDoc *pDoc = UMLApp::app()->document(); ++ UMLObject* obj = pDoc->findUMLObject(param); ++ if (obj == NULL) { ++ obj = pDoc->findUMLObject(param.remove(QLatin1Char(' '))); ++ } ++ if (obj != NULL) { ++ //We want to list only the params that already exist in this document ++ //If the param doesnt't already exist, we couldn't draw an association anyway ++ UMLClassifier* tmpClassifier = static_cast(obj); ++ if (templateParamList.indexOf(tmpClassifier) == -1) { ++ templateParamList.append(tmpClassifier); ++ } ++ } ++ } ++ } ++ } ++} ++ ++/** ++ * Returns all the template params (if any) that are in the type of this attribute ++ */ ++UMLClassifierList UMLAttribute::getTemplateParams() ++{ ++ UMLClassifierList templateParamList; ++ QString type = getType()->name(); ++ QString templateParam; ++ // Handle C++/D/Java template/generic parameters ++ const Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); ++ if (pl == Uml::ProgrammingLanguage::Cpp || ++ pl == Uml::ProgrammingLanguage::Java || pl == Uml::ProgrammingLanguage::D) { ++ int start = type.indexOf(QLatin1Char('<')); ++ if (start >= 0) { ++ int end = type.lastIndexOf(QLatin1Char('>')); ++ if (end > start) { ++ templateParam = type.mid(start + 1, end - start - 1); ++ setTemplateParams(templateParam, templateParamList); ++ } ++ } ++ } ++ return templateParamList; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.h umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,84 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ATTRIBUTE_H ++#define ATTRIBUTE_H ++ ++#include "basictypes.h" ++#include "classifierlistitem.h" ++#include "umlclassifierlist.h" ++ ++/** ++ * This class is used to set up information for an attribute. This is like ++ * a programming attribute. It has a type, name, visibility and initial value. ++ * ++ * @short Sets up attribute information. ++ * @author Paul Hensgen ++ * @see UMLObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLAttribute : public UMLClassifierListItem ++{ ++ Q_OBJECT ++public: ++ ++ UMLAttribute(UMLObject *parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None, ++ Uml::Visibility::Enum s = Uml::Visibility::Private, ++ UMLObject *type = 0, const QString& iv = QString()); ++ explicit UMLAttribute(UMLObject *parent); ++ ++ bool operator==(const UMLAttribute &rhs) const; ++ ++ virtual ~UMLAttribute(); ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ void setName(const QString &name); ++ ++ void setVisibility(Uml::Visibility::Enum s); ++ ++ virtual UMLObject* clone() const; ++ ++ QString getInitialValue() const; ++ void setInitialValue(const QString &iv); ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ QString getFullyQualifiedName(const QString& separator = QString(), ++ bool includeRoot = false) const; ++ ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++ void setParmKind(Uml::ParameterDirection::Enum pk); ++ Uml::ParameterDirection::Enum getParmKind() const; ++ ++ virtual UMLClassifierList getTemplateParams(); ++ ++signals: ++ ++ void attributeChanged(); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++ QString m_InitialValue; ///< text for the attribute's initial value. ++ Uml::ParameterDirection::Enum m_ParmKind; ++ ++private: ++ ++ void setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/category.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/category.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,101 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "category.h" ++ ++/** ++ * Constructs a Category. ++ * ++ * @param name The name of the Category. ++ * @param id The unique id to assign to this Category. ++ */ ++UMLCategory::UMLCategory(const QString & name, Uml::ID::Type id) ++ : UMLCanvasObject(name, id) ++{ ++ init(); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLCategory::~UMLCategory() ++{ ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLCategory::init() ++{ ++ m_BaseType = UMLObject::ot_Category; ++ m_CategoryType = ct_Disjoint_Specialisation; ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLCategory::copyInto(UMLObject *lhs) const ++{ ++ UMLCategory *target = static_cast(lhs); ++ ++ // call the parent first ++ UMLCanvasObject::copyInto(target); ++ ++ target->m_CategoryType = m_CategoryType; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLCategory::clone() const ++{ ++ UMLCategory *clone = new UMLCategory(); ++ copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLCategory::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement categoryElement = UMLObject::save(QLatin1String("UML:Category"), qDoc); ++ categoryElement.setAttribute(QLatin1String("categoryType"), (int)m_CategoryType); ++ qElement.appendChild(categoryElement); ++} ++ ++/** ++ * Loads the XMI element (empty.) ++ */ ++bool UMLCategory::load(QDomElement& element) ++{ ++ m_CategoryType = (Category_Type)element.attribute(QLatin1String("categoryType"), ++ QLatin1String("0")).toInt(); ++ return true; ++} ++ ++/** ++ * Get the category type ++ */ ++UMLCategory::Category_Type UMLCategory::getType() ++{ ++ return m_CategoryType; ++} ++ ++/** ++ * Set the category type ++ */ ++void UMLCategory::setType(Category_Type type) ++{ ++ m_CategoryType = type; ++ emitModified(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.h umbrello-kf6-15.08.1/umbrello/umlmodel/category.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/category.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,62 @@ ++/*************************************************************************** ++ * * ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef CATEGORY_H ++#define CATEGORY_H ++ ++#include "umlcanvasobject.h" ++ ++/** ++ * This class contains the non-graphical information required for a UML Category. ++ * This class inherits from @ref UMLCanvasObject which contains most of the ++ * information. ++ * The @ref UMLDoc class creates instances of this type. ++ * ++ * @short Information for a non-graphical UML Category. ++ * @author Sharan Rao ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLCategory : public UMLCanvasObject { ++ Q_OBJECT ++public: ++ ++ enum Category_Type { ++ ct_Disjoint_Specialisation, ++ ct_Overlapping_Specialisation, ++ ct_Union ++ }; ++ ++ explicit UMLCategory(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ ~UMLCategory(); ++ ++ virtual void init(); ++ ++ void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ UMLCategory::Category_Type getType(); ++ ++ void setType(Category_Type type); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++private: ++ ++ Category_Type m_CategoryType; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,160 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++//own header ++#include "checkconstraint.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "umlcheckconstraintdialog.h" ++ ++/** ++ * Sets up a constraint. ++ * ++ * @param parent The parent of this UMLCheckConstraint. ++ * @param name The name of this UMLCheckConstraint. ++ * @param id The unique id given to this UMLCheckConstraint. ++ */ ++UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent, ++ const QString& name, Uml::ID::Type id) ++ : UMLEntityConstraint(parent, name, id) ++{ ++ init(); ++} ++ ++/** ++ * Sets up a constraint. ++ * ++ * @param parent The parent of this UMLCheckConstraint. ++ */ ++UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent) ++ : UMLEntityConstraint(parent) ++{ ++ init(); ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLCheckConstraint::operator==(const UMLCheckConstraint &rhs) const ++{ ++ if (this == &rhs) ++ return true; ++ ++ if (!UMLObject::operator==(rhs)) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLCheckConstraint::~UMLCheckConstraint() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the UMLCheckConstraint ++ * object. ++ */ ++void UMLCheckConstraint::copyInto(UMLObject *lhs) const ++{ ++ UMLCheckConstraint *target = static_cast(lhs); ++ ++ // call the parent first. ++ UMLEntityConstraint::copyInto(target); ++ ++ // Copy all datamembers ++ target->m_CheckCondition = m_CheckCondition; ++} ++ ++/** ++ * Make a clone of the UMLCheckConstraint. ++ */ ++UMLObject* UMLCheckConstraint::clone() const ++{ ++ //FIXME: The new attribute should be slaved to the NEW parent not the old. ++ UMLCheckConstraint *clone = new UMLCheckConstraint(static_cast(parent())); ++ copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Returns a string representation of the UMLCheckConstraint. ++ * ++ * @param sig If true will show the attribute type and initial value. ++ * @return Returns a string representation of the UMLAttribute. ++ */ ++QString UMLCheckConstraint::toString(Uml::SignatureType::Enum sig) ++{ ++ QString s; ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { ++ s = name() ; ++ } ++ ++ return s; ++} ++ ++QString UMLCheckConstraint::getFullyQualifiedName(const QString& separator, ++ bool includeRoot) const ++{ ++ Q_UNUSED(separator); Q_UNUSED(includeRoot); ++ return this->name(); ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLCheckConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement checkConstraintElement = UMLObject::save(QLatin1String("UML:CheckConstraint"), qDoc); ++ ++ QDomNode checkCondition = qDoc.createTextNode(m_CheckCondition); ++ checkConstraintElement.appendChild(checkCondition); ++ ++ qElement.appendChild(checkConstraintElement); ++} ++ ++/** ++ * Display the properties configuration dialog for the attribute. ++ */ ++bool UMLCheckConstraint::showPropertiesDialog(QWidget* parent) ++{ ++ UMLCheckConstraintDialog dialog(parent, this); ++ return dialog.exec(); ++} ++ ++/** ++ * Loads the XMI element. ++ */ ++bool UMLCheckConstraint::load(QDomElement & element) ++{ ++ QDomNode node = element.firstChild(); ++ ++ QDomText checkConstraintText = node.toText(); ++ if (checkConstraintText.isNull()) ++ m_CheckCondition = QString(); ++ else ++ m_CheckCondition = checkConstraintText.data(); ++ ++ return true; ++} ++ ++/** ++ * Initialises Check Constraint ++ */ ++void UMLCheckConstraint::init() ++{ ++ m_BaseType = UMLObject::ot_CheckConstraint; ++ m_CheckCondition.clear(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,71 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef CHECKCONSTRAINT_H ++#define CHECKCONSTRAINT_H ++ ++#include "basictypes.h" ++#include "entityconstraint.h" ++ ++/** ++ * This class is used to set up information for a unique entity constraint. ++ * ++ * @short Sets up Check Constraint information for UMLEntities. ++ * @author Sharan Rao ++ * @see UMLObject UMLClassifierListItem UMLEntityConstraint ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLCheckConstraint : public UMLEntityConstraint ++{ ++ Q_OBJECT ++public: ++ ++ UMLCheckConstraint(UMLObject *parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None); ++ explicit UMLCheckConstraint(UMLObject *parent); ++ ++ bool operator==(const UMLCheckConstraint &rhs) const; ++ ++ virtual ~UMLCheckConstraint(); ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ QString getFullyQualifiedName(const QString& separator = QString(), ++ bool includeRoot = false) const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++ QString getCheckCondition() const { ++ return m_CheckCondition; ++ } ++ ++ void setCheckCondition(const QString& condition) { ++ m_CheckCondition = condition.trimmed(); ++ } ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++private: ++ ++ void init(); ++ ++ QString m_CheckCondition; ///< the check condition ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,1631 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++#include "classifier.h" ++ ++// app includes ++#include "association.h" ++#include "debug_utils.h" ++#include "umlassociationlist.h" ++#include "operation.h" ++#include "attribute.h" ++#include "template.h" ++#include "enumliteral.h" ++#include "entityattribute.h" ++#include "enum.h" ++#include "entity.h" ++#include "stereotype.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "uniqueid.h" ++#include "object_factory.h" ++#include "model_utils.h" ++#include "idchangelog.h" ++#include "umloperationdialog.h" ++#include "umlattributedialog.h" ++#include "umltemplatedialog.h" ++#include "optionstate.h" ++#include "icon_utils.h" ++ ++// kde includes ++#include ++#include ++ ++// qt includes ++#include ++ ++using namespace Uml; ++ ++/** ++ * @brief holds set of classifiers for recursive loop detection ++ */ ++class UMLClassifierSet: public QSet { ++public: ++ UMLClassifierSet() : level(0) ++ { ++ } ++ int level; ++}; ++ ++/** ++ * Sets up a Classifier. ++ * ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLClassifier::UMLClassifier(const QString & name, Uml::ID::Type id) ++ : UMLPackage(name, id) ++{ ++ m_BaseType = UMLObject::ot_Class; // default value ++ m_pClassAssoc = NULL; ++ m_isRef = false; ++} ++ ++/** ++ * Standard deconstructor. ++ */ ++UMLClassifier::~UMLClassifier() ++{ ++} ++ ++/** ++ * Reimplementation of method from class UMLObject for controlling the ++ * exact type of this classifier: class, interface, or datatype. ++ * @param ot the base type to set ++ */ ++void UMLClassifier::setBaseType(UMLObject::ObjectType ot) ++{ ++ m_BaseType = ot; ++ Icon_Utils::IconType newIcon; ++ switch (ot) { ++ case ot_Interface: ++ UMLObject::setStereotypeCmd(QLatin1String("interface")); ++ UMLObject::m_bAbstract = true; ++ newIcon = Icon_Utils::it_Interface; ++ break; ++ case ot_Class: ++ UMLObject::setStereotypeCmd(QString()); ++ UMLObject::m_bAbstract = false; ++ newIcon = Icon_Utils::it_Class; ++ break; ++ case ot_Datatype: ++ UMLObject::setStereotypeCmd(QLatin1String("datatype")); ++ UMLObject::m_bAbstract = false; ++ newIcon = Icon_Utils::it_Datatype; ++ break; ++ case ot_Package: ++ UMLObject::setStereotypeCmd(QString()); ++ UMLObject::m_bAbstract = false; ++ newIcon = Icon_Utils::it_Package; ++ break; ++ default: ++ uError() << "cannot set to type " << ot; ++ return; ++ } ++ Model_Utils::treeViewChangeIcon(this, newIcon); ++} ++ ++/** ++ * Returns true if this classifier represents an interface. ++ */ ++bool UMLClassifier::isInterface() const ++{ ++ return (m_BaseType == ot_Interface); ++} ++ ++/** ++ * Returns true if this classifier represents a datatype. ++ */ ++bool UMLClassifier::isDatatype() const ++{ ++ return (m_BaseType == ot_Datatype); ++} ++ ++/** ++ * Checks whether an operation is valid based on its signature - ++ * An operation is "valid" if the operation's name and parameter list ++ * are unique in the classifier. ++ * ++ * @param name Name of the operation to check. ++ * @param opParams The operation's argument list. ++ * @param exemptOp Pointer to the exempt method (optional.) ++ * @return NULL if the signature is valid (ok), else return a pointer ++ * to the existing UMLOperation that causes the conflict. ++ */ ++UMLOperation * UMLClassifier::checkOperationSignature( ++ const QString& name, ++ UMLAttributeList opParams, ++ UMLOperation *exemptOp) ++{ ++ UMLOperationList list = findOperations(name); ++ if (list.count() == 0) { ++ return NULL; ++ } ++ const int inputParmCount = opParams.count(); ++ ++ // there is at least one operation with the same name... compare the parameter list ++ foreach (UMLOperation* test, list) { ++ if (test == exemptOp) { ++ continue; ++ } ++ UMLAttributeList testParams = test->getParmList(); ++ const int pCount = testParams.count(); ++ if (pCount != inputParmCount) { ++ continue; ++ } ++ int i = 0; ++ while (i < pCount) { ++ // The only criterion for equivalence is the parameter types. ++ // (Default values are not considered.) ++ if(testParams.at(i)->getTypeName() != opParams.at(i)->getTypeName()) ++ break; ++ i++; ++ } ++ if (i == pCount) { // all parameters matched->the signature is not unique ++ return test; ++ } ++ } ++ // we did not find an exact match, so the signature is unique (acceptable) ++ return NULL; ++} ++ ++/** ++ * Find an operation of the given name and parameter signature. ++ * ++ * @param name The name of the operation to find. ++ * @param params The parameter descriptors of the operation to find. ++ * ++ * @return The operation found. Will return 0 if none found. ++ */ ++UMLOperation* UMLClassifier::findOperation(const QString& name, ++ Model_Utils::NameAndType_List params) ++{ ++ UMLOperationList list = findOperations(name); ++ if (list.count() == 0) { ++ return NULL; ++ } ++ // if there are operation(s) with the same name then compare the parameter list ++ const int inputParmCount = params.count(); ++ ++ foreach (UMLOperation* test, list) { ++ UMLAttributeList testParams = test->getParmList(); ++ const int pCount = testParams.count(); ++ if (inputParmCount == 0 && pCount == 0) ++ return test; ++ if (inputParmCount != pCount) ++ continue; ++ int i = 0; ++ for (; i < pCount; ++i) { ++ Model_Utils::NameAndType_ListIt nt(params.begin() + i); ++ UMLClassifier *type = dynamic_cast((*nt).m_type); ++ UMLClassifier *testType = testParams.at(i)->getType(); ++ if (type == NULL && testType == NULL) { //no parameter type ++ continue; ++ } else if (type == NULL) { //template parameter ++ if (testType->name() != QLatin1String("class")) ++ break; ++ } else if (type != testType) ++ break; ++ } ++ if (i == pCount) ++ return test; // all parameters matched ++ } ++ return 0; ++} ++ ++/** ++ * Creates an operation in the current document. ++ * The new operation is initialized with name, id, etc. ++ * If a method with the given profile already exists in the classifier, ++ * no new method is created and the existing operation is returned. ++ * If no name is provided, or if the params are NULL, an Operation ++ * Dialog is shown to ask the user for a name and parameters. ++ * The operation's signature is checked for validity within the parent ++ * classifier. ++ * ++ * @param name The operation name (will be chosen internally if ++ * none given.) ++ * @param isExistingOp Optional pointer to bool. If supplied, the bool is ++ * set to true if an existing operation is returned. ++ * @param params Optional list of parameter names and types. ++ * If supplied, new operation parameters are ++ * constructed using this list. ++ * @return The new operation, or NULL if the operation could not be ++ * created because for example, the user canceled the dialog ++ * or no appropriate name can be found. ++ */ ++UMLOperation* UMLClassifier::createOperation( ++ const QString &name /*=QString()*/, ++ bool *isExistingOp /*=NULL*/, ++ Model_Utils::NameAndType_List *params /*=NULL*/) ++{ ++ bool nameNotSet = (name.isNull() || name.isEmpty()); ++ if (! nameNotSet) { ++ Model_Utils::NameAndType_List parList; ++ if (params) ++ parList = *params; ++ UMLOperation* existingOp = findOperation(name, parList); ++ if (existingOp != NULL) { ++ if (isExistingOp != NULL) ++ *isExistingOp = true; ++ return existingOp; ++ } ++ } ++ // we did not find an exact match, so the signature is unique ++ UMLOperation *op = new UMLOperation(this, name); ++ if (params) { ++ for (Model_Utils::NameAndType_ListIt it = params->begin(); it != params->end(); ++it) { ++ const Model_Utils::NameAndType &nt = *it; ++ UMLAttribute *par = new UMLAttribute(op, nt.m_name, Uml::ID::None, Uml::Visibility::Private, ++ nt.m_type, nt.m_initialValue); ++ par->setParmKind(nt.m_direction); ++ op->addParm(par); ++ } ++ } ++ ++ // Only show the operation dialog if no name was provided (allows quick-create ++ // from listview) ++ if (nameNotSet) { ++ op->setName(uniqChildName(UMLObject::ot_Operation)); ++ ++ while (true) { ++ QPointer operationDialog = new UMLOperationDialog(0, op); ++ if(operationDialog->exec() != QDialog::Accepted) { ++ delete op; ++ delete operationDialog; ++ return NULL; ++ } else if (checkOperationSignature(op->name(), op->getParmList())) { ++ KMessageBox::information(0, ++ i18n("An operation with the same name and signature already exists. You cannot add it again.")); ++ } else { ++ break; ++ } ++ delete operationDialog; ++ } ++ } ++ ++ // operation name is ok, formally add it to the classifier ++ if (! addOperation(op)) { ++ delete op; ++ return NULL; ++ } ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(op); ++ return op; ++} ++ ++/** ++ * Appends an operation to the classifier. ++ * This function is mainly intended for the clipboard. ++ * ++ * @param op Pointer to the UMLOperation to add. ++ * @param position Inserted at the given position. ++ * @return True if the operation was added successfully. ++ */ ++bool UMLClassifier::addOperation(UMLOperation* op, int position) ++{ ++ Q_ASSERT(op); ++ if (m_List.indexOf(op) != -1) { ++ uDebug() << "findRef(" << op->name() << ") finds op (bad)"; ++ return false; ++ } ++ if (checkOperationSignature(op->name(), op->getParmList())) { ++ uDebug() << "checkOperationSignature(" << op->name() << ") op is non-unique"; ++ return false; ++ } ++ ++ if (position >= 0 && position <= m_List.count()) { ++ uDebug() << op->name() << ": inserting at position " << position; ++ m_List.insert(position, op); ++ UMLClassifierListItemList itemList = getFilteredList(UMLObject::ot_Operation); ++ QString buf; ++ foreach (UMLClassifierListItem* currentAtt, itemList) { ++ buf.append(QLatin1Char(' ') + currentAtt->name()); ++ } ++ uDebug() << " list after change: " << buf; ++ } ++ else { ++ m_List.append(op); ++ } ++ emit operationAdded(op); ++ UMLObject::emitModified(); ++ connect(op, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++} ++ ++/** ++ * Appends an operation to the classifier. ++ * @see bool addOperation(UMLOperation* Op, int position = -1) ++ * This function is mainly intended for the clipboard. ++ * ++ * @param op Pointer to the UMLOperation to add. ++ * @param log Pointer to the IDChangeLog. ++ * @return True if the operation was added successfully. ++ */ ++bool UMLClassifier::addOperation(UMLOperation* op, IDChangeLog* log) ++{ ++ if (addOperation(op, -1)) { ++ return true; ++ } ++ else if (log) { ++ log->removeChangeByNewID(op->id()); ++ } ++ return false; ++} ++ ++/** ++ * Remove an operation from the Classifier. ++ * The operation is not deleted so the caller is responsible for what ++ * happens to it after this. ++ * ++ * @param op The operation to remove. ++ * @return Count of the remaining operations after removal, or ++ * -1 if the given operation was not found. ++ */ ++int UMLClassifier::removeOperation(UMLOperation *op) ++{ ++ if (op == NULL) { ++ uDebug() << "called on NULL op"; ++ return -1; ++ } ++ if (!m_List.removeAll(op)) { ++ uDebug() << "cannot find op " << op->name() << " in list"; ++ return -1; ++ } ++ // disconnection needed. ++ // note that we don't delete the operation, just remove it from the Classifier ++ disconnect(op, SIGNAL(modified()), this, SIGNAL(modified())); ++ emit operationRemoved(op); ++ UMLObject::emitModified(); ++ return m_List.count(); ++} ++ ++/** ++ * Create and add a just created template. ++ * @param currentName the name of the template ++ * @return the template or NULL ++ */ ++UMLObject* UMLClassifier::createTemplate(const QString& currentName /*= QString()*/) ++{ ++ QString name = currentName; ++ bool goodName = !name.isEmpty(); ++ if (!goodName) { ++ name = uniqChildName(UMLObject::ot_Template); ++ } ++ UMLTemplate* newTemplate = new UMLTemplate(this, name); ++ ++ int button = QDialog::Accepted; ++ ++ while (button == QDialog::Accepted && !goodName) { ++ QPointer templateDialog = new UMLTemplateDialog(0, newTemplate); ++ button = templateDialog->exec(); ++ name = newTemplate->name(); ++ ++ if (name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } ++ else if (findChildObject(name) != NULL) { ++ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); ++ } ++ else { ++ goodName = true; ++ } ++ delete templateDialog; ++ } ++ ++ if (button != QDialog::Accepted) { ++ return NULL; ++ } ++ ++ addTemplate(newTemplate); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newTemplate); ++ return newTemplate; ++} ++ ++/** ++ * Returns the number of attributes for the class. ++ * ++ * @return The number of attributes for the class. ++ */ ++int UMLClassifier::attributes() ++{ ++ UMLClassifierListItemList atts = getFilteredList(UMLObject::ot_Attribute); ++ return atts.count(); ++} ++ ++/** ++ * Returns the attributes for the specified scope. ++ * @return List of true attributes for the class. ++ */ ++UMLAttributeList UMLClassifier::getAttributeList() const ++{ ++ UMLAttributeList attributeList; ++ foreach (UMLObject* listItem, m_List) { ++ uIgnoreZeroPointer(listItem); ++ if (listItem->baseType() == UMLObject::ot_Attribute) { ++ attributeList.append(static_cast(listItem)); ++ } ++ } ++ return attributeList; ++} ++ ++/** ++ * Returns the attributes for the specified scope. ++ * @param scope The scope of the attribute. ++ * @return List of true attributes for the class. ++ */ ++UMLAttributeList UMLClassifier::getAttributeList(Visibility::Enum scope) const ++{ ++ UMLAttributeList list; ++ if (!isInterface()) ++ { ++ UMLAttributeList atl = getAttributeList(); ++ foreach(UMLAttribute* at, atl) ++ { ++ uIgnoreZeroPointer(at); ++ if (! at->isStatic()) ++ { ++ if (scope == Uml::Visibility::Private) ++ { ++ if ((at->visibility() == Uml::Visibility::Private) || ++ (at->visibility() == Uml::Visibility::Implementation)) ++ { ++ list.append(at); ++ } ++ } ++ else if (scope == at->visibility()) ++ { ++ list.append(at); ++ } ++ } ++ } ++ } ++ return list; ++} ++ ++/** ++ * Returns the static attributes for the specified scope. ++ * ++ * @param scope The scope of the attribute. ++ * @return List of true attributes for the class. ++ */ ++UMLAttributeList UMLClassifier::getAttributeListStatic(Visibility::Enum scope) const ++{ ++ UMLAttributeList list; ++ if (!isInterface()) ++ { ++ UMLAttributeList atl = getAttributeList(); ++ foreach(UMLAttribute* at, atl) ++ { ++ uIgnoreZeroPointer(at); ++ if (at->isStatic()) ++ { ++ if (scope == Uml::Visibility::Private) ++ { ++ if ((at->visibility() == Uml::Visibility::Private) || ++ (at->visibility() == Uml::Visibility::Implementation)) ++ { ++ list.append(at); ++ } ++ } ++ else if (scope == at->visibility()) ++ { ++ list.append(at); ++ } ++ } ++ } ++ } ++ return list; ++} ++ ++/** ++ * Find a list of operations with the given name. ++ * ++ * @param n The name of the operation to find. ++ * @return The list of objects found; will be empty if none found. ++ */ ++UMLOperationList UMLClassifier::findOperations(const QString &n) ++{ ++ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); ++ UMLOperationList list; ++ foreach (UMLObject* obj, m_List) { ++ uIgnoreZeroPointer(obj); ++ if (obj->baseType() != UMLObject::ot_Operation) ++ continue; ++ UMLOperation *op = static_cast(obj); ++ if (caseSensitive) { ++ if (obj->name() == n) ++ list.append(op); ++ } else if (obj->name().toLower() == n.toLower()) { ++ list.append(op); ++ } ++ } ++ return list; ++} ++ ++/** ++ * Find the child object by the given id. ++ * @param id the id of the child object ++ * @param considerAncestors flag whether the ancestors should be considered during search ++ * @return the found child object or NULL ++ */ ++UMLObject* UMLClassifier::findChildObjectById(Uml::ID::Type id, bool considerAncestors /* =false */) ++{ ++ UMLObject *o = UMLCanvasObject::findChildObjectById(id); ++ if (o) { ++ return o; ++ } ++ if (considerAncestors) { ++ UMLClassifierList ancestors = findSuperClassConcepts(); ++ foreach (UMLClassifier *anc, ancestors) { ++ UMLObject *o = anc->findChildObjectById(id); ++ if (o) { ++ return o; ++ } ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * Returns a list of concepts which inherit from this concept. ++ * ++ * @param type The ClassifierType to seek. ++ * @return List of UMLClassifiers that inherit from us. ++ */ ++UMLClassifierList UMLClassifier::findSubClassConcepts (ClassifierType type) ++{ ++ UMLClassifierList list = getSubClasses(); ++ UMLAssociationList rlist = getRealizations(); ++ ++ UMLClassifierList inheritingConcepts; ++ Uml::ID::Type myID = id(); ++ foreach(UMLClassifier *c, list) { ++ uIgnoreZeroPointer(c); ++ if (type == ALL || (!c->isInterface() && type == CLASS) ++ || (c->isInterface() && type == INTERFACE)) { ++ inheritingConcepts.append(c); ++ } ++ } ++ ++ foreach (UMLAssociation *a, rlist) { ++ uIgnoreZeroPointer(a); ++ if (a->getObjectId(RoleType::A) != myID) ++ { ++ UMLObject* obj = a->getObject(RoleType::A); ++ UMLClassifier *concept = dynamic_cast(obj); ++ if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) ++ || (concept->isInterface() && type == INTERFACE)) ++ && (inheritingConcepts.indexOf(concept) == -1)) ++ { ++ inheritingConcepts.append(concept); ++ } ++ } ++ } ++ ++ return inheritingConcepts; ++} ++ ++/** ++ * Returns a list of concepts which this concept inherits from. ++ * ++ * @param type The ClassifierType to seek. ++ * @return List of UMLClassifiers we inherit from. ++ */ ++UMLClassifierList UMLClassifier::findSuperClassConcepts (ClassifierType type) ++{ ++ UMLClassifierList list = getSuperClasses(); ++ UMLAssociationList rlist = getRealizations(); ++ ++ UMLClassifierList parentConcepts; ++ Uml::ID::Type myID = id(); ++ foreach (UMLClassifier *concept, list) { ++ uIgnoreZeroPointer(concept); ++ if (type == ALL || (!concept->isInterface() && type == CLASS) ++ || (concept->isInterface() && type == INTERFACE)) ++ parentConcepts.append(concept); ++ } ++ ++ foreach (UMLAssociation *a, rlist) { ++ if (a->getObjectId(RoleType::A) == myID) ++ { ++ UMLObject* obj = a->getObject(RoleType::B); ++ UMLClassifier *concept = dynamic_cast(obj); ++ if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) ++ || (concept->isInterface() && type == INTERFACE)) ++ && (parentConcepts.indexOf(concept) == -1)) ++ parentConcepts.append(concept); ++ } ++ } ++ ++ return parentConcepts; ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLClassifier::operator==(const UMLClassifier & rhs) const ++{ ++ return UMLCanvasObject::operator==(rhs); ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLClassifier::copyInto(UMLObject *lhs) const ++{ ++ UMLClassifier *target = static_cast(lhs); ++ UMLCanvasObject::copyInto(target); ++ target->setBaseType(m_BaseType); ++ // CHECK: association property m_pClassAssoc is not copied ++ m_List.copyInto(&(target->m_List)); ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLClassifier::clone() const ++{ ++ UMLClassifier *clone = new UMLClassifier(); ++ copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Needs to be called after all UML objects are loaded from file. ++ * Calls the parent resolveRef(), and calls resolveRef() on all ++ * UMLClassifierListItems. ++ * Overrides the method from UMLObject. ++ * ++ * @return true for success. ++ */ ++bool UMLClassifier::resolveRef() ++{ ++ bool success = UMLPackage::resolveRef(); ++ // Using reentrant iteration is a bare necessity here: ++ foreach (UMLObject* obj, m_List) { ++ uIgnoreZeroPointer(obj); ++ /**** For reference, here is the non-reentrant iteration scheme - ++ DO NOT USE THIS ! ++ for (UMLObject *obj = m_List.first(); obj; obj = m_List.next()) ++ { .... } ++ ****/ ++ if (obj->resolveRef()) { ++ UMLClassifierListItem *cli = static_cast(obj); ++ switch (cli->baseType()) { ++ case UMLObject::ot_Attribute: ++ emit attributeAdded(cli); ++ break; ++ case UMLObject::ot_Operation: ++ emit operationAdded(cli); ++ break; ++ case UMLObject::ot_Template: ++ emit templateAdded(cli); ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ return success; ++} ++ ++/** ++ * Reimplemented from UMLObject. ++ */ ++bool UMLClassifier::acceptAssociationType(AssociationType::Enum type) ++{ ++ switch(type) ++ { ++ case AssociationType::Generalization: ++ case AssociationType::Aggregation: ++ case AssociationType::Relationship: ++ case AssociationType::Dependency: ++ case AssociationType::Association: ++ case AssociationType::Association_Self: ++ case AssociationType::Containment: ++ case AssociationType::Composition: ++ case AssociationType::Realization: ++ case AssociationType::UniAssociation: ++ return true; ++ default: ++ return false; ++ } ++ return false; //shutup compiler warning ++} ++ ++/** ++ * Creates an attribute for the class. ++ * ++ * @param name An optional name, used by when creating through UMLListView ++ * @param type An optional type, used by when creating through UMLListView ++ * @param vis An optional visibility, used by when creating through UMLListView ++ * @param init An optional initial value, used by when creating through UMLListView ++ * @return The UMLAttribute created ++ */ ++UMLAttribute* UMLClassifier::createAttribute(const QString &name, ++ UMLObject *type, ++ Visibility::Enum vis, ++ const QString &init) ++{ ++ Uml::ID::Type id = UniqueID::gen(); ++ QString currentName; ++ if (name.isNull()) { ++ currentName = uniqChildName(UMLObject::ot_Attribute); ++ } else { ++ currentName = name; ++ } ++ UMLAttribute* newAttribute = new UMLAttribute(this, currentName, id, vis, type, init); ++ ++ int button = QDialog::Accepted; ++ bool goodName = false; ++ ++ //check for name.isNull() stops dialog being shown ++ //when creating attribute via list view ++ while (button == QDialog::Accepted && !goodName && name.isNull()) { ++ QPointer attributeDialog = new UMLAttributeDialog(0, newAttribute); ++ button = attributeDialog->exec(); ++ QString name = newAttribute->name(); ++ ++ if(name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } else if (findChildObject(name) != NULL) { ++ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); ++ } else { ++ goodName = true; ++ } ++ delete attributeDialog; ++ } ++ ++ if (button != QDialog::Accepted) { ++ delete newAttribute; ++ return NULL; ++ } ++ ++ addAttribute(newAttribute); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newAttribute); ++ return newAttribute; ++} ++ ++/** ++ * Creates and adds an attribute for the class. ++ * ++ * @param name an optional name, used by when creating through UMLListView ++ * @param id an optional id ++ * @return the UMLAttribute created and added ++ */ ++ ++UMLAttribute* UMLClassifier::addAttribute(const QString &name, Uml::ID::Type id /* = Uml::id_None */) ++{ ++ foreach (UMLObject* obj, m_List) { ++ uIgnoreZeroPointer(obj); ++ if (obj->baseType() == UMLObject::ot_Attribute && obj->name() == name) ++ return static_cast(obj); ++ } ++ Uml::Visibility::Enum scope = Settings::optionState().classState.defaultAttributeScope; ++ UMLAttribute *a = new UMLAttribute(this, name, id, scope); ++ m_List.append(a); ++ emit attributeAdded(a); ++ UMLObject::emitModified(); ++ connect(a, SIGNAL(modified()), this, SIGNAL(modified())); ++ return a; ++} ++ ++/** ++ * Adds an already created attribute. ++ * The attribute object must not belong to any other concept. ++ * ++ * @param name the name of the attribute ++ * @param type the type of the attribute ++ * @param scope the visibility of the attribute ++ * @return the just created and added attribute ++ */ ++UMLAttribute* UMLClassifier::addAttribute(const QString &name, UMLObject *type, Visibility::Enum scope) ++{ ++ UMLAttribute *a = new UMLAttribute(this); ++ a->setName(name); ++ a->setVisibility(scope); ++ a->setID(UniqueID::gen()); ++ if (type) { ++ a->setType(type); ++ } ++ m_List.append(a); ++ emit attributeAdded(a); ++ UMLObject::emitModified(); ++ connect(a, SIGNAL(modified()), this, SIGNAL(modified())); ++ return a; ++} ++ ++/** ++ * Adds an already created attribute. ++ * The attribute object must not belong to any other concept. ++ * ++ * @param att Pointer to the UMLAttribute. ++ * @param log Pointer to the IDChangeLog (optional.) ++ * @param position Position index for the insertion (optional.) ++ * If the position is omitted, or if it is ++ * negative or too large, the attribute is added ++ * to the end of the list. ++ * @return True if the attribute was successfully added. ++ */ ++bool UMLClassifier::addAttribute(UMLAttribute* att, IDChangeLog* log /* = 0 */, ++ int position /* = -1 */) ++{ ++ Q_ASSERT(att); ++ if (findChildObject(att->name()) == NULL) { ++ att->setParent(this); ++ if (position >= 0 && position < (int)m_List.count()) { ++ m_List.insert(position, att); ++ } ++ else { ++ m_List.append(att); ++ } ++ emit attributeAdded(att); ++ UMLObject::emitModified(); ++ connect(att, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } else if (log) { ++ log->removeChangeByNewID(att->id()); ++ delete att; ++ } ++ return false; ++} ++ ++/** ++ * Removes an attribute from the class. ++ * ++ * @param att The attribute to remove. ++ * @return Count of the remaining attributes after removal. ++ * Returns -1 if the given attribute was not found. ++ */ ++int UMLClassifier::removeAttribute(UMLAttribute* att) ++{ ++ if (!m_List.removeAll(att)) { ++ uDebug() << "cannot find att given in list"; ++ return -1; ++ } ++ emit attributeRemoved(att); ++ UMLObject::emitModified(); ++ // If we are deleting the object, then we don't need to disconnect..this is done auto-magically ++ // for us by QObject. -b.t. ++ // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); ++ delete att; ++ return m_List.count(); ++} ++ ++/** ++ * Sets the UMLAssociation for which this class shall act as an ++ * association class. ++ */ ++void UMLClassifier::setClassAssoc(UMLAssociation *assoc) ++{ ++ m_pClassAssoc = assoc; ++} ++ ++/** ++ * Returns the UMLAssociation for which this class acts as an ++ * association class. Returns NULL if this class does not act ++ * as an association class. ++ */ ++UMLAssociation *UMLClassifier::getClassAssoc() const ++{ ++ return m_pClassAssoc; ++} ++ ++/** ++ * Return true if this classifier has abstract operations. ++ */ ++bool UMLClassifier::hasAbstractOps () ++{ ++ UMLOperationList opl(getOpList()); ++ foreach(UMLOperation *op, opl) { ++ uIgnoreZeroPointer(op); ++ if (op->isAbstract()) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++/** ++ * Counts the number of operations in the Classifier. ++ * ++ * @return The number of operations for the Classifier. ++ */ ++int UMLClassifier::operations() ++{ ++ return getOpList().count(); ++} ++ ++ ++/** ++ * Return a list of operations for the Classifier. ++ * ++ * @param includeInherited Includes operations from superclasses. ++ * @param alreadyTraversed internal used object to avoid recursive loops ++ * @return The list of operations for the Classifier. ++ */ ++UMLOperationList UMLClassifier::getOpList(bool includeInherited, UMLClassifierSet *alreadyTraversed) ++{ ++ UMLOperationList ops; ++ foreach (UMLObject* li, m_List) { ++ uIgnoreZeroPointer(li); ++ if (li->baseType() == ot_Operation) { ++ ops.append(static_cast(li)); ++ } ++ } ++ if (includeInherited) { ++ if (!alreadyTraversed) { ++ alreadyTraversed = new UMLClassifierSet; ++ } ++ else ++ alreadyTraversed->level++; ++ ++ if (!alreadyTraversed->contains(this)) ++ *alreadyTraversed << this; ++ ++ // get a list of parents of this class ++ UMLClassifierList parents = findSuperClassConcepts(); ++ foreach(UMLClassifier *c, parents) { ++ if (alreadyTraversed->contains(c)) { ++ uError() << "class " << c->name() << " is starting a dependency loop!"; ++ continue; ++ } ++ // get operations for each parent by recursive call ++ UMLOperationList pops = c->getOpList(true, alreadyTraversed); ++ // add these operations to operation list, but only if unique. ++ foreach (UMLOperation *po, pops) { ++ QString po_as_string(po->toString(Uml::SignatureType::SigNoVis)); ++ bool breakFlag = false; ++ foreach (UMLOperation* o, ops) { ++ if (o->toString(Uml::SignatureType::SigNoVis) == po_as_string) { ++ breakFlag = true; ++ break; ++ } ++ } ++ if (breakFlag == false) ++ ops.append(po); ++ } ++ // remember this node ++ *alreadyTraversed << c; ++ } ++ if (alreadyTraversed->level-- == 0) { ++ delete alreadyTraversed; ++ alreadyTraversed = 0; ++ } ++ } ++ return ops; ++} ++ ++/** ++ * Returns the entries in m_List that are of the requested type. ++ * If the requested type is UMLObject::ot_UMLObject then all entries ++ * are returned. ++ * @param ot the requested object type ++ * @return The list of true operations for the Concept. ++ */ ++UMLClassifierListItemList UMLClassifier::getFilteredList(UMLObject::ObjectType ot) const ++{ ++ UMLClassifierListItemList resultList; ++ foreach (UMLObject* o, m_List) { ++ uIgnoreZeroPointer(o); ++ if (!o || o->baseType() == UMLObject::ot_Association) { ++ continue; ++ } ++ UMLClassifierListItem *listItem = static_cast(o); ++ if (ot == UMLObject::ot_UMLObject || listItem->baseType() == ot) { ++ resultList.append(listItem); ++ } ++ } ++ return resultList; ++} ++ ++/** ++ * Adds an already created template. ++ * The template object must not belong to any other concept. ++ * ++ * @param name the name of the template ++ * @param id the id of the template ++ * @return the added template ++ */ ++UMLTemplate* UMLClassifier::addTemplate(const QString &name, Uml::ID::Type id) ++{ ++ UMLTemplate *templt = findTemplate(name); ++ if (templt) { ++ return templt; ++ } ++ templt = new UMLTemplate(this, name, id); ++ m_List.append(templt); ++ emit templateAdded(templt); ++ UMLObject::emitModified(); ++ connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); ++ return templt; ++} ++ ++/** ++ * Adds an already created template. ++ * The template object must not belong to any other concept. ++ * ++ * @param newTemplate Pointer to the UMLTemplate object to add. ++ * @param log Pointer to the IDChangeLog. ++ * @return True if the template was successfully added. ++ */ ++bool UMLClassifier::addTemplate(UMLTemplate* newTemplate, IDChangeLog* log /* = 0*/) ++{ ++ QString name = newTemplate->name(); ++ if (findChildObject(name) == NULL) { ++ newTemplate->setParent(this); ++ m_List.append(newTemplate); ++ emit templateAdded(newTemplate); ++ UMLObject::emitModified(); ++ connect(newTemplate, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } ++ else if (log) { ++ log->removeChangeByNewID(newTemplate->id()); ++ delete newTemplate; ++ } ++ return false; ++} ++ ++/** ++ * Adds an template to the class. ++ * The template object must not belong to any other class. ++ * TODO: If the param IDChangeLog from the method above is not being used, ++ * give position a default value of -1 and the method can replace the above one. ++ * @param templt Pointer to the UMLTemplate to add. ++ * @param position The position of the template in the list. ++ * A value of -1 will add the template at the end. ++ * @return True if the template was successfully added. ++ */ ++bool UMLClassifier::addTemplate(UMLTemplate* templt, int position) ++{ ++ Q_ASSERT(templt); ++ QString name = templt->name(); ++ if (findChildObject(name) == NULL) { ++ templt->setParent(this); ++ if (position >= 0 && position <= (int)m_List.count()) { ++ m_List.insert(position, templt); ++ } ++ else { ++ m_List.append(templt); ++ } ++ emit templateAdded(templt); ++ UMLObject::emitModified(); ++ connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } ++ //else ++ return false; ++} ++ ++/** ++ * Removes a template from the class. ++ * ++ * @param umltemplate The template to remove. ++ * @return Count of the remaining templates after removal. ++ * Returns -1 if the given template was not found. ++ */ ++int UMLClassifier::removeTemplate(UMLTemplate* umltemplate) ++{ ++ if (!m_List.removeAll(umltemplate)) { ++ uWarning() << "cannot find att given in list"; ++ return -1; ++ } ++ emit templateRemoved(umltemplate); ++ UMLObject::emitModified(); ++ disconnect(umltemplate, SIGNAL(modified()), this, SIGNAL(modified())); ++ return m_List.count(); ++} ++ ++/** ++ * Seeks the template parameter of the given name. ++ * @param name the template name ++ * @return the found template or 0 ++ */ ++UMLTemplate *UMLClassifier::findTemplate(const QString& name) ++{ ++ UMLTemplateList templParams = getTemplateList(); ++ foreach (UMLTemplate *templt, templParams) { ++ if (templt->name() == name) { ++ return templt; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * Returns the number of templates for the class. ++ * ++ * @return The number of templates for the class. ++ */ ++int UMLClassifier::templates() ++{ ++ UMLClassifierListItemList tempList = getFilteredList(UMLObject::ot_Template); ++ return tempList.count(); ++} ++ ++/** ++ * Returns the templates. ++ * Same as UMLClassifier::getFilteredList(ot_Template) but ++ * return type is a true UMLTemplateList. ++ * ++ * @return Pointer to the list of true templates for the class. ++ */ ++UMLTemplateList UMLClassifier::getTemplateList() const ++{ ++ UMLTemplateList templateList; ++ foreach (UMLObject* listItem, m_List) { ++ uIgnoreZeroPointer(listItem); ++ if (listItem->baseType() == UMLObject::ot_Template) { ++ templateList.append(static_cast(listItem)); ++ } ++ } ++ return templateList; ++} ++ ++/** ++ * Take and return a subordinate item from this classifier. ++ * Ownership of the item is passed to the caller. ++ * ++ * @param item Subordinate item to take. ++ * @return Index in m_List of the item taken. ++ * Return -1 if the item is not found in m_List. ++ */ ++int UMLClassifier::takeItem(UMLClassifierListItem *item) ++{ ++ QString buf; ++ foreach (UMLObject* currentAtt, m_List) { ++ uIgnoreZeroPointer(currentAtt); ++ QString txt = currentAtt->name(); ++ if (txt.isEmpty()) { ++ txt = QLatin1String("Type-") + QString::number((int) currentAtt->baseType()); ++ } ++ buf.append(QLatin1Char(' ') + currentAtt->name()); ++ } ++ uDebug() << " UMLClassifier::takeItem (before): m_List is " << buf; ++ ++ int index = m_List.indexOf(item); ++ if (index == -1) { ++ return -1; ++ } ++ switch (item->baseType()) { ++ case UMLObject::ot_Operation: { ++ if (removeOperation(dynamic_cast(item)) < 0) { ++ index = -1; ++ } ++ break; ++ } ++ case UMLObject::ot_Attribute: { ++ UMLAttribute *retval = dynamic_cast(m_List.takeAt(index).data()); ++ if (retval) { ++ emit attributeRemoved(retval); ++ UMLObject::emitModified(); ++ } else { ++ index = -1; ++ } ++ break; ++ } ++ case UMLObject::ot_Template: { ++ UMLTemplate *templt = dynamic_cast(m_List.takeAt(index).data()); ++ if (templt) { ++ emit templateRemoved(templt); ++ UMLObject::emitModified(); ++ } else { ++ index = -1; ++ } ++ break; ++ } ++ case UMLObject::ot_EnumLiteral: { ++ UMLEnumLiteral *el = dynamic_cast(m_List.takeAt(index).data()); ++ if (el) { ++ UMLEnum *e = static_cast(this); ++ e->signalEnumLiteralRemoved(el); ++ UMLObject::emitModified(); ++ } else { ++ index = -1; ++ } ++ break; ++ } ++ case UMLObject::ot_EntityAttribute: { ++ UMLEntityAttribute* el = dynamic_cast(m_List.takeAt(index).data()); ++ if (el) { ++ UMLEntity *e = static_cast(this); ++ e->signalEntityAttributeRemoved(el); ++ UMLObject::emitModified(); ++ } else { ++ index = -1; ++ } ++ break; ++ } ++ default: ++ index = -1; ++ break; ++ } ++ return index; ++} ++ ++/** ++ * Set the origin type (in case of e.g. typedef) ++ * @param origType the origin type to set ++ */ ++void UMLClassifier::setOriginType(UMLClassifier *origType) ++{ ++ m_pSecondary = origType; ++} ++ ++/** ++ * Get the origin type (in case of e.g. typedef) ++ * @return the origin type ++ */ ++UMLClassifier * UMLClassifier::originType() const ++{ ++ return dynamic_cast(m_pSecondary.data()); ++} ++ ++/** ++ * Set the m_isRef flag (true when dealing with a pointer type) ++ * @param isRef the flag to set ++ */ ++void UMLClassifier::setIsReference(bool isRef) ++{ ++ m_isRef = isRef; ++} ++ ++/** ++ * Get the m_isRef flag. ++ * @return true if is reference, otherwise false ++ */ ++bool UMLClassifier::isReference() const ++{ ++ return m_isRef; ++} ++ ++/** ++ * Return true if this classifier has associations. ++ * @return true if classifier has associations ++ */ ++bool UMLClassifier::hasAssociations() ++{ ++ return getSpecificAssocs(AssociationType::Association).count() > 0 ++ || getAggregations().count() > 0 ++ || getCompositions().count() > 0 ++ || getUniAssociationToBeImplemented().count() > 0; ++} ++ ++/** ++ * Return true if this classifier has attributes. ++ */ ++bool UMLClassifier::hasAttributes() ++{ ++ return getAttributeList(Uml::Visibility::Public).count() > 0 ++ || getAttributeList(Uml::Visibility::Protected).count() > 0 ++ || getAttributeList(Uml::Visibility::Private).count() > 0 ++ || getAttributeListStatic(Uml::Visibility::Public).count() > 0 ++ || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 ++ || getAttributeListStatic(Uml::Visibility::Private).count() > 0; ++} ++ ++/** ++ * Return true if this classifier has static attributes. ++ */ ++bool UMLClassifier::hasStaticAttributes() ++{ ++ return getAttributeListStatic(Uml::Visibility::Public).count() > 0 ++ || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 ++ || getAttributeListStatic(Uml::Visibility::Private).count() > 0; ++} ++ ++/** ++ * Return true if this classifier has accessor methods. ++ */ ++bool UMLClassifier::hasAccessorMethods() ++{ ++ return hasAttributes() || hasAssociations(); ++} ++ ++/** ++ * Return true if this classifier has operation methods. ++ */ ++bool UMLClassifier::hasOperationMethods() ++{ ++ return getOpList().last() ? true : false; ++} ++ ++/** ++ * Return true if this classifier has methods. ++ */ ++bool UMLClassifier::hasMethods() ++{ ++ return hasOperationMethods() || hasAccessorMethods(); ++} ++ ++// this is a bit too simplistic..some associations are for ++// SINGLE objects, and WONT be declared as Vectors, so this ++// is a bit overly inclusive (I guess that's better than the other way around) ++ ++/** ++ * Return true if this classifier has vector fields. ++ */ ++bool UMLClassifier::hasVectorFields() ++{ ++ return hasAssociations(); ++} ++ ++/** ++ * Return the list of unidirectional association that should show up in the code ++ */ ++UMLAssociationList UMLClassifier::getUniAssociationToBeImplemented() ++{ ++ UMLAssociationList associations = getSpecificAssocs(AssociationType::UniAssociation); ++ UMLAssociationList uniAssocListToBeImplemented; ++ ++ foreach (UMLAssociation *a, associations) { ++ uIgnoreZeroPointer(a); ++ if (a->getObjectId(RoleType::B) == id()) { ++ continue; // we need to be at the A side ++ } ++ QString roleNameB = a->getRoleName(RoleType::B); ++ if (!roleNameB.isEmpty()) { ++ UMLAttributeList atl = getAttributeList(); ++ bool found = false; ++ //make sure that an attribute with the same name doesn't already exist ++ foreach (UMLAttribute *at, atl) { ++ uIgnoreZeroPointer(a); ++ if (at->name() == roleNameB) { ++ found = true; ++ break; ++ } ++ } ++ if (!found) { ++ uniAssocListToBeImplemented.append(a); ++ } ++ } ++ } ++ return uniAssocListToBeImplemented; ++} ++ ++/** ++ * Creates XML tag , , or ++ * depending on m_BaseType. ++ * Saves possible template parameters, generalizations, attributes, ++ * operations, and contained objects to the given QDomElement. ++ */ ++void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QString tag; ++ switch (m_BaseType) { ++ case UMLObject::ot_Class: ++ tag = QLatin1String("UML:Class"); ++ break; ++ case UMLObject::ot_Interface: ++ tag = QLatin1String("UML:Interface"); ++ break; ++ case UMLObject::ot_Datatype: ++ tag = QLatin1String("UML:DataType"); ++ break; ++ case UMLObject::ot_Package: ++ UMLPackage::saveToXMI(qDoc, qElement); ++ return; ++ break; ++ default: ++ uError() << "internal error: basetype is " << m_BaseType; ++ return; ++ } ++ QDomElement classifierElement = UMLObject::save(tag, qDoc); ++ if (m_BaseType == UMLObject::ot_Datatype && m_pSecondary != NULL) ++ classifierElement.setAttribute(QLatin1String("elementReference"), ++ Uml::ID::toString(m_pSecondary->id())); ++ ++ //save templates ++ UMLClassifierListItemList list = getFilteredList(UMLObject::ot_Template); ++ if (list.count()) { ++ QDomElement tmplElement = qDoc.createElement(QLatin1String("UML:ModelElement.templateParameter")); ++ foreach (UMLClassifierListItem *tmpl, list) { ++ tmpl->saveToXMI(qDoc, tmplElement); ++ } ++ classifierElement.appendChild(tmplElement); ++ } ++ ++ //save generalizations (we are the subclass, the other end is the superclass) ++ UMLAssociationList generalizations = getSpecificAssocs(AssociationType::Generalization); ++ if (generalizations.count()) { ++ QDomElement genElement = qDoc.createElement(QLatin1String("UML:GeneralizableElement.generalization")); ++ foreach (UMLAssociation *a, generalizations) { ++ // We are the subclass if we are at the role A end. ++ if (m_nId != a->getObjectId(RoleType::A)) { ++ continue; ++ } ++ QDomElement gElem = qDoc.createElement(QLatin1String("UML:Generalization")); ++ gElem.setAttribute(QLatin1String("xmi.idref"), Uml::ID::toString(a->id())); ++ genElement.appendChild(gElem); ++ } ++ if (genElement.hasChildNodes()) { ++ classifierElement.appendChild(genElement); ++ } ++ } ++ ++ // save attributes ++ QDomElement featureElement = qDoc.createElement(QLatin1String("UML:Classifier.feature")); ++ UMLClassifierListItemList attList = getFilteredList(UMLObject::ot_Attribute); ++ foreach (UMLClassifierListItem *pAtt, attList) { ++ pAtt->saveToXMI(qDoc, featureElement); ++ } ++ ++ // save operations ++ UMLOperationList opList = getOpList(); ++ foreach (UMLOperation *pOp, opList) { ++ pOp->saveToXMI(qDoc, featureElement); ++ } ++ if (featureElement.hasChildNodes()) { ++ classifierElement.appendChild(featureElement); ++ } ++ ++ // save contained objects ++ if (m_objects.count()) { ++ QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); ++ foreach (UMLObject* obj, m_objects) { ++ uIgnoreZeroPointer(obj); ++ obj->saveToXMI (qDoc, ownedElement); ++ } ++ classifierElement.appendChild(ownedElement); ++ } ++ qElement.appendChild(classifierElement); ++} ++ ++/** ++ * Create a new ClassifierListObject (attribute, operation, template) ++ * according to the given XMI tag. ++ * Returns NULL if the string given does not contain one of the tags ++ * , , or . ++ * Used by the clipboard for paste operation. ++ */ ++UMLClassifierListItem* UMLClassifier::makeChildObject(const QString& xmiTag) ++{ ++ UMLClassifierListItem* pObject = NULL; ++ if (UMLDoc::tagEq(xmiTag, QLatin1String("Operation")) || ++ UMLDoc::tagEq(xmiTag, QLatin1String("ownedOperation"))) { ++ pObject = new UMLOperation(this); ++ } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Attribute")) || ++ UMLDoc::tagEq(xmiTag, QLatin1String("ownedAttribute"))) { ++ if (baseType() != UMLObject::ot_Class) ++ return NULL; ++ pObject = new UMLAttribute(this); ++ } else if (UMLDoc::tagEq(xmiTag, QLatin1String("TemplateParameter"))) { ++ pObject = new UMLTemplate(this); ++ } ++ return pObject; ++} ++ ++/** ++ * Auxiliary to loadFromXMI: ++ * The loading of operations is implemented here. ++ * Calls loadSpecialized() for any other tag. ++ * Child classes can override the loadSpecialized method ++ * to load its additional tags. ++ */ ++bool UMLClassifier::load(QDomElement& element) ++{ ++ UMLClassifierListItem *child = NULL; ++ m_SecondaryId = element.attribute(QLatin1String("elementReference")); ++ if (!m_SecondaryId.isEmpty()) { ++ // @todo We do not currently support composition. ++ m_isRef = true; ++ } ++ bool totalSuccess = true; ++ for (QDomNode node = element.firstChild(); !node.isNull(); ++ node = node.nextSibling()) { ++ if (node.isComment()) ++ continue; ++ element = node.toElement(); ++ QString tag = element.tagName(); ++ QString stereotype = element.attribute(QLatin1String("stereotype")); ++ if (UMLDoc::tagEq(tag, QLatin1String("ModelElement.templateParameter")) || ++ UMLDoc::tagEq(tag, QLatin1String("Classifier.feature")) || ++ UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) || ++ UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe ++ UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { ++ load(element); ++ // Not evaluating the return value from load() ++ // because we want a best effort. ++ ++ } else if ((child = makeChildObject(tag)) != NULL) { ++ if (child->loadFromXMI(element)) { ++ switch (child->baseType()) { ++ case UMLObject::ot_Template: ++ addTemplate(static_cast(child)); ++ break; ++ case UMLObject::ot_Operation: ++ if (! addOperation(static_cast(child))) { ++ uError() << "error from addOperation(op)"; ++ delete child; ++ totalSuccess = false; ++ } ++ break; ++ case UMLObject::ot_Attribute: ++ addAttribute(static_cast(child)); ++ break; ++ default: ++ break; ++ } ++ } else { ++ uWarning() << "failed to load " << tag; ++ delete child; ++ totalSuccess = false; ++ } ++ } else if (!Model_Utils::isCommonXMIAttribute(tag)) { ++ UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag, stereotype); ++ if (pObject == NULL) { ++ // Not setting totalSuccess to false ++ // because we want a best effort. ++ continue; ++ } ++ pObject->setUMLPackage(this); ++ if (! pObject->loadFromXMI(element)) { ++ removeObject(pObject); ++ delete pObject; ++ totalSuccess = false; ++ } ++ } ++ } ++ return totalSuccess; ++} ++ ++/* ++UMLClassifierList UMLClassifier::getPlainAssocChildClassifierList() ++{ ++ UMLAssociationList plainAssociations = getSpecificAssocs(Uml::AssociationType::Association); ++ return findAssocClassifierObjsInRoles(&plainAssociations); ++} ++ ++UMLClassifierList UMLClassifier::getAggregateChildClassifierList() ++{ ++ UMLAssociationList aggregations = getAggregations(); ++ return findAssocClassifierObjsInRoles(&aggregations); ++} ++ ++UMLClassifierList UMLClassifier::getCompositionChildClassifierList() ++{ ++ UMLAssociationList compositions = getCompositions(); ++ return findAssocClassifierObjsInRoles(&compositions); ++} ++ ++UMLClassifierList UMLClassifier::findAssocClassifierObjsInRoles (UMLAssociationList * list) ++{ ++ UMLClassifierList classifiers; ++ ++ for (UMLAssociationListIt alit(*list); alit.hasNext(); ) { ++ UMLAssociation* a = alit.next(); ++ // DON'T accept a classifier IF the association role is empty, by ++ // convention, that means to ignore the classifier on that end of ++ // the association. ++ // We also ignore classifiers which are the same as the current one ++ // (e.g. id matches), we only want the "other" classifiers ++ if (a->getObjectId(RoleType::A) == id() && !a->getRoleName(RoleType::B).isEmpty()) { ++ UMLClassifier *c = dynamic_cast(a->getObject(RoleType::B)); ++ if(c) ++ classifiers.append(c); ++ } else if (a->getObjectId(RoleType::B) == id() && !a->getRoleName(RoleType::A).isEmpty()) { ++ UMLClassifier *c = dynamic_cast(a->getObject(RoleType::A)); ++ if(c) ++ classifiers.append(c); ++ } ++ } ++ ++ return classifiers; ++} ++*/ ++ ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.h umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,199 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++#ifndef CLASSIFIER_H ++#define CLASSIFIER_H ++ ++#include "package.h" ++#include "umlattributelist.h" ++#include "umloperationlist.h" ++#include "umlclassifierlistitemlist.h" ++#include "classifierlistitem.h" ++#include "umltemplatelist.h" ++#include "model_utils.h" ++ ++// forward declarations ++class UMLAssociation; ++class IDChangeLog; ++class UMLClassifierSet; ++ ++/** ++ * This class defines the non-graphical information required for a ++ * UML Classifier (ie a class or interface). ++ * This class inherits from @ref UMLPackage which allows classifiers ++ * to also act as namespaces, i.e. it allows classifiers to nest. ++ * ++ * NOTE: There is a unit test available for this class. ++ * Please, use and adapt it when necessary. ++ * ++ * @short Information for a non-graphical Concept/Class. ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLClassifier : public UMLPackage ++{ ++ Q_OBJECT ++public: ++ ++ /** ++ * Enumeration identifying the type of classifier. ++ */ ++ enum ClassifierType { ALL = 0, CLASS, INTERFACE, DATATYPE }; ++ ++ explicit UMLClassifier(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLClassifier(); ++ ++ bool operator==(const UMLClassifier & rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ UMLObject* clone() const; ++ ++ virtual UMLAttribute* createAttribute(const QString &name = QString(), ++ UMLObject *type = 0, ++ Uml::Visibility::Enum vis = Uml::Visibility::Private, ++ const QString &init = QString()); ++ ++ UMLAttribute* addAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); ++ UMLAttribute* addAttribute(const QString &name, UMLObject *type, Uml::Visibility::Enum scope); ++ ++ bool addAttribute(UMLAttribute* att, IDChangeLog* log = 0, ++ int position = -1); ++ ++ int removeAttribute(UMLAttribute *att); ++ ++ int attributes() ; ++ ++ UMLAttributeList getAttributeList() const; ++ UMLAttributeList getAttributeList(Uml::Visibility::Enum scope) const; ++ UMLAttributeList getAttributeListStatic(Uml::Visibility::Enum scope) const; ++ ++ UMLOperation* createOperation(const QString &name = QString(), ++ bool *isExistingOp = NULL, ++ Model_Utils::NameAndType_List *params = NULL); ++ ++ bool addOperation(UMLOperation* op, int position = -1); ++ bool addOperation(UMLOperation* op, IDChangeLog* log); ++ ++ UMLOperation * checkOperationSignature(const QString& name, ++ UMLAttributeList opParams, ++ UMLOperation *exemptOp = NULL); ++ ++ int removeOperation(UMLOperation *op); ++ ++ int operations(); ++ ++ UMLOperationList getOpList(bool includeInherited = false, UMLClassifierSet *alreadyTraversed = 0); ++ ++ UMLObject* createTemplate(const QString& name = QString()); ++ ++ UMLTemplate* addTemplate(const QString &name, Uml::ID::Type id = Uml::ID::None); ++ ++ bool addTemplate(UMLTemplate* newTemplate, IDChangeLog* log = 0); ++ bool addTemplate(UMLTemplate* templt, int position); ++ ++ int removeTemplate(UMLTemplate* umltemplate); ++ ++ UMLTemplate *findTemplate(const QString& name); ++ ++ int templates(); ++ ++ UMLTemplateList getTemplateList() const; ++ ++ int takeItem(UMLClassifierListItem* item); ++ ++ virtual UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; ++ ++ virtual bool resolveRef(); ++ ++ UMLOperationList findOperations(const QString &n); ++ ++ virtual UMLObject* findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); ++ ++ UMLOperation* findOperation(const QString& name, ++ Model_Utils::NameAndType_List params); ++ ++ UMLClassifierList findSuperClassConcepts(ClassifierType type = ALL); ++ ++ UMLClassifierList findSubClassConcepts(ClassifierType type = ALL); ++ ++ virtual bool acceptAssociationType(Uml::AssociationType::Enum type); ++ ++ void setClassAssoc(UMLAssociation *assoc); ++ UMLAssociation *getClassAssoc() const; ++ ++ void setBaseType(UMLObject::ObjectType ot); ++ ++ bool isInterface() const; ++ ++ bool isDatatype() const; ++ ++ void setOriginType(UMLClassifier *origType); ++ UMLClassifier * originType() const; ++ ++ void setIsReference(bool isRef = true); ++ bool isReference() const; ++ ++ bool hasAbstractOps(); ++ bool hasAssociations(); ++ bool hasAttributes(); ++ bool hasStaticAttributes(); ++ bool hasMethods(); ++ bool hasAccessorMethods(); ++ bool hasOperationMethods(); ++ bool hasVectorFields(); ++ ++ /** ++ * utility functions to allow easy determination of what classifiers ++ * are "owned" by the current one via named association type (e.g. ++ * plain, aggregate or compositions). ++ */ ++// UMLClassifierList getPlainAssocChildClassifierList(); ++// UMLClassifierList getAggregateChildClassifierList(); ++// UMLClassifierList getCompositionChildClassifierList(); ++ ++ virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); ++ ++ virtual UMLAssociationList getUniAssociationToBeImplemented(); ++ ++signals: ++ ++ void operationAdded(UMLClassifierListItem *); ++ void operationRemoved(UMLClassifierListItem *); ++ ++ void templateAdded(UMLClassifierListItem*); ++ void templateRemoved(UMLClassifierListItem*); ++ ++ // only applies when (m_Type == ot_Class) ++ void attributeAdded(UMLClassifierListItem*); ++ void attributeRemoved(UMLClassifierListItem*); ++ ++private: ++ ++ UMLAssociation *m_pClassAssoc; ++ ++ bool m_isRef; ++ ++ /** ++ * Utility method called by "get*ChildClassfierList()" methods. It basically ++ * finds all the classifiers named in each association in the given association list ++ * which aren't the current one. Useful for finding which classifiers are "owned" by the ++ * current one via declared associations such as in aggregations/compositions. ++ */ ++// UMLClassifierList findAssocClassifierObjsInRoles (UMLAssociationList * list); ++ ++protected: ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual bool load(QDomElement& element); ++ ++}; ++ ++#endif // CLASSIFIER_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,159 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "classifierlistitem.h" ++ ++// local includes ++#include "debug_utils.h" ++#include "classifier.h" ++#include "model_utils.h" ++#include "object_factory.h" ++#include "uml.h" ++#include "umldoc.h" ++ ++// kde includes ++#include ++ ++/** ++ * Constructor. ++ * ++ * @param parent The parent to this operation. ++ * At first sight it would appear that the type of the ++ * parent should be UMLClassifier. However, the class ++ * UMLAttribute is also used for the parameters of ++ * operations, and in this case the UMLOperation is the ++ * parent. ++ * @param name The name of the operation. ++ * @param id The id of the operation. ++ */ ++UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent, ++ const QString& name, Uml::ID::Type id) ++ : UMLObject(parent, name, id) ++{ ++ UMLObject *parentObj = const_cast(parent); ++ UMLClassifier *pc = dynamic_cast(parentObj); ++ if (pc) ++ UMLObject::setUMLPackage(pc); ++} ++ ++/** ++ * Constructor. ++ * ++ * @param parent The parent to this operation. ++ * At first sight it would appear that the type of the ++ * parent should be UMLClassifier. However, the class ++ * UMLAttribute is also used for the parameters of ++ * operations, and in this case the UMLOperation is the ++ * parent. ++ */ ++UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent) ++ : UMLObject(parent) ++{ ++ UMLObject *parentObj = const_cast(parent); ++ UMLClassifier *pc = dynamic_cast(parentObj); ++ if (pc) ++ UMLObject::setUMLPackage(pc); ++} ++ ++/** ++ * Destructor. Empty. ++ */ ++UMLClassifierListItem::~UMLClassifierListItem() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLClassifierListItem::copyInto(UMLObject *lhs) const ++{ ++ // Call the parent. ++ UMLObject::copyInto(lhs); ++} ++ ++/** ++ * Returns a string representation of the list item. ++ * ++ * @param sig What type of operation string to show. ++ * @return The string representation of the operation. ++ */ ++QString UMLClassifierListItem::toString(Uml::SignatureType::Enum sig) ++{ ++ Q_UNUSED(sig); ++ return name(); ++} ++ ++/** ++ * Returns the type of the UMLClassifierListItem. ++ * ++ * @return The type of the UMLClassifierListItem. ++ */ ++UMLClassifier * UMLClassifierListItem::getType() const ++{ ++ return dynamic_cast(m_pSecondary.data()); ++} ++ ++/** ++ * Returns the type name of the UMLClassifierListItem. ++ * ++ * @return The type name of the UMLClassifierListItem. ++ */ ++QString UMLClassifierListItem::getTypeName() const ++{ ++ if (m_pSecondary == NULL) ++ return m_SecondaryId; ++ const UMLPackage *typePkg = m_pSecondary->umlPackage(); ++ if (typePkg != NULL && typePkg != m_pUMLPackage) ++ return m_pSecondary->fullyQualifiedName(); ++ return m_pSecondary->name(); ++} ++ ++/** ++ * Sets the type of the UMLAttribute. ++ * ++ * @param type Pointer to the UMLObject of the type. ++ */ ++void UMLClassifierListItem::setType(UMLObject *type) ++{ ++ if (m_pSecondary != type) { ++ m_pSecondary = type; ++ UMLObject::emitModified(); ++ } ++} ++ ++/** ++ * Sets the type name of the UMLClassifierListItem. ++ * DEPRECATED - use setType() instead. ++ * ++ * @param type The type name of the UMLClassifierListItem. ++ */ ++void UMLClassifierListItem::setTypeName(const QString &type) ++{ ++ if (type.isEmpty() || type == QLatin1String("void")) { ++ m_pSecondary = NULL; ++ m_SecondaryId.clear(); ++ return; ++ } ++ UMLDoc *pDoc = UMLApp::app()->document(); ++ m_pSecondary = pDoc->findUMLObject(type); ++ if (m_pSecondary == NULL) { ++ // Make data type for easily identified cases ++ if (Model_Utils::isCommonDataType(type) || type.contains(QLatin1Char('*'))) { ++ m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, type); ++ uDebug() << "created datatype for " << type; ++ } else { ++ m_SecondaryId = type; ++ } ++ } ++ UMLObject::emitModified(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.h umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,58 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef CLASSIFIERLISTITEM_H ++#define CLASSIFIERLISTITEM_H ++ ++#include "umlobject.h" ++ ++// forward declaration ++class UMLClassifier; ++ ++/** ++ * Classifiers (classes, interfaces) have lists of operations, ++ * attributes, templates and others. This is a base class for ++ * the items in this list. This abstraction should remove ++ * duplication of dialogs and allow for stereotypes in lists. ++ * ++ * @short A base class for classifier list items (e.g. attributes) ++ * @author Jonathan Riddell ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLClassifierListItem : public UMLObject ++{ ++ Q_OBJECT ++public: ++ ++ UMLClassifierListItem(UMLObject *parent, ++ const QString& name, ++ Uml::ID::Type id = Uml::ID::None); ++ explicit UMLClassifierListItem(UMLObject *parent); ++ virtual ~UMLClassifierListItem(); ++ ++ virtual void setType(UMLObject *type); ++ UMLClassifier * getType() const; ++ ++ void setTypeName(const QString &type); ++ virtual QString getTypeName() const; ++ ++ virtual QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ /** ++ * The abstract method UMLObject::clone() must be implemented ++ * by the classes inheriting from UMLClassifierListItem. ++ */ ++ virtual UMLObject* clone() const = 0; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/component.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/component.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,127 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "component.h" ++// app includes ++#include "association.h" ++#include "debug_utils.h" ++#include "object_factory.h" ++#include "model_utils.h" ++#include "clipboard/idchangelog.h" ++#include "umldoc.h" ++// kde includes ++#include ++ ++/** ++ * Sets up a Component. ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLComponent::UMLComponent(const QString & name, Uml::ID::Type id) ++ : UMLPackage(name, id), ++ m_executable(false) ++{ ++ m_BaseType = UMLObject::ot_Component; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLComponent::~UMLComponent() ++{ ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLComponent::clone() const ++{ ++ UMLComponent *clone = new UMLComponent(); ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the UML:Component element including its operations, ++ * attributes and templates ++ */ ++void UMLComponent::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement componentElement = UMLObject::save(QLatin1String("UML:Component"), qDoc); ++ componentElement.setAttribute(QLatin1String("executable"), m_executable); ++ // Save contained components if any. ++ if (m_objects.count()) { ++ QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); ++ for (UMLObjectListIt objectsIt(m_objects); objectsIt.hasNext();) { ++ UMLObject* obj = objectsIt.next(); ++ uIgnoreZeroPointer(obj); ++ obj->saveToXMI (qDoc, ownedElement); ++ } ++ componentElement.appendChild(ownedElement); ++ } ++ qElement.appendChild(componentElement); ++} ++ ++/** ++ * Loads the UML:Component element including its ports et al. ++ */ ++bool UMLComponent::load(QDomElement& element) ++{ ++ QString executable = element.attribute(QLatin1String("executable"), QLatin1String("0")); ++ m_executable = (bool)executable.toInt(); ++ 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::isCommonXMIAttribute(type)) ++ continue; ++ if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || ++ UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { ++ //CHECK: umbrello-kf6 currently assumes that nested elements ++ // are ownedElements anyway. ++ // Therefore these tags are not further interpreted. ++ if (! load(tempElement)) ++ return false; ++ continue; ++ } ++ UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); ++ if (!pObject) { ++ uWarning() << "Unknown type of umlobject to create: " << type; ++ continue; ++ } ++ pObject->setUMLPackage(this); ++ if (pObject->loadFromXMI(tempElement)) { ++ addObject(pObject); ++ } else { ++ delete pObject; ++ } ++ } ++ return true; ++} ++ ++/** ++ * Sets m_executable. ++ */ ++void UMLComponent::setExecutable(bool executable) ++{ ++ m_executable = executable; ++} ++ ++/** ++ * Returns the value of m_executable. ++ */ ++bool UMLComponent::getExecutable() ++{ ++ return m_executable; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.h umbrello-kf6-15.08.1/umbrello/umlmodel/component.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/component.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,48 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef COMPONENT_H ++#define COMPONENT_H ++ ++#include "package.h" ++ ++/** ++ * This class contains the non-graphical information required for a ++ * UML Component. ++ * This class inherits from @ref UMLPackage which contains most ++ * of the information. ++ * ++ * @short Non-graphical information for a Component. ++ * @author Jonathan Riddell ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLComponent : public UMLPackage ++{ ++ Q_OBJECT ++public: ++ explicit UMLComponent(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLComponent(); ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ void setExecutable(bool executable); ++ bool getExecutable(); ++ ++protected: ++ bool load(QDomElement & element); ++ ++private: ++ bool m_executable; ///< holds whether this is an executable component or not ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,280 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "entityattribute.h" ++ ++// app includes ++#include "debug_utils.h" ++//#include "umlcanvasobject.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "umlentityattributedialog.h" ++#include "object_factory.h" ++ ++// qt includes ++#include ++ ++/** ++ * Sets up an entityattribute. ++ * @param parent The parent of this UMLEntityAttribute. ++ * @param name The name of this UMLEntityAttribute. ++ * @param id The unique id given to this UMLEntityAttribute. ++ * @param s The visibility of the UMLEntityAttribute. ++ * @param type The type of this UMLEntityAttribute. ++ * @param iv The initial value of the entityattribute. ++ */ ++UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent, const QString& name, ++ Uml::ID::Type id, Uml::Visibility::Enum s, ++ UMLObject *type, const QString& iv) ++ : UMLAttribute(parent, name, id, s, type, iv) ++{ ++ init(); ++ if (m_pSecondary) { ++ m_pSecondary->setBaseType(UMLObject::ot_Entity); ++ } ++} ++ ++/** ++ * Sets up an entityattribute. ++ * @param parent The parent of this UMLEntityAttribute. ++ */ ++UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent) ++ : UMLAttribute(parent) ++{ ++ init(); ++} ++ ++/** ++ * Destructor. ++ */ ++UMLEntityAttribute::~UMLEntityAttribute() ++{ ++} ++ ++/** ++ * Initialize members of this class. ++ * Auxiliary method used by constructors. ++ */ ++void UMLEntityAttribute::init() ++{ ++ m_BaseType = UMLObject::ot_EntityAttribute; ++ m_indexType = UMLEntityAttribute::None; ++ m_autoIncrement = false; ++ m_null = false; ++} ++ ++/** ++ * Returns the value of the UMLEntityAttribute's attributes property. ++ * @return The value of the UMLEntityAttribute's attributes property. ++ */ ++QString UMLEntityAttribute::getAttributes() const ++{ ++ return m_attributes; ++} ++ ++/** ++ * Sets the UMLEntityAttribute's attributes property. ++ * @param attributes The new value for the attributes property. ++ */ ++void UMLEntityAttribute::setAttributes(const QString& attributes) ++{ ++ m_attributes = attributes; ++} ++ ++/** ++ * Returns the UMLEntityAttribute's length/values property. ++ * @return The new value of the length/values property. ++ */ ++QString UMLEntityAttribute::getValues() const ++{ ++ return m_values; ++} ++ ++/** ++ * Sets the UMLEntityAttribute's length/values property. ++ * @param values The new value of the length/values property. ++ */ ++void UMLEntityAttribute::setValues(const QString& values) ++{ ++ m_values = values; ++} ++ ++/** ++ * Returns the UMLEntityAttribute's auto_increment boolean ++ * @return The UMLEntityAttribute's auto_increment boolean ++ */ ++bool UMLEntityAttribute::getAutoIncrement() const ++{ ++ return m_autoIncrement; ++} ++ ++/** ++ * Sets the UMLEntityAttribute's auto_increment boolean ++ * @param autoIncrement The UMLEntityAttribute's auto_increment boolean ++ */ ++void UMLEntityAttribute::setAutoIncrement(const bool autoIncrement) ++{ ++ m_autoIncrement = autoIncrement; ++} ++ ++/** ++ * Returns the UMLEntityAttribute's index type property. ++ * @return The value of the UMLEntityAttribute's index type property. ++ */ ++UMLEntityAttribute::DBIndex_Type UMLEntityAttribute::indexType() const ++{ ++ return m_indexType; ++} ++ ++/** ++ * Sets the initial value of the UMLEntityAttribute's index type property. ++ * @param indexType The initial value of the UMLEntityAttribute's index type property. ++ */ ++void UMLEntityAttribute::setIndexType(const UMLEntityAttribute::DBIndex_Type indexType) ++{ ++ m_indexType = indexType; ++} ++ ++/** ++ * Returns the UMLEntityAttribute's allow null value. ++ * @return The UMLEntityAttribute's allow null value. ++ */ ++bool UMLEntityAttribute::getNull() const ++{ ++ return m_null; ++} ++ ++/** ++ * Sets the initial value of the UMLEntityAttribute's allow null value. ++ * @param nullIn The initial value of the UMLEntityAttribute's allow null value. ++ */ ++void UMLEntityAttribute::setNull(const bool nullIn) ++{ ++ m_null = nullIn; ++} ++ ++/** ++ * Returns a string representation of the UMLEntityAttribute. ++ * @param sig If true will show the entityattribute type and initial value. ++ * @return Returns a string representation of the UMLEntityAttribute. ++ */ ++QString UMLEntityAttribute::toString(Uml::SignatureType::Enum sig) ++{ ++ QString s; ++ //FIXME ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { ++ s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); ++ } ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { ++ QString string = s + name() + QLatin1String(" : ") + getTypeName(); ++ if(m_InitialValue.length() > 0) ++ string += QLatin1String(" = ") + m_InitialValue; ++ return string; ++ } else ++ return s + name(); ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLEntityAttribute::operator==(const UMLEntityAttribute &rhs) const ++{ ++ if(this == &rhs) ++ return true; ++ ++ if(!UMLObject::operator==(rhs)) ++ return false; ++ ++ // The type name is the only distinguishing criterion. ++ // (Some programming languages might support more, but others don't.) ++ if (m_pSecondary != rhs.m_pSecondary) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * Copy the internal presentation of this object into the UMLEntityAttribute ++ * object. ++ */ ++void UMLEntityAttribute::copyInto(UMLObject *lhs) const ++{ ++ UMLEntityAttribute *target = static_cast(lhs); ++ ++ // call the parent first. ++ UMLClassifierListItem::copyInto(target); ++ ++ // Copy all datamembers ++ target->m_pSecondary = m_pSecondary; ++ target->m_SecondaryId = m_SecondaryId; ++ target->m_InitialValue = m_InitialValue; ++ target->m_ParmKind = m_ParmKind; ++} ++ ++/** ++ * Make a clone of the UMLEntityAttribute. ++ */ ++UMLObject* UMLEntityAttribute::clone() const ++{ ++ UMLEntityAttribute* clone = new UMLEntityAttribute((UMLEntityAttribute*)parent()); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLEntityAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement entityattributeElement = UMLObject::save(QLatin1String("UML:EntityAttribute"), qDoc); ++ if (m_pSecondary == NULL) { ++ uDebug() << name() << ": m_pSecondary is NULL, using local name " << m_SecondaryId; ++ entityattributeElement.setAttribute(QLatin1String("type"), m_SecondaryId); ++ } else { ++ entityattributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); ++ } ++ entityattributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); ++ entityattributeElement.setAttribute(QLatin1String("dbindex_type"), m_indexType); ++ entityattributeElement.setAttribute(QLatin1String("values"), m_values); ++ entityattributeElement.setAttribute(QLatin1String("attributes"), m_attributes); ++ entityattributeElement.setAttribute(QLatin1String("auto_increment"), m_autoIncrement); ++ entityattributeElement.setAttribute(QLatin1String("allow_null"), m_null); ++ qElement.appendChild(entityattributeElement); ++} ++ ++/** ++ * Loads the XMI element. ++ */ ++bool UMLEntityAttribute::load(QDomElement & element) ++{ ++ if (! UMLAttribute::load(element)) ++ return false; ++ int indexType = element.attribute(QLatin1String("dbindex_type"), QLatin1String("1100")).toInt(); ++ m_indexType = (UMLEntityAttribute::DBIndex_Type)indexType; ++ m_values = element.attribute(QLatin1String("values")); ++ m_attributes = element.attribute(QLatin1String("attributes")); ++ m_autoIncrement = (bool)element.attribute(QLatin1String("auto_increment")).toInt(); ++ m_null = (bool)element.attribute(QLatin1String("allow_null")).toInt(); ++ return true; ++} ++ ++/** ++ * Display the properties configuration dialog for the entityattribute. ++ */ ++bool UMLEntityAttribute::showPropertiesDialog(QWidget* parent) ++{ ++ UMLEntityAttributeDialog dialog(parent, this); ++ return dialog.exec(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.h umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,85 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENTITYATTRIBUTE_H ++#define ENTITYATTRIBUTE_H ++ ++#include "attribute.h" ++#include "basictypes.h" ++ ++/** ++ * This class is used to set up information for an entityattribute. This is a database field ++ * It has a type, name, index type and default value. ++ * ++ * @short Sets up entityattribute information. ++ * @author Jonathan Riddell ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLEntityAttribute : public UMLAttribute ++{ ++ Q_OBJECT ++ Q_ENUMS(DBIndex_Type) ++public: ++ enum DBIndex_Type ++ { ++ None = 1100, ++ Primary, ++ Index, ++ Unique ++ }; ++ ++ UMLEntityAttribute(UMLObject* parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None, ++ Uml::Visibility::Enum s = Uml::Visibility::Private, ++ UMLObject *type = 0, const QString& iv = QString()); ++ explicit UMLEntityAttribute(UMLObject* parent); ++ virtual ~UMLEntityAttribute(); ++ ++ bool operator==(const UMLEntityAttribute& rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ void setAttributes(const QString& attributes); ++ QString getAttributes() const; ++ ++ void setIndexType(const DBIndex_Type indexType); ++ DBIndex_Type indexType() const; ++ ++ void setValues(const QString& values); ++ QString getValues() const; ++ ++ void setAutoIncrement(const bool autoIncrement); ++ bool getAutoIncrement() const; ++ ++ void setNull(const bool null); ++ bool getNull() const; ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++protected: ++ void init(); ++ ++ bool load(QDomElement& element); ++ ++private: ++ DBIndex_Type m_indexType; ++ QString m_values; ++ QString m_attributes; ++ bool m_autoIncrement; ++ bool m_null; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,76 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++//own header ++#include "entityconstraint.h" ++ ++// app includes ++#include "umlobject.h" ++#include "umldoc.h" ++#include "uml.h" ++ ++// qt includes ++#include ++ ++/** ++ * Sets up a constraint. ++ * @param parent The parent of this UMLEntityConstraint. ++ * @param name The name of this UMLEntityConstraint. ++ * @param id The unique id given to this UMLEntityConstraint. ++ */ ++UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent, ++ const QString& name, Uml::ID::Type id) ++ : UMLClassifierListItem(parent, name, id) ++{ ++ m_BaseType = UMLObject::ot_EntityConstraint; ++} ++ ++/** ++ * Sets up a constraint. ++ * @param parent The parent of this UMLEntityConstraint. ++ */ ++UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent) ++ : UMLClassifierListItem(parent) ++{ ++ m_BaseType = UMLObject::ot_EntityConstraint; ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLEntityConstraint::operator==(const UMLEntityConstraint &rhs) const ++{ ++ if(this == &rhs) ++ return true; ++ ++ if(!UMLObject::operator==(rhs)) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * destructor. ++ */ ++UMLEntityConstraint::~UMLEntityConstraint() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the UMLEntityConstraint ++ * object. ++ */ ++void UMLEntityConstraint::copyInto(UMLObject *lhs) const ++{ ++ // call the parent first. ++ UMLClassifierListItem::copyInto(lhs); ++} ++ ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,49 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENTITYCONSTRAINT_H ++#define ENTITYCONSTRAINT_H ++ ++#include "basictypes.h" ++#include "classifierlistitem.h" ++#include "umlclassifierlist.h" ++ ++/** ++ * This class is used to set up information for a entity constraint. ++ * ++ * @short Sets up entity constraint information. ++ * @author Sharan Rao ++ * @see UMLObject UMLClassifierListItem ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLEntityConstraint : public UMLClassifierListItem ++{ ++ Q_OBJECT ++ ++public: ++ UMLEntityConstraint(UMLObject *parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None); ++ ++ explicit UMLEntityConstraint(UMLObject *parent); ++ ++ bool operator==(const UMLEntityConstraint &rhs) const; ++ ++ virtual ~UMLEntityConstraint(); ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ /** ++ * Make a clone of the UMLEntityConstraint. ++ */ ++ virtual UMLObject* clone() const = 0; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/entity.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/entity.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,719 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "entity.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "entityattribute.h" ++#include "uniqueconstraint.h" ++#include "foreignkeyconstraint.h" ++#include "checkconstraint.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "uniqueid.h" ++#include "umlentityattributelist.h" ++#include "umlentityconstraintlist.h" ++#include "idchangelog.h" ++#include "umlentityattributedialog.h" ++#include "umluniqueconstraintdialog.h" ++#include "umlforeignkeyconstraintdialog.h" ++#include "umlcheckconstraintdialog.h" ++ ++// kde includes ++#include ++#include ++ ++// qt includes ++#include ++ ++/** ++ * Constructor. ++ */ ++UMLEntity::UMLEntity(const QString& name, Uml::ID::Type id) ++ : UMLClassifier(name, id), ++ m_PrimaryKey(0) ++{ ++ m_BaseType = UMLObject::ot_Entity; ++ connect(this, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), ++ this, SLOT(slotEntityAttributeRemoved(UMLClassifierListItem*))); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLEntity::~UMLEntity() ++{ ++ m_List.clear(); ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLEntity::operator==(const UMLEntity& rhs) const ++{ ++ return UMLClassifier::operator==(rhs); ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLEntity::copyInto(UMLObject *lhs) const ++{ ++ UMLEntity *target = static_cast(lhs); ++ ++ // call base class copy function ++ UMLClassifier::copyInto(target); ++ ++ // copy local data items ++ target->m_PrimaryKey = m_PrimaryKey; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLEntity::clone() const ++{ ++ UMLEntity* clone = new UMLEntity(); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Create an UMLAttribute. ++ * @param name an optional name for the attribute ++ * @param type an optional type object for the attribute ++ * @param vis the visibility of the attribute ++ * @param iv the initial value for the attribute ++ * @return the just created attribute or null ++ */ ++UMLAttribute* UMLEntity::createAttribute(const QString &name /*= QString()*/, UMLObject *type /*= 0*/, ++ Uml::Visibility::Enum vis /* = Uml::Visibility::Private*/, ++ const QString& iv /* = QString()*/) ++{ ++ Uml::ID::Type id = UniqueID::gen(); ++ QString currentName; ++ if (name.isNull()) { ++ currentName = uniqChildName(UMLObject::ot_EntityAttribute); ++ } else { ++ currentName = name; ++ } ++ ++ UMLEntityAttribute* newAttribute = new UMLEntityAttribute(this, currentName, id, vis, type, iv); ++ ++ int button = QDialog::Accepted; ++ bool goodName = false; ++ ++ //check for name.isNull() stops dialog being shown ++ //when creating attribute via list view ++ while (button == QDialog::Accepted && !goodName && name.isNull()) { ++ QPointer dialog = new UMLEntityAttributeDialog(0, newAttribute); ++ button = dialog->exec(); ++ QString name = newAttribute->name(); ++ ++ if (name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } else if (findChildObject(name) != NULL) { ++ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); ++ } else { ++ goodName = true; ++ } ++ delete dialog; ++ } ++ ++ if (button != QDialog::Accepted) { ++ delete newAttribute; ++ return 0; ++ } ++ ++ addEntityAttribute(newAttribute); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newAttribute); ++ return newAttribute; ++} ++ ++/** ++ * Creates a Unique Constraint for this Entity. ++ * @param name an optional name ++ * @return the UniqueConstraint created ++ */ ++UMLUniqueConstraint* UMLEntity::createUniqueConstraint(const QString &name) ++{ ++ Uml::ID::Type id = UniqueID::gen(); ++ QString currentName; ++ if (name.isNull()) { ++ ++ /** ++ * @todo check parameter ++ */ ++ currentName = uniqChildName(UMLObject::ot_UniqueConstraint); ++ } else { ++ currentName = name; ++ } ++ ++ UMLUniqueConstraint* newUniqueConstraint = new UMLUniqueConstraint(this, currentName, id); ++ ++ int button = QDialog::Accepted; ++ bool goodName = false; ++ ++ //check for name.isNull() stops dialog being shown ++ //when creating attribute via list view ++ while (button == QDialog::Accepted && !goodName && name.isNull()) { ++ QPointer dialog = new UMLUniqueConstraintDialog(0, newUniqueConstraint); ++ button = dialog->exec(); ++ QString name = newUniqueConstraint->name(); ++ ++ if (name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } else if (findChildObject(name) != NULL) { ++ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); ++ } else { ++ goodName = true; ++ } ++ delete dialog; ++ } ++ ++ if (button != QDialog::Accepted) { ++ delete newUniqueConstraint; ++ return NULL; ++ } ++ ++ addConstraint(newUniqueConstraint); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newUniqueConstraint); ++ emitModified(); ++ return newUniqueConstraint; ++} ++ ++/** ++ * Creates a Foreign Key Constraint for this Entity. ++ * @param name an optional name ++ * @return the ForeignKeyConstraint created ++ */ ++UMLForeignKeyConstraint* UMLEntity::createForeignKeyConstraint(const QString &name) ++{ ++ Uml::ID::Type id = UniqueID::gen(); ++ QString currentName; ++ if (name.isNull()) { ++ currentName = uniqChildName(UMLObject::ot_ForeignKeyConstraint); ++ } else { ++ currentName = name; ++ } ++ ++ UMLForeignKeyConstraint* newForeignKeyConstraint = new UMLForeignKeyConstraint(this, currentName, id); ++ ++ int button = QDialog::Accepted; ++ bool goodName = false; ++ ++ //check for name.isNull() stops dialog being shown ++ //when creating attribute via list view ++ while (button == QDialog::Accepted && !goodName && name.isNull()) { ++ QPointer dialog = new UMLForeignKeyConstraintDialog(0, newForeignKeyConstraint); ++ button = dialog->exec(); ++ QString name = newForeignKeyConstraint->name(); ++ ++ if (name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } else if (findChildObject(name) != NULL) { ++ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); ++ } else { ++ goodName = true; ++ } ++ delete dialog; ++ } ++ ++ if (button != QDialog::Accepted) { ++ return NULL; ++ } ++ ++ addConstraint(newForeignKeyConstraint); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newForeignKeyConstraint); ++ emitModified(); ++ return newForeignKeyConstraint; ++} ++ ++/** ++ * Creates a Check Constraint for this Entity. ++ * @param name an optional name ++ * @return the CheckConstraint created ++ */ ++UMLCheckConstraint* UMLEntity::createCheckConstraint(const QString &name) ++{ ++ Uml::ID::Type id = UniqueID::gen(); ++ QString currentName; ++ if (name.isNull()) { ++ currentName = uniqChildName(UMLObject::ot_CheckConstraint); ++ } else { ++ currentName = name; ++ } ++ ++ UMLCheckConstraint* newCheckConstraint = new UMLCheckConstraint(this, currentName, id); ++ ++ int button = QDialog::Accepted; ++ bool goodName = false; ++ ++ //check for name.isNull() stops dialog being shown ++ //when creating attribute via list view ++ while (button == QDialog::Accepted && !goodName && name.isNull()) { ++ QPointer dialog = new UMLCheckConstraintDialog(0, newCheckConstraint); ++ button = dialog->exec(); ++ QString name = newCheckConstraint->name(); ++ ++ if (name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } else if (findChildObject(name) != NULL) { ++ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); ++ } else { ++ goodName = true; ++ } ++ delete dialog; ++ } ++ ++ if (button != QDialog::Accepted) { ++ return NULL; ++ } ++ ++ addConstraint(newCheckConstraint); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newCheckConstraint); ++ emitModified(); ++ return newCheckConstraint; ++} ++ ++/** ++ * Adds an entityAttribute. ++ * The entityAttribute object must not belong to any other concept. ++ * @param name name of the UMLEntityAttribute ++ * @param id id of the UMLEntityAttribute ++ * @return True if the entityAttribute was successfully added. ++ */ ++UMLObject* UMLEntity::addEntityAttribute(const QString& name, Uml::ID::Type id) ++{ ++ UMLEntityAttribute* literal = new UMLEntityAttribute(this, name, id); ++ m_List.append(literal); ++ emit entityAttributeAdded(literal); ++ UMLObject::emitModified(); ++ connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); ++ return literal; ++} ++ ++/** ++ * Adds an already created entityAttribute. ++ * The entityAttribute object must not belong to any other concept. ++ * @param att Pointer to the UMLEntityAttribute. ++ * @param log Pointer to the IDChangeLog. ++ * @return True if the entityAttribute was successfully added. ++ */ ++bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log /* = 0*/) ++{ ++ QString name = (QString)att->name(); ++ if (findChildObject(name) == NULL) { ++ att->setParent(this); ++ m_List.append(att); ++ emit entityAttributeAdded(att); ++ UMLObject::emitModified(); ++ connect(att, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } else if (log) { ++ log->removeChangeByNewID(att->id()); ++ delete att; ++ } ++ return false; ++} ++ ++/** ++ * Adds an entityAttribute to the entity, at the given position. ++ * If position is negative or too large, the entityAttribute is added ++ * to the end of the list. ++ * TODO: give default value -1 to position (append) - now it conflicts with the method above.. ++ * @param att Pointer to the UMLEntityAttribute. ++ * @param position Position index for the insertion. ++ * @return True if the entityAttribute was successfully added. ++ */ ++bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, int position) ++{ ++ Q_ASSERT(att); ++ QString name = (QString)att->name(); ++ if (findChildObject(name) == NULL) { ++ att->setParent(this); ++ if (position >= 0 && position <= (int)m_List.count()) { ++ m_List.insert(position, att); ++ } else { ++ m_List.append(att); ++ } ++ emit entityAttributeAdded(att); ++ UMLObject::emitModified(); ++ connect(att, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } ++ return false; ++} ++ ++/** ++ * Removes an entityAttribute from the class. ++ * @param att The entityAttribute to remove. ++ * @return Count of the remaining entityAttributes after removal. ++ * Returns -1 if the given entityAttribute was not found. ++ */ ++int UMLEntity::removeEntityAttribute(UMLClassifierListItem* att) ++{ ++ if (!m_List.removeAll((UMLEntityAttribute*)att)) { ++ uDebug() << "cannot find att given in list"; ++ return -1; ++ } ++ emit entityAttributeRemoved(att); ++ UMLObject::emitModified(); ++ // If we are deleting the object, then we don't need to disconnect..this is done auto-magically ++ // for us by QObject. -b.t. ++ // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); ++ delete att; ++ return m_List.count(); ++} ++ ++/** ++ * Returns the number of entityAttributes for the class. ++ * @return The number of entityAttributes for the class. ++ */ ++int UMLEntity::entityAttributes() ++{ ++ UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); ++ return entityAttributes.count(); ++} ++ ++/** ++ * Emit the entityAttributeRemoved signal. ++ */ ++void UMLEntity::signalEntityAttributeRemoved(UMLClassifierListItem *eattr) ++{ ++ emit entityAttributeRemoved(eattr); ++} ++ ++/** ++ * Resolve the types referenced by our UMLEntityAttributes. ++ * Reimplements the method from UMLClassifier. ++ */ ++bool UMLEntity::resolveRef() ++{ ++ bool success = UMLClassifier::resolveRef(); ++ for (UMLObjectListIt oit(m_List); oit.hasNext();) { ++ UMLObject* obj = oit.next(); ++ if (obj->resolveRef()) { ++ UMLClassifierListItem *cli = static_cast(obj); ++ switch (cli->baseType()) { ++ case UMLObject::ot_EntityAttribute: ++ emit entityAttributeAdded(cli); ++ break; ++ case UMLObject::ot_UniqueConstraint: ++ case UMLObject::ot_ForeignKeyConstraint: ++ emit entityConstraintAdded(cli); ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ return success; ++} ++ ++/** ++ * Creates the element including its entityliterals. ++ */ ++void UMLEntity::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement entityElement = UMLObject::save(QLatin1String("UML:Entity"), qDoc); ++ //save operations ++ UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); ++ UMLClassifierListItem* pEntityAttribute = 0; ++ foreach (pEntityAttribute, entityAttributes) { ++ pEntityAttribute->saveToXMI(qDoc, entityElement); ++ } ++ ++ UMLClassifierListItemList entityConstraints = getFilteredList(UMLObject::ot_EntityConstraint); ++ foreach(UMLClassifierListItem* cli, entityConstraints) { ++ cli->saveToXMI(qDoc, entityElement); ++ } ++ ++ qElement.appendChild(entityElement); ++} ++ ++/** ++ * Loads the element including its entityAttributes. ++ */ ++bool UMLEntity::load(QDomElement& element) ++{ ++ QDomNode node = element.firstChild(); ++ while(!node.isNull()) { ++ if (node.isComment()) { ++ node = node.nextSibling(); ++ continue; ++ } ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { // for backward compatibility ++ UMLEntityAttribute* pEntityAttribute = new UMLEntityAttribute(this); ++ if(!pEntityAttribute->loadFromXMI(tempElement)) { ++ return false; ++ } ++ m_List.append(pEntityAttribute); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("UniqueConstraint"))) { ++ UMLUniqueConstraint* pUniqueConstraint = new UMLUniqueConstraint(this); ++ if (!pUniqueConstraint->loadFromXMI(tempElement)) { ++ return false; ++ } ++ addConstraint(pUniqueConstraint); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("ForeignKeyConstraint"))) { ++ UMLForeignKeyConstraint* pForeignKeyConstraint = new UMLForeignKeyConstraint(this); ++ if (!pForeignKeyConstraint->loadFromXMI(tempElement)) { ++ return false; ++ } ++ ++ addConstraint(pForeignKeyConstraint); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("CheckConstraint"))) { ++ ++ UMLCheckConstraint* pCheckConstraint = new UMLCheckConstraint(this); ++ if (!pCheckConstraint->loadFromXMI(tempElement)) { ++ return false; ++ } ++ ++ addConstraint(pCheckConstraint); ++ } else if (tag == QLatin1String("stereotype")) { ++ uDebug() << name() << ": losing old-format stereotype."; ++ } else { ++ uWarning() << "unknown child type in UMLEntity::load"; ++ } ++ node = node.nextSibling(); ++ }//end while ++ return true; ++} ++ ++/** ++ * Sets the UniqueConstraint passed as the Primary Key of this Entity ++ * If the UniqueConstraint exists, then it is made a primary key ++ * Else the UniqueConstraint is added and set as PrimaryKey ++ * @param uconstr The Unique Constraint that is to be set as Primary Key ++ * @return true if Primary key could be set successfully ++ */ ++bool UMLEntity::setAsPrimaryKey(UMLUniqueConstraint* uconstr) ++{ ++ if (uconstr == NULL) { ++ uDebug() << "NULL value passed. To unset a Primary Key use " ++ << "unsetPrimaryKey()"; ++ return false; ++ } ++ ++ if (static_cast(uconstr->parent()) != this) { ++ ++ uDebug() << "Parent of " << uconstr->name() ++ << " does not match with current entity"; ++ return false; ++ } ++ ++ // check if this constraint already exists as a unique constraint for this entity ++ UMLUniqueConstraint* uuc = static_cast(findChildObjectById(uconstr->id())); ++ if (uuc == NULL) { ++ addConstraint(uconstr); ++ uuc = uconstr; ++ } ++ ++ UMLUniqueConstraint* oldPrimaryKey = m_PrimaryKey; ++ ++ m_PrimaryKey = uuc; ++ ++ if (oldPrimaryKey != NULL) ++ oldPrimaryKey->emitModified(); ++ ++ uuc->emitModified(); ++ emitModified(); ++ return true; ++} ++ ++/** ++ * Unset a Primary Key Constraint if it exists, else does nothing ++ * This function will make the primary key into just another UniqueConstraint ++ * if it exists ++ */ ++void UMLEntity::unsetPrimaryKey() ++{ ++ m_PrimaryKey = 0; ++} ++ ++/** ++ * Checks if This UMLEntity has a primary key set. ++ * @return true if a Primary Key Exists for this UMLEntity ++ */ ++bool UMLEntity::hasPrimaryKey() const ++{ ++ if (m_PrimaryKey) { ++ return true; ++ } ++ ++ return false; ++} ++ ++/** ++ * Adds a Constraint to this UMLEntity. ++ * To set a UMLUniqueConstraint as Primary Key use setAsPrimaryKey. ++ * @param constr The UMLEntityConstraint that is to be added ++ * @return true if the constraint could be added successfully ++ */ ++bool UMLEntity::addConstraint(UMLEntityConstraint* constr) ++{ ++ if (findChildObjectById(constr->id()) != NULL) { ++ uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) ++ << " already exists "; ++ return false; ++ } ++ ++ m_List.append(constr); ++ ++ emit entityConstraintAdded(constr); ++ UMLObject::emitModified(); ++ connect(constr, SIGNAL(modified()), this, SIGNAL(modified())); ++ ++ return true; ++} ++ ++/** ++ * Removes an existing constraint from this UMLEntity. ++ * If the Contraint is a Primary Key, this Entity will no longer have a PrimaryKey. ++ * @param constr the constraint to be removed ++ * @return true if the constraint could be removed successfully ++ */ ++bool UMLEntity::removeConstraint(UMLEntityConstraint* constr) ++{ ++ if (findChildObjectById(constr->id()) == NULL) { ++ uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) ++ << " does not exist "; ++ return false; ++ } ++ ++ if (m_PrimaryKey == constr) { ++ unsetPrimaryKey(); ++ } ++ ++ m_List.removeAll(constr); ++ ++ emit entityConstraintRemoved(constr); ++ UMLObject::emitModified(); ++ ++ delete constr; ++ return true; ++} ++ ++/** ++ * Slot for entity attribute removed. ++ */ ++void UMLEntity::slotEntityAttributeRemoved(UMLClassifierListItem* cli) ++{ ++ // this function does some cleanjobs related to this entity when the attribute is ++ // removed, like, removing the attribute from all constraints ++ ++ UMLEntityAttribute* entAtt = static_cast(cli); ++ if (cli) { ++ UMLClassifierListItemList ual = this->getFilteredList(UMLObject::ot_UniqueConstraint); ++ ++ foreach(UMLClassifierListItem* ucli, ual) { ++ UMLUniqueConstraint* uuc = static_cast(ucli); ++ if (uuc->hasEntityAttribute(entAtt)) { ++ uuc->removeEntityAttribute(entAtt); ++ } ++ } ++ } ++ ++} ++ ++/** ++ * Reimplementation of getFilteredList to support ot=UMLObject::ot_EntityConstraint. ++ */ ++UMLClassifierListItemList UMLEntity::getFilteredList(UMLObject::ObjectType ot) const ++{ ++ if (ot == UMLObject::ot_EntityConstraint) { ++ UMLClassifierListItemList ucList, fcList, ccList, rcList; ++ ucList = UMLClassifier::getFilteredList(UMLObject::ot_UniqueConstraint); ++ fcList = UMLClassifier::getFilteredList(UMLObject::ot_ForeignKeyConstraint); ++ ccList = UMLClassifier::getFilteredList(UMLObject::ot_CheckConstraint); ++ ++ // append the lists to rcList ++ // first the Unique Constraints ++ foreach(UMLClassifierListItem* ucli, ucList) { ++ rcList.append(ucli); ++ } ++ ++ // then the Foreign Key Constraints ++ foreach(UMLClassifierListItem* ucli, fcList) { ++ rcList.append(ucli); ++ } ++ ++ foreach(UMLClassifierListItem* ucli, ccList) { ++ rcList.append(ucli); ++ } ++ ++ return rcList; ++ } else { ++ return UMLClassifier::getFilteredList(ot); ++ } ++} ++ ++/** ++ * Checks if a given Unique Constraint is primary key of this entity ++ * @param uConstr a Unique Constraint ++ * @return bool true if passed parameter is a primary key of this entity ++ */ ++bool UMLEntity::isPrimaryKey(UMLUniqueConstraint* uConstr) const ++{ ++ if (uConstr == m_PrimaryKey) { ++ return true; ++ } ++ ++ return false; ++} ++ ++/** ++ * Returns the Entity Attributes. ++ * Same as getFilteredList(UMLObject::ot_EntityAttribute). ++ */ ++UMLEntityAttributeList UMLEntity::getEntityAttributes() const ++{ ++ UMLEntityAttributeList entityAttributeList; ++ for (UMLObjectListIt lit(m_List); lit.hasNext();) { ++ UMLObject *listItem = lit.next(); ++ if (listItem->baseType() == UMLObject::ot_EntityAttribute) { ++ entityAttributeList.append(static_cast(listItem)); ++ } ++ } ++ return entityAttributeList; ++} ++ ++ ++/** ++ * Create a new ClassifierListObject (entityattribute) ++ * according to the given XMI tag. ++ * Returns NULL if the string given does not contain one of the tags ++ * ++ * Used by the clipboard for paste operation. ++ * Reimplemented from UMLClassifier for UMLEntity ++ */ ++UMLClassifierListItem* UMLEntity::makeChildObject(const QString& xmiTag) ++{ ++ UMLClassifierListItem* pObject = NULL; ++ if (UMLDoc::tagEq(xmiTag, QLatin1String("EntityAttribute"))) { ++ pObject = new UMLEntityAttribute(this); ++ } ++ return pObject; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.h umbrello-kf6-15.08.1/umbrello/umlmodel/entity.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/entity.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,108 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENTITY_H ++#define ENTITY_H ++ ++#include "classifier.h" ++ ++// forward declarations ++class UMLEntityAttribute; ++class UMLEntityConstraint; ++class UMLUniqueConstraint; ++class UMLForeignKeyConstraint; ++class UMLCheckConstraint; ++class UMLEntityAttributeList; ++ ++/** ++ * This class contains the non-graphical information required for a UML ++ * Entity. ++ * This class inherits from @ref UMLClassifier which contains most of the ++ * information. ++ * ++ * @short Non-graphical Information for an Entity. ++ * @author Jonathan Riddell ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLEntity : public UMLClassifier ++{ ++ Q_OBJECT ++public: ++ explicit UMLEntity(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLEntity(); ++ ++ bool operator==(const UMLEntity& rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ virtual UMLAttribute* createAttribute(const QString &name = QString(), ++ UMLObject *type = 0, Uml::Visibility::Enum vis = Uml::Visibility::Private, ++ const QString &init = QString()); ++ ++ UMLUniqueConstraint* createUniqueConstraint(const QString &name = QString()); ++ UMLForeignKeyConstraint* createForeignKeyConstraint(const QString &name = QString()); ++ UMLCheckConstraint* createCheckConstraint(const QString &name = QString()); ++ ++ UMLObject* addEntityAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); ++ bool addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log = 0); ++ bool addEntityAttribute(UMLEntityAttribute* att, int position); ++ ++ int removeEntityAttribute(UMLClassifierListItem* att); ++ ++ void signalEntityAttributeRemoved(UMLClassifierListItem *eattr); ++ ++ int entityAttributes() ; ++ ++ bool setAsPrimaryKey(UMLUniqueConstraint* uconstr); ++ void unsetPrimaryKey(); ++ bool hasPrimaryKey() const; ++ bool isPrimaryKey(UMLUniqueConstraint* uConstr) const; ++ ++ bool addConstraint(UMLEntityConstraint* constr); ++ bool removeConstraint(UMLEntityConstraint* constr); ++ ++ virtual bool resolveRef(); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; ++ ++ UMLEntityAttributeList getEntityAttributes() const; ++ ++ virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); ++ ++private slots: ++ void slotEntityAttributeRemoved(UMLClassifierListItem*); ++ ++signals: ++ void entityAttributeAdded(UMLClassifierListItem*); ++ void entityAttributeRemoved(UMLClassifierListItem*); ++ void entityConstraintAdded(UMLClassifierListItem*); ++ void entityConstraintRemoved(UMLClassifierListItem*); ++ ++protected: ++ bool load(QDomElement& element); ++ ++private: ++ ++ /** ++ * Primary Key of this Entity ++ * This is a pointer kept for easy access to the primary key, and to distinguish it ++ * from all other UniqueConstraints. It is also there in m_List (inherited from ++ * UMLCanvasObject) ++ */ ++ UMLUniqueConstraint* m_PrimaryKey; ++ ++}; ++ ++#endif // ENTITY_H ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/enum.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/enum.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,302 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "enum.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "enumliteral.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "uniqueid.h" ++#include "idchangelog.h" ++ ++// kde includes ++#include ++#include ++ ++/** ++ * Sets up an enum. ++ * @param name The name of the Enum. ++ * @param id The unique id of the Enum. ++ */ ++UMLEnum::UMLEnum(const QString& name, Uml::ID::Type id) : UMLClassifier(name, id) ++{ ++ init(); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLEnum::~UMLEnum() ++{ ++ m_List.clear(); ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLEnum::operator==(const UMLEnum & rhs) const ++{ ++ return UMLClassifier::operator==(rhs); ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLEnum::copyInto(UMLObject *lhs) const ++{ ++ UMLClassifier::copyInto(lhs); ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLEnum::clone() const ++{ ++ UMLEnum *clone = new UMLEnum(); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLEnum::init() ++{ ++ m_BaseType = UMLObject::ot_Enum; ++ setStereotypeCmd(QLatin1String("enum")); ++} ++ ++/** ++ * Creates a literal for the enum. ++ * @return The UMLEnum created ++ */ ++UMLObject* UMLEnum::createEnumLiteral(const QString& name) ++{ ++ Uml::ID::Type id = UniqueID::gen(); ++ QString currentName; ++ if (name.isNull()) { ++ currentName = uniqChildName(UMLObject::ot_EnumLiteral); ++ } else { ++ currentName = name; ++ } ++ ++ UMLEnumLiteral* newEnumLiteral = new UMLEnumLiteral(this, currentName); ++ ++ bool ok = true; ++ bool goodName = false; ++ ++ //check for name.isNull() stops dialog being shown ++ //when creating enum literal via list view ++ while (ok && !goodName && name.isNull()) { ++ ok = newEnumLiteral->showPropertiesDialog(UMLApp::app()); ++ QString name = newEnumLiteral->name(); ++ ++ if(name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); ++ } else { ++ goodName = true; ++ } ++ } ++ ++ if (!ok) { ++ delete newEnumLiteral; ++ return NULL; ++ } ++ ++ addEnumLiteral(newEnumLiteral); ++ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(newEnumLiteral); ++ return newEnumLiteral; ++} ++ ++/** ++ * Adds an enumliteral to the enum. ++ * @param name The name of the enumliteral. ++ * @param id The id of the enumliteral (optional.) ++ * If omitted a new ID is assigned internally. ++ * @return Pointer to the UMLEnumliteral created. ++ */ ++UMLObject* UMLEnum::addEnumLiteral(const QString &name, Uml::ID::Type id) ++{ ++ UMLObject *el = UMLCanvasObject::findChildObject(name); ++ if (el != NULL) { ++ uDebug() << name << " is already present"; ++ return el; ++ } ++ UMLEnumLiteral* literal = new UMLEnumLiteral(this, name, id); ++ m_List.append(literal); ++ UMLObject::emitModified(); ++ emit enumLiteralAdded(literal); ++ connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); ++ return literal; ++} ++ ++/** ++ * Adds an already created enumliteral. ++ * The enumliteral object must not belong to any other concept. ++ * @param literal Pointer to the UMLEnumLiteral. ++ * @param Log Pointer to the IDChangeLog. ++ * @return True if the enumliteral was successfully added. ++ */ ++bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log /* = 0*/) ++{ ++ QString name = (QString)literal->name(); ++ if (findChildObject(name) == NULL) { ++ literal->setParent(this); ++ m_List.append(literal); ++ UMLObject::emitModified(); ++ emit enumLiteralAdded(literal); ++ connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } else if (Log) { ++ Log->removeChangeByNewID(literal->id()); ++ delete literal; ++ } ++ return false; ++} ++ ++/** ++ * Adds an enumliteral to the enum, at the given position. ++ * If position is negative or too large, the enumliteral is added ++ * to the end of the list. ++ * TODO: give default value -1 to position (append) - now it conflicts with the method above.. ++ * @param literal Pointer to the UMLEnumLiteral. ++ * @param position Position index for the insertion. ++ * @return True if the enumliteral was successfully added. ++ */ ++bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, int position) ++{ ++ Q_ASSERT(literal); ++ QString name = (QString)literal->name(); ++ if (findChildObject(name) == NULL) { ++ literal->setParent(this); ++ if (position >= 0 && position <= (int)m_List.count()) { ++ m_List.insert(position, literal); ++ } else { ++ m_List.append(literal); ++ } ++ UMLObject::emitModified(); ++ emit enumLiteralAdded(literal); ++ connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); ++ return true; ++ } ++ return false; ++} ++ ++/** ++ * Removes an enumliteral from the class. ++ * @param literal The enumliteral to remove. ++ * @return Count of the remaining enumliterals after removal. ++ * Returns -1 if the given enumliteral was not found. ++ */ ++int UMLEnum::removeEnumLiteral(UMLEnumLiteral* literal) ++{ ++ if (!m_List.removeAll(literal)) { ++ uDebug() << "cannot find att given in list"; ++ return -1; ++ } ++ emit enumLiteralRemoved(literal); ++ UMLObject::emitModified(); ++ // If we are deleting the object, then we don't need to disconnect..this is done auto-magically ++ // for us by QObject. -b.t. ++ // disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); ++ delete literal; ++ return m_List.count(); ++} ++ ++/** ++ * Returns the number of enumliterals for the class. ++ * @return The number of enumliterals for the class. ++ */ ++int UMLEnum::enumLiterals() ++{ ++ return m_List.count(); ++} ++ ++/** ++ * Emit the enumLiteralRemoved signal. ++ */ ++void UMLEnum::signalEnumLiteralRemoved(UMLClassifierListItem *elit) ++{ ++ emit enumLiteralRemoved(elit); ++} ++ ++/** ++ * Creates the element including its enumliterals. ++ */ ++void UMLEnum::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement enumElement = UMLObject::save(QLatin1String("UML:Enumeration"), qDoc); ++ // save enum literals ++ UMLClassifierListItemList enumLiterals = getFilteredList(UMLObject::ot_EnumLiteral); ++ foreach (UMLClassifierListItem* pEnumLiteral, enumLiterals) { ++ pEnumLiteral->saveToXMI(qDoc, enumElement); ++ } ++ qElement.appendChild(enumElement); ++} ++ ++/** ++ * Loads the element including its enumliterals. ++ */ ++bool UMLEnum::load(QDomElement& element) ++{ ++ QDomNode node = element.firstChild(); ++ while(!node.isNull()) { ++ if (node.isComment()) { ++ node = node.nextSibling(); ++ continue; ++ } ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("EnumerationLiteral")) || ++ UMLDoc::tagEq(tag, QLatin1String("ownedLiteral")) || ++ UMLDoc::tagEq(tag, QLatin1String("EnumLiteral"))) { // for backward compatibility ++ UMLEnumLiteral* pEnumLiteral = new UMLEnumLiteral(this); ++ if(!pEnumLiteral->loadFromXMI(tempElement)) { ++ return false; ++ } ++ m_List.append(pEnumLiteral); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("Enumeration.literal"))) { // Embarcadero's Describe ++ if (! load(tempElement)) ++ return false; ++ } else if (tag == QLatin1String("stereotype")) { ++ uDebug() << name() << ": losing old-format stereotype."; ++ } else { ++ uWarning() << "unknown child type: " << tag; ++ } ++ node = node.nextSibling(); ++ }//end while ++ return true; ++} ++ ++/** ++ * Create a new ClassifierListObject (enumLiteral) ++ * according to the given XMI tag. ++ * Returns NULL if the string given does not contain one of the tags ++ * ++ * Used by the clipboard for paste operation. ++ * Reimplemented from UMLClassifier for UMLEnum ++ */ ++UMLClassifierListItem* UMLEnum::makeChildObject(const QString& xmiTag) ++{ ++ UMLClassifierListItem* pObject = NULL; ++ if (UMLDoc::tagEq(xmiTag, QLatin1String("EnumerationLiteral")) || ++ UMLDoc::tagEq(xmiTag, QLatin1String("EnumLiteral"))) { ++ pObject = new UMLEnumLiteral(this); ++ } ++ return pObject; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.h umbrello-kf6-15.08.1/umbrello/umlmodel/enum.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/enum.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,72 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENUM_H ++#define ENUM_H ++ ++#include "classifier.h" ++ ++class UMLEnumLiteral; ++ ++/** ++ * This class contains the non-graphical information required for a UML ++ * Enum. ++ * This class inherits from @ref UMLClassifier which contains most of the ++ * information. ++ * ++ * @short Non-graphical Information for an Enum. ++ * @author Jonathan Riddell ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLEnum : public UMLClassifier ++{ ++ Q_OBJECT ++public: ++ explicit UMLEnum(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); ++ ++ virtual ~UMLEnum(); ++ ++ bool operator==(const UMLEnum& rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ UMLObject* createEnumLiteral(const QString& name = QString()); ++ ++ UMLObject* addEnumLiteral(const QString &name, Uml::ID::Type id = Uml::ID::None); ++ ++ bool addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log = 0); ++ bool addEnumLiteral(UMLEnumLiteral* literal, int position); ++ ++ int removeEnumLiteral(UMLEnumLiteral* literal); ++ ++ int enumLiterals(); ++ ++ void signalEnumLiteralRemoved(UMLClassifierListItem *elit); ++ ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); ++ ++signals: ++ void enumLiteralAdded(UMLClassifierListItem*); ++ void enumLiteralRemoved(UMLClassifierListItem*); ++ ++protected: ++ bool load(QDomElement & element); ++ ++private: ++ void init(); ++ ++}; ++ ++#endif // ENUM_H ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,126 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "enumliteral.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++ ++/** ++ * Sets up an enum literal. ++ * @param parent The parent of this UMLEnumLiteral. ++ * @param name The name of this UMLEnumLiteral. ++ * @param id The unique id given to this UMLEnumLiteral. ++ */ ++UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent, ++ const QString& name, Uml::ID::Type id) ++ : UMLClassifierListItem(parent, name, id) ++{ ++ m_BaseType = UMLObject::ot_EnumLiteral; ++} ++ ++/** ++ * Sets up an enum literal. ++ * @param parent The parent of this UMLEnumLiteral. ++ */ ++UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent) ++ : UMLClassifierListItem(parent) ++{ ++ m_BaseType = UMLObject::ot_EnumLiteral; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLEnumLiteral::~UMLEnumLiteral() ++{ ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLEnumLiteral::operator==(const UMLEnumLiteral& 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 UMLEnumLiteral::copyInto(UMLObject *lhs) const ++{ ++ UMLClassifierListItem::copyInto(lhs); ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLEnumLiteral::clone() const ++{ ++ UMLEnumLiteral *clone = new UMLEnumLiteral((UMLObject *) parent()); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLEnumLiteral::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement attributeElement = UMLObject::save(QLatin1String("UML:EnumerationLiteral"), qDoc); ++ qElement.appendChild(attributeElement); ++} ++ ++/** ++ * Loads the XMI element (empty.) ++ */ ++bool UMLEnumLiteral::load(QDomElement& element) ++{ ++ Q_UNUSED(element); ++ return true; ++} ++ ++/** ++ * Display the properties configuration dialog for the enum literal. ++ */ ++bool UMLEnumLiteral::showPropertiesDialog(QWidget* parent) ++{ ++ bool ok; ++#if QT_VERSION >= 0x050000 ++ QString enumName = QInputDialog::getText(parent, ++ i18nc("enum name", "Name"), i18n("Enter name:"), ++ QLineEdit::Normal, ++ name(), &ok); ++#else ++ QString enumName = KInputDialog::getText(i18nc("enum name", "Name"), i18n("Enter name:"), name(), &ok, parent); ++#endif ++ if (ok && !enumName.isEmpty()) { ++ setName(enumName); ++ return true; ++ } else { ++ return false; ++ } ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.h umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,49 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENUMLITERAL_H ++#define ENUMLITERAL_H ++ ++#include "classifierlistitem.h" ++ ++/** ++ * This class is used to set up information for an enum literal. Enum ++ * literals are the values that enums can be set to. ++ * ++ * @short Sets up attribute information. ++ * @author Paul Hensgen ++ * @see UMLObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLEnumLiteral : public UMLClassifierListItem ++{ ++public: ++ UMLEnumLiteral(UMLObject* parent, ++ const QString& name, Uml::ID::Type id = Uml::ID::None); ++ explicit UMLEnumLiteral(UMLObject* parent); ++ ++ bool operator==(const UMLEnumLiteral &rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ virtual ~UMLEnumLiteral(); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++protected: ++ bool load(QDomElement& element); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/folder.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/folder.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,558 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "folder.h" ++ ++// app includes ++#include "debug_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); ++ delete 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 = static_cast(o); ++ 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 = static_cast(o); ++ 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->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 = static_cast(o); ++ 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 = static_cast(o); ++ 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 = static_cast(o); ++ 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 saveToXMI(): 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::saveContents(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->saveToXMI (qDoc, ownedElement); ++ } ++ // Save asscociations if any. ++ for (UMLObjectListIt ait(m_List); ait.hasNext();) { ++ obj = ait.next(); ++ obj->saveToXMI (qDoc, ownedElement); ++ } ++ qElement.appendChild(ownedElement); ++ // Save diagrams to `extension'. ++ if (m_diagrams.count()) { ++ QDomElement diagramsElement = qDoc.createElement(QLatin1String("diagrams")); ++ ++ foreach (UMLView* pView, m_diagrams) { ++ pView->umlScene()->saveToXMI(qDoc, diagramsElement); ++ } ++ QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); ++ extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); ++ extension.appendChild(diagramsElement); ++ qElement.appendChild(extension); ++ } ++} ++ ++/** ++ * Auxiliary to saveToXMI(): 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::save(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::save(elementName, qDoc); ++ saveContents(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::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ if (m_folderFile.isEmpty()) { ++ save(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(); ++ save(qDoc, qElement); ++ return; ++ } ++ // Okay, external file is writable. Wrap up main file. ++ QDomElement folderElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); ++ QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); ++ extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); ++ 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(m_pUMLPackage->id())); ++ folderRoot.setAttribute(QLatin1String("parent"), m_pUMLPackage->fullyQualifiedName(QLatin1String("::"), true)); ++ saveContents(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::loadDiagramsFromXMI(QDomNode& diagrams) ++{ ++ 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()->loadFromXMI(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 load(element); ++} ++ ++/** ++ * Loads the owned elements of the . ++ */ ++bool UMLFolder::load(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::isCommonXMIAttribute(type)) ++ continue; ++ if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || ++ UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { ++ //CHECK: umbrello-kf6 currently assumes that nested elements ++ // are ownedElements anyway. ++ // Therefore these tags are not further interpreted. ++ if (! load(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")) { ++ QDomNode diagramNode = xtnode.firstChild(); ++ if (!loadDiagramsFromXMI(diagramNode)) ++ totalSuccess = false; ++ } 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->loadFromXMI(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; ++ } ++ } ++ pObject->setUMLPackage(this); ++ if (!pObject->loadFromXMI(tempElement)) { ++ removeObject(pObject); ++ delete pObject; ++ totalSuccess = false; ++ } ++ } ++ return totalSuccess; ++} ++ ++/** ++ * 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.h umbrello-kf6-15.08.1/umbrello/umlmodel/folder.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/folder.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,92 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLFOLDER_H ++#define UMLFOLDER_H ++ ++#include "package.h" ++#include "umlviewlist.h" ++#include "optionstate.h" ++ ++/** ++ * This class manages the UMLObjects and UMLViews of a Folder. ++ * This class inherits from UMLPackage which contains most ++ * of the information. ++ * ++ * The UMLDoc class allocates a fixed instance of this class for ++ * each of the predefined Logical, UseCase, Component, Deployment, and ++ * Entity-Relationship folders. Further instances are created on demand ++ * for user folders. ++ * ++ * @short Non-graphical management of objects and diagrams of a Folder ++ * @author Oliver Kellogg ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ * ++ * TODO: This whole class needs a relook regarding view/scene. ++ */ ++class UMLFolder : public UMLPackage ++{ ++ Q_OBJECT ++public: ++ explicit UMLFolder(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLFolder(); ++ ++ virtual UMLObject* clone() const; ++ ++ void setLocalName(const QString& localName); ++ QString localName() const; ++ ++ void addView(UMLView *view); ++ ++ void removeView(UMLView *view); ++ ++ void appendViews(UMLViewList& viewList, bool includeNested = true); ++ ++ void activateViews(); ++ ++ UMLView* findView(Uml::ID::Type id); ++ UMLView* findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes = true); ++ ++ void setViewOptions(const Settings::OptionState& optionState); ++ ++ void removeAllViews(); ++ ++ void setFolderFile(const QString& fileName); ++ QString folderFile() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ friend QDebug operator<<(QDebug out, const UMLFolder& item); ++ ++protected: ++ void saveContents(QDomDocument& qDoc, QDomElement& qElement); ++ ++ void save(QDomDocument& qDoc, QDomElement& qElement); ++ ++ bool loadDiagramsFromXMI(QDomNode& diagrams); ++ ++ bool loadFolderFile(const QString& path); ++ ++ bool load(QDomElement & element); ++ ++private: ++ QString m_localName; ///< i18n name, only used for predefined root folders ++ /** ++ * If m_folderFile is not empty then it contains a file name to which ++ * this folder is saved. ++ * In this case the folder file acts as a physically separate submodel. ++ * What is saved in the main model is not the folder contents but a ++ * reference to the folder file. ++ */ ++ QString m_folderFile; ++ UMLViewList m_diagrams; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++//own header ++#include "foreignkeyconstraint.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "entity.h" ++#include "entityattribute.h" ++#include "umlobject.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "umlforeignkeyconstraintdialog.h" ++#include "object_factory.h" ++ ++/** ++ * Sets up a constraint. ++ * @param parent The parent of this UMLForeignKeyConstraint. ++ * @param name The name of this UMLForeignKeyConstraint. ++ * @param id The unique id given to this UMLForeignKeyConstraint. ++ */ ++UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent, ++ const QString& name, Uml::ID::Type id) ++ : UMLEntityConstraint(parent, name, id) ++{ ++ init(); ++} ++ ++/** ++ * Sets up a constraint. ++ * @param parent The parent of this UMLForeignKeyConstraint. ++ */ ++UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent) ++ : UMLEntityConstraint(parent) ++{ ++ init(); ++} ++ ++/** ++ * Initialisation of common variables ++ */ ++void UMLForeignKeyConstraint::init() ++{ ++ // initialise attributes ++ m_BaseType = UMLObject::ot_ForeignKeyConstraint; ++ ++ // should be NULL actually ++ // self referencing assigned to protect default behaviour ++ m_ReferencedEntity = static_cast(parent()); ++ ++ m_UpdateAction = uda_NoAction; ++ m_DeleteAction = uda_NoAction; ++ ++ // connecte signals and slots ++ connect(this, SIGNAL(sigReferencedEntityChanged()), this, SLOT(slotReferencedEntityChanged())); ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLForeignKeyConstraint::operator==(const UMLForeignKeyConstraint &rhs) const ++{ ++ if(this == &rhs) ++ return true; ++ ++ if(!UMLObject::operator==(rhs)) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLForeignKeyConstraint::~UMLForeignKeyConstraint() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the UMLForeignKeyConstraint ++ * object. ++ */ ++void UMLForeignKeyConstraint::copyInto(UMLObject *lhs) const ++{ ++ UMLForeignKeyConstraint *target = static_cast(lhs); ++ ++ // call the parent first. ++ UMLEntityConstraint::copyInto(target); ++ ++ // Copy all datamembers ++ target->m_ReferencedEntity = m_ReferencedEntity; ++ target->m_AttributeMap = m_AttributeMap; ++ target->m_DeleteAction = m_DeleteAction; ++ target->m_UpdateAction = m_UpdateAction; ++} ++ ++/** ++ * Make a clone of the UMLForeignKeyConstraint. ++ */ ++UMLObject* UMLForeignKeyConstraint::clone() const ++{ ++ //FIXME: The new attribute should be slaved to the NEW parent not the old. ++ UMLForeignKeyConstraint *clone = new UMLForeignKeyConstraint(static_cast(parent())); ++ copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Returns a string representation of the UMLForeignKeyConstraint. ++ * @param sig If true will show the attribute type and initial value. ++ * @return Returns a string representation of the UMLAttribute. ++ */ ++QString UMLForeignKeyConstraint::toString(Uml::SignatureType::Enum sig) ++{ ++ QString s; ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { ++ s = name() + QLatin1Char(':'); ++ s += QLatin1String(" Foreign Key ("); ++ QList keys = m_AttributeMap.keys(); ++ bool first = true; ++ foreach(UMLEntityAttribute* key, keys) { ++ if (first) { ++ first = false; ++ } else ++ s += QLatin1Char(','); ++ s += key->name(); ++ } ++ s += QLatin1Char(')'); ++ } ++ ++ return s; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLForeignKeyConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement foreignKeyConstraintElement = UMLObject::save(QLatin1String("UML:ForeignKeyConstraint"), qDoc); ++ ++ foreignKeyConstraintElement.setAttribute(QLatin1String("referencedEntity"), Uml::ID::toString(m_ReferencedEntity->id())); ++ ++ int updateAction = (int)m_UpdateAction; ++ int deleteAction = (int)m_DeleteAction; ++ ++ foreignKeyConstraintElement.setAttribute(QLatin1String("updateAction"), updateAction); ++ foreignKeyConstraintElement.setAttribute(QLatin1String("deleteAction"), deleteAction); ++ ++ QMap::iterator i; ++ for (i = m_AttributeMap.begin(); i!= m_AttributeMap.end() ; ++i) { ++ QDomElement mapElement = qDoc.createElement(QLatin1String("AttributeMap")); ++ mapElement.setAttribute(QLatin1String("key"), Uml::ID::toString((i.key())->id())); ++ mapElement.setAttribute(QLatin1String("value"), Uml::ID::toString((i.value())->id())); ++ foreignKeyConstraintElement.appendChild(mapElement); ++ } ++ ++ qElement.appendChild(foreignKeyConstraintElement); ++} ++ ++/** ++ * Display the properties configuration dialog for the attribute. ++ */ ++bool UMLForeignKeyConstraint::showPropertiesDialog(QWidget* parent) ++{ ++ UMLForeignKeyConstraintDialog dialog(parent, this); ++ return dialog.exec(); ++} ++ ++/** ++ * Adds the attribute pair to the attributeMap ++ * @param pAttr The Attribute of the Parent Entity ++ * @param rAttr The Attribute of the Referenced Entity ++ * @return true if the attribute pair could be added successfully ++ */ ++bool UMLForeignKeyConstraint::addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) ++{ ++ UMLEntity *owningParent = dynamic_cast(parent()); ++ ++ if (pAttr == NULL || rAttr == NULL) { ++ uError() << "null values passed to function"; ++ return false; ++ } ++ // check for sanity of pAttr (parent entity attribute) ++ if (owningParent == NULL) { ++ uError() << name() << ": parent is not a UMLEntity"; ++ return false; ++ } ++ ++ if (owningParent->findChildObjectById(pAttr->id()) == NULL) { ++ uError() << " parent " << owningParent->name() ++ << " does not contain attribute " << pAttr->name(); ++ return false; ++ } ++ ++ //check for sanity of rAttr (referenced entity attribute) ++ if (m_ReferencedEntity != NULL) { ++ if (m_ReferencedEntity->findChildObjectById(rAttr->id()) == NULL) { ++ uError() << " parent " << m_ReferencedEntity->name() ++ << " does not contain attribute " << rAttr->name(); ++ return false; ++ } ++ } else { ++ uError() << "Referenced Table Not set. Not Adding Pair "; ++ return false; ++ } ++ ++ // check if key takes part in some mapping ++ if (m_AttributeMap.contains(pAttr) == true) ++ return false; ++ ++ // check if value takes part in some mapping (no direct function) ++ foreach(UMLEntityAttribute* attr, m_AttributeMap.values()) { ++ if (rAttr == attr) ++ return false; ++ } ++ ++ // passed all checks, insert now ++ m_AttributeMap.insert(pAttr, rAttr); ++ ++ QMap::iterator i; ++ for (i = m_AttributeMap.begin(); i != m_AttributeMap.end(); ++i) ++ uDebug() << i.key()->name() << QLatin1String(" ") << i.key()->baseType() ++ << QLatin1String(" ") << i.value()->name() << QLatin1String(" ") << i.value()->baseType(); ++ ++ return true; ++} ++ ++/** ++ * Removes an Attribute pair ++ * @param pAttr The Attribute of the Parent Entity in the map. This attribute is the ++ key of the map. ++ * @return true of the attribute pair could be removed successfully ++ */ ++bool UMLForeignKeyConstraint::removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr) ++{ ++ bool state = m_AttributeMap.remove(pAttr); ++ ++ return state; ++} ++ ++/** ++ * Check if a attribute pair already exists ++ * @param pAttr The Attribute of the Parent Entity ++ * @param rAttr The Attribute of the Referenced Entity ++ * @return true if the attribute pair could be found. ++ */ ++bool UMLForeignKeyConstraint::hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const ++{ ++ if (m_AttributeMap.contains(pAttr)) { ++ if (m_AttributeMap.value(pAttr) == rAttr) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/** ++ * Loads the XMI element. ++ */ ++bool UMLForeignKeyConstraint::load(QDomElement & element) ++{ ++ UMLDoc* doc = UMLApp::app()->document(); ++ ++ Uml::ID::Type referencedEntityId = Uml::ID::fromString(element.attribute(QLatin1String("referencedEntity"))); ++ ++ UMLObject* obj = doc->findObjectById(referencedEntityId); ++ m_ReferencedEntity = static_cast(obj); ++ ++ if (m_ReferencedEntity == NULL) { ++ // save for resolving later ++ m_pReferencedEntityID = referencedEntityId; ++ } ++ ++ m_UpdateAction = (UpdateDeleteAction)element.attribute(QLatin1String("updateAction")).toInt(); ++ m_DeleteAction = (UpdateDeleteAction)element.attribute(QLatin1String("deleteAction")).toInt(); ++ ++ QDomNode node = element.firstChild(); ++ while (!node.isNull()) { ++ if (node.isComment()) { ++ node = node.nextSibling(); ++ continue; ++ } ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("AttributeMap"))) { ++ ++ QString xmiKey = tempElement.attribute(QLatin1String("key")); ++ QString xmiValue = tempElement.attribute(QLatin1String("value")); ++ Uml::ID::Type keyId = Uml::ID::fromString(xmiKey); ++ Uml::ID::Type valueId = Uml::ID::fromString(xmiValue); ++ ++ UMLEntity* parentEntity = static_cast(parent()); ++ UMLObject* keyObj = parentEntity->findChildObjectById(keyId); ++ UMLEntityAttribute* key = static_cast(keyObj); ++ ++ if (keyObj == NULL) { ++ uWarning() << "unable to resolve foreign key referencing attribute " << xmiKey; ++ } else if (m_ReferencedEntity == NULL) { ++ // if referenced entity is null, then we won't find its attributes even ++ // save for resolving later ++ m_pEntityAttributeIDMap.insert(key, valueId); ++ } else { ++ UMLObject* valueObj = m_ReferencedEntity->findChildObjectById(valueId); ++ if (valueObj == NULL) { ++ uWarning() << "unable to resolve foreign key referenced attribute" << xmiValue; ++ } else { ++ m_AttributeMap[key] = static_cast(valueObj); ++ } ++ } ++ ++ } else { ++ uWarning() << "unknown child type in UMLForeignKeyConstraint::load"; ++ } ++ ++ node = node.nextSibling(); ++ } ++ ++ return true; ++} ++ ++/** ++ * Set the Referenced Entity. ++ * @param ent The Entity to Reference ++ */ ++void UMLForeignKeyConstraint::setReferencedEntity(UMLEntity* ent) ++{ ++ if (ent == m_ReferencedEntity) ++ return; ++ ++ m_ReferencedEntity = ent; ++ ++ emit sigReferencedEntityChanged(); ++} ++ ++/** ++ * Get the Referenced Entity. ++ * @return the UML entity object ++ */ ++UMLEntity* UMLForeignKeyConstraint::getReferencedEntity() const ++{ ++ return m_ReferencedEntity; ++} ++ ++/** ++ * Slot for referenced entity changed. ++ */ ++void UMLForeignKeyConstraint::slotReferencedEntityChanged() ++{ ++ // clear all mappings ++ m_AttributeMap.clear(); ++} ++ ++/** ++ * Clears all mappings between local and referenced attributes ++ */ ++void UMLForeignKeyConstraint::clearMappings() ++{ ++ m_AttributeMap.clear(); ++} ++ ++/** ++ * Remimplementation from base classes ++ * Used to resolve forward references to referenced entities in xmi ++ */ ++bool UMLForeignKeyConstraint::resolveRef() ++{ ++ // resolve referenced entity first ++ UMLDoc* doc = UMLApp::app()->document(); ++ ++ bool success = true; ++ ++ //resolve the referenced entity ++ if (!Uml::ID::toString(m_pReferencedEntityID).isEmpty()) { ++ UMLObject* obj = doc->findObjectById(m_pReferencedEntityID); ++ m_ReferencedEntity = static_cast(obj); ++ if (m_ReferencedEntity == NULL) { ++ success = false; ++ } ++ } ++ ++ QMap::iterator i; ++ for (i = m_pEntityAttributeIDMap.begin(); i!= m_pEntityAttributeIDMap.end() ; ++i) { ++ if (!Uml::ID::toString(i.value()).isEmpty()) { ++ UMLObject* obj = doc->findObjectById(i.value()); ++ m_AttributeMap[i.key()] = static_cast(obj); ++ if (m_AttributeMap[i.key()] == NULL) { ++ success = false; ++ } ++ } ++ } ++ ++ return success; ++} ++ ++/** ++ * Retrieve all Pairs of Attributes. ++ */ ++QMap UMLForeignKeyConstraint::getEntityAttributePairs() ++{ ++ return m_AttributeMap; ++} ++ ++/** ++ * Get the Delete Action. ++ */ ++UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getDeleteAction() const ++{ ++ return m_DeleteAction; ++} ++ ++/** ++ * Get the Update Action. ++ */ ++UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getUpdateAction() const ++{ ++ return m_UpdateAction; ++} ++ ++/** ++ * Set the Delete Action to the specified UpdateDeleteAction. ++ */ ++void UMLForeignKeyConstraint::setDeleteAction(UpdateDeleteAction uda) ++{ ++ m_DeleteAction = uda; ++} ++ ++/** ++ * Set the Update Action to the specified UpdateDeleteAction ++ */ ++void UMLForeignKeyConstraint::setUpdateAction(UpdateDeleteAction uda) ++{ ++ m_UpdateAction = uda; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,120 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef FOREIGNKEYCONSTRAINT_H ++#define FOREIGNKEYCONSTRAINT_H ++ ++// appl includes ++#include "basictypes.h" ++#include "entityconstraint.h" ++ ++// qt includes ++#include ++ ++//forward declarations ++class UMLEntityAttribute; ++class UMLEntity; ++ ++/** ++ * This class is used to set up information for a foreign key entity constraint. ++ * @short Sets up Foreign Key entity constraint information. ++ * @author Sharan Rao ++ * @see UMLObject UMLClassifierListItem UMLEntityConstraint ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLForeignKeyConstraint : public UMLEntityConstraint ++{ ++ Q_OBJECT ++ ++public: ++ ++ /** ++ * Update/Delete Action: Action to be taken on Update or Delete of a referenced attribute ++ * is either, No Action, Restrict, Cascade, Set NULL, Set Default. ++ */ ++ enum UpdateDeleteAction { uda_NoAction = 0, ++ uda_Restrict, ++ uda_Cascade, ++ uda_SetNull, ++ uda_SetDefault }; ++ ++ UMLForeignKeyConstraint(UMLObject *parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None); ++ explicit UMLForeignKeyConstraint(UMLObject *parent); ++ ++ bool operator==(const UMLForeignKeyConstraint &rhs) const; ++ ++ virtual ~UMLForeignKeyConstraint(); ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ void setReferencedEntity(UMLEntity* ent); ++ UMLEntity* getReferencedEntity() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++ bool addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr); ++ ++ bool removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr); ++ ++ bool hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const; ++ ++ QMap getEntityAttributePairs(); ++ ++ void setDeleteAction(UpdateDeleteAction uda); ++ UpdateDeleteAction getDeleteAction() const; ++ ++ void setUpdateAction(UpdateDeleteAction uda); ++ UpdateDeleteAction getUpdateAction() const; ++ ++ void clearMappings(); ++ ++ bool resolveRef(); ++ ++signals: ++ void sigReferencedEntityChanged(); ++ ++private slots: ++ void slotReferencedEntityChanged(); ++ ++protected: ++ bool load(QDomElement & element); ++ ++private: ++ ++ Uml::ID::Type m_pReferencedEntityID; ///< Used to resolve forward references to UMLEntity. ++ ++ /** ++ * Used to resolve forward references to UMLEntityAttributes ++ * Key -> The local attribute ++ * Value -> Id of the attribute it is mapping to ++ */ ++ QMap m_pEntityAttributeIDMap; ++ ++ void init(); ++ ++ UMLEntity* m_ReferencedEntity; ///< The UMLEntity that this foreign key references. ++ ++ /** ++ * Stores the Mapping of attributes between parent table and referenced table ++ */ ++ QMap m_AttributeMap; ++ ++ UpdateDeleteAction m_UpdateAction; ///< What to do on Update of referenced attributes. ++ UpdateDeleteAction m_DeleteAction; ///< What to do on Deletion of referenced attributes. ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/node.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/node.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,68 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "node.h" ++ ++#include ++ ++/** ++ * Sets up a Node. ++ * ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLNode::UMLNode(const QString & name, Uml::ID::Type id) ++ : UMLCanvasObject(name, id) ++{ ++ init(); ++} ++ ++/** ++ * Destructor. ++ */ ++UMLNode::~UMLNode() ++{ ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLNode::init() ++{ ++ m_BaseType = UMLObject::ot_Node; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLNode::clone() const ++{ ++ UMLNode *clone = new UMLNode(); ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLNode::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement nodeElement = UMLObject::save(QLatin1String("UML:Node"), qDoc); ++ qElement.appendChild(nodeElement); ++} ++ ++/** ++ * Loads the XMI element (empty.) ++ */ ++bool UMLNode::load(QDomElement&) ++{ ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.h umbrello-kf6-15.08.1/umbrello/umlmodel/node.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/node.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,46 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef NODE_H ++#define NODE_H ++ ++#include "umlcanvasobject.h" ++ ++/** ++ * This class contains the non-graphical information required for a UML Node. ++ * This class inherits from @ref UMLCanvasObject which contains most of the ++ * information. ++ * ++ * @short Non-graphical information for a Node. ++ * @author Jonathan Riddell ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLNode : public UMLCanvasObject ++{ ++ Q_OBJECT ++public: ++ ++ explicit UMLNode(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLNode(); ++ ++ virtual void init(); ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/operation.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/operation.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,611 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "operation.h" ++ ++// app includes ++#include "attribute.h" ++#include "classifier.h" ++#include "model_utils.h" ++#include "debug_utils.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "uniqueid.h" ++#include "umloperationdialog.h" ++#include "codegenerator.h" ++#include "codedocument.h" ++#include "codeblock.h" ++ ++// kde includes ++#include ++ ++// qt includes ++#include ++ ++/** ++ * Constructs an UMLOperation. ++ * Not intended for general use: The operation is not tied in with ++ * umbrello-kf6's Qt signalling for object creation. ++ * If you want to create an Operation use the method in UMLDoc instead. ++ * ++ * @param parent the parent to this operation ++ * @param name the name of the operation ++ * @param id the id of the operation ++ * @param s the visibility of the operation ++ * @param rt the return type of the operation ++ */ ++UMLOperation::UMLOperation(UMLClassifier *parent, const QString& name, ++ Uml::ID::Type id, Uml::Visibility::Enum s, UMLObject *rt) ++ : UMLClassifierListItem(parent, name, id) ++{ ++ if (rt) ++ m_returnId = UniqueID::gen(); ++ else ++ m_returnId = Uml::ID::None; ++ m_pSecondary = rt; ++ m_visibility = s; ++ m_BaseType = UMLObject::ot_Operation; ++ m_bConst = false; ++ m_Code.clear(); ++} ++ ++/** ++ * Constructs an UMLOperation. ++ * Not intended for general use: The operation is not tied in with ++ * umbrello-kf6's Qt signalling for object creation. ++ * If you want to create an Operation use the method in UMLDoc instead. ++ * ++ * @param parent the parent to this operation ++ */ ++UMLOperation::UMLOperation(UMLClassifier * parent) ++ : UMLClassifierListItem (parent) ++{ ++ m_BaseType = UMLObject::ot_Operation; ++ m_bConst = false; ++ m_Code.clear(); ++} ++ ++/** ++ * Destructor. ++ */ ++UMLOperation::~UMLOperation() ++{ ++} ++ ++/** ++ * Reimplement method from UMLClassifierListItem. ++ * ++ * @param type pointer to the type object ++ */ ++void UMLOperation::setType(UMLObject* type) ++{ ++ UMLClassifierListItem::setType(type); ++ if (m_returnId == Uml::ID::None) ++ m_returnId = UniqueID::gen(); ++} ++ ++/** ++ * Move a parameter one position to the left. ++ * ++ * @param a the parameter to move ++ */ ++void UMLOperation::moveParmLeft(UMLAttribute * a) ++{ ++ if (a == NULL) { ++ uDebug() << "called on NULL attribute"; ++ return; ++ } ++ uDebug() << "called for " << a->name(); ++ disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); ++ int idx; ++ if ((idx=m_List.indexOf(a)) == -1) { ++ uDebug() << "Error move parm left " << a->name(); ++ return; ++ } ++ if (idx == 0) ++ return; ++ m_List.removeAll(a); ++ m_List.insert(idx-1, a); ++} ++ ++/** ++ * Move a parameter one position to the right. ++ * ++ * @param a the parameter to move ++ */ ++void UMLOperation::moveParmRight(UMLAttribute * a) ++{ ++ if (a == NULL) { ++ uDebug() << "called on NULL attribute"; ++ return; ++ } ++ uDebug() << "called for " << a->name(); ++ disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); ++ int idx; ++ if ((idx=m_List.indexOf(a)) == -1) { ++ uDebug() << "Error move parm right " << a->name(); ++ return; ++ } ++ int count = m_List.count(); ++ if (idx == count-1) ++ return; ++ m_List.removeAll(a); ++ m_List.insert(idx+1, a); ++} ++ ++/** ++ * Remove a parameter from the operation. ++ * ++ * @param a the parameter to remove ++ * @param emitModifiedSignal whether to emit the "modified" signal ++ * which creates an entry in the Undo stack for the ++ * removal, default: true ++ */ ++void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) ++{ ++ if (a == NULL) { ++ uDebug() << "called on NULL attribute"; ++ return; ++ } ++ uDebug() << "called for " << a->name(); ++ disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); ++ if(!m_List.removeAll(a)) ++ uDebug() << "Error removing parm " << a->name(); ++ ++ if (emitModifiedSignal) ++ emit modified(); ++} ++ ++/** ++ * Returns a list of parameters. ++ * ++ * @return a list of the parameters in the operation ++ */ ++UMLAttributeList UMLOperation::getParmList() const ++{ ++ return m_List; ++} ++ ++/** ++ * Finds a parameter of the operation. ++ * ++ * @param name the parameter name to search for ++ * @return the found parameter, 0 if not found ++ */ ++UMLAttribute* UMLOperation::findParm(const QString &name) ++{ ++ UMLAttribute * obj=0; ++ foreach (obj, m_List) { ++ if (obj->name() == name) ++ return obj; ++ } ++ return 0; ++} ++ ++/** ++ * Returns a string representation of the operation. ++ * ++ * @param sig what type of operation string to show ++ * @return the string representation of the operation ++ */ ++QString UMLOperation::toString(Uml::SignatureType::Enum sig) ++{ ++ QString s; ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) ++ s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); ++ ++ s += name(); ++ Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); ++ bool parameterlessOpNeedsParentheses = ++ (pl != Uml::ProgrammingLanguage::Pascal && pl != Uml::ProgrammingLanguage::Ada); ++ ++ if (sig == Uml::SignatureType::NoSig || sig == Uml::SignatureType::NoSigNoVis) { ++ if (parameterlessOpNeedsParentheses) ++ s.append(QLatin1String("()")); ++ return s; ++ } ++ int last = m_List.count(); ++ if (last) { ++ s.append(QLatin1String("(")); ++ int i = 0; ++ foreach (UMLAttribute *param, m_List) { ++ i++; ++ s.append(param->toString(Uml::SignatureType::SigNoVis)); ++ if (i < last) ++ s.append(QLatin1String(", ")); ++ } ++ s.append(QLatin1String(")")); ++ } else if (parameterlessOpNeedsParentheses) { ++ s.append(QLatin1String("()")); ++ } ++ UMLClassifier *ownParent = static_cast(parent()); ++ QString returnType; ++ UMLClassifier *retType = UMLClassifierListItem::getType(); ++ if (retType) { ++ UMLPackage *retVisibility = retType->umlPackage(); ++ if (retVisibility != ownParent && retVisibility != ownParent->umlPackage()) ++ returnType = retType->fullyQualifiedName(); ++ else ++ returnType = retType->name(); ++ } ++ if (returnType.length() > 0 && returnType != QLatin1String("void")) { ++ s.append(QLatin1String(" : ")); ++ ++ if (returnType.startsWith(QLatin1String(QLatin1String("virtual ")))) { ++ s += returnType.mid(8); ++ } else { ++ s += returnType; ++ } ++ } ++ return s; ++} ++ ++/** ++ * Add a parameter to the operation. ++ * ++ * @param parameter the parameter to add ++ * @param position the position in the parameter list. ++ * If position = -1 the parameter will be ++ * appended to the list. ++ */ ++void UMLOperation::addParm(UMLAttribute *parameter, int position) ++{ ++ if(position >= 0 && position <= (int)m_List.count()) ++ m_List.insert(position, parameter); ++ else ++ m_List.append(parameter); ++ UMLObject::emitModified(); ++ connect(parameter, SIGNAL(modified()), this, SIGNAL(modified())); ++} ++ ++/** ++ * Returns an unused parameter name for a new parameter. ++ */ ++QString UMLOperation::getUniqueParameterName() ++{ ++ QString currentName = i18n("new_parameter"); ++ QString name = currentName; ++ for (int number = 1; findParm(name); ++number) { ++ name = currentName + QLatin1Char('_') + QString::number(number); ++ } ++ return name; ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLOperation::operator==(const UMLOperation & rhs) const ++{ ++ if (this == &rhs) ++ return true; ++ ++ if (!UMLObject::operator==(rhs)) ++ return false; ++ ++ if (getTypeName() != rhs.getTypeName()) ++ return false; ++ ++ if (m_List.count() != rhs.m_List.count()) ++ return false; ++ ++ if (!(m_List == rhs.m_List)) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLOperation::copyInto(UMLObject *lhs) const ++{ ++ UMLOperation *target = static_cast(lhs); ++ ++ UMLClassifierListItem::copyInto(target); ++ ++ m_List.copyInto(&(target->m_List)); ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLOperation::clone() const ++{ ++ //FIXME: The new operation should be slaved to the NEW parent not the old. ++ UMLOperation *clone = new UMLOperation(static_cast(parent())); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Calls resolveRef() on all parameters. ++ * Needs to be called after all UML objects are loaded from file. ++ * ++ * @return true for success ++ */ ++bool UMLOperation::resolveRef() ++{ ++ bool overallSuccess = UMLObject::resolveRef(); ++ // See remark on iteration style in UMLClassifier::resolveRef() ++ foreach (UMLAttribute* pAtt, m_List) { ++ if (! pAtt->resolveRef()) ++ overallSuccess = false; ++ } ++ return overallSuccess; ++} ++ ++/** ++ * Returns whether this operation is a constructor. ++ * ++ * @return true if this operation is a constructor ++ */ ++bool UMLOperation::isConstructorOperation() ++{ ++ // if an operation has the stereotype constructor ++ // return true ++ if (stereotype() == QLatin1String("constructor")) ++ return true; ++ ++ UMLClassifier * c = static_cast(this->parent()); ++ QString cName = c->name(); ++ QString opName = name(); ++ // It's a constructor operation if the operation name ++ // matches that of the parent classifier. ++ return (cName == opName); ++} ++ ++/** ++ * Returns whether this operation is a destructor. ++ * ++ * @return true if this operation is a destructor ++ */ ++bool UMLOperation::isDestructorOperation() ++{ ++ if (stereotype() == QLatin1String("destructor")) ++ return true; ++ UMLClassifier * c = static_cast(this->parent()); ++ ++ QString cName = c->name(); ++ QString opName = name(); ++ // Special support for C++ syntax: ++ // It's a destructor operation if the operation name begins ++ // with "~" followed by the name of the parent classifier. ++ if (! opName.startsWith(QLatin1Char('~'))) ++ return false; ++ opName.remove(QRegExp(QLatin1String("^~\\s*"))); ++ return (cName == opName); ++} ++ ++/** ++ * Shortcut for (isConstructorOperation() || isDestructorOperation()). ++ * ++ * @return true if this operation is a constructor or destructor ++ */ ++bool UMLOperation::isLifeOperation() ++{ ++ return (isConstructorOperation() || isDestructorOperation()); ++} ++ ++/** ++ * Sets whether this operation is a query (C++ "const"). ++ */ ++void UMLOperation::setConst(bool b) ++{ ++ m_bConst = b; ++} ++ ++/** ++ * Returns whether this operation is a query (C++ "const"). ++ */ ++bool UMLOperation::getConst() const ++{ ++ return m_bConst; ++} ++ ++/** ++ * Display the properties configuration dialog for the template. ++ * ++ * @param parent the parent for the dialog ++ */ ++bool UMLOperation::showPropertiesDialog(QWidget* parent) ++{ ++ UMLOperationDialog dialog(parent, this); ++ return dialog.exec(); ++} ++ ++/** ++ * Sets the source code for this operation. ++ * ++ * @param code the body of this operation ++ */ ++void UMLOperation::setSourceCode(const QString& code) ++{ ++ m_Code = code; ++} ++ ++/** ++ * Returns the source code for this operation. ++ */ ++QString UMLOperation::getSourceCode() const ++{ ++ return m_Code; ++} ++ ++/** ++ * Saves to the XMI element. ++ */ ++void UMLOperation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement operationElement = UMLObject::save(QLatin1String("UML:Operation"), qDoc); ++ operationElement.setAttribute(QLatin1String("isQuery"), m_bConst ? QLatin1String("true") : QLatin1String("false")); ++ QDomElement featureElement = qDoc.createElement(QLatin1String("UML:BehavioralFeature.parameter")); ++ if (m_pSecondary) { ++ QDomElement retElement = qDoc.createElement(QLatin1String("UML:Parameter")); ++ if (m_returnId == Uml::ID::None) { ++ uDebug() << name() << ": m_returnId is not set, setting it now."; ++ m_returnId = UniqueID::gen(); ++ } ++ retElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_returnId)); ++ retElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); ++ retElement.setAttribute(QLatin1String("kind"), QLatin1String("return")); ++ featureElement.appendChild(retElement); ++ } else { ++ uDebug() << "m_SecondaryId is " << m_SecondaryId; ++ } ++ ++ //save each attribute here, type different ++ foreach(UMLAttribute* pAtt, m_List) { ++ QDomElement attElement = pAtt->UMLObject::save(QLatin1String("UML:Parameter"), qDoc); ++ UMLClassifier *attrType = pAtt->getType(); ++ if (attrType) { ++ attElement.setAttribute(QLatin1String("type"), Uml::ID::toString(attrType->id())); ++ } else { ++ attElement.setAttribute(QLatin1String("type"), pAtt->getTypeName()); ++ } ++ attElement.setAttribute(QLatin1String("value"), pAtt->getInitialValue()); ++ ++ Uml::ParameterDirection::Enum kind = pAtt->getParmKind(); ++ if (kind == Uml::ParameterDirection::Out) ++ attElement.setAttribute(QLatin1String("kind"), QLatin1String("out")); ++ else if (kind == Uml::ParameterDirection::InOut) ++ attElement.setAttribute(QLatin1String("kind"), QLatin1String("inout")); ++ // The default for the parameter kind is "in". ++ ++ featureElement.appendChild(attElement); ++ } ++ if (featureElement.hasChildNodes()) { ++ operationElement.appendChild(featureElement); ++ } ++ qElement.appendChild(operationElement); ++} ++ ++/** ++ * Loads a XMI element. ++ */ ++bool UMLOperation::load(QDomElement & element) ++{ ++ m_SecondaryId = element.attribute(QLatin1String("type")); ++ QString isQuery = element.attribute(QLatin1String("isQuery")); ++ if (!isQuery.isEmpty()) { ++ // We need this extra test for isEmpty() because load() might have been ++ // called again by the processing for BehavioralFeature.parameter (see below) ++ m_bConst = (isQuery == QLatin1String("true")); ++ } ++ QDomNode node = element.firstChild(); ++ if (node.isComment()) ++ node = node.nextSibling(); ++ QDomElement attElement = node.toElement(); ++ while (!attElement.isNull()) { ++ QString tag = attElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("BehavioralFeature.parameter")) || ++ UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement"))) { // Embarcadero's Describe ++ if (! load(attElement)) ++ return false; ++ } else if (UMLDoc::tagEq(tag, QLatin1String("Parameter"))) { ++ QString kind = attElement.attribute(QLatin1String("kind")); ++ if (kind.isEmpty()) { ++ kind = attElement.attribute(QLatin1String("direction")); // Embarcadero's Describe ++ if (kind.isEmpty()) { ++ // Perhaps the kind is stored in a child node: ++ for (QDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) { ++ if (n.isComment()) ++ continue; ++ QDomElement tempElement = n.toElement(); ++ QString tag = tempElement.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("kind"))) ++ continue; ++ kind = tempElement.attribute(QLatin1String("xmi.value")); ++ break; ++ } ++ } ++ if (kind.isEmpty()) { ++ kind = QLatin1String("in"); ++ } ++ } ++ if (kind == QLatin1String("return") || ++ kind == QLatin1String("result")) { // Embarcadero's Describe ++ QString returnId = Model_Utils::getXmiId(attElement); ++ if (!returnId.isEmpty()) ++ m_returnId = Uml::ID::fromString(returnId); ++ m_SecondaryId = attElement.attribute(QLatin1String("type")); ++ if (m_SecondaryId.isEmpty()) { ++ // Perhaps the type is stored in a child node: ++ QDomNode node = attElement.firstChild(); ++ while (!node.isNull()) { ++ if (node.isComment()) { ++ node = node.nextSibling(); ++ continue; ++ } ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { ++ node = node.nextSibling(); ++ continue; ++ } ++ m_SecondaryId = Model_Utils::getXmiId(tempElement); ++ if (m_SecondaryId.isEmpty()) ++ m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); ++ if (m_SecondaryId.isEmpty()) { ++ QDomNode inner = node.firstChild(); ++ QDomElement tmpElem = inner.toElement(); ++ m_SecondaryId = Model_Utils::getXmiId(tmpElem); ++ if (m_SecondaryId.isEmpty()) ++ m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); ++ } ++ break; ++ } ++ if (m_SecondaryId.isEmpty()) { ++ uError() << name() << ": cannot find return type."; ++ } ++ } ++ // Use deferred xmi.id resolution. ++ m_pSecondary = NULL; ++ } else { ++ UMLAttribute * pAtt = new UMLAttribute(this); ++ if(!pAtt->loadFromXMI(attElement)) { ++ delete pAtt; ++ return false; ++ } ++ if (kind == QLatin1String("out")) ++ pAtt->setParmKind(Uml::ParameterDirection::Out); ++ else if (kind == QLatin1String("inout")) ++ pAtt->setParmKind(Uml::ParameterDirection::InOut); ++ else ++ pAtt->setParmKind(Uml::ParameterDirection::In); ++ m_List.append(pAtt); ++ } ++ } ++ node = node.nextSibling(); ++ if (node.isComment()) ++ node = node.nextSibling(); ++ attElement = node.toElement(); ++ ++ // loading the source code which was entered in the 'classpropdlg' dialog is not done ++ // with the following code, because there is no CodeDocument. ++ /* ++ CodeGenerator* codegen = UMLApp::app()->getGenerator(); ++ if (codegen) { ++ uDebug() << "CodeDocument searching with id=" << Uml::ID::toString(UMLObject::ID()); ++ CodeDocument* codeDoc = codegen->findCodeDocumentByID(Uml::ID::toString(UMLObject::ID())); ++ if (codeDoc) { ++ uDebug() << "CodeDocument found:\n" << codeDoc; ++ } ++ } ++ */ ++ // it is done in the code generators by calling CodeGenerator::loadFromXMI(...). ++ ++ }//end while ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.h umbrello-kf6-15.08.1/umbrello/umlmodel/operation.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/operation.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,84 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef OPERATION_H ++#define OPERATION_H ++ ++#include "umlattributelist.h" ++#include "classifierlistitem.h" ++ ++class UMLClassifier; ++ ++/** ++ * This class represents an operation in the UML model. ++ * ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLOperation : public UMLClassifierListItem ++{ ++ Q_OBJECT ++public: ++ UMLOperation(UMLClassifier * parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None, ++ Uml::Visibility::Enum s = Uml::Visibility::Public, ++ UMLObject *rt = 0); ++ explicit UMLOperation(UMLClassifier * parent); ++ virtual ~UMLOperation(); ++ ++ bool operator==(const UMLOperation & rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ void setType(UMLObject* type); ++ ++ void moveParmLeft(UMLAttribute *a); ++ void moveParmRight(UMLAttribute *a); ++ ++ void removeParm(UMLAttribute *a, bool emitModifiedSignal = true); ++ ++ UMLAttributeList getParmList() const; ++ ++ UMLAttribute * findParm(const QString &name); ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ void addParm(UMLAttribute *parameter, int position = -1); ++ ++ bool resolveRef(); ++ ++ QString getUniqueParameterName(); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++ bool isConstructorOperation(); ++ bool isDestructorOperation(); ++ bool isLifeOperation(); ++ ++ void setConst(bool b); ++ bool getConst() const; ++ ++ void setSourceCode(const QString& code); ++ QString getSourceCode() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ bool load(QDomElement & element); ++ ++private: ++ Uml::ID::Type m_returnId; ///< Holds the xmi.id of the ++ UMLAttributeList m_List; ///< Parameter list ++ bool m_bConst; ///< Holds the isQuery attribute of the ++ QString m_Code; ///< Holds the entered source code ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/package.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/package.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,461 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header file ++#include "package.h" ++ ++// local includes ++#include "debug_utils.h" ++#include "dialog_utils.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "classifier.h" ++#include "association.h" ++#include "entity.h" ++#include "object_factory.h" ++#include "model_utils.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++ ++using namespace Uml; ++ ++/** ++ * Sets up a Package. ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLPackage::UMLPackage(const QString & name, Uml::ID::Type id) ++ : UMLCanvasObject(name, id) ++{ ++ m_BaseType = ot_Package; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLPackage::~UMLPackage() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new object. ++ */ ++void UMLPackage::copyInto(UMLObject *lhs) const ++{ ++ UMLPackage *target = static_cast(lhs); ++ ++ UMLCanvasObject::copyInto(target); ++ ++ m_objects.copyInto(&(target->m_objects)); ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLPackage::clone() const ++{ ++ UMLPackage *clone = new UMLPackage(); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Adds an existing association to the matching concept in the list of concepts. ++ * The selection of the matching concept depends on the association type: ++ * For generalizations, the assoc is added to the concept that matches role A. ++ * For aggregations and compositions, the assoc is added to the concept ++ * that matches role B. ++ * @param assoc the association to add ++ */ ++void UMLPackage::addAssocToConcepts(UMLAssociation* assoc) ++{ ++ if (! AssociationType::hasUMLRepresentation(assoc->getAssocType())) ++ return; ++ Uml::ID::Type AId = assoc->getObjectId(Uml::RoleType::A); ++ Uml::ID::Type BId = assoc->getObjectId(Uml::RoleType::B); ++ UMLObject *o = NULL; ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ o = oit.next(); ++ UMLCanvasObject *c = dynamic_cast(o); ++ if (c == NULL) ++ continue; ++ if (AId == c->id() || (BId == c->id())) { ++ if (c->hasAssociation(assoc)) ++ uDebug() << c->name() << " already has association id=" << Uml::ID::toString(assoc->id()); ++ else ++ c->addAssociationEnd(assoc); ++ } ++ UMLPackage *pkg = dynamic_cast(c); ++ if (pkg) ++ pkg->addAssocToConcepts(assoc); ++ } ++} ++ ++/** ++ * Remove the association from the participating concepts. ++ * @param assoc the association to remove ++ */ ++void UMLPackage::removeAssocFromConcepts(UMLAssociation *assoc) ++{ ++ UMLObject *o = 0; ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ o = oit.next(); ++ UMLCanvasObject *c = dynamic_cast(o); ++ if (c) { ++ if (c->hasAssociation(assoc)) ++ c->removeAssociationEnd(assoc); ++ UMLPackage *pkg = dynamic_cast(c); ++ if (pkg) ++ pkg->removeAssocFromConcepts(assoc); ++ } ++ } ++} ++ ++/** ++ * Adds an object in this package. ++ * ++ * @param pObject Pointer to the UMLObject to add. ++ * @return True if the object was actually added. ++ */ ++bool UMLPackage::addObject(UMLObject *pObject) ++{ ++ if (pObject == NULL) { ++ uError() << "is called with a NULL object"; ++ return false; ++ } ++ if (pObject == this) { ++ uError() << "adding myself as child is not allowed"; ++ return false; ++ } ++ ++ if (m_objects.indexOf(pObject) != -1) { ++ uDebug() << pObject->name() << " is already there"; ++ return false; ++ } ++ if (pObject->baseType() == UMLObject::ot_Association) { ++ UMLAssociation *assoc = static_cast(pObject); ++ // Adding the UMLAssociation at the participating concepts is done ++ // again later (in UMLAssociation::resolveRef()) if they are not yet ++ // known right here. ++ if (assoc->getObject(Uml::RoleType::A) && assoc->getObject(Uml::RoleType::B)) { ++ UMLPackage *pkg = pObject->umlPackage(); ++ if (pkg != this) { ++ uError() << "UMLPackage " << name() << " addObject: " ++ << "assoc's UMLPackage is " << pkg->name(); ++ } ++ addAssocToConcepts(assoc); ++ } ++ } ++ else { ++ QString name = pObject->name(); ++ QString oldName = name; ++ while (findObject(name) != NULL) { ++ QString prevName = name; ++ name = Model_Utils::uniqObjectName(pObject->baseType(), this); ++ bool ok = Dialog_Utils::askName(i18nc("object name", "Name"), ++ i18n("An object with the name %1\nalready exists in the package %2.\nPlease enter a new name:", prevName, this->name()), ++ name); ++ if (!ok) { ++ name = oldName; ++ continue; ++ } ++ if (name.length() == 0) { ++ KMessageBox::error(0, i18n("That is an invalid name."), ++ i18n("Invalid Name")); ++ continue; ++ } ++ } ++ if (oldName != name) { ++ pObject->setName(name); ++ } ++ } ++ m_objects.append(pObject); ++ return true; ++} ++ ++/** ++ * Removes an object from this package. ++ * Does not physically delete the object. ++ * ++ * @param pObject Pointer to the UMLObject to be removed. ++ */ ++void UMLPackage::removeObject(UMLObject *pObject) ++{ ++ if (pObject->baseType() == UMLObject::ot_Association) { ++ UMLObject *o = const_cast(pObject); ++ UMLAssociation *assoc = static_cast(o); ++ removeAssocFromConcepts(assoc); ++ } ++ if (m_objects.indexOf(pObject) == -1) ++ uDebug() << name() << " removeObject: object with id=" ++ << Uml::ID::toString(pObject->id()) << "not found."; ++ else ++ m_objects.removeAll(pObject); ++} ++ ++/** ++ * Removes all objects from this package. ++ * Inner containers (e.g. nested packages) are removed recursively. ++ */ ++void UMLPackage::removeAllObjects() ++{ ++ UMLCanvasObject::removeAllChildObjects(); ++ UMLObject *o = NULL; ++ ++ while (!m_objects.isEmpty() && (o = m_objects.first()) != NULL) { ++ UMLPackage *pkg = dynamic_cast(o); ++ if (pkg) ++ pkg->removeAllObjects(); ++ removeObject(o); ++ delete o; ++ } ++} ++ ++/** ++ * Returns the list of objects contained in this package. ++ */ ++UMLObjectList UMLPackage::containedObjects() ++{ ++ return m_objects; ++} ++ ++/** ++ * Find the object of the given name in the list of contained objects. ++ * ++ * @param name The name to seek. ++ * @return Pointer to the UMLObject found or NULL if not found. ++ */ ++UMLObject * UMLPackage::findObject(const QString &name) ++{ ++ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ UMLObject *obj = oit.next(); ++ if (!obj) ++ continue; ++ if (caseSensitive) { ++ if (obj->name() == name) ++ return obj; ++ } else if (obj->name().toLower() == name.toLower()) { ++ return obj; ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * Find the object of the given ID in the list of contained objects. ++ * ++ * @param id The ID to seek. ++ * @return Pointer to the UMLObject found or NULL if not found. ++ */ ++UMLObject * UMLPackage::findObjectById(Uml::ID::Type id) ++{ ++ return Model_Utils::findObjectInList(id, m_objects); ++} ++ ++/** ++ * Append all packages from this package (and those from nested packages) ++ * to the given UMLPackageList. ++ * ++ * @param packages The list to append to ++ * @param includeNested Whether to include the packages from nested packages ++ * (default:true) ++ */ ++void UMLPackage::appendPackages(UMLPackageList& packages, bool includeNested) ++{ ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ UMLObject *o = oit.next(); ++ uIgnoreZeroPointer(o); ++ ObjectType ot = o->baseType(); ++ if (ot == ot_Package || ot == ot_Folder) { ++ packages.append(static_cast(o)); ++ if (includeNested) { ++ UMLPackage *inner = static_cast(o); ++ inner->appendPackages(packages); ++ } ++ } ++ } ++} ++ ++/** ++ * Append all classifiers from this package (and those from ++ * nested packages) to the given UMLClassifierList. ++ * ++ * @param classifiers The list to append to. ++ * @param includeNested Whether to include the classifiers from ++ * nested packages (default: true.) ++ */ ++void UMLPackage::appendClassifiers(UMLClassifierList& classifiers, ++ bool includeNested /* = true */) ++{ ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ UMLObject *o = oit.next(); ++ uIgnoreZeroPointer(o); ++ ObjectType ot = o->baseType(); ++ if (ot == ot_Class || ot == ot_Interface || ++ ot == ot_Datatype || ot == ot_Enum || ot == ot_Entity) { ++ classifiers.append((UMLClassifier *)o); ++ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { ++ UMLPackage *inner = static_cast(o); ++ inner->appendClassifiers(classifiers); ++ } ++ } ++} ++ ++/** ++ * Append all entities from this package (and those ++ * from nested packages) to the given UMLEntityList. ++ * ++ * @param entities The list to append to. ++ * @param includeNested Whether to include the entities from ++ * nested packages (default: true.) ++ */ ++void UMLPackage::appendEntities(UMLEntityList& entities, ++ bool includeNested /* = true */) ++{ ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ UMLObject *o = oit.next(); ++ uIgnoreZeroPointer(o); ++ ObjectType ot = o->baseType(); ++ if (ot == ot_Entity) { ++ UMLEntity *c = static_cast(o); ++ entities.append(c); ++ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { ++ UMLPackage *inner = static_cast(o); ++ inner->appendEntities(entities); ++ } ++ } ++} ++ ++/** ++ * Append all classes and interfaces from this package (and those ++ * from nested packages) to the given UMLClassifierList. ++ * ++ * @param classifiers The list to append to. ++ * @param includeNested Whether to include the classifiers from ++ * nested packages (default: true.) ++ */ ++void UMLPackage::appendClassesAndInterfaces(UMLClassifierList& classifiers, ++ bool includeNested /* = true */) ++{ ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ UMLObject *o = oit.next(); ++ uIgnoreZeroPointer(o); ++ ObjectType ot = o->baseType(); ++ if (ot == ot_Class || ot == ot_Interface) { ++ UMLClassifier *c = static_cast(o); ++ classifiers.append(c); ++ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { ++ UMLPackage *inner = static_cast(o); ++ inner->appendClassesAndInterfaces(classifiers); ++ } ++ } ++} ++ ++/** ++ * Resolve types. Required when dealing with foreign XMI files. ++ * Needs to be called after all UML objects are loaded from file. ++ * Overrides the method from UMLObject. ++ * Calls resolveRef() on each contained object. ++ * ++ * @return True for overall success. ++ */ ++bool UMLPackage::resolveRef() ++{ ++ bool overallSuccess = UMLCanvasObject::resolveRef(); ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ UMLObject *obj = oit.next(); ++ uIgnoreZeroPointer(obj); ++ if (! obj->resolveRef()) { ++ UMLObject::ObjectType ot = obj->baseType(); ++ if (ot != UMLObject::ot_Package && ot != UMLObject::ot_Folder) ++ m_objects.removeAll(obj); ++ overallSuccess = false; ++ } ++ } ++ return overallSuccess; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLPackage::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement packageElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); ++ QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); ++ UMLObject *obj = NULL; ++ // save classifiers etc. ++ for (UMLObjectListIt oit(m_objects); oit.hasNext();) { ++ obj = oit.next(); ++ uIgnoreZeroPointer(obj); ++ obj->saveToXMI (qDoc, ownedElement); ++ } ++ // save associations ++ for (UMLObjectListIt ait(m_List); ait.hasNext();) { ++ obj = ait.next(); ++ obj->saveToXMI (qDoc, ownedElement); ++ } ++ ++ packageElement.appendChild(ownedElement); ++ qElement.appendChild(packageElement); ++} ++ ++/** ++ * Loads the XMI element. ++ * Auxiliary to UMLObject::loadFromXMI. ++ */ ++bool UMLPackage::load(QDomElement& element) ++{ ++ 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::isCommonXMIAttribute(type)) ++ continue; ++ if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || ++ UMLDoc::tagEq(type, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe ++ UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { ++ //CHECK: umbrello-kf6 currently assumes that nested elements ++ // are ownedElements anyway. ++ // Therefore these tags are not further interpreted. ++ if (! load(tempElement)) ++ return false; ++ continue; ++ } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || ++ UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { ++ type = tempElement.attribute(QLatin1String("xmi:type")); ++ } ++ UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); ++ if(!pObject) { ++ uWarning() << "Unknown type of umlobject to create: " << type; ++ continue; ++ } ++ pObject->setUMLPackage(this); ++ if (!pObject->loadFromXMI(tempElement)) { ++ removeObject(pObject); ++ delete pObject; ++ } ++ } ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.h umbrello-kf6-15.08.1/umbrello/umlmodel/package.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/package.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,79 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PACKAGE_H ++#define PACKAGE_H ++ ++#include "umlcanvasobject.h" ++#include "umlclassifierlist.h" ++#include "umlentitylist.h" ++ ++// forward declarations ++class UMLAssociation; ++ ++/** ++ * This class contains the non-graphical information required for a UML ++ * Package. ++ * This class inherits from @ref UMLCanvasObject which contains most of the ++ * information. ++ * ++ * @short Non-graphical information for a Package. ++ * @author Jonathan Riddell ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLPackage : public UMLCanvasObject ++{ ++ Q_OBJECT ++public: ++ explicit UMLPackage(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLPackage(); ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ bool addObject(UMLObject *pObject); ++ void removeObject(UMLObject *pObject); ++ ++ virtual void removeAllObjects(); ++ ++ UMLObjectList containedObjects(); ++ ++ void addAssocToConcepts(UMLAssociation* assoc); ++ void removeAssocFromConcepts(UMLAssociation *assoc); ++ ++ UMLObject * findObject(const QString &name); ++ UMLObject * findObjectById(Uml::ID::Type id); ++ ++ void appendPackages(UMLPackageList& packages, bool includeNested = true); ++ void appendClassifiers(UMLClassifierList& classifiers, ++ bool includeNested = true); ++ void appendClassesAndInterfaces(UMLClassifierList& classifiers, ++ bool includeNested = true); ++ void appendEntities(UMLEntityList& entities, ++ bool includeNested = true); ++ ++ virtual bool resolveRef(); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++protected: ++ virtual bool load(QDomElement& element); ++ ++ /** ++ * References to the objects contained in this package. ++ * The UMLPackage is the owner of the objects. ++ */ ++ UMLObjectList m_objects; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/port.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/port.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,68 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "port.h" ++ ++#include ++ ++/** ++ * Sets up a Port. ++ * ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLPort::UMLPort(const QString & name, Uml::ID::Type id) ++ : UMLCanvasObject(name, id) ++{ ++ init(); ++} ++ ++/** ++ * Destructor. ++ */ ++UMLPort::~UMLPort() ++{ ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLPort::init() ++{ ++ m_BaseType = UMLObject::ot_Port; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLPort::clone() const ++{ ++ UMLPort *clone = new UMLPort(); ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLPort::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement portElement = UMLObject::save(QLatin1String("UML:Port"), qDoc); ++ qElement.appendChild(portElement); ++} ++ ++/** ++ * Loads the XMI element (empty.) ++ */ ++bool UMLPort::load(QDomElement&) ++{ ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.h umbrello-kf6-15.08.1/umbrello/umlmodel/port.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/port.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,46 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PORT_H ++#define PORT_H ++ ++#include "umlcanvasobject.h" ++ ++/** ++ * This class contains the non-graphical information required for a UML Port. ++ * This class inherits from @ref UMLCanvasObject which contains most of the ++ * information. ++ * ++ * @short Non-graphical information for a Port. ++ * @author Oliver Kellogg ++ * @see UMLCanvasObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLPort : public UMLCanvasObject ++{ ++ Q_OBJECT ++public: ++ ++ explicit UMLPort(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLPort(); ++ ++ virtual void init(); ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,165 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "stereotype.h" ++ ++// local includes ++#include "debug_utils.h" ++#include "umldoc.h" ++#include "uml.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++ ++/** ++ * 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::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ //FIXME: uml13.dtd compliance ++ QDomElement stereotypeElement = UMLObject::save(QLatin1String("UML:Stereotype"), qDoc); ++ qElement.appendChild(stereotypeElement); ++} ++ ++/** ++ * Display the properties configuration dialog for the stereotype ++ * (just a line edit). ++ */ ++bool UMLStereotype::showPropertiesDialog(QWidget* parent) ++{ ++ bool ok; ++#if QT_VERSION >= 0x050000 ++ QString stereoTypeName = QInputDialog::getText(parent, ++ i18n("Stereotype"), i18n("Enter name:"), ++ QLineEdit::Normal, ++ name(), &ok); ++#else ++ QString stereoTypeName = KInputDialog::getText(i18n("Stereotype"), i18n("Enter name:"), name(), &ok, parent); ++#endif ++ 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.h umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,71 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef STEREOTYPE_H ++#define STEREOTYPE_H ++ ++#include "umlobject.h" ++ ++/** ++ * This class is used to set up information for a stereotype. ++ * Stereotypes are used essentially as properties of ++ * attributes and operations etc. ++ * ++ * Each stereotype object is reference counted, i.e. client code ++ * manages it such that it comes into existence as soon as there is ++ * at least one user, and ceases existing when the number of users ++ * drops to 0. ++ * m_refCount reflects the number of users. It is externally managed, ++ * i.e. client code must take care to call incrRefCount() and ++ * decrRefCount() as appropriate. ++ * ++ * The one and only owner of all stereotypes is the UMLDoc, and the ++ * ownership is specially managed (umlPackage() returns NULL for a ++ * UMLStereotype.) The reason for this special treatment is that ++ * class UMLDoc does not inherit from class UMLPackage, and therefore ++ * setUMLPackage() cannot be used for stereotypes. ++ * ++ * @short Sets up stereotype information. ++ * @author Jonathan Riddell ++ * @author Oliver Kellogg ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLStereotype : public UMLObject ++{ ++ Q_OBJECT ++public: ++ explicit UMLStereotype(const QString &name, Uml::ID::Type id = Uml::ID::None); ++ UMLStereotype(); ++ ++ virtual ~UMLStereotype(); ++ ++ bool operator==(const UMLStereotype &rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ void incrRefCount(); ++ void decrRefCount(); ++ ++ int refCount() const; ++ ++ QString name(bool includeAdornments=false) const; ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent); ++ ++protected: ++ int m_refCount; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/template.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/template.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,146 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "template.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umltemplatedialog.h" ++ ++/** ++ * Sets up a template. ++ * ++ * @param parent The parent of this UMLTemplate (i.e. its concept). ++ * @param name The name of this UMLTemplate. ++ * @param id The unique id given to this UMLTemplate. ++ * @param type The type of this UMLTemplate. ++ */ ++UMLTemplate::UMLTemplate(UMLObject *parent, const QString& name, ++ Uml::ID::Type id, const QString& type) ++ : UMLClassifierListItem(parent, name, id) ++{ ++ setTypeName(type); ++ m_BaseType = UMLObject::ot_Template; ++} ++ ++/** ++ * Sets up a template. ++ * ++ * @param parent The parent of this UMLTemplate (i.e. its concept). ++ */ ++UMLTemplate::UMLTemplate(UMLObject *parent) ++ : UMLClassifierListItem(parent) ++{ ++ m_BaseType = UMLObject::ot_Template; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLTemplate::~UMLTemplate() ++{ ++} ++ ++QString UMLTemplate::toString(Uml::SignatureType::Enum sig) ++{ ++ Q_UNUSED(sig); ++ if (m_pSecondary == NULL || m_pSecondary->name() == QLatin1String("class")) { ++ return name(); ++ } else { ++ return name() + QLatin1String(" : ") + m_pSecondary->name(); ++ } ++} ++ ++/** ++ * Overrides method from UMLClassifierListItem. ++ * Returns the type name of the UMLTemplate. ++ * If the template parameter is a class, there is no separate ++ * type object. In this case, getTypeName() returns "class". ++ * ++ * @return The type name of the UMLClassifierListItem. ++ */ ++QString UMLTemplate::getTypeName() const ++{ ++ if (m_pSecondary == NULL) ++ return QLatin1String("class"); ++ return m_pSecondary->name(); ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLTemplate::operator==(const UMLTemplate &rhs) const ++{ ++ if (this == &rhs) { ++ return true; ++ } ++ if (!UMLObject::operator==(rhs)) { ++ return false; ++ } ++ if (m_pSecondary != rhs.m_pSecondary) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLTemplate::copyInto(UMLObject *lhs) const ++{ ++ UMLClassifierListItem::copyInto(lhs); ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLTemplate::clone() const ++{ ++ UMLTemplate *clone = new UMLTemplate((UMLTemplate*) parent()); ++ copyInto(clone); ++ ++ return clone; ++} ++ ++/** ++ * Writes the XMI element. ++ */ ++void UMLTemplate::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ //FIXME: uml13.dtd compliance ++ QDomElement attributeElement = UMLObject::save(QLatin1String("UML:TemplateParameter"), qDoc); ++ if (m_pSecondary) ++ attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); ++ qElement.appendChild(attributeElement); ++} ++ ++/** ++ * Loads the XMI element. ++ */ ++bool UMLTemplate::load(QDomElement& element) ++{ ++ m_SecondaryId = element.attribute(QLatin1String("type")); ++ return true; ++} ++ ++/** ++ * Display the properties configuration dialog for the template. ++ * ++ * @return Success status. ++ */ ++bool UMLTemplate::showPropertiesDialog(QWidget* parent) ++{ ++ UMLTemplateDialog dialog(parent, this); ++ return dialog.exec(); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.h umbrello-kf6-15.08.1/umbrello/umlmodel/template.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/template.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,57 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef TEMPLATE_H ++#define TEMPLATE_H ++ ++#include "classifierlistitem.h" ++ ++/** ++ * This class holds information used by template classes, called ++ * paramaterised class in UML and a generic in Java. It has a ++ * type (usually just "class") and name. ++ * ++ * @short Sets up template information. ++ * @author Jonathan Riddell ++ * @see UMLObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLTemplate : public UMLClassifierListItem ++{ ++public: ++ ++ UMLTemplate(UMLObject *parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None, const QString& type = QLatin1String("class")); ++ ++ explicit UMLTemplate(UMLObject *parent); ++ ++ bool operator==(const UMLTemplate &rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ virtual ~UMLTemplate(); ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ virtual QString getTypeName() const; ++ ++ virtual bool showPropertiesDialog(QWidget* parent); ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlassociationlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlassociationlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlassociationlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlassociationlist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,23 @@ ++/*************************************************************************** ++ * * ++ * 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-2007 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLASSOCIATIONLIST_H ++#define UMLASSOCIATIONLIST_H ++ ++#include ++ ++// forward declaration ++class UMLAssociation; ++ ++typedef QList UMLAssociationList; ++typedef QListIterator UMLAssociationListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,61 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "umlattributelist.h" ++ ++#include "attribute.h" ++ ++#include ++ ++UMLAttributeList::UMLAttributeList() ++{ ++} ++ ++UMLAttributeList::UMLAttributeList(const UMLAttributeList& other) ++ : QList(other) ++{ ++} ++ ++UMLAttributeList::~UMLAttributeList() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLAttributeList::copyInto(UMLAttributeList *rhs) const ++{ ++ // Don't copy yourself. ++ if (rhs == this) return; ++ ++ rhs->clear(); ++ ++ // Suffering from const; we shall not modify our object. ++ UMLAttributeList *tmp = new UMLAttributeList(*this); ++ ++ UMLAttribute *item; ++ for (UMLAttributeListIt ait(*tmp); ait.hasNext() ;) ++ { ++ item = ait.next(); ++ rhs->append((UMLAttribute*)item->clone()); ++ } ++ delete tmp; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLAttributeList* UMLAttributeList::clone() const ++{ ++ UMLAttributeList *clone = new UMLAttributeList(); ++ copyInto(clone); ++ return clone; ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,42 @@ ++/*************************************************************************** ++ * * ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLATTRIBUTELIST_H ++#define UMLATTRIBUTELIST_H ++ ++#include ++ ++#include "attribute.h" ++ ++//typedef QPtrList UMLAttributeList; ++typedef QListIterator UMLAttributeListIt; ++ ++/** ++ * This sub-class adds copyInto and clone to the QPtrList ++ * base class. ++ */ ++class UMLAttributeList : public QList ++{ ++public: ++ ++ UMLAttributeList(); ++ ++ UMLAttributeList(const UMLAttributeList&); ++ ++ virtual ~UMLAttributeList(); ++ ++ virtual void copyInto(UMLAttributeList *rhs) const; ++ ++ virtual UMLAttributeList* clone() const; ++}; ++ ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,464 @@ ++/*************************************************************************** ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * copyright (C) 2003-2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "umlcanvasobject.h" ++ ++// local includes ++#include "debug_utils.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "classifier.h" ++#include "association.h" ++#include "attribute.h" ++#include "operation.h" ++#include "template.h" ++#include "stereotype.h" ++#include "idchangelog.h" ++ ++// kde includes ++#include ++ ++DEBUG_REGISTER_DISABLED(UMLCanvasObject) ++ ++/** ++ * Sets up a UMLCanvasObject. ++ * ++ * @param name The name of the Concept. ++ * @param id The unique id of the Concept. ++ */ ++UMLCanvasObject::UMLCanvasObject(const QString & name, Uml::ID::Type id) ++ : UMLObject(name, id) ++{ ++} ++ ++/** ++ * Standard deconstructor. ++ */ ++UMLCanvasObject::~UMLCanvasObject() ++{ ++ //removeAllAssociations(); ++ // No! This is way too late to do that. ++ // It should have been called explicitly before destructing the ++ // UMLCanvasObject. ++ if (associations()) ++ DEBUG(DBG_SRC) << "UMLCanvasObject destructor: FIXME: there are still associations()"; ++} ++ ++/** ++ * Return the subset of m_List that matches the given type. ++ * ++ * @param assocType The AssociationType::Enum to match. ++ * @return The list of associations that match assocType. ++ */ ++UMLAssociationList UMLCanvasObject::getSpecificAssocs(Uml::AssociationType::Enum assocType) ++{ ++ UMLAssociationList list; ++ UMLObject *o = NULL; ++ for (UMLObjectListIt oit(m_List); oit.hasNext();) { ++ o = oit.next(); ++ uIgnoreZeroPointer(o); ++ if (o->baseType() != UMLObject::ot_Association) ++ continue; ++ UMLAssociation *a = static_cast(o); ++ if (a->getAssocType() == assocType) ++ list.append(a); ++ } ++ return list; ++} ++ ++/** ++ * Adds an association end to m_List. ++ * ++ * @param assoc The association to add. ++ * @todo change param type to UMLRole ++ */ ++bool UMLCanvasObject::addAssociationEnd(UMLAssociation* assoc) ++{ ++ Q_ASSERT(assoc); ++ // add association only if not already present in list ++ if (!hasAssociation(assoc)) ++ { ++ m_List.append(assoc); ++ ++ // Don't emit signals during load from XMI ++ UMLObject::emitModified(); ++ emit sigAssociationEndAdded(assoc); ++ return true; ++ } ++ return false; ++} ++ ++/** ++ * Determine if this canvasobject has the given association. ++ * ++ * @param assoc The association to check. ++ */ ++bool UMLCanvasObject::hasAssociation(UMLAssociation* assoc) ++{ ++ uint cnt = m_List.count(assoc); ++ DEBUG(DBG_SRC) << "count is " << cnt; ++ return (cnt > 0); ++} ++ ++/** ++ * Remove an association end from the CanvasObject. ++ * ++ * @param assoc The association to remove. ++ * @todo change param type to UMLRole ++ */ ++int UMLCanvasObject::removeAssociationEnd(UMLAssociation * assoc) ++{ ++ if (!hasAssociation(assoc) || !m_List.removeAll(assoc)) { ++ DEBUG(DBG_SRC) << "cannot find given assoc " << assoc << " in list"; ++ return -1; ++ } ++ UMLApp::app()->document()->removeAssociation(assoc, false); ++ UMLObject::emitModified(); ++ emit sigAssociationEndRemoved(assoc); ++ return m_List.count(); ++} ++ ++/** ++ * Remove all association ends from the CanvasObject. ++ */ ++void UMLCanvasObject::removeAllAssociationEnds() ++{ ++ for (int i = 0; i < m_List.count(); i++) { ++ UMLObject *o = m_List.at(i); ++ uIgnoreZeroPointer(o); ++ if (o->baseType() != UMLObject::ot_Association) { ++ continue; ++ } ++ UMLAssociation *assoc = static_cast(o); ++ //umldoc->slotRemoveUMLObject(assoc); ++ UMLObject* objA = assoc->getObject(Uml::RoleType::A); ++ UMLObject* objB = assoc->getObject(Uml::RoleType::B); ++ UMLCanvasObject *roleAObj = dynamic_cast(objA); ++ if (roleAObj) { ++ roleAObj->removeAssociationEnd(assoc); ++ } else if (objA) { ++ DEBUG(DBG_SRC) << name() << ": objA " << objA->name() << " is not a UMLCanvasObject"; ++ } else ++ DEBUG(DBG_SRC) << name() << "): objA is NULL"; ++ UMLCanvasObject *roleBObj = dynamic_cast(objB); ++ if (roleBObj) { ++ roleBObj->removeAssociationEnd(assoc); ++ } else if (objB) { ++ DEBUG(DBG_SRC) << name() << "): objB " << objB->name() << " is not a UMLCanvasObject"; ++ } else ++ DEBUG(DBG_SRC) << name() << "): objB is NULL"; ++ } ++} ++ ++/** ++ * Remove all child objects. ++ * Just clear list, objects must be deleted where they were created ++ * (or we have bad crashes). ++ */ ++void UMLCanvasObject::removeAllChildObjects() ++{ ++ if (!m_List.isEmpty()) { ++ removeAllAssociationEnds(); ++ m_List.clear(); ++ } ++} ++ ++/** ++ * Returns a name for the new association, operation, template ++ * or attribute appended with a number if the default name is ++ * taken e.g. new_association, new_association_1 etc. ++ * ++ * @param type The object type for which to make a name. ++ * @param prefix Optional prefix to use for the name. ++ * If not given then uniqChildName() will choose the prefix ++ * internally based on the object type. ++ * @return Unique name string for the ObjectType given. ++ */ ++QString UMLCanvasObject::uniqChildName(const UMLObject::ObjectType type, ++ const QString &prefix /* = QString() */) ++{ ++ QString currentName; ++ currentName = prefix; ++ if (currentName.isEmpty()) { ++ switch (type) { ++ case UMLObject::ot_Association: ++ currentName = i18n("new_association"); ++ break; ++ case UMLObject::ot_Attribute: ++ currentName = i18n("new_attribute"); ++ break; ++ case UMLObject::ot_Template: ++ currentName = i18n("new_template"); ++ break; ++ case UMLObject::ot_Operation: ++ currentName = i18n("new_operation"); ++ break; ++ case UMLObject::ot_EnumLiteral: ++ currentName = i18n("new_literal"); ++ break; ++ case UMLObject::ot_EntityAttribute: ++ currentName = i18n("new_field"); ++ break; ++ case UMLObject::ot_UniqueConstraint: ++ currentName = i18n("new_unique_constraint"); ++ break; ++ case UMLObject::ot_ForeignKeyConstraint: ++ currentName = i18n("new_fkey_constraint"); ++ break; ++ case UMLObject::ot_CheckConstraint: ++ currentName = i18n("new_check_constraint"); ++ break; ++ default: ++ uWarning() << "uniqChildName() called for unknown child type " << UMLObject::toString(type); ++ return QLatin1String("ERROR_in_UMLCanvasObject_uniqChildName"); ++ } ++ } ++ ++ QString name = currentName; ++ for (int number = 1; findChildObject(name); ++number) { ++ name = currentName + QLatin1Char('_') + QString::number(number); ++ } ++ return name; ++} ++ ++/** ++ * Find a child object with the given name. ++ * ++ * @param n The name of the object to find. ++ * @param t The type to find (optional.) If not given then ++ * any object type will match. ++ * @return Pointer to the object found; NULL if none found. ++ */ ++UMLObject * UMLCanvasObject::findChildObject(const QString &n, UMLObject::ObjectType t) ++{ ++ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); ++ UMLObject *obj = NULL; ++ for (UMLObjectListIt oit(m_List); oit.hasNext();) { ++ obj = oit.next(); ++ uIgnoreZeroPointer(obj); ++ if (t != UMLObject::ot_UMLObject && obj->baseType() != t) ++ continue; ++ if (caseSensitive) { ++ if (obj->name() == n) ++ return obj; ++ } else if (obj->name().toLower() == n.toLower()) { ++ return obj; ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * Find an association. ++ * ++ * @param id The id of the object to find. ++ * @param considerAncestors boolean switch to consider ancestors while searching ++ * @return Pointer to the object found (NULL if not found.) ++ */ ++UMLObject* UMLCanvasObject::findChildObjectById(Uml::ID::Type id, bool considerAncestors) ++{ ++ Q_UNUSED(considerAncestors); ++ UMLObject *o = NULL; ++ for (UMLObjectListIt oit(m_List); oit.hasNext();) { ++ o = oit.next(); ++ uIgnoreZeroPointer(o); ++ if (o->id() == id) ++ return o; ++ } ++ return 0; ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLCanvasObject::operator==(const UMLCanvasObject& rhs) const ++{ ++ if (this == &rhs) { ++ return true; ++ } ++ if (!UMLObject::operator==(rhs)) { ++ return false; ++ } ++ if (m_List.count() != rhs.m_List.count()) { ++ return false; ++ } ++ if (&m_List != &(rhs.m_List)) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLCanvasObject::copyInto(UMLObject *lhs) const ++{ ++ UMLObject::copyInto(lhs); ++ ++ // TODO Associations are not copied at the moment. This because ++ // the duplicate function (on umlwidgets) do not copy the associations. ++ // ++ //target->m_List = m_List; ++} ++ ++/** ++ * Returns the number of associations for the CanvasObject. ++ * This is the sum of the aggregations and compositions. ++ * ++ * @return The number of associations for the Concept. ++ */ ++int UMLCanvasObject::associations() ++{ ++ int count = 0; ++ UMLObject *obj = NULL; ++ for (UMLObjectListIt oit(m_List); oit.hasNext();) { ++ obj = oit.next(); ++ uIgnoreZeroPointer(obj); ++ if (obj->baseType() == UMLObject::ot_Association) ++ count++; ++ } ++ return count; ++} ++ ++/** ++ * Return the list of associations for the CanvasObject. ++ * ++ * @return The list of associations for the CanvasObject. ++ */ ++UMLAssociationList UMLCanvasObject::getAssociations() ++{ ++ UMLAssociationList assocs; ++ UMLObject *o = NULL; ++ for (UMLObjectListIt oit(m_List); oit.hasNext() ;) { ++ o = oit.next(); ++ uIgnoreZeroPointer(o); ++ if (o->baseType() != UMLObject::ot_Association) ++ continue; ++ UMLAssociation *assoc = static_cast(o); ++ assocs.append(assoc); ++ } ++ return assocs; ++} ++ ++/** ++ * Return a list of the superclasses of this concept. ++ * TODO: This overlaps with UMLClassifier::findSuperClassConcepts(), ++ * see if we can merge the two. ++ * ++ * @param withRealizations include realizations in the returned list (default=yes) ++ * @return The list of superclasses for the concept. ++ */ ++UMLClassifierList UMLCanvasObject::getSuperClasses(bool withRealizations) ++{ ++ UMLClassifierList list; ++ UMLAssociationList assocs = getAssociations(); ++ foreach (UMLAssociation* a, assocs) { ++ uIgnoreZeroPointer(a); ++ if ((a->getAssocType() != Uml::AssociationType::Generalization && ++ a->getAssocType() != Uml::AssociationType::Realization) || ++ (!withRealizations && a->getAssocType() == Uml::AssociationType::Realization) || ++ a->getObjectId(Uml::RoleType::A) != id()) ++ continue; ++ UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::B)); ++ if (c) ++ list.append(c); ++ else ++ DEBUG(DBG_SRC) << name() << ": generalization's other end is not a " ++ << "UMLClassifier (id= " << Uml::ID::toString(a->getObjectId(Uml::RoleType::B)) << ")"; ++ } ++ return list; ++} ++ ++/** ++ * Return a list of the classes that inherit from this concept. ++ * TODO: This overlaps with UMLClassifier::findSubClassConcepts(), ++ * see if we can merge the two. ++ * ++ * @return The list of classes inheriting from the concept. ++ */ ++UMLClassifierList UMLCanvasObject::getSubClasses() ++{ ++ UMLClassifierList list; ++ UMLAssociationList assocs = getAssociations(); ++ foreach (UMLAssociation* a, assocs) { ++ uIgnoreZeroPointer(a); ++ if ((a->getAssocType() != Uml::AssociationType::Generalization && ++ a->getAssocType() != Uml::AssociationType::Realization) || ++ a->getObjectId(Uml::RoleType::B) != id()) ++ continue; ++ UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::A)); ++ if (c) ++ list.append(c); ++ else ++ DEBUG(DBG_SRC) << "specialization's other end is not a UMLClassifier" ++ << " (id=" << Uml::ID::toString(a->getObjectId(Uml::RoleType::A)) << ")"; ++ } ++ return list; ++} ++ ++/** ++ * Shorthand for getSpecificAssocs(Uml::at_Realization) ++ * ++ * @return The list of realizations for the Concept. ++ */ ++UMLAssociationList UMLCanvasObject::getRealizations() ++{ ++ return getSpecificAssocs(Uml::AssociationType::Realization); ++} ++ ++/** ++ * Shorthand for getSpecificAssocs(Uml::at_Aggregation) ++ * ++ * @return The list of aggregations for the Concept. ++ */ ++UMLAssociationList UMLCanvasObject::getAggregations() ++{ ++ return getSpecificAssocs(Uml::AssociationType::Aggregation); ++} ++ ++/** ++ * Shorthand for getSpecificAssocs(Uml::at_Composition) ++ * ++ * @return The list of compositions for the Concept. ++ */ ++UMLAssociationList UMLCanvasObject::getCompositions() ++{ ++ return getSpecificAssocs(Uml::AssociationType::Composition); ++} ++ ++/** ++ * Shorthand for getSpecificAssocs(Uml::at_Relationship) ++ * ++ * @return The list of relationships for the entity. ++ */ ++UMLAssociationList UMLCanvasObject::getRelationships() ++{ ++ return getSpecificAssocs(Uml::AssociationType::Relationship); ++} ++ ++/** ++ * Reimplementation of UMLObject method. ++ */ ++bool UMLCanvasObject::resolveRef() ++{ ++ bool overallSuccess = UMLObject::resolveRef(); ++ for (UMLObjectListIt ait(m_List); ait.hasNext();) { ++ UMLObject *obj = ait.next(); ++ uIgnoreZeroPointer(obj); ++ if (! obj->resolveRef()) { ++ m_List.removeAll(obj); ++ overallSuccess = false; ++ } ++ } ++ return overallSuccess; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,108 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef CANVASOBJECT_H ++#define CANVASOBJECT_H ++ ++#include "umlobject.h" ++#include "umlobjectlist.h" ++#include "umlclassifierlist.h" ++#include "umlassociationlist.h" ++ ++/** ++ * This class contains the non-graphical information required for UMLObjects ++ * which appear as moveable widgets on the scene. ++ * ++ * This class inherits from @ref UMLObject which contains most of the ++ * information. ++ * It is not instantiated itself, it's just used as a super class for ++ * actual model objects. ++ * ++ * @short Non-graphical information for a UMLCanvasObject. ++ * @author Jonathan Riddell ++ * @see UMLObject ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLCanvasObject : public UMLObject ++{ ++ Q_OBJECT ++ ++public: ++ explicit UMLCanvasObject(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLCanvasObject(); ++ ++ bool operator==(const UMLCanvasObject& rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ // The abstract method UMLObject::clone() is implemented ++ // in the classes inheriting from UMLCanvasObject. ++ ++ bool addAssociationEnd(UMLAssociation* assoc); ++ ++ bool hasAssociation(UMLAssociation* assoc); ++ ++ int removeAssociationEnd(UMLAssociation *assoc); ++ ++ void removeAllAssociationEnds(); ++ ++ int associations(); ++ ++ UMLAssociationList getAssociations(); ++ ++ UMLAssociationList getSpecificAssocs(Uml::AssociationType::Enum assocType); ++ ++ UMLClassifierList getSuperClasses(bool withRealizations = true); ++ UMLClassifierList getSubClasses(); ++ ++ virtual UMLAssociationList getRealizations(); ++ ++ UMLAssociationList getAggregations(); ++ UMLAssociationList getCompositions(); ++ UMLAssociationList getRelationships(); ++ ++ virtual UMLObject *findChildObject(const QString &n, ++ UMLObject::ObjectType t = UMLObject::ot_UMLObject); ++ virtual UMLObject *findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); ++ ++ virtual QString uniqChildName(const UMLObject::ObjectType type, ++ const QString &prefix = QString()); ++ ++ virtual void removeAllChildObjects(); ++ ++ UMLObjectList subordinates() const { ++ return m_List; ++ } ++ ++ virtual bool resolveRef(); ++ ++ // The abstract method UMLObject::saveToXMI() is implemented ++ // in the classes inheriting from UMLCanvasObject. ++ ++protected: ++ ++ /** ++ * List of all the associations in this object. ++ * Inheriting classes add more types of objects that are possible in this list; ++ * for example, UMLClassifier adds operations, attributes, and templates. ++ * ++ * @todo Only a pointer to the appropriate assocation end object ++ * (UMLRole) should be saved here, not the entire UMLAssociation. ++ */ ++ UMLObjectList m_List; ++ ++signals: ++ ++ void sigAssociationEndAdded(UMLAssociation * assoc); ++ void sigAssociationEndRemoved(UMLAssociation * assoc); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,22 @@ ++/*************************************************************************** ++ * 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-2010 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLCLASSIFIERLIST_H ++#define UMLCLASSIFIERLIST_H ++ ++#include ++ ++// forward declaration ++class UMLClassifier; ++ ++typedef QList UMLClassifierList; ++typedef QListIterator UMLClassifierListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,60 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "umlclassifierlistitemlist.h" ++ ++#include "classifierlistitem.h" ++ ++#include ++ ++UMLClassifierListItemList::UMLClassifierListItemList() ++{ ++} ++ ++UMLClassifierListItemList::UMLClassifierListItemList(const UMLClassifierListItemList& other) ++ : QList(other) ++{ ++} ++ ++UMLClassifierListItemList::~UMLClassifierListItemList() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLClassifierListItemList::copyInto(UMLClassifierListItemList *rhs) const ++{ ++ // Prevent copying to yourself. (Can cause serious injuries) ++ if (rhs == this) return; ++ ++ rhs->clear(); ++ ++ // Suffering from const; we shall not modify our object. ++ UMLClassifierListItemList *tmp = new UMLClassifierListItemList(*this); ++ ++ UMLClassifierListItem *item; ++ for (UMLClassifierListItemListIt clit(*tmp); clit.hasNext() ;) { ++ item = clit.next(); ++ rhs->append((UMLClassifierListItem*)item->clone()); ++ } ++ delete tmp; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLClassifierListItemList* UMLClassifierListItemList::clone() const ++{ ++ UMLClassifierListItemList *clone = new UMLClassifierListItemList(); ++ copyInto(clone); ++ return clone; ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,41 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLCLASSIFIERLISTITEMLIST_H ++#define UMLCLASSIFIERLISTITEMLIST_H ++ ++#include ++ ++// forward declaration ++class UMLClassifierListItem; ++ ++//typedef QPtrList UMLClassifierListItemList; ++typedef QListIterator UMLClassifierListItemListIt; ++ ++/** ++ * This sub-class adds copyInto and clone to the QPtrList ++ * base class. ++ */ ++class UMLClassifierListItemList : public QList ++{ ++public: ++ ++ UMLClassifierListItemList(); ++ UMLClassifierListItemList(const UMLClassifierListItemList& other); ++ ++ virtual ~UMLClassifierListItemList(); ++ ++ virtual void copyInto (UMLClassifierListItemList *rhs) const; ++ ++ virtual UMLClassifierListItemList* clone() const; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,60 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "umlentityattributelist.h" ++ ++#include "entityattribute.h" ++ ++#include ++ ++UMLEntityAttributeList::UMLEntityAttributeList() ++{ ++} ++ ++UMLEntityAttributeList::UMLEntityAttributeList(const UMLEntityAttributeList& other) ++ : QList(other) ++{ ++} ++ ++UMLEntityAttributeList::~UMLEntityAttributeList() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLEntityAttributeList::copyInto(UMLEntityAttributeList* rhs) const ++{ ++ // Don't copy yourself. ++ if (rhs == this) return; ++ ++ rhs->clear(); ++ ++ // Suffering from const; we shall not modify our object. ++ UMLEntityAttributeList* tmp = new UMLEntityAttributeList(*this); ++ ++ UMLEntityAttribute* item; ++ for (UMLEntityAttributeListIt eait(*tmp); eait.hasNext() ;) { ++ item = eait.next(); ++ rhs->append((UMLEntityAttribute*)item->clone()); ++ } ++ delete tmp; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLEntityAttributeList* UMLEntityAttributeList::clone() const ++{ ++ UMLEntityAttributeList *clone = new UMLEntityAttributeList(); ++ copyInto(clone); ++ return clone; ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,41 @@ ++/*************************************************************************** ++ * * ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLENTITYATTRIBUTELIST_H ++#define UMLENTITYATTRIBUTELIST_H ++ ++#include ++#include "entityattribute.h" ++ ++//typedef QPtrList UMLEntityAttributeList; ++typedef QListIterator UMLEntityAttributeListIt; ++ ++/** ++ * This sub-class adds copyInto and clone to the QPtrList ++ * base class. ++ */ ++class UMLEntityAttributeList : public QList ++{ ++public: ++ ++ UMLEntityAttributeList(); ++ ++ UMLEntityAttributeList(const UMLEntityAttributeList&); ++ ++ virtual ~UMLEntityAttributeList(); ++ ++ virtual void copyInto (UMLEntityAttributeList* rhs) const; ++ ++ virtual UMLEntityAttributeList* clone() const; ++}; ++ ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,60 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "umlentityconstraintlist.h" ++ ++#include "entityconstraint.h" ++ ++#include ++ ++UMLEntityConstraintList::UMLEntityConstraintList() ++{ ++} ++ ++UMLEntityConstraintList::UMLEntityConstraintList(const UMLEntityConstraintList& other) ++ : QList(other) ++{ ++} ++ ++UMLEntityConstraintList::~UMLEntityConstraintList() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLEntityConstraintList::copyInto(UMLEntityConstraintList* rhs) const ++{ ++ // Don't copy yourself. ++ if (rhs == this) return; ++ ++ rhs->clear(); ++ ++ // Suffering from const; we shall not modify our object. ++ UMLEntityConstraintList* tmp = new UMLEntityConstraintList(*this); ++ ++ UMLEntityConstraint* item; ++ for (UMLEntityConstraintListIt ecit(*tmp); ecit.hasNext() ;) { ++ item = ecit.next(); ++ rhs->append((UMLEntityConstraint*)item->clone()); ++ } ++ delete tmp; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLEntityConstraintList* UMLEntityConstraintList::clone() const ++{ ++ UMLEntityConstraintList *clone = new UMLEntityConstraintList(); ++ copyInto(clone); ++ return clone; ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,43 @@ ++/*************************************************************************** ++ * * ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLENTITYCONSTRAINTLIST_H ++#define UMLENTITYCONSTRAINTLIST_H ++ ++#include ++ ++// forward declaration ++class UMLEntityConstraint; ++ ++ ++typedef QListIterator UMLEntityConstraintListIt; ++ ++/** ++ * This sub-class adds copyInto and clone to the QPtrList ++ * base class. ++ */ ++class UMLEntityConstraintList : public QList ++{ ++public: ++ ++ UMLEntityConstraintList(); ++ ++ UMLEntityConstraintList(const UMLEntityConstraintList&); ++ ++ virtual ~UMLEntityConstraintList(); ++ ++ virtual void copyInto (UMLEntityConstraintList* rhs) const; ++ ++ virtual UMLEntityConstraintList* clone() const; ++}; ++ ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentitylist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlentitylist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentitylist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentitylist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,22 @@ ++/*************************************************************************** ++ * 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-2010 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLENTITYLIST_H ++#define UMLENTITYLIST_H ++ ++#include ++ ++// forward declaration ++class UMLEntity; ++ ++typedef QList UMLEntityList; ++typedef QListIterator UMLEntityListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlenumliterallist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlenumliterallist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlenumliterallist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlenumliterallist.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,23 @@ ++/*************************************************************************** ++ * * ++ * 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-2007 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLENUMLITERALLIST_H ++#define UMLENUMLITERALLIST_H ++ ++#include ++ ++// forward declaration ++class UMLEnumLiteral; ++ ++typedef QList UMLEnumLiteralList; ++typedef QListIterator UMLEnumLiteralListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,1157 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "umlobject.h" ++ ++// app includes ++#include "classpropertiesdialog.h" ++#include "debug_utils.h" ++#include "enumliteral.h" ++#include "uniqueid.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umllistview.h" ++#include "package.h" ++#include "folder.h" ++#include "stereotype.h" ++#include "object_factory.h" ++#include "model_utils.h" ++#include "import_utils.h" ++#include "docwindow.h" ++#include "cmds.h" ++ ++// kde includes ++#include ++ ++// qt includes ++#include ++#include ++ ++using namespace Uml; ++ ++DEBUG_REGISTER_DISABLED(UMLObject) ++ ++/** ++ * Creates a UMLObject. ++ * @param other object to created from ++ */ ++UMLObject::UMLObject(const UMLObject &other) ++ : QObject(other.parent()) ++{ ++ other.copyInto(this); ++} ++ ++/** ++ * Creates a UMLObject. ++ * @param parent The parent of the object. ++ * @param name The name of the object. ++ * @param id The ID of the object (optional.) If omitted ++ * then a new ID will be assigned internally. ++ */ ++UMLObject::UMLObject(UMLObject* parent, const QString& name, ID::Type id) ++ : QObject(parent), ++ m_nId(id), ++ m_name(name) ++{ ++ init(); ++ if (id == Uml::ID::None) ++ m_nId = UniqueID::gen(); ++} ++ ++/** ++ * Creates a UMLObject. ++ * @param name The name of the object. ++ * @param id The ID of the object (optional.) If omitted ++ * then a new ID will be assigned internally. ++ */ ++UMLObject::UMLObject(const QString& name, ID::Type id) ++ : QObject(UMLApp::app()->document()), ++ m_nId(id), ++ m_name(name) ++{ ++ init(); ++ if (id == Uml::ID::None) ++ m_nId = UniqueID::gen(); ++} ++ ++/** ++ * Creates a UMLObject. ++ * @param parent The parent of the object. ++ */ ++UMLObject::UMLObject(UMLObject * parent) ++ : QObject(parent), ++ m_nId(Uml::ID::None), ++ m_name(QString()) ++{ ++ init(); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLObject::~UMLObject() ++{ ++ // unref stereotype ++ setUMLStereotype(0); ++ if (m_pSecondary && m_pSecondary->baseType() == ot_Stereotype) { ++ UMLStereotype* stereotype = dynamic_cast(m_pSecondary.data()); ++ if (stereotype) ++ stereotype->decrRefCount(); ++ } ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLObject::init() ++{ ++ setObjectName(QLatin1String("UMLObject")); ++ m_BaseType = ot_UMLObject; ++ m_pUMLPackage = 0; ++ m_visibility = Uml::Visibility::Public; ++ m_pStereotype = 0; ++ m_Doc.clear(); ++ m_bAbstract = false; ++ m_bStatic = false; ++ m_bCreationWasSignalled = false; ++ m_pSecondary = 0; ++} ++ ++/** ++ * Display the properties configuration dialog for the object. ++ * ++ * @param parent The parent widget. ++ * @return True for success of this operation. ++ */ ++bool UMLObject::showPropertiesDialog(QWidget *parent) ++{ ++ DocWindow *docwindow = UMLApp::app()->docWindow(); ++ docwindow->updateDocumentation(false); ++ QPointer dlg = new ClassPropertiesDialog(parent, this, false); ++ bool modified = false; ++ if (dlg->exec()) { ++ docwindow->showDocumentation(this, true); ++ UMLApp::app()->document()->setModified(true); ++ modified = true; ++ } ++ dlg->close(); ++ delete dlg; ++ return modified; ++} ++ ++/** ++ * This should be reimplemented by subclasses if they wish to ++ * accept certain types of associations. Note that this only ++ * tells if this UMLObject can accept the association ++ * type. When creating an association another check is made to ++ * see if the association is valid. For example a UMLClass ++ * (UMLClassifier) can accept generalizations and should ++ * return true. If while creating a generalization the ++ * superclass is already subclassed from this, the association ++ * is not valid and will not be created. The default accepts ++ * nothing (returns false) ++ */ ++bool UMLObject::acceptAssociationType(Uml::AssociationType::Enum type) ++{ ++ Q_UNUSED(type); ++ // A UMLObject accepts nothing. This should be reimplemented by the subclasses ++ return false; ++} ++ ++/** ++ * Assigns a new Id to the object ++ */ ++void UMLObject::setID(ID::Type NewID) ++{ ++ m_nId = NewID; ++ emitModified(); ++} ++ ++/** ++ * Set the UMLObject's name ++ */ ++void UMLObject::setName(const QString &strName) ++{ ++ if (name() != strName) { ++ UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(this, strName)); ++ } ++} ++ ++/** ++ * Method used by setName: it is called by cmdSetName, Don't use it! ++ */ ++void UMLObject::setNameCmd(const QString &strName) ++{ ++ m_name = strName; ++ emitModified(); ++} ++ ++/** ++ * Returns a copy of m_name ++ */ ++QString UMLObject::name() const ++{ ++ return m_name; ++} ++ ++/** ++ * Returns the fully qualified name, i.e. all package prefixes and then m_name. ++ * ++ * @param separator The separator string to use (optional.) ++ * If not given then the separator is chosen according ++ * to the currently selected active programming language ++ * of import and code generation. ++ * @param includeRoot Whether to prefix the root folder name to the FQN. ++ * See UMLDoc::getRootFolder(). Default: false. ++ * @return The fully qualified name of this UMLObject. ++ */ ++QString UMLObject::fullyQualifiedName(const QString& separator, ++ bool includeRoot /* = false */) const ++{ ++ QString fqn; ++ if (m_pUMLPackage && m_pUMLPackage != this) { ++ bool skipPackage = false; ++ if (!includeRoot) { ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ if (umldoc->rootFolderType(m_pUMLPackage) != Uml::ModelType::N_MODELTYPES || ++ m_pUMLPackage == umldoc->datatypeFolder()) ++ skipPackage = true; ++ } ++ if (!skipPackage) { ++ QString tempSeparator = separator; ++ if (tempSeparator.isEmpty()) ++ tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); ++ fqn = m_pUMLPackage->fullyQualifiedName(tempSeparator, includeRoot); ++ fqn.append(tempSeparator); ++ } ++ } ++ fqn.append(m_name); ++ return fqn; ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLObject::operator==(const UMLObject & rhs) const ++{ ++ if (this == &rhs) ++ return true; ++ ++ //don't compare IDs, these are program specific and ++ //don't mean the objects are the same ++ //***** CHECK: Who put in this comment? What was the reason? ++ //***** Currently some operator== in umbrello-kf6 compare the IDs ++ //***** while others don't. ++ ++ if (m_name != rhs.m_name) ++ return false; ++ ++ // Packages create different namespaces, therefore they should be ++ // part of the equality test. ++ if (m_pUMLPackage != rhs.m_pUMLPackage) ++ return false; ++ ++ // Making the type part of an object's identity has its problems: ++ // Not all programming languages support declarations of the same ++ // name but different type. ++ // In such cases, the code generator is responsible for generating ++ // the appropriate error message. ++ if (m_BaseType != rhs.m_BaseType) ++ return false; ++ ++ // The documentation should not be part of the equality test. ++ // If two objects are the same but differ only in their documentation, ++ // what does that mean? ++ //if(m_Doc != rhs.m_Doc) ++ // return false; ++ ++ // The visibility should not be part of the equality test. ++ // What does it mean if two objects are the same but differ in their ++ // visibility? - I'm not aware of any programming language that would ++ // support that. ++ //if(m_visibility != rhs.m_visibility) ++ // return false; ++ ++ // See comments above ++ //if(m_pStereotype != rhs.m_pStereotype) ++ // return false; ++ ++ // See comments above ++ //if(m_bAbstract != rhs.m_bAbstract) ++ // return false; ++ ++ // See comments above ++ //if(m_bStatic != rhs.m_bStatic) ++ // return false; ++ ++ return true; ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLObject::copyInto(UMLObject *lhs) const ++{ ++ // Data members with copy constructor ++ lhs->m_Doc = m_Doc; ++ lhs->m_pStereotype = m_pStereotype; ++ if (lhs->m_pStereotype) ++ lhs->m_pStereotype->incrRefCount(); ++ lhs->m_bAbstract = m_bAbstract; ++ lhs->m_bStatic = m_bStatic; ++ lhs->m_BaseType = m_BaseType; ++ lhs->m_visibility = m_visibility; ++ lhs->m_pUMLPackage = m_pUMLPackage; ++ ++ // We don't want the same name existing twice. ++ lhs->m_name = Model_Utils::uniqObjectName(m_BaseType, m_pUMLPackage, m_name); ++ ++ // Create a new ID. ++ lhs->m_nId = UniqueID::gen(); ++ ++ // Hope that the parent from QObject is okay. ++ if (lhs->parent() != parent()) ++ uDebug() << "copyInto has a wrong parent"; ++} ++ ++UMLObject *UMLObject::clone() const ++{ ++ UMLObject *clone = new UMLObject; ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Returns the abstract state of the object. ++ */ ++bool UMLObject::isAbstract() const ++{ ++ return m_bAbstract; ++} ++ ++/** ++ * Sets the paste state of the object. ++ */ ++void UMLObject::setAbstract(bool bAbstract) ++{ ++ m_bAbstract = bAbstract; ++ emitModified(); ++} ++ ++/** ++ * Returns true if this UMLObject has classifier scope, ++ * otherwise false (the default). ++ */ ++bool UMLObject::isStatic() const ++{ ++ return m_bStatic; ++} ++ ++/** ++ * Sets the value for m_bStatic. ++ */ ++void UMLObject::setStatic(bool bStatic) ++{ ++ m_bStatic = bStatic; ++ emitModified(); ++} ++ ++/** ++ * Forces the emission of the modified signal. Useful when ++ * updating several attributes at a time: you can block the ++ * signals, update all atts, and then force the signal. ++ */ ++void UMLObject::emitModified() ++{ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ if (!umldoc->loading() && !umldoc->closing()) ++ emit modified(); ++} ++ ++/** ++ * Returns the type of the object. ++ * ++ * @return Returns the type of the object. ++ */ ++UMLObject::ObjectType UMLObject::baseType() const ++{ ++ return m_BaseType; ++} ++ ++/** ++ * @return The type used for rtti as string. ++ */ ++QLatin1String UMLObject::baseTypeStr() const ++{ ++ return QLatin1String(ENUM_NAME(UMLObject, ObjectType, m_BaseType)); ++} ++ ++/** ++ * Set the type of the object. ++ * ++ * @param ot The ObjectType to set. ++ */ ++void UMLObject::setBaseType(ObjectType ot) ++{ ++ m_BaseType = ot; ++} ++ ++/** ++ * Returns the ID of the object. ++ * ++ * @return Returns the ID of the object. ++ */ ++ID::Type UMLObject::id() const ++{ ++ return m_nId; ++} ++ ++/** ++ * Returns the documentation for the object. ++ * ++ * @return Returns the documentation for the object. ++ */ ++QString UMLObject::doc() const ++{ ++ return m_Doc; ++} ++ ++/** ++ * Returns state of documentation for the object. ++ * ++ * @return false if documentation is empty ++ */ ++bool UMLObject::hasDoc() const ++{ ++ return !m_Doc.isEmpty(); ++} ++ ++/** ++ * Sets the documentation for the object. ++ * ++ * @param d The documentation for the object. ++ */ ++void UMLObject::setDoc(const QString &d) ++{ ++ m_Doc = d; ++ //emit modified(); No, this is done centrally at DocWindow::updateDocumentation() ++} ++ ++/** ++ * Returns the visibility of the object. ++ * ++ * @return Returns the visibility of the object. ++ */ ++Visibility::Enum UMLObject::visibility() const ++{ ++ return m_visibility; ++} ++ ++/** ++ * Sets the visibility of the object. ++ * ++ * @param visibility The visibility of the object. ++ */ ++void UMLObject::setVisibility(Visibility::Enum visibility) ++{ ++ if (m_visibility != visibility) { ++ UMLApp::app()->executeCommand(new CmdSetVisibility(this, visibility)); ++ } ++} ++ ++/** ++ * Method used by setVisibility: it is called by cmdSetVisibility, Don't use it! ++ */ ++void UMLObject::setVisibilityCmd(Visibility::Enum visibility) ++{ ++ m_visibility = visibility; ++ emitModified(); ++} ++ ++/** ++ * Sets the class' UMLStereotype. Adjusts the reference counts ++ * at the previously set stereotype and at the new stereotype. ++ * If the previously set UMLStereotype's reference count drops ++ * to zero then the UMLStereotype is removed at the UMLDoc and ++ * it is then physically deleted. ++ * ++ * @param stereo Sets the classes UMLStereotype. ++ */ ++void UMLObject::setUMLStereotype(UMLStereotype *stereo) ++{ ++ if (stereo == m_pStereotype) ++ return; ++ if (stereo) { ++ stereo->incrRefCount(); ++ } ++ if (m_pStereotype) { ++ m_pStereotype->decrRefCount(); ++ if (m_pStereotype->refCount() == 0) { ++ UMLDoc *pDoc = UMLApp::app()->document(); ++ pDoc->removeStereotype(m_pStereotype); ++ delete m_pStereotype; ++ } ++ } ++ m_pStereotype = stereo; ++ // TODO: don't emit modified() if predefined folder ++ emitModified(); ++} ++ ++/** ++ * Sets the classes stereotype name. ++ * Internally uses setUMLStereotype(). ++ * ++ * @param name Sets the classes stereotype name. ++ */ ++void UMLObject::setStereotype(const QString &name) ++{ ++ if (name != stereotype()) { ++ UMLApp::app()->executeCommand(new CmdSetStereotype(this, name)); ++ } ++} ++ ++void UMLObject::setStereotypeCmd(const QString& name) ++{ ++ if (name.isEmpty()) { ++ setUMLStereotype(NULL); ++ return; ++ } ++ UMLDoc *pDoc = UMLApp::app()->document(); ++ UMLStereotype *s = pDoc->findOrCreateStereotype(name); ++ setUMLStereotype(s); ++} ++ ++/** ++ * Sets the UMLPackage in which this class is located. ++ * ++ * @param pPkg Pointer to the class' UMLPackage. ++ */ ++bool UMLObject::setUMLPackage(UMLPackage* pPkg) ++{ ++ if (pPkg == this) { ++ uDebug() << "setting parent to myself is not allowed"; ++ return false; ++ } ++ ++ if (pPkg == NULL) { ++ // Allow setting to NULL for stereotypes ++ m_pUMLPackage = pPkg; ++ return true; ++ } ++ ++ if (pPkg->umlPackage() == this) { ++ uDebug() << "setting parent to an object of which I'm already the parent is not allowed"; ++ return false; ++ } ++ ++ m_pUMLPackage = pPkg; ++ emitModified(); ++ return true; ++} ++ ++/** ++ * Returns the classes UMLStereotype object. ++ * ++ * @return Returns the classes UMLStereotype object. ++ */ ++UMLStereotype * UMLObject::umlStereotype() ++{ ++ return m_pStereotype; ++} ++ ++/** ++ * Returns the stereotype. ++ */ ++QString UMLObject::stereotype(bool includeAdornments /* = false */) const ++{ ++ if (m_pStereotype == NULL) ++ return QString(); ++ return m_pStereotype->name(includeAdornments); ++} ++ ++/** ++ * Return the package(s) in which this UMLObject is contained ++ * as a text. ++ * ++ * @param separator Separator string for joining together the ++ * individual package prefixes (optional.) ++ * If no separator is given then the separator ++ * of the currently selected language is used. ++ * @param includeRoot Whether to prefix the root folder name. ++ * Default: false. ++ * @return The UMLObject's enclosing package(s) as a text. ++ */ ++QString UMLObject::package(const QString& separator, bool includeRoot) ++{ ++ QString tempSeparator = separator; ++ if (tempSeparator.isEmpty()) ++ tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); ++ QString fqn = fullyQualifiedName(tempSeparator, includeRoot); ++ if (!fqn.contains(tempSeparator)) ++ return QString(); ++ QString scope = fqn.left(fqn.length() - tempSeparator.length() - m_name.length()); ++ return scope; ++} ++ ++/** ++ * Return a list of the packages in which this class is embedded. ++ * The outermost package is first in the list. ++ * ++ * @param includeRoot Whether to prefix the root folder name. ++ * Default: false. ++ * @return UMLPackageList of the containing packages. ++ */ ++UMLPackageList UMLObject::packages(bool includeRoot) const ++{ ++ UMLPackageList pkgList; ++ UMLPackage* pkg = m_pUMLPackage; ++ while (pkg != NULL) { ++ pkgList.prepend(pkg); ++ pkg = pkg->umlPackage(); ++ } ++ if (!includeRoot) ++ pkgList.removeFirst(); ++ return pkgList; ++} ++ ++/** ++ * Returns the UMLPackage that this class is located in. ++ * ++ * @return Pointer to the UMLPackage of this class. ++ */ ++UMLPackage* UMLObject::umlPackage() ++{ ++ return m_pUMLPackage; ++} ++ ++/** ++ * Return secondary ID. Required by resolveRef(). ++ */ ++QString UMLObject::secondaryId() const ++{ ++ return m_SecondaryId; ++} ++ ++/** ++ * Set the secondary ID. ++ * Currently only required by petalTree2Uml(); all other setting of the ++ * m_SecondaryID is internal to the UMLObject class hierarchy. ++ */ ++void UMLObject::setSecondaryId(const QString& id) ++{ ++ m_SecondaryId = id; ++} ++ ++/** ++ * Return secondary ID fallback. ++ * Required by resolveRef() for imported model files. ++ */ ++QString UMLObject::secondaryFallback() const ++{ ++ return m_SecondaryFallback; ++} ++ ++/** ++ * Set the secondary ID fallback. ++ * Currently only used by petalTree2Uml(). ++ */ ++void UMLObject::setSecondaryFallback(const QString& id) ++{ ++ m_SecondaryFallback = id; ++} ++ ++/** ++ * Calls UMLDoc::signalUMLObjectCreated() if m_BaseType affords ++ * doing so. ++ */ ++void UMLObject::maybeSignalObjectCreated() ++{ ++ if (!m_bCreationWasSignalled && ++ m_BaseType != ot_Stereotype && ++ m_BaseType != ot_Association && ++ m_BaseType != ot_Role) { ++ m_bCreationWasSignalled = true; ++ UMLDoc* umldoc = UMLApp::app()->document(); ++ umldoc->signalUMLObjectCreated(this); ++ } ++} ++ ++/** ++ * Resolve referenced objects (if any.) ++ * Needs to be called after all UML objects are loaded from file. ++ * This needs to be done after all model objects are loaded because ++ * some of the xmi.id's might be forward references, i.e. they may ++ * identify model objects which were not yet loaded at the point of ++ * reference. ++ * The default implementation attempts resolution of the m_SecondaryId. ++ * ++ * @return True for success. ++ */ ++bool UMLObject::resolveRef() ++{ ++ if (m_pSecondary || (m_SecondaryId.isEmpty() && m_SecondaryFallback.isEmpty())) { ++ maybeSignalObjectCreated(); ++ return true; ++ } ++#ifdef VERBOSE_DEBUGGING ++ uDebug() << m_name << ": m_SecondaryId is " << m_SecondaryId; ++#endif ++ UMLDoc *pDoc = UMLApp::app()->document(); ++ // In the new, XMI standard compliant save format, ++ // the type is the xmi.id of a UMLClassifier. ++ if (! m_SecondaryId.isEmpty()) { ++ m_pSecondary = pDoc->findObjectById(Uml::ID::fromString(m_SecondaryId)); ++ if (m_pSecondary != NULL) { ++ if (m_pSecondary->baseType() == ot_Stereotype) { ++ if (m_pStereotype) ++ m_pStereotype->decrRefCount(); ++ m_pStereotype = dynamic_cast(m_pSecondary.data()); ++ m_pStereotype->incrRefCount(); ++ m_pSecondary = NULL; ++ } ++ m_SecondaryId = QString(); ++ maybeSignalObjectCreated(); ++ return true; ++ } ++ if (m_SecondaryFallback.isEmpty()) { ++ uDebug() << "object with xmi.id=" << m_SecondaryId << " not found, setting to undef"; ++ UMLFolder *datatypes = pDoc->datatypeFolder(); ++ m_pSecondary = Object_Factory::createUMLObject(ot_Datatype, QLatin1String("undef"), datatypes, false); ++ return true; ++ } ++ } ++ if (m_SecondaryFallback.isEmpty()) { ++ uError() << m_name << ": cannot find type with id " << m_SecondaryId; ++ return false; ++ } ++#ifdef VERBOSE_DEBUGGING ++ uDebug() << m_name << ": could not resolve secondary ID " << m_SecondaryId ++ << ", using secondary fallback " << m_SecondaryFallback; ++#endif ++ m_SecondaryId = m_SecondaryFallback; ++ // Assume we're dealing with the older umbrello-kf6 format where ++ // the type name was saved in the "type" attribute rather ++ // than the xmi.id of the model object of the attribute type. ++ m_pSecondary = pDoc->findUMLObject(m_SecondaryId, ot_UMLObject, this); ++ if (m_pSecondary) { ++ m_SecondaryId = QString(); ++ maybeSignalObjectCreated(); ++ return true; ++ } ++ // Work around Object_Factory::createUMLObject()'s incapability ++ // of on-the-fly scope creation: ++ if (m_SecondaryId.contains(QLatin1String("::"))) { ++ // TODO: Merge Import_Utils::createUMLObject() into Object_Factory::createUMLObject() ++ m_pSecondary = Import_Utils::createUMLObject(ot_UMLObject, m_SecondaryId, m_pUMLPackage); ++ if (m_pSecondary) { ++ if (Import_Utils::newUMLObjectWasCreated()) { ++ maybeSignalObjectCreated(); ++ qApp->processEvents(); ++ uDebug() << "Import_Utils::createUMLObject() created a new type for " ++ << m_SecondaryId; ++ } else { ++ uDebug() << "Import_Utils::createUMLObject() returned an existing type for " ++ << m_SecondaryId; ++ } ++ m_SecondaryId = QString(); ++ return true; ++ } ++ uError() << "Import_Utils::createUMLObject() failed to create a new type for " ++ << m_SecondaryId; ++ return false; ++ } ++ uDebug() << "Creating new type for " << m_SecondaryId; ++ // This is very C++ specific - we rely on some '*' or ++ // '&' to decide it's a ref type. Plus, we don't recognize ++ // typedefs of ref types. ++ bool isReferenceType = (m_SecondaryId.contains(QLatin1Char('*')) || ++ m_SecondaryId.contains(QLatin1Char('&'))); ++ ObjectType ot = ot_Class; ++ if (isReferenceType) { ++ ot = ot_Datatype; ++ } else { ++ if (Model_Utils::isCommonDataType(m_SecondaryId)) ++ ot = ot_Datatype; ++ } ++ m_pSecondary = Object_Factory::createUMLObject(ot, m_SecondaryId, NULL); ++ if (m_pSecondary == NULL) ++ return false; ++ m_SecondaryId = QString(); ++ maybeSignalObjectCreated(); ++ //qApp->processEvents(); ++ return true; ++} ++ ++void UMLObject::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) ++{ ++ Q_UNUSED(qDoc); Q_UNUSED(qElement); ++} ++ ++/** ++ * Auxiliary to saveToXMI. ++ * Create a QDomElement with the given tag, and save the XMI attributes ++ * that are common to all child classes to the newly created element. ++ * This method does not need to be overridden by child classes. ++ */ ++QDomElement UMLObject::save(const QString &tag, QDomDocument & qDoc) ++{ ++ /* ++ Call as the first action of saveToXMI() in child class: ++ This creates the QDomElement with which to work. ++ */ ++ QDomElement qElement = qDoc.createElement(tag); ++ qElement.setAttribute(QLatin1String("isSpecification"), QLatin1String("false")); ++ if (m_BaseType != ot_Association && ++ m_BaseType != ot_Role && ++ m_BaseType != ot_Attribute) { ++ qElement.setAttribute(QLatin1String("isLeaf"), QLatin1String("false")); ++ qElement.setAttribute(QLatin1String("isRoot"), QLatin1String("false")); ++ if (m_bAbstract) ++ qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("true")); ++ else ++ qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("false")); ++ } ++ qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_nId)); ++ qElement.setAttribute(QLatin1String("name"), m_name); ++ if (m_BaseType != ot_Operation && ++ m_BaseType != ot_Role && ++ m_BaseType != ot_Attribute) { ++ Uml::ID::Type nmSpc; ++ if (m_pUMLPackage) ++ nmSpc = m_pUMLPackage->id(); ++ else ++ nmSpc = UMLApp::app()->document()->modelID(); ++ qElement.setAttribute(QLatin1String("namespace"), Uml::ID::toString(nmSpc)); ++ } ++ if (! m_Doc.isEmpty()) ++ qElement.setAttribute(QLatin1String("comment"), m_Doc); //CHECK: uml13.dtd compliance ++#ifdef XMI_FLAT_PACKAGES ++ if (m_pUMLPackage) //FIXME: uml13.dtd compliance ++ qElement.setAttribute(QLatin1String("package"), m_pUMLPackage->ID()); ++#endif ++ QString visibility = Uml::Visibility::toString(m_visibility, false); ++ qElement.setAttribute(QLatin1String("visibility"), visibility); ++ if (m_pStereotype != NULL) ++ qElement.setAttribute(QLatin1String("stereotype"), Uml::ID::toString(m_pStereotype->id())); ++ if (m_bStatic) ++ qElement.setAttribute(QLatin1String("ownerScope"), QLatin1String("classifier")); ++ /* else ++ qElement.setAttribute("ownerScope", "instance"); ++ *** ownerScope defaults to instance if not set **********/ ++ return qElement; ++} ++ ++/** ++ * Auxiliary to loadFromXMI. ++ * This method is usually overridden by child classes. ++ * It is responsible for loading the specific XMI structure ++ * of the child class. ++ */ ++bool UMLObject::load(QDomElement&) ++{ ++ // This body is not usually executed because child classes ++ // overwrite the load method. ++ return true; ++} ++ ++/** ++ * Analyzes the given QDomElement for a reference to a stereotype. ++ * ++ * @param element QDomElement to analyze. ++ * @return True if a stereotype reference was found, else false. ++ */ ++bool UMLObject::loadStereotype(QDomElement & element) ++{ ++ QString tag = element.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("stereotype"))) ++ return false; ++ QString stereo = element.attribute(QLatin1String("xmi.value")); ++ if (stereo.isEmpty() && element.hasChildNodes()) { ++ /* like so: ++ ++ ++ ++ */ ++ QDomNode stereoNode = element.firstChild(); ++ QDomElement stereoElem = stereoNode.toElement(); ++ tag = stereoElem.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("Stereotype"))) { ++ stereo = stereoElem.attribute(QLatin1String("xmi.idref")); ++ } ++ } ++ if (stereo.isEmpty()) ++ return false; ++ Uml::ID::Type stereoID = Uml::ID::fromString(stereo); ++ UMLDoc *pDoc = UMLApp::app()->document(); ++ if (m_pStereotype) ++ m_pStereotype->decrRefCount(); ++ m_pStereotype = pDoc->findStereotypeById(stereoID); ++ if (m_pStereotype) ++ m_pStereotype->incrRefCount(); ++ else ++ m_SecondaryId = stereo; // leave it to resolveRef() ++ return true; ++} ++ ++/** ++ * This method loads the generic parts of the XMI common to most model ++ * classes. It is not usually reimplemented by child classes. ++ * Instead, it invokes the load() method which implements the loading ++ * of the specifics of each child class. ++ * ++ * @param element The QDomElement from which to load. ++ */ ++bool UMLObject::loadFromXMI(QDomElement & element) ++{ ++ UMLDoc* umldoc = UMLApp::app()->document(); ++ if (umldoc == 0) { ++ uError() << "umldoc is NULL"; ++ return false; ++ } ++ // Read the name first so that if we encounter a problem, the error ++ // message can say the name. ++ m_name = element.attribute(QLatin1String("name")); ++ QString id = Model_Utils::getXmiId(element); ++ if (id.isEmpty() || id == QLatin1String("-1")) { ++ // Before version 1.4, umbrello-kf6 did not save the xmi.id of UMLRole objects. ++ // Some tools (such as Embarcadero's) do not have an xmi.id on all attributes. ++ m_nId = UniqueID::gen(); ++ uWarning() << m_name << ": xmi.id not present, generating a new one"; ++ } else { ++ Uml::ID::Type nId = Uml::ID::fromString(id); ++ if (m_BaseType == ot_Role) { ++ // Some older umbrello-kf6 versions had a problem with xmi.id's ++ // of other objects being reused for the UMLRole, see e.g. ++ // attachment 21179 at http://bugs.kde.org/147988 . ++ // If the xmi.id is already being used then we generate a new one. ++ UMLObject *o = umldoc->findObjectById(nId); ++ if (o) { ++ uError() << "loadFromXMI(UMLRole): id " << id ++ << " is already in use!!! Please fix your XMI file."; ++ } ++ } ++ m_nId = nId; ++ } ++ ++ if (element.hasAttribute(QLatin1String("documentation"))) // for bkwd compat. ++ m_Doc = element.attribute(QLatin1String("documentation")); ++ else ++ m_Doc = element.attribute(QLatin1String("comment")); //CHECK: need a UML:Comment? ++ ++ m_visibility = Uml::Visibility::Public; ++ if (element.hasAttribute(QLatin1String("scope"))) { // for bkwd compat. ++ QString scope = element.attribute(QLatin1String("scope")); ++ if (scope == QLatin1String("instance_level")) // nsuml compat. ++ m_bStatic = false; ++ else if (scope == QLatin1String("classifier_level")) // nsuml compat. ++ m_bStatic = true; ++ else { ++ int nScope = scope.toInt(); ++ switch (nScope) { ++ case 200: ++ m_visibility = Uml::Visibility::Public; ++ break; ++ case 201: ++ m_visibility = Uml::Visibility::Private; ++ break; ++ case 202: ++ m_visibility = Uml::Visibility::Protected; ++ break; ++ default: ++ uError() << m_name << ": illegal scope " << nScope; ++ } ++ } ++ } else { ++ QString visibility = element.attribute(QLatin1String("visibility"), QLatin1String("public")); ++ if (visibility == QLatin1String("private") ++ || visibility == QLatin1String("private_vis")) // for compatibility with other programs ++ m_visibility = Uml::Visibility::Private; ++ else if (visibility == QLatin1String("protected") ++ || visibility == QLatin1String("protected_vis")) // for compatibility with other programs ++ m_visibility = Uml::Visibility::Protected; ++ else if (visibility == QLatin1String("implementation")) ++ m_visibility = Uml::Visibility::Implementation; ++ } ++ ++ QString stereo = element.attribute(QLatin1String("stereotype")); ++ if (!stereo.isEmpty()) { ++ Uml::ID::Type stereoID = Uml::ID::fromString(stereo); ++ if (m_pStereotype) ++ m_pStereotype->decrRefCount(); ++ m_pStereotype = umldoc->findStereotypeById(stereoID); ++ if (m_pStereotype) { ++ m_pStereotype->incrRefCount(); ++ } else { ++ uDebug() << m_name << ": UMLStereotype " << Uml::ID::toString(stereoID) ++ << " not found, creating now."; ++ setStereotypeCmd(stereo); ++ } ++ } ++ ++ if (element.hasAttribute(QLatin1String("abstract"))) { // for bkwd compat. ++ QString abstract = element.attribute(QLatin1String("abstract"), QLatin1String("0")); ++ m_bAbstract = (bool)abstract.toInt(); ++ } else { ++ QString isAbstract = element.attribute(QLatin1String("isAbstract"), QLatin1String("false")); ++ m_bAbstract = (isAbstract == QLatin1String("true")); ++ } ++ ++ if (element.hasAttribute(QLatin1String("static"))) { // for bkwd compat. ++ QString staticScope = element.attribute(QLatin1String("static"), QLatin1String("0")); ++ m_bStatic = (bool)staticScope.toInt(); ++ } else { ++ QString ownerScope = element.attribute(QLatin1String("ownerScope"), QLatin1String("instance")); ++ m_bStatic = (ownerScope == QLatin1String("classifier")); ++ } ++ ++ // If the node has child nodes, check whether attributes can be ++ // extracted from them. ++ if (element.hasChildNodes()) { ++ QDomNode node = element.firstChild(); ++ if (node.isComment()) ++ node = node.nextSibling(); ++ QDomElement elem = node.toElement(); ++ while (!elem.isNull()) { ++ QString tag = elem.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("name"))) { ++ m_name = elem.attribute(QLatin1String("xmi.value")); ++ if (m_name.isEmpty()) ++ m_name = elem.text(); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("visibility"))) { ++ QString vis = elem.attribute(QLatin1String("xmi.value")); ++ if (vis.isEmpty()) ++ vis = elem.text(); ++ if (vis == QLatin1String("private") || vis == QLatin1String("private_vis")) ++ m_visibility = Uml::Visibility::Private; ++ else if (vis == QLatin1String("protected") || vis == QLatin1String("protected_vis")) ++ m_visibility = Uml::Visibility::Protected; ++ else if (vis == QLatin1String("implementation")) ++ m_visibility = Uml::Visibility::Implementation; ++ } else if (UMLDoc::tagEq(tag, QLatin1String("isAbstract"))) { ++ QString isAbstract = elem.attribute(QLatin1String("xmi.value")); ++ if (isAbstract.isEmpty()) ++ isAbstract = elem.text(); ++ m_bAbstract = (isAbstract == QLatin1String("true")); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("ownerScope"))) { ++ QString ownerScope = elem.attribute(QLatin1String("xmi.value")); ++ if (ownerScope.isEmpty()) ++ ownerScope = elem.text(); ++ m_bStatic = (ownerScope == QLatin1String("classifier")); ++ } else { ++ loadStereotype(elem); ++ } ++ node = node.nextSibling(); ++ if (node.isComment()) ++ node = node.nextSibling(); ++ elem = node.toElement(); ++ } ++ } ++ ++ // Operations, attributes, enum literals, templates, stereotypes, ++ // and association role objects get added and signaled elsewhere. ++ if (m_BaseType != ot_Operation && m_BaseType != ot_Attribute && ++ m_BaseType != ot_EnumLiteral && m_BaseType != ot_EntityAttribute && ++ m_BaseType != ot_Template && m_BaseType != ot_Stereotype && ++ m_BaseType != ot_Role && m_BaseType != ot_UniqueConstraint && ++ m_BaseType != ot_ForeignKeyConstraint && m_BaseType != ot_CheckConstraint) { ++ if (m_pUMLPackage) { ++ m_pUMLPackage->addObject(this); ++ } else if (umldoc->rootFolderType(this) == Uml::ModelType::N_MODELTYPES) { ++ // m_pUMLPackage is not set on the root folders. ++ uDebug() << m_name << ": m_pUMLPackage is not set"; ++ } ++ } ++ return load(element); ++} ++ ++/** ++ * Helper function for debug output. ++ * Returns the given enum value as string. ++ * @param ot ObjectType of which a string representation is wanted ++ * @return the ObjectType as string ++ */ ++QString UMLObject::toString(ObjectType ot) ++{ ++ return QLatin1String(ENUM_NAME(UMLObject, ObjectType, ot)); ++} ++ ++/** ++ * Returns the given object type value as localized string. ++ * @param ot ObjectType of which a string representation is wanted ++ * @return the ObjectType as localized string ++ */ ++QString UMLObject::toI18nString(ObjectType t) ++{ ++ QString name; ++ ++ switch (t) { ++ case UMLObject::ot_Actor: ++ name = i18n("Actor &name:"); ++ break; ++ case UMLObject::ot_Artifact: ++ name = i18n("Artifact &name:"); ++ break; ++ case UMLObject::ot_Class: ++ name = i18n("Class &name:"); ++ break; ++ case UMLObject::ot_Component: ++ name = i18n("Component &name:"); ++ break; ++ case UMLObject::ot_Datatype: ++ name = i18n("Datatype &name:"); ++ break; ++ case UMLObject::ot_Entity: ++ name = i18n("Entity &name:"); ++ break; ++ case UMLObject::ot_Enum: ++ name = i18n("Enum &name:"); ++ break; ++ case UMLObject::ot_Folder: ++ name = i18n("Folder &name:"); ++ break; ++ case UMLObject::ot_Interface: ++ name = i18n("Interface &name:"); ++ break; ++ case UMLObject::ot_Node: ++ name = i18n("Node &name:"); ++ break; ++ case UMLObject::ot_Package: ++ name = i18n("Package &name:"); ++ break; ++ case UMLObject::ot_Port: ++ name = i18n("Port &name:"); ++ break; ++ case UMLObject::ot_Stereotype: ++ name = i18n("Stereotype &name:"); ++ break; ++ case UMLObject::ot_UseCase: ++ name = i18n("Use case &name:"); ++ break; ++ default: ++ name = QLatin1String(" &name:"); ++ uWarning() << "unknown object type"; ++ break; ++ } ++ return name; ++} ++ ++/** ++ * Print UML Object to debug output stream, so it can be used like ++ * uDebug() << "This object shouldn't be here: " << illegalObject; ++ */ ++QDebug operator<<(QDebug out, const UMLObject& obj) ++{ ++ out.nospace() << "UMLObject: name= " << obj.name() ++ << ", type= " << UMLObject::toString(obj.m_BaseType); ++ return out.space(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.h 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,198 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLOBJECT_H ++#define UMLOBJECT_H ++ ++#include "basictypes.h" ++#include "umlpackagelist.h" ++ ++//qt includes ++#include ++#include ++#include ++#include ++#include ++ ++class UMLStereotype; ++ ++/** ++ * This class is the non-graphical version of @ref UMLWidget. These are ++ * created and maintained in the class @ref UMLDoc. This class holds all ++ * the generic information needed for all UML objects. ++ * ++ * @ref clone needs to be implemented by each child class. ++ * ++ * @ref saveToXMI saves the XMI attributes of each specific model class. ++ * It needs to be implemented by each child class. ++ * For creating the QDomElement and saving the common XMI parts, ++ * it can use the save() method. ++ * ++ * @short The base class for UML objects. ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLObject : public QObject ++{ ++ Q_OBJECT ++ Q_ENUMS(ObjectType) ++ ++public: ++ enum ObjectType ++ { ++ ot_Unknown = -1, ++ ot_UMLObject = 100, ++ ot_Actor, ++ ot_UseCase, ++ ot_Package, ++ ot_Interface, ++ ot_Datatype, ++ ot_Enum, ++ ot_Class, ++ ot_Association, ++ ot_Attribute, ++ ot_Operation, ++ ot_EnumLiteral, ++ ot_Template, ++ ot_Component, ++ ot_Artifact, ++ ot_Node, ++ ot_Stereotype, ++ ot_Role, ++ ot_Entity, ++ ot_EntityAttribute, ++ ot_Folder, ++ ot_EntityConstraint, ++ ot_UniqueConstraint, ++ ot_ForeignKeyConstraint, ++ ot_CheckConstraint, ++ ot_Category, ++ ot_Port ++ }; ++ ++ static QString toString(ObjectType ot); ++ static QString toI18nString(ObjectType t); ++ ++ explicit UMLObject(const UMLObject& other); ++ explicit UMLObject(UMLObject* parent, const QString& name, Uml::ID::Type id = Uml::ID::None); ++ explicit UMLObject(UMLObject* parent); ++ explicit UMLObject(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~UMLObject(); ++ ++ bool operator==(const UMLObject & rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ virtual void setBaseType(ObjectType ot); ++ ObjectType baseType() const; ++ QLatin1String baseTypeStr() const; ++ ++ virtual void setID(Uml::ID::Type NewID); ++ virtual Uml::ID::Type id() const; ++ ++ QString doc() const; ++ bool hasDoc() const; ++ void setDoc(const QString &d); ++ ++ void setVisibility(Uml::Visibility::Enum visibility); ++ void setVisibilityCmd(Uml::Visibility::Enum visibility); ++ Uml::Visibility::Enum visibility() const; ++ ++ void setStereotype(const QString &_name); ++ void setStereotypeCmd(const QString &_name); ++ QString stereotype(bool includeAdornments = false) const; ++ ++ void setUMLStereotype(UMLStereotype *stereo); ++ UMLStereotype *umlStereotype(); ++ ++ QString package(const QString& separator = QString(), ++ bool includeRoot = false); ++ ++ bool setUMLPackage(UMLPackage* pPkg); ++ UMLPackage* umlPackage(); ++ ++ UMLPackageList packages(bool includeRoot = false) const; ++ ++ virtual void setName(const QString &strName); ++ void setNameCmd(const QString &strName) ; ++ QString name() const; ++ ++ virtual QString fullyQualifiedName(const QString& separator = QString(), ++ bool includeRoot = false) const; ++ ++ void setAbstract(bool bAbstract); ++ bool isAbstract() const; ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++ virtual bool resolveRef(); ++ ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ virtual bool loadFromXMI(QDomElement & element); ++ ++ bool loadStereotype(QDomElement & element); ++ ++ void setStatic(bool bStatic); ++ bool isStatic() const; ++ ++ virtual bool acceptAssociationType(Uml::AssociationType::Enum); //:TODO: check if this is really needed here ++ ++ void setSecondaryId(const QString& id); ++ QString secondaryId() const; ++ ++ void setSecondaryFallback(const QString& id); ++ QString secondaryFallback() const; ++ ++ QDomElement save(const QString &tag, QDomDocument & qDoc); ++ ++ friend QDebug operator<< (QDebug out, const UMLObject& obj); ++ ++public slots: ++ void emitModified(); ++ ++signals: ++ void modified(); ++ ++protected: ++ void init(); ++ ++ void maybeSignalObjectCreated(); ++ ++ virtual bool load(QDomElement& element); ++ ++ Uml::ID::Type m_nId; ///< object's id ++ QString m_Doc; ///< object's documentation ++ UMLPackage* m_pUMLPackage; ///< package the object belongs to if applicable ++ QPointer m_pStereotype; ///< stereotype of the object if applicable ++ QString m_name; ///< objects name ++ ObjectType m_BaseType; ///< objects type ++ Uml::Visibility::Enum m_visibility; ///< objects visibility ++ bool m_bAbstract; ///< state of whether the object is abstract or not ++ bool m_bStatic; ///< flag for instance scope ++ bool m_bInPaste; ///< caller sets this true when in paste operation ++ bool m_bCreationWasSignalled; ///< auxiliary to maybeSignalObjectCreated() ++ QPointer m_pSecondary; ///< pointer to an associated object ++ ///< Only a few of the classes inheriting from UMLObject use this. ++ ///< However, it needs to be here because of inheritance graph ++ ///< disjunctness. ++ QString m_SecondaryId; ///< xmi.id of the secondary object for intermediate use during ++ ///< loading. The secondary ID is resolved to the m_pSecondary ++ ///< in the course of resolveRef() at the end of loading. ++ QString m_SecondaryFallback; ///< Last-chance backup for when m_SecondaryId is not found. ++ ///< Used by Rose import: MDL files specify both a "quidu" ++ ///< (which corresponds to m_SecondaryId) and the human readable ++ ///< fully qualified target name of a reference. ++ ///< In case the quidu is not found, the human readable name is ++ ///< used which we store in m_SecondaryFallback. ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.cpp 2015-10-08 11:48:59.507089026 +0300 +@@ -0,0 +1,53 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "umlobjectlist.h" ++#include "umlobject.h" ++ ++UMLObjectList::UMLObjectList() ++{ ++} ++ ++UMLObjectList::~UMLObjectList() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the new ++ * object. ++ */ ++void UMLObjectList::copyInto(UMLObjectList *rhs) const ++{ ++ // Don't copy yourself. ++ if (rhs == this) return; ++ ++ rhs->clear(); ++ ++ // Suffering from const; we shall not modify our object. ++ UMLObjectList *tmp = new UMLObjectList(*this); ++ ++ UMLObject *item = NULL; ++ for (UMLObjectListIt oit(*tmp); oit.hasNext() ;) ++ { ++ item = oit.next(); ++ rhs->append(item->clone()); ++ } ++ delete tmp; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObjectList* UMLObjectList::clone() const ++{ ++ UMLObjectList *clone = new UMLObjectList(); ++ copyInto(clone); ++ return clone; ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,40 @@ ++/*************************************************************************** ++ * 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) 2001 Gustavo Madrigal gmadrigal@nextphere.com * ++ * copyright (C) 2002-2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLOBJECTLIST_H ++#define UMLOBJECTLIST_H ++ ++#include ++#include ++ ++// forward declarations ++class UMLObject; ++ ++typedef QListIterator > ++UMLObjectListIt; ++ ++/** ++ * This sub-class adds copyInto and clone to the QList ++ * base class. ++ */ ++class UMLObjectList : public QList > ++{ ++public: ++ ++ UMLObjectList(); ++ virtual ~UMLObjectList(); ++ ++ virtual void copyInto(UMLObjectList *rhs) const; ++ ++ virtual UMLObjectList* clone() const; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umloperationlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umloperationlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umloperationlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umloperationlist.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,23 @@ ++/*************************************************************************** ++ * * ++ * 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-2007 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLOPERATIONLIST_H ++#define UMLOPERATIONLIST_H ++ ++#include ++ ++// forward declaration ++class UMLOperation; ++ ++typedef QList UMLOperationList; ++typedef QListIterator UMLOperationListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlpackagelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlpackagelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlpackagelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlpackagelist.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,22 @@ ++/*************************************************************************** ++ * * ++ * 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-2007 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLPACKAGELIST_H ++#define UMLPACKAGELIST_H ++ ++#include ++ ++class UMLPackage; ++ ++typedef QList UMLPackageList; ++typedef QListIterator UMLPackageListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,415 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "umlrole.h" ++ ++// local includes ++#include "association.h" ++#include "debug_utils.h" ++#include "umldoc.h" ++#include "umlroledialog.h" ++#include "uml.h" ++ ++// qt includes ++#include ++#include ++ ++/** ++ * Sets up an association. ++ * ++ * @param parent The parent (association) of this UMLRole. ++ * @param parentObj The Parent UML Object of this UMLRole ++ * @param role The Uml::RoleType::Enum of this UMLRole ++ */ ++UMLRole::UMLRole(UMLAssociation * parent, UMLObject * parentObj, Uml::RoleType::Enum role) ++ : UMLObject(const_cast(parent)), ++ m_pAssoc(parent), ++ m_role(role), ++ m_Multi(QString()), ++ m_Changeability(Uml::Changeability::Changeable) ++{ ++ m_BaseType = UMLObject::ot_Role; ++ m_name.clear(); ++ m_pSecondary = parentObj; ++ ++ // connect this up to parent ++ connect(this, SIGNAL(modified()), parent, SIGNAL(modified())); ++} ++ ++/** ++ * Standard destructor. ++ */ ++UMLRole::~UMLRole() ++{ ++} ++ ++/** ++ * Overloaded '==' operator. ++ */ ++bool UMLRole::operator==(const UMLRole &rhs) const ++{ ++ if (this == &rhs) { ++ return true; ++ } ++ return (UMLObject::operator==(rhs) && ++ m_Changeability == rhs.m_Changeability && ++ m_Multi == rhs.m_Multi && ++ m_name == rhs.m_name ++ ); ++} ++ ++UMLAssociation * UMLRole::parentAssociation() const ++{ ++ return m_pAssoc; ++} ++ ++/** ++ * Returns the UMLObject assigned to the role. ++ * @return Pointer to the UMLObject in role. ++ */ ++UMLObject* UMLRole::object() const ++{ ++ return m_pSecondary; ++} ++ ++/** ++ * Returns the Changeablity of the role. ++ * ++ * @return Changeability of role. ++ */ ++Uml::Changeability::Enum UMLRole::changeability() const ++{ ++ return m_Changeability; ++} ++ ++/** ++ * Returns the multiplicity assigned to the role. ++ * ++ * @return The multiplicity assigned to the role. ++ */ ++QString UMLRole::multiplicity() const ++{ ++ return m_Multi; ++} ++ ++/** ++ * Sets the UMLObject playing the role in the association. ++ * ++ * @param obj Pointer to the UMLObject of role. ++ */ ++void UMLRole::setObject(UMLObject *obj) ++{ ++ // because we will get the id of this role from the parent ++ // object, we CANT allow UMLRoles to take other UMLRoles as ++ // parent objects. In fact, there is probably good reason ++ // to only take UMLClassifiers here, but I'll leave it more open ++ // for the time being. -b.t. ++ if (obj && dynamic_cast(obj)) { ++ uError() << "UMLRole(" << Uml::ID::toString(m_nId) << ") cannot setObject() to another UMLRole(" ++ << Uml::ID::toString(obj->id()) << ")"; ++ return; ++ } ++ ++ m_pSecondary = obj; ++ UMLObject::emitModified(); ++} ++ ++/** ++ * Sets the changeability of the role. ++ * ++ * @param value Changeability::Enum of role. ++ */ ++void UMLRole::setChangeability(Uml::Changeability::Enum value) ++{ ++ m_Changeability = value; ++ UMLObject::emitModified(); ++} ++ ++/** ++ * Sets the multiplicity of the role. ++ * ++ * @param multi The multiplicity of role. ++ */ ++void UMLRole::setMultiplicity(const QString &multi) ++{ ++ m_Multi = multi; ++ UMLObject::emitModified(); ++} ++ ++/** ++ * Get the 'id' of the role (NOT the parent object). This could be ++ * either Uml::RoleType::A or Uml::RoleType::B. Yes, it would be better if we ++ * could get along without this, but we need it to distinguish saved ++ * umlrole objects in the XMI for 'self' associations where both roles ++ * will point to the same underlying UMLObject. ++ */ ++Uml::RoleType::Enum UMLRole::role() const ++{ ++ return m_role; ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLRole::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement roleElement = UMLObject::save(QLatin1String("UML:AssociationEnd"), qDoc); ++ if (m_pSecondary) ++ roleElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); ++ else ++ uError() << "id " << Uml::ID::toString(m_nId) << ": m_pSecondary is NULL"; ++ if (!m_Multi.isEmpty()) ++ roleElement.setAttribute(QLatin1String("multiplicity"), m_Multi); ++ if (m_role == Uml::RoleType::A) { // role aggregation based on parent type ++ // role A ++ switch (m_pAssoc->getAssocType()) { ++ case Uml::AssociationType::Composition: ++ roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("composite")); ++ break; ++ case Uml::AssociationType::Aggregation: ++ roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("aggregate")); ++ break; ++ default: ++ roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); ++ break; ++ } ++ if (m_pAssoc->getAssocType() == Uml::AssociationType::UniAssociation) { ++ // Normally the isNavigable attribute is "true". ++ // We set it to false on role A to indicate that ++ // role B gets an explicit arrowhead. ++ roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("false")); ++ } else { ++ roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); ++ } ++ } else { ++ roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); ++ roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); ++ //FIXME obviously this isn't standard XMI ++ if (m_pAssoc->getAssocType() == Uml::AssociationType::Relationship) { ++ roleElement.setAttribute(QLatin1String("relationship"), QLatin1String("true")); ++ } ++ } ++ ++ roleElement.setAttribute(QLatin1String("visibility"), Uml::Visibility::toString(visibility(), false)); ++ ++ switch (m_Changeability) { ++ case Uml::Changeability::Frozen: ++ roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("frozen")); ++ break; ++ case Uml::Changeability::AddOnly: ++ roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("addOnly")); ++ break; ++ case Uml::Changeability::Changeable: ++ roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("changeable")); ++ break; ++ } ++ qElement.appendChild(roleElement); ++} ++ ++/** ++ * Display the properties configuration dialog for the object. ++ * ++ * @param parent The parent widget. ++ * @return True for success of this operation. ++ */ ++bool UMLRole::showPropertiesDialog(QWidget *parent) ++{ ++ QPointer dlg = new UMLRoleDialog(parent, this); ++ bool modified = false; ++ if (dlg->exec() == QDialog::Accepted) { ++ modified = true; ++ } ++ delete dlg; ++ return modified; ++} ++ ++/** ++ * Loads the XMI element. ++ * Auxiliary to UMLObject::loadFromXMI. ++ */ ++bool UMLRole::load(QDomElement & element) ++{ ++ UMLDoc * doc = UMLApp::app()->document(); ++ QString type = element.attribute(QLatin1String("type")); ++ if (!type.isEmpty()) { ++ if (!m_SecondaryId.isEmpty()) ++ uWarning() << "overwriting old m_SecondaryId \"" << m_SecondaryId ++ << " with new value \"" << type << "\""; ++ m_SecondaryId = type; ++ } ++ // Inspect child nodes - for multiplicity (and type if not set above.) ++ for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { ++ if (node.isComment()) ++ continue; ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("name"))) { ++ m_name = tempElement.text(); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("AssociationEnd.multiplicity"))) { ++ /* ++ * There are different ways in which the multiplicity might be given: ++ * - direct value in the tag, ++ * - attributes "lower" and "upper" of a subordinate , ++ * - direct value in subordinate and ++ * tags ++ */ ++ QDomNode n = tempElement.firstChild(); ++ if (node.isNull() || tempElement.isNull() || n.isNull() || ++ n.toElement().isNull()) { ++ m_Multi = tempElement.text().trimmed(); ++ continue; ++ } ++ tempElement = n.toElement(); ++ tag = tempElement.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity"))) { ++ m_Multi = tempElement.text().trimmed(); ++ continue; ++ } ++ n = tempElement.firstChild(); ++ tempElement = n.toElement(); ++ tag = tempElement.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity.range"))) { ++ m_Multi = tempElement.text().trimmed(); ++ continue; ++ } ++ n = tempElement.firstChild(); ++ tempElement = n.toElement(); ++ tag = tempElement.tagName(); ++ if (!UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange"))) { ++ m_Multi = tempElement.text().trimmed(); ++ continue; ++ } ++ QString multiUpper; ++ if (tempElement.hasAttribute(QLatin1String("lower"))) { ++ m_Multi = tempElement.attribute(QLatin1String("lower")); ++ multiUpper = tempElement.attribute(QLatin1String("upper")); ++ if (!multiUpper.isEmpty()) { ++ if (!m_Multi.isEmpty()) ++ m_Multi.append(QLatin1String("..")); ++ m_Multi.append(multiUpper); ++ } ++ continue; ++ } ++ n = tempElement.firstChild(); ++ while (!n.isNull()) { ++ tempElement = n.toElement(); ++ tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.lower"))) { ++ m_Multi = tempElement.text(); ++ } else if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.upper"))) { ++ multiUpper = tempElement.text(); ++ } ++ n = n.nextSibling(); ++ } ++ if (!multiUpper.isEmpty()) { ++ if (!m_Multi.isEmpty()) ++ m_Multi.append(QLatin1String("..")); ++ m_Multi.append(multiUpper); ++ } ++ } else if (m_SecondaryId.isEmpty() && ++ (UMLDoc::tagEq(tag, QLatin1String("type")) || ++ UMLDoc::tagEq(tag, QLatin1String("participant")))) { ++ m_SecondaryId = tempElement.attribute(QLatin1String("xmi.id")); ++ if (m_SecondaryId.isEmpty()) ++ m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); ++ if (m_SecondaryId.isEmpty()) { ++ QDomNode inner = tempElement.firstChild(); ++ QDomElement innerElem = inner.toElement(); ++ m_SecondaryId = innerElem.attribute(QLatin1String("xmi.id")); ++ if (m_SecondaryId.isEmpty()) ++ m_SecondaryId = innerElem.attribute(QLatin1String("xmi.idref")); ++ } ++ } ++ } ++ if (!m_Multi.isEmpty()) ++ uDebug() << name() << ": m_Multi is " << m_Multi; ++ if (m_SecondaryId.isEmpty()) { ++ uError() << name() << ": type not given or illegal"; ++ return false; ++ } ++ UMLObject * obj; ++ obj = doc->findObjectById(Uml::ID::fromString(m_SecondaryId)); ++ if (obj) { ++ m_pSecondary = obj; ++ m_SecondaryId = QString(); ++ } ++ ++ // block signals to prevent needless updating ++ blockSignals(true); ++ // Here comes the handling of the association type. ++ // This is open for discussion - I'm pretty sure there are better ways.. ++ ++ // Yeah, for one, setting the *parent* object parameters from here is sucky ++ // as hell. Why are we using roleA to store what is essentially a parent (association) ++ // parameter, eh? The UML13.dtd is pretty silly, but since that is what ++ // is driving us to that point, we have to go with it. Some analysis of ++ // the component roles/linked items needs to be done in order to get things ++ // right. *sigh* -b.t. ++ ++ // Setting association type from the role (A) ++ // Determination of the "aggregation" attribute used to be done only ++ // when (m_role == Uml::RoleType::A) but some XMI writers (e.g. StarUML) place ++ // the aggregation attribute at role B. ++ // The role end with the aggregation unequal to "none" wins. ++ QString aggregation = element.attribute(QLatin1String("aggregation"), QLatin1String("none")); ++ if (aggregation == QLatin1String("composite")) ++ m_pAssoc->setAssociationType(Uml::AssociationType::Composition); ++ else if (aggregation == QLatin1String("shared") // UML1.3 ++ || aggregation == QLatin1String("aggregate")) // UML1.4 ++ m_pAssoc->setAssociationType(Uml::AssociationType::Aggregation); ++ ++ if (!element.hasAttribute(QLatin1String("isNavigable"))) { ++ // Backward compatibility mode: In umbrello-kf6 version 1.3.x the ++ // logic for saving the isNavigable flag was wrong. ++ // May happen on loading role A. ++ m_pAssoc->setOldLoadMode(true); ++ } else if (m_pAssoc->getOldLoadMode() == true) { ++ // Here is the original logic: ++ // "Role B: ++ // If isNavigable is not given, we make no change to the ++ // association type. ++ // If isNavigable is given, and is "true", then we assume that ++ // the association's other end (role A) is not navigable, and ++ // therefore we change the association type to UniAssociation. ++ // The case that isNavigable is given as "false" is ignored. ++ // Combined with the association type logic for role A, this ++ // allows us to support at_Association and at_UniAssociation." ++ if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("true")) ++ m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); ++ } else if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("false")) { ++ m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); ++ } ++ ++ //FIXME not standard XMI ++ if (element.hasAttribute(QLatin1String("relationship"))) { ++ if (element.attribute(QLatin1String("relationship")) == QLatin1String("true")) { ++ m_pAssoc->setAssociationType(Uml::AssociationType::Relationship); ++ } ++ } ++ ++ if (m_Multi.isEmpty()) ++ m_Multi = element.attribute(QLatin1String("multiplicity")); ++ ++ // Changeability defaults to Changeable if it cant set it here.. ++ m_Changeability = Uml::Changeability::Changeable; ++ QString changeability = element.attribute(QLatin1String("changeability")); ++ if (changeability.isEmpty()) ++ element.attribute(QLatin1String("changeable")); // for backward compatibility ++ if (changeability == QLatin1String("frozen")) ++ m_Changeability = Uml::Changeability::Frozen; ++ else if (changeability == QLatin1String("addOnly")) ++ m_Changeability = Uml::Changeability::AddOnly; ++ ++ // finished config, now unblock ++ blockSignals(false); ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,65 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLROLE_H ++#define UMLROLE_H ++ ++#include "umlobject.h" ++ ++class UMLAssociation; ++ ++/** ++ * This class contains the non-graphic representation of an association role. ++ * ++ * @author Brian Thomas ++ * @see UMLObject ++ */ ++class UMLRole : public UMLObject ++{ ++ Q_OBJECT ++public: ++ ++ UMLRole(UMLAssociation * parent, UMLObject * parentUMLObject, Uml::RoleType::Enum role); ++ virtual ~UMLRole(); ++ ++ bool operator==(const UMLRole & rhs) const; ++ ++ void setObject(UMLObject *obj); ++ UMLObject* object() const; ++ ++ void setChangeability(Uml::Changeability::Enum value); ++ Uml::Changeability::Enum changeability() const; ++ ++ void setMultiplicity(const QString &multi); ++ QString multiplicity() const; ++ ++ UMLAssociation * parentAssociation() const; ++ ++ Uml::RoleType::Enum role() const; ++ ++ UMLObject* clone() const { return NULL; } ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual bool showPropertiesDialog(QWidget *parent = 0); ++ ++protected: ++ ++ bool load(QDomElement& element); ++ ++private: ++ ++ UMLAssociation * m_pAssoc; ++ Uml::RoleType::Enum m_role; ++ QString m_Multi; ++ Uml::Changeability::Enum m_Changeability; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlstereotypelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlstereotypelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlstereotypelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlstereotypelist.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,22 @@ ++/*************************************************************************** ++ * 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-2012 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLSTEREOTYPELIST_H ++#define UMLSTEREOTYPELIST_H ++ ++#include ++ ++// forward declaration ++class UMLStereotype; ++ ++typedef QList UMLStereotypeList; ++typedef QListIterator UMLStereotypeListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umltemplatelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umltemplatelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umltemplatelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/umltemplatelist.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,23 @@ ++/*************************************************************************** ++ * * ++ * 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-2007 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLTEMPLATELIST_H ++#define UMLTEMPLATELIST_H ++ ++#include ++ ++// forward declaration ++class UMLTemplate; ++ ++typedef QList UMLTemplateList; ++typedef QListIterator UMLTemplateListIt; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,325 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++//own header ++#include "uniqueconstraint.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "entity.h" ++#include "entityattribute.h" ++#include "umldoc.h" ++#include "uml.h" ++#include "umlattributedialog.h" ++#include "umluniqueconstraintdialog.h" ++#include "object_factory.h" ++ ++/** ++ * Sets up a constraint. ++ * ++ * @param parent The parent of this UMLUniqueConstraint. ++ * @param name The name of this UMLUniqueConstraint. ++ * @param id The unique id given to this UMLUniqueConstraint. ++ */ ++UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent, const QString& name, Uml::ID::Type id) ++ : UMLEntityConstraint(parent, name, id) ++{ ++ init(); ++} ++ ++/** ++ * Sets up a constraint. ++ * ++ * @param parent The parent of this UMLUniqueConstraint. ++ */ ++UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent) ++ : UMLEntityConstraint(parent) ++{ ++ init(); ++} ++ ++/** ++ * Overloaded '==' operator ++ */ ++bool UMLUniqueConstraint::operator==(const UMLUniqueConstraint &rhs) const ++{ ++ if(this == &rhs) ++ return true; ++ ++ if(!UMLObject::operator==(rhs)) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * Destructor. ++ */ ++UMLUniqueConstraint::~UMLUniqueConstraint() ++{ ++} ++ ++/** ++ * Copy the internal presentation of this object into the UMLUniqueConstraint ++ * object. ++ */ ++void UMLUniqueConstraint::copyInto(UMLObject *lhs) const ++{ ++ UMLUniqueConstraint *target = static_cast(lhs); ++ ++ // call the parent first. ++ UMLEntityConstraint::copyInto(target); ++ ++ // Copy all datamembers ++ target->m_EntityAttributeList.clear(); ++ bool valid = true; ++ foreach(UMLEntityAttribute* attr, m_EntityAttributeList) { ++ if (!valid) ++ break; ++ valid = target->addEntityAttribute(attr); ++ } ++ ++ if (!valid) { ++ target->m_EntityAttributeList.clear(); ++ uDebug() <<"Copying Attributes Failed : Target list cleared instead"; ++ } ++} ++ ++/** ++ * Make a clone of the UMLUniqueConstraint. ++ */ ++UMLObject* UMLUniqueConstraint::clone() const ++{ ++ //FIXME: The new attribute should be slaved to the NEW parent not the old. ++ UMLUniqueConstraint *clone = new UMLUniqueConstraint(static_cast(parent())); ++ copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Returns a string representation of the UMLUniqueConstraint. ++ * ++ * @param sig If true will show the attribute type and initial value. ++ * @return Returns a string representation of the UMLAttribute. ++ */ ++QString UMLUniqueConstraint::toString(Uml::SignatureType::Enum sig) ++{ ++ QString s; ++ ++ if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { ++ s = name() + QLatin1Char(':'); ++ ++ if (static_cast(parent())->isPrimaryKey(this)) { ++ s += QLatin1String("Primary Key ("); ++ } else { ++ s += QLatin1String("Unique ("); ++ } ++ ++ bool first = true; ++ foreach(UMLEntityAttribute* att, m_EntityAttributeList) { ++ if (first) { ++ first = false; ++ } else ++ s += QLatin1Char(','); ++ s += att->name(); ++ } ++ s += QLatin1Char(')') ; ++ } ++ ++ return s; ++} ++ ++QString UMLUniqueConstraint::getFullyQualifiedName(const QString& separator, ++ bool includeRoot) const ++{ ++ Q_UNUSED(separator); Q_UNUSED(includeRoot); ++ return this->name(); ++} ++ ++/** ++ * Creates the XMI element. ++ */ ++void UMLUniqueConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement uniqueConstraintElement = UMLObject::save(QLatin1String("UML:UniqueConstraint"), qDoc); ++ ++ UMLEntity* parentEnt = static_cast(parent()); ++ if (parentEnt->isPrimaryKey(this)) { ++ uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("1")); ++ } else { ++ uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("0")); ++ } ++ ++ foreach(UMLEntityAttribute* att, m_EntityAttributeList) { ++ att->saveToXMI(qDoc, uniqueConstraintElement); ++ } ++ ++ qElement.appendChild(uniqueConstraintElement); ++} ++ ++/** ++ * Display the properties configuration dialog for the attribute. ++ */ ++bool UMLUniqueConstraint::showPropertiesDialog(QWidget* parent) ++{ ++ UMLUniqueConstraintDialog dialog(parent, this); ++ return dialog.exec(); ++} ++ ++/** ++ * Loads the XMI element. ++ */ ++bool UMLUniqueConstraint::load(QDomElement & element) ++{ ++ int isPrimary = element.attribute(QLatin1String("isPrimary"), QLatin1String("0")).toInt(); ++ UMLEntity* parentEnt = static_cast(parent()); ++ ++ if (isPrimary == 1) { ++ parentEnt->setAsPrimaryKey(this); ++ } ++ ++ QDomNode node = element.firstChild(); ++ while (!node.isNull()) { ++ if (node.isComment()) { ++ node = node.nextSibling(); ++ continue; ++ } ++ QDomElement tempElement = node.toElement(); ++ QString tag = tempElement.tagName(); ++ if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { ++ ++ QString attName = tempElement.attribute(QLatin1String("name")); ++ UMLObject* obj = parentEnt->findChildObject(attName); ++ ++ UMLEntityAttribute* entAtt = static_cast(obj); ++ if (entAtt == NULL) ++ continue; ++ ++ m_EntityAttributeList.append(entAtt); ++ ++ } else { ++ uWarning() << "unknown child type in UMLUniqueConstraint::load"; ++ } ++ ++ node = node.nextSibling(); ++ } ++ ++ return true; ++} ++ ++ ++/** ++ * Check if a entity attribute is present in m_entityAttributeList ++ * ++ * @param attr The Entity Attribute to check for existence in list ++ * @return true if it exists in the list, else false ++ */ ++bool UMLUniqueConstraint::hasEntityAttribute(UMLEntityAttribute* attr) ++{ ++ if (m_EntityAttributeList.indexOf(attr) == -1) { ++ //not present ++ return false; ++ } ++ ++ // else present ++ return true; ++} ++ ++/** ++ * Adds a UMLEntityAttribute to the list. ++ * The UMLEntityAttribute should already exist and should ++ * belong to the parent UMLEntity. ++ * ++ * @param attr The UMLEntityAttribute to add ++ * @return false if it failed to add, else true ++ */ ++bool UMLUniqueConstraint::addEntityAttribute(UMLEntityAttribute* attr) ++{ ++ UMLEntity *owningParent = dynamic_cast(parent()); ++ ++ if (hasEntityAttribute(attr)) { ++ uDebug() << "Unique Constraint already contains" << attr->name(); ++ return false; ++ ++ } ++ if (owningParent == NULL) { ++ uError() << name() << ": parent is not a UMLEntity"; ++ return false; ++ } ++ ++ if (owningParent->findChildObjectById(attr->id()) == NULL) { ++ uError() ++ << " parent " << owningParent->name() ++ << " does not contain attribute " << attr->name(); ++ return false; ++ } ++ ++ //else add the attribute to the Entity Attribute List ++ m_EntityAttributeList.append(attr); ++ ++ return true; ++} ++ ++/** ++ * Removes a UMLEntityAttribute from the list ++ * ++ * @param attr The UMLEntityAttribute to remove from list ++ * @return false if it failed to remove the attribute from the list ++ */ ++bool UMLUniqueConstraint::removeEntityAttribute(UMLEntityAttribute* attr) ++{ ++ UMLEntity *owningParent = dynamic_cast(parent()); ++ ++ if (owningParent == NULL) { ++ uError() << name() << ": parent is not a UMLEntity"; ++ return false; ++ } ++ ++ /* ++ * The attribute may already be removed from the Entity when this function ++ * is called. So checking this is not right ++ * ++ * if (owningParent->findChildObjectById(attr->ID()) == NULL) { ++ * uError() ++ * << " parent " << owningParent->getName() ++ * << " does not contain attribute " << attr->getName(); ++ * return false; ++ * } ++ */ ++ ++ //else remove the attribute from the Entity Attribute List ++ if (m_EntityAttributeList.removeAll(attr)) { ++ return true; ++ } ++ ++ return false; ++} ++ ++/** ++ * Get the Entity Attributes List. ++ */ ++UMLEntityAttributeList UMLUniqueConstraint::getEntityAttributeList() const ++{ ++ return m_EntityAttributeList; ++} ++ ++void UMLUniqueConstraint::init() ++{ ++ m_BaseType = UMLObject::ot_UniqueConstraint; ++} ++ ++/** ++ * Clear the list of attributes contained in this UniqueConstraint ++ */ ++void UMLUniqueConstraint::clearAttributeList() ++{ ++ m_EntityAttributeList.clear(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,77 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UNIQUECONSTRAINT_H ++#define UNIQUECONSTRAINT_H ++ ++#include "basictypes.h" ++#include "classifierlistitem.h" ++#include "entityconstraint.h" ++#include "umlclassifierlist.h" ++#include "umlentityattributelist.h" ++ ++/** ++ * This class is used to set up information for a unique entity constraint. ++ * ++ * @short Sets up Unique entity constraint information. ++ * @author Sharan Rao ++ * @see UMLObject UMLClassifierListItem UMLEntityConstraint ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLUniqueConstraint : public UMLEntityConstraint ++{ ++public: ++ ++ UMLUniqueConstraint(UMLObject *parent, const QString& name, ++ Uml::ID::Type id = Uml::ID::None); ++ explicit UMLUniqueConstraint(UMLObject *parent); ++ virtual ~UMLUniqueConstraint(); ++ ++ bool operator==(const UMLUniqueConstraint &rhs) const; ++ ++ virtual void copyInto(UMLObject *lhs) const; ++ ++ virtual UMLObject* clone() const; ++ ++ QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); ++ ++ QString getFullyQualifiedName(const QString& separator = QString(), ++ bool includeRoot = false) const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ virtual bool showPropertiesDialog(QWidget* parent = 0); ++ ++ bool hasEntityAttribute(UMLEntityAttribute* attr); ++ ++ bool addEntityAttribute(UMLEntityAttribute* attr); ++ ++ bool removeEntityAttribute(UMLEntityAttribute* attr); ++ ++ UMLEntityAttributeList getEntityAttributeList() const; ++ ++ void clearAttributeList(); ++ ++protected: ++ ++ bool load(QDomElement & element); ++ ++private: ++ ++ void init(); ++ ++ /** ++ * The list of entity attributes that together make up the unique constraint. ++ */ ++ UMLEntityAttributeList m_EntityAttributeList; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,67 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "usecase.h" ++ ++/** ++ * Creates a UseCase object ++ * ++ * @param name The name of the object. ++ * @param id The id of the object. ++ */ ++UMLUseCase::UMLUseCase(const QString & name, Uml::ID::Type id) ++ : UMLCanvasObject(name, id) ++{ ++ init(); ++} ++ ++/** ++ * Standard decstructor. ++ */ ++UMLUseCase::~UMLUseCase() ++{ ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void UMLUseCase::init() ++{ ++ m_BaseType = UMLObject::ot_UseCase; ++} ++ ++/** ++ * Make a clone of this object. ++ */ ++UMLObject* UMLUseCase::clone() const ++{ ++ UMLUseCase *clone = new UMLUseCase(); ++ UMLObject::copyInto(clone); ++ return clone; ++} ++ ++/** ++ * Creates the element. ++ */ ++void UMLUseCase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement usecaseElement = UMLObject::save(QLatin1String("UML:UseCase"), qDoc); ++ qElement.appendChild(usecaseElement); ++} ++ ++/** ++ * Loads the element (TODO). ++ */ ++bool UMLUseCase::load(QDomElement&) ++{ ++ return true; ++} ++ ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.h umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,40 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef USECASE_H ++#define USECASE_H ++ ++#include "umlcanvasobject.h" ++ ++/** ++ * This class contains the non-graphical information required for a UML UseCase. ++ * This class inherits from @ref UMLCanvasObject which contains most of the information. ++ * ++ * @short Information for a non-graphical UML UseCase. ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UMLUseCase : public UMLCanvasObject ++{ ++public: ++ explicit UMLUseCase(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); ++ ~UMLUseCase(); ++ ++ virtual void init(); ++ ++ virtual UMLObject* clone() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ bool load(QDomElement & element); ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobject.cpp umbrello-kf6-15.08.1/umbrello/umlobject.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlobject.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlobject.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1142 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "umlobject.h" +- +-// app includes +-#include "classpropertiesdialog.h" +-#include "debug_utils.h" +-#include "enumliteral.h" +-#include "uniqueid.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umllistview.h" +-#include "package.h" +-#include "folder.h" +-#include "stereotype.h" +-#include "object_factory.h" +-#include "model_utils.h" +-#include "import_utils.h" +-#include "docwindow.h" +-#include "cmds.h" +- +-// kde includes +-#include +- +-// qt includes +-#include +-#include +- +-using namespace Uml; +- +-DEBUG_REGISTER_DISABLED(UMLObject) +- +-/** +- * Creates a UMLObject. +- * @param other object to created from +- */ +-UMLObject::UMLObject(const UMLObject &other) +- : QObject(other.parent()) +-{ +- other.copyInto(this); +-} +- +-/** +- * Creates a UMLObject. +- * @param parent The parent of the object. +- * @param name The name of the object. +- * @param id The ID of the object (optional.) If omitted +- * then a new ID will be assigned internally. +- */ +-UMLObject::UMLObject(UMLObject* parent, const QString& name, ID::Type id) +- : QObject(parent), +- m_nId(id), +- m_name(name) +-{ +- init(); +- if (id == Uml::ID::None) +- m_nId = UniqueID::gen(); +-} +- +-/** +- * Creates a UMLObject. +- * @param name The name of the object. +- * @param id The ID of the object (optional.) If omitted +- * then a new ID will be assigned internally. +- */ +-UMLObject::UMLObject(const QString& name, ID::Type id) +- : QObject(UMLApp::app()->document()), +- m_nId(id), +- m_name(name) +-{ +- init(); +- if (id == Uml::ID::None) +- m_nId = UniqueID::gen(); +-} +- +-/** +- * Creates a UMLObject. +- * @param parent The parent of the object. +- */ +-UMLObject::UMLObject(UMLObject * parent) +- : QObject(parent), +- m_nId(Uml::ID::None), +- m_name(QString()) +-{ +- init(); +-} +- +-/** +- * Standard destructor. +- */ +-UMLObject::~UMLObject() +-{ +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLObject::init() +-{ +- setObjectName(QLatin1String("UMLObject")); +- m_BaseType = ot_UMLObject; +- m_pUMLPackage = 0; +- m_visibility = Uml::Visibility::Public; +- m_pStereotype = 0; +- m_Doc.clear(); +- m_bAbstract = false; +- m_bStatic = false; +- m_bCreationWasSignalled = false; +- m_pSecondary = 0; +-} +- +-/** +- * Display the properties configuration dialog for the object. +- * +- * @param parent The parent widget. +- * @return True for success of this operation. +- */ +-bool UMLObject::showPropertiesDialog(QWidget *parent) +-{ +- DocWindow *docwindow = UMLApp::app()->docWindow(); +- docwindow->updateDocumentation(false); +- QPointer dlg = new ClassPropertiesDialog(parent, this, false); +- bool modified = false; +- if (dlg->exec()) { +- docwindow->showDocumentation(this, true); +- UMLApp::app()->document()->setModified(true); +- modified = true; +- } +- dlg->close(); +- delete dlg; +- return modified; +-} +- +-/** +- * This should be reimplemented by subclasses if they wish to +- * accept certain types of associations. Note that this only +- * tells if this UMLObject can accept the association +- * type. When creating an association another check is made to +- * see if the association is valid. For example a UMLClass +- * (UMLClassifier) can accept generalizations and should +- * return true. If while creating a generalization the +- * superclass is already subclassed from this, the association +- * is not valid and will not be created. The default accepts +- * nothing (returns false) +- */ +-bool UMLObject::acceptAssociationType(Uml::AssociationType::Enum type) +-{ +- Q_UNUSED(type); +- // A UMLObject accepts nothing. This should be reimplemented by the subclasses +- return false; +-} +- +-/** +- * Assigns a new Id to the object +- */ +-void UMLObject::setID(ID::Type NewID) +-{ +- m_nId = NewID; +- emitModified(); +-} +- +-/** +- * Set the UMLObject's name +- */ +-void UMLObject::setName(const QString &strName) +-{ +- if (name() != strName) { +- UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(this, strName)); +- } +-} +- +-/** +- * Method used by setName: it is called by cmdSetName, Don't use it! +- */ +-void UMLObject::setNameCmd(const QString &strName) +-{ +- m_name = strName; +- emitModified(); +-} +- +-/** +- * Returns a copy of m_name +- */ +-QString UMLObject::name() const +-{ +- return m_name; +-} +- +-/** +- * Returns the fully qualified name, i.e. all package prefixes and then m_name. +- * +- * @param separator The separator string to use (optional.) +- * If not given then the separator is chosen according +- * to the currently selected active programming language +- * of import and code generation. +- * @param includeRoot Whether to prefix the root folder name to the FQN. +- * See UMLDoc::getRootFolder(). Default: false. +- * @return The fully qualified name of this UMLObject. +- */ +-QString UMLObject::fullyQualifiedName(const QString& separator, +- bool includeRoot /* = false */) const +-{ +- QString fqn; +- if (m_pUMLPackage && m_pUMLPackage != this) { +- bool skipPackage = false; +- if (!includeRoot) { +- UMLDoc *umldoc = UMLApp::app()->document(); +- if (umldoc->rootFolderType(m_pUMLPackage) != Uml::ModelType::N_MODELTYPES || +- m_pUMLPackage == umldoc->datatypeFolder()) +- skipPackage = true; +- } +- if (!skipPackage) { +- QString tempSeparator = separator; +- if (tempSeparator.isEmpty()) +- tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); +- fqn = m_pUMLPackage->fullyQualifiedName(tempSeparator, includeRoot); +- fqn.append(tempSeparator); +- } +- } +- fqn.append(m_name); +- return fqn; +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLObject::operator==(const UMLObject & rhs) const +-{ +- if (this == &rhs) +- return true; +- +- //don't compare IDs, these are program specific and +- //don't mean the objects are the same +- //***** CHECK: Who put in this comment? What was the reason? +- //***** Currently some operator== in umbrello-kf6 compare the IDs +- //***** while others don't. +- +- if (m_name != rhs.m_name) +- return false; +- +- // Packages create different namespaces, therefore they should be +- // part of the equality test. +- if (m_pUMLPackage != rhs.m_pUMLPackage) +- return false; +- +- // Making the type part of an object's identity has its problems: +- // Not all programming languages support declarations of the same +- // name but different type. +- // In such cases, the code generator is responsible for generating +- // the appropriate error message. +- if (m_BaseType != rhs.m_BaseType) +- return false; +- +- // The documentation should not be part of the equality test. +- // If two objects are the same but differ only in their documentation, +- // what does that mean? +- //if(m_Doc != rhs.m_Doc) +- // return false; +- +- // The visibility should not be part of the equality test. +- // What does it mean if two objects are the same but differ in their +- // visibility? - I'm not aware of any programming language that would +- // support that. +- //if(m_visibility != rhs.m_visibility) +- // return false; +- +- // See comments above +- //if(m_pStereotype != rhs.m_pStereotype) +- // return false; +- +- // See comments above +- //if(m_bAbstract != rhs.m_bAbstract) +- // return false; +- +- // See comments above +- //if(m_bStatic != rhs.m_bStatic) +- // return false; +- +- return true; +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLObject::copyInto(UMLObject *lhs) const +-{ +- // Data members with copy constructor +- lhs->m_Doc = m_Doc; +- lhs->m_pStereotype = m_pStereotype; +- lhs->m_bAbstract = m_bAbstract; +- lhs->m_bStatic = m_bStatic; +- lhs->m_BaseType = m_BaseType; +- lhs->m_visibility = m_visibility; +- lhs->m_pUMLPackage = m_pUMLPackage; +- +- // We don't want the same name existing twice. +- lhs->m_name = Model_Utils::uniqObjectName(m_BaseType, m_pUMLPackage, m_name); +- +- // Create a new ID. +- lhs->m_nId = UniqueID::gen(); +- +- // Hope that the parent from QObject is okay. +- if (lhs->parent() != parent()) +- uDebug() << "copyInto has a wrong parent"; +-} +- +-UMLObject *UMLObject::clone() const +-{ +- UMLObject *clone = new UMLObject; +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Returns the abstract state of the object. +- */ +-bool UMLObject::isAbstract() const +-{ +- return m_bAbstract; +-} +- +-/** +- * Sets the paste state of the object. +- */ +-void UMLObject::setAbstract(bool bAbstract) +-{ +- m_bAbstract = bAbstract; +- emitModified(); +-} +- +-/** +- * Returns true if this UMLObject has classifier scope, +- * otherwise false (the default). +- */ +-bool UMLObject::isStatic() const +-{ +- return m_bStatic; +-} +- +-/** +- * Sets the value for m_bStatic. +- */ +-void UMLObject::setStatic(bool bStatic) +-{ +- m_bStatic = bStatic; +- emitModified(); +-} +- +-/** +- * Forces the emission of the modified signal. Useful when +- * updating several attributes at a time: you can block the +- * signals, update all atts, and then force the signal. +- */ +-void UMLObject::emitModified() +-{ +- UMLDoc *umldoc = UMLApp::app()->document(); +- if (!umldoc->loading() && !umldoc->closing()) +- emit modified(); +-} +- +-/** +- * Returns the type of the object. +- * +- * @return Returns the type of the object. +- */ +-UMLObject::ObjectType UMLObject::baseType() const +-{ +- return m_BaseType; +-} +- +-/** +- * @return The type used for rtti as string. +- */ +-QLatin1String UMLObject::baseTypeStr() const +-{ +- return QLatin1String(ENUM_NAME(UMLObject, ObjectType, m_BaseType)); +-} +- +-/** +- * Set the type of the object. +- * +- * @param ot The ObjectType to set. +- */ +-void UMLObject::setBaseType(ObjectType ot) +-{ +- m_BaseType = ot; +-} +- +-/** +- * Returns the ID of the object. +- * +- * @return Returns the ID of the object. +- */ +-ID::Type UMLObject::id() const +-{ +- return m_nId; +-} +- +-/** +- * Returns the documentation for the object. +- * +- * @return Returns the documentation for the object. +- */ +-QString UMLObject::doc() const +-{ +- return m_Doc; +-} +- +-/** +- * Returns state of documentation for the object. +- * +- * @return false if documentation is empty +- */ +-bool UMLObject::hasDoc() const +-{ +- return !m_Doc.isEmpty(); +-} +- +-/** +- * Sets the documentation for the object. +- * +- * @param d The documentation for the object. +- */ +-void UMLObject::setDoc(const QString &d) +-{ +- m_Doc = d; +- //emit modified(); No, this is done centrally at DocWindow::updateDocumentation() +-} +- +-/** +- * Returns the visibility of the object. +- * +- * @return Returns the visibility of the object. +- */ +-Visibility::Enum UMLObject::visibility() const +-{ +- return m_visibility; +-} +- +-/** +- * Sets the visibility of the object. +- * +- * @param visibility The visibility of the object. +- */ +-void UMLObject::setVisibility(Visibility::Enum visibility) +-{ +- if (m_visibility != visibility) { +- UMLApp::app()->executeCommand(new CmdSetVisibility(this, visibility)); +- } +-} +- +-/** +- * Method used by setVisibility: it is called by cmdSetVisibility, Don't use it! +- */ +-void UMLObject::setVisibilityCmd(Visibility::Enum visibility) +-{ +- m_visibility = visibility; +- emitModified(); +-} +- +-/** +- * Sets the class' UMLStereotype. Adjusts the reference counts +- * at the previously set stereotype and at the new stereotype. +- * If the previously set UMLStereotype's reference count drops +- * to zero then the UMLStereotype is removed at the UMLDoc and +- * it is then physically deleted. +- * +- * @param stereo Sets the classes UMLStereotype. +- */ +-void UMLObject::setUMLStereotype(UMLStereotype *stereo) +-{ +- if (stereo == m_pStereotype) +- return; +- if (stereo) { +- stereo->incrRefCount(); +- } +- if (m_pStereotype) { +- m_pStereotype->decrRefCount(); +- if (m_pStereotype->refCount() == 0) { +- UMLDoc *pDoc = UMLApp::app()->document(); +- pDoc->removeStereotype(m_pStereotype); +- delete m_pStereotype; +- } +- } +- m_pStereotype = stereo; +- // TODO: don't emit modified() if predefined folder +- emitModified(); +-} +- +-/** +- * Sets the classes stereotype name. +- * Internally uses setUMLStereotype(). +- * +- * @param name Sets the classes stereotype name. +- */ +-void UMLObject::setStereotype(const QString &name) +-{ +- if (name != stereotype()) { +- UMLApp::app()->executeCommand(new CmdSetStereotype(this, name)); +- } +-} +- +-void UMLObject::setStereotypeCmd(const QString& name) +-{ +- if (name.isEmpty()) { +- setUMLStereotype(NULL); +- return; +- } +- UMLDoc *pDoc = UMLApp::app()->document(); +- UMLStereotype *s = pDoc->findOrCreateStereotype(name); +- setUMLStereotype(s); +-} +- +-/** +- * Sets the UMLPackage in which this class is located. +- * +- * @param pPkg Pointer to the class' UMLPackage. +- */ +-bool UMLObject::setUMLPackage(UMLPackage* pPkg) +-{ +- if (pPkg == this) { +- uDebug() << "setting parent to myself is not allowed"; +- return false; +- } +- +- if (pPkg == NULL) { +- // Allow setting to NULL for stereotypes +- m_pUMLPackage = pPkg; +- return true; +- } +- +- if (pPkg->umlPackage() == this) { +- uDebug() << "setting parent to an object of which I'm already the parent is not allowed"; +- return false; +- } +- +- m_pUMLPackage = pPkg; +- emitModified(); +- return true; +-} +- +-/** +- * Returns the classes UMLStereotype object. +- * +- * @return Returns the classes UMLStereotype object. +- */ +-UMLStereotype * UMLObject::umlStereotype() +-{ +- return m_pStereotype; +-} +- +-/** +- * Returns the stereotype. +- */ +-QString UMLObject::stereotype(bool includeAdornments /* = false */) const +-{ +- if (m_pStereotype == NULL) +- return QString(); +- return m_pStereotype->name(includeAdornments); +-} +- +-/** +- * Return the package(s) in which this UMLObject is contained +- * as a text. +- * +- * @param separator Separator string for joining together the +- * individual package prefixes (optional.) +- * If no separator is given then the separator +- * of the currently selected language is used. +- * @param includeRoot Whether to prefix the root folder name. +- * Default: false. +- * @return The UMLObject's enclosing package(s) as a text. +- */ +-QString UMLObject::package(const QString& separator, bool includeRoot) +-{ +- QString tempSeparator = separator; +- if (tempSeparator.isEmpty()) +- tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); +- QString fqn = fullyQualifiedName(tempSeparator, includeRoot); +- if (!fqn.contains(tempSeparator)) +- return QString(); +- QString scope = fqn.left(fqn.length() - tempSeparator.length() - m_name.length()); +- return scope; +-} +- +-/** +- * Return a list of the packages in which this class is embedded. +- * The outermost package is first in the list. +- * +- * @param includeRoot Whether to prefix the root folder name. +- * Default: false. +- * @return UMLPackageList of the containing packages. +- */ +-UMLPackageList UMLObject::packages(bool includeRoot) const +-{ +- UMLPackageList pkgList; +- UMLPackage* pkg = m_pUMLPackage; +- while (pkg != NULL) { +- pkgList.prepend(pkg); +- pkg = pkg->umlPackage(); +- } +- if (!includeRoot) +- pkgList.removeFirst(); +- return pkgList; +-} +- +-/** +- * Returns the UMLPackage that this class is located in. +- * +- * @return Pointer to the UMLPackage of this class. +- */ +-UMLPackage* UMLObject::umlPackage() +-{ +- return m_pUMLPackage; +-} +- +-/** +- * Return secondary ID. Required by resolveRef(). +- */ +-QString UMLObject::secondaryId() const +-{ +- return m_SecondaryId; +-} +- +-/** +- * Set the secondary ID. +- * Currently only required by petalTree2Uml(); all other setting of the +- * m_SecondaryID is internal to the UMLObject class hierarchy. +- */ +-void UMLObject::setSecondaryId(const QString& id) +-{ +- m_SecondaryId = id; +-} +- +-/** +- * Return secondary ID fallback. +- * Required by resolveRef() for imported model files. +- */ +-QString UMLObject::secondaryFallback() const +-{ +- return m_SecondaryFallback; +-} +- +-/** +- * Set the secondary ID fallback. +- * Currently only used by petalTree2Uml(). +- */ +-void UMLObject::setSecondaryFallback(const QString& id) +-{ +- m_SecondaryFallback = id; +-} +- +-/** +- * Calls UMLDoc::signalUMLObjectCreated() if m_BaseType affords +- * doing so. +- */ +-void UMLObject::maybeSignalObjectCreated() +-{ +- if (!m_bCreationWasSignalled && +- m_BaseType != ot_Stereotype && +- m_BaseType != ot_Association && +- m_BaseType != ot_Role) { +- m_bCreationWasSignalled = true; +- UMLDoc* umldoc = UMLApp::app()->document(); +- umldoc->signalUMLObjectCreated(this); +- } +-} +- +-/** +- * Resolve referenced objects (if any.) +- * Needs to be called after all UML objects are loaded from file. +- * This needs to be done after all model objects are loaded because +- * some of the xmi.id's might be forward references, i.e. they may +- * identify model objects which were not yet loaded at the point of +- * reference. +- * The default implementation attempts resolution of the m_SecondaryId. +- * +- * @return True for success. +- */ +-bool UMLObject::resolveRef() +-{ +- if (m_pSecondary || (m_SecondaryId.isEmpty() && m_SecondaryFallback.isEmpty())) { +- maybeSignalObjectCreated(); +- return true; +- } +-#ifdef VERBOSE_DEBUGGING +- uDebug() << m_name << ": m_SecondaryId is " << m_SecondaryId; +-#endif +- UMLDoc *pDoc = UMLApp::app()->document(); +- // In the new, XMI standard compliant save format, +- // the type is the xmi.id of a UMLClassifier. +- if (! m_SecondaryId.isEmpty()) { +- m_pSecondary = pDoc->findObjectById(Uml::ID::fromString(m_SecondaryId)); +- if (m_pSecondary != NULL) { +- if (m_pSecondary->baseType() == ot_Stereotype) { +- m_pStereotype = dynamic_cast(m_pSecondary.data()); +- m_pStereotype->incrRefCount(); +- m_pSecondary = NULL; +- } +- m_SecondaryId = QString(); +- maybeSignalObjectCreated(); +- return true; +- } +- if (m_SecondaryFallback.isEmpty()) { +- uDebug() << "object with xmi.id=" << m_SecondaryId << " not found, setting to undef"; +- UMLFolder *datatypes = pDoc->datatypeFolder(); +- m_pSecondary = Object_Factory::createUMLObject(ot_Datatype, QLatin1String("undef"), datatypes, false); +- return true; +- } +- } +- if (m_SecondaryFallback.isEmpty()) { +- uError() << m_name << ": cannot find type with id " << m_SecondaryId; +- return false; +- } +-#ifdef VERBOSE_DEBUGGING +- uDebug() << m_name << ": could not resolve secondary ID " << m_SecondaryId +- << ", using secondary fallback " << m_SecondaryFallback; +-#endif +- m_SecondaryId = m_SecondaryFallback; +- // Assume we're dealing with the older umbrello-kf6 format where +- // the type name was saved in the "type" attribute rather +- // than the xmi.id of the model object of the attribute type. +- m_pSecondary = pDoc->findUMLObject(m_SecondaryId, ot_UMLObject, this); +- if (m_pSecondary) { +- m_SecondaryId = QString(); +- maybeSignalObjectCreated(); +- return true; +- } +- // Work around Object_Factory::createUMLObject()'s incapability +- // of on-the-fly scope creation: +- if (m_SecondaryId.contains(QLatin1String("::"))) { +- // TODO: Merge Import_Utils::createUMLObject() into Object_Factory::createUMLObject() +- m_pSecondary = Import_Utils::createUMLObject(ot_UMLObject, m_SecondaryId, m_pUMLPackage); +- if (m_pSecondary) { +- if (Import_Utils::newUMLObjectWasCreated()) { +- maybeSignalObjectCreated(); +- qApp->processEvents(); +- uDebug() << "Import_Utils::createUMLObject() created a new type for " +- << m_SecondaryId; +- } else { +- uDebug() << "Import_Utils::createUMLObject() returned an existing type for " +- << m_SecondaryId; +- } +- m_SecondaryId = QString(); +- return true; +- } +- uError() << "Import_Utils::createUMLObject() failed to create a new type for " +- << m_SecondaryId; +- return false; +- } +- uDebug() << "Creating new type for " << m_SecondaryId; +- // This is very C++ specific - we rely on some '*' or +- // '&' to decide it's a ref type. Plus, we don't recognize +- // typedefs of ref types. +- bool isReferenceType = (m_SecondaryId.contains(QLatin1Char('*')) || +- m_SecondaryId.contains(QLatin1Char('&'))); +- ObjectType ot = ot_Class; +- if (isReferenceType) { +- ot = ot_Datatype; +- } else { +- if (Model_Utils::isCommonDataType(m_SecondaryId)) +- ot = ot_Datatype; +- } +- m_pSecondary = Object_Factory::createUMLObject(ot, m_SecondaryId, NULL); +- if (m_pSecondary == NULL) +- return false; +- m_SecondaryId = QString(); +- maybeSignalObjectCreated(); +- //qApp->processEvents(); +- return true; +-} +- +-void UMLObject::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +-{ +- Q_UNUSED(qDoc); Q_UNUSED(qElement); +-} +- +-/** +- * Auxiliary to saveToXMI. +- * Create a QDomElement with the given tag, and save the XMI attributes +- * that are common to all child classes to the newly created element. +- * This method does not need to be overridden by child classes. +- */ +-QDomElement UMLObject::save(const QString &tag, QDomDocument & qDoc) +-{ +- /* +- Call as the first action of saveToXMI() in child class: +- This creates the QDomElement with which to work. +- */ +- QDomElement qElement = qDoc.createElement(tag); +- qElement.setAttribute(QLatin1String("isSpecification"), QLatin1String("false")); +- if (m_BaseType != ot_Association && +- m_BaseType != ot_Role && +- m_BaseType != ot_Attribute) { +- qElement.setAttribute(QLatin1String("isLeaf"), QLatin1String("false")); +- qElement.setAttribute(QLatin1String("isRoot"), QLatin1String("false")); +- if (m_bAbstract) +- qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("true")); +- else +- qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("false")); +- } +- qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_nId)); +- qElement.setAttribute(QLatin1String("name"), m_name); +- if (m_BaseType != ot_Operation && +- m_BaseType != ot_Role && +- m_BaseType != ot_Attribute) { +- Uml::ID::Type nmSpc; +- if (m_pUMLPackage) +- nmSpc = m_pUMLPackage->id(); +- else +- nmSpc = UMLApp::app()->document()->modelID(); +- qElement.setAttribute(QLatin1String("namespace"), Uml::ID::toString(nmSpc)); +- } +- if (! m_Doc.isEmpty()) +- qElement.setAttribute(QLatin1String("comment"), m_Doc); //CHECK: uml13.dtd compliance +-#ifdef XMI_FLAT_PACKAGES +- if (m_pUMLPackage) //FIXME: uml13.dtd compliance +- qElement.setAttribute(QLatin1String("package"), m_pUMLPackage->ID()); +-#endif +- QString visibility = Uml::Visibility::toString(m_visibility, false); +- qElement.setAttribute(QLatin1String("visibility"), visibility); +- if (m_pStereotype != NULL) +- qElement.setAttribute(QLatin1String("stereotype"), Uml::ID::toString(m_pStereotype->id())); +- if (m_bStatic) +- qElement.setAttribute(QLatin1String("ownerScope"), QLatin1String("classifier")); +- /* else +- qElement.setAttribute("ownerScope", "instance"); +- *** ownerScope defaults to instance if not set **********/ +- return qElement; +-} +- +-/** +- * Auxiliary to loadFromXMI. +- * This method is usually overridden by child classes. +- * It is responsible for loading the specific XMI structure +- * of the child class. +- */ +-bool UMLObject::load(QDomElement&) +-{ +- // This body is not usually executed because child classes +- // overwrite the load method. +- return true; +-} +- +-/** +- * Analyzes the given QDomElement for a reference to a stereotype. +- * +- * @param element QDomElement to analyze. +- * @return True if a stereotype reference was found, else false. +- */ +-bool UMLObject::loadStereotype(QDomElement & element) +-{ +- QString tag = element.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("stereotype"))) +- return false; +- QString stereo = element.attribute(QLatin1String("xmi.value")); +- if (stereo.isEmpty() && element.hasChildNodes()) { +- /* like so: +- +- +- +- */ +- QDomNode stereoNode = element.firstChild(); +- QDomElement stereoElem = stereoNode.toElement(); +- tag = stereoElem.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("Stereotype"))) { +- stereo = stereoElem.attribute(QLatin1String("xmi.idref")); +- } +- } +- if (stereo.isEmpty()) +- return false; +- Uml::ID::Type stereoID = Uml::ID::fromString(stereo); +- UMLDoc *pDoc = UMLApp::app()->document(); +- m_pStereotype = pDoc->findStereotypeById(stereoID); +- if (m_pStereotype) +- m_pStereotype->incrRefCount(); +- else +- m_SecondaryId = stereo; // leave it to resolveRef() +- return true; +-} +- +-/** +- * This method loads the generic parts of the XMI common to most model +- * classes. It is not usually reimplemented by child classes. +- * Instead, it invokes the load() method which implements the loading +- * of the specifics of each child class. +- * +- * @param element The QDomElement from which to load. +- */ +-bool UMLObject::loadFromXMI(QDomElement & element) +-{ +- UMLDoc* umldoc = UMLApp::app()->document(); +- if (umldoc == 0) { +- uError() << "umldoc is NULL"; +- return false; +- } +- // Read the name first so that if we encounter a problem, the error +- // message can say the name. +- m_name = element.attribute(QLatin1String("name")); +- QString id = Model_Utils::getXmiId(element); +- if (id.isEmpty() || id == QLatin1String("-1")) { +- // Before version 1.4, umbrello-kf6 did not save the xmi.id of UMLRole objects. +- // Some tools (such as Embarcadero's) do not have an xmi.id on all attributes. +- m_nId = UniqueID::gen(); +- uWarning() << m_name << ": xmi.id not present, generating a new one"; +- } else { +- Uml::ID::Type nId = Uml::ID::fromString(id); +- if (m_BaseType == ot_Role) { +- // Some older umbrello-kf6 versions had a problem with xmi.id's +- // of other objects being reused for the UMLRole, see e.g. +- // attachment 21179 at http://bugs.kde.org/147988 . +- // If the xmi.id is already being used then we generate a new one. +- UMLObject *o = umldoc->findObjectById(nId); +- if (o) { +- uError() << "loadFromXMI(UMLRole): id " << id +- << " is already in use!!! Please fix your XMI file."; +- } +- } +- m_nId = nId; +- } +- +- if (element.hasAttribute(QLatin1String("documentation"))) // for bkwd compat. +- m_Doc = element.attribute(QLatin1String("documentation")); +- else +- m_Doc = element.attribute(QLatin1String("comment")); //CHECK: need a UML:Comment? +- +- m_visibility = Uml::Visibility::Public; +- if (element.hasAttribute(QLatin1String("scope"))) { // for bkwd compat. +- QString scope = element.attribute(QLatin1String("scope")); +- if (scope == QLatin1String("instance_level")) // nsuml compat. +- m_bStatic = false; +- else if (scope == QLatin1String("classifier_level")) // nsuml compat. +- m_bStatic = true; +- else { +- int nScope = scope.toInt(); +- switch (nScope) { +- case 200: +- m_visibility = Uml::Visibility::Public; +- break; +- case 201: +- m_visibility = Uml::Visibility::Private; +- break; +- case 202: +- m_visibility = Uml::Visibility::Protected; +- break; +- default: +- uError() << m_name << ": illegal scope " << nScope; +- } +- } +- } else { +- QString visibility = element.attribute(QLatin1String("visibility"), QLatin1String("public")); +- if (visibility == QLatin1String("private") +- || visibility == QLatin1String("private_vis")) // for compatibility with other programs +- m_visibility = Uml::Visibility::Private; +- else if (visibility == QLatin1String("protected") +- || visibility == QLatin1String("protected_vis")) // for compatibility with other programs +- m_visibility = Uml::Visibility::Protected; +- else if (visibility == QLatin1String("implementation")) +- m_visibility = Uml::Visibility::Implementation; +- } +- +- QString stereo = element.attribute(QLatin1String("stereotype")); +- if (!stereo.isEmpty()) { +- Uml::ID::Type stereoID = Uml::ID::fromString(stereo); +- m_pStereotype = umldoc->findStereotypeById(stereoID); +- if (m_pStereotype) { +- m_pStereotype->incrRefCount(); +- } else { +- uDebug() << m_name << ": UMLStereotype " << Uml::ID::toString(stereoID) +- << " not found, creating now."; +- setStereotypeCmd(stereo); +- } +- } +- +- if (element.hasAttribute(QLatin1String("abstract"))) { // for bkwd compat. +- QString abstract = element.attribute(QLatin1String("abstract"), QLatin1String("0")); +- m_bAbstract = (bool)abstract.toInt(); +- } else { +- QString isAbstract = element.attribute(QLatin1String("isAbstract"), QLatin1String("false")); +- m_bAbstract = (isAbstract == QLatin1String("true")); +- } +- +- if (element.hasAttribute(QLatin1String("static"))) { // for bkwd compat. +- QString staticScope = element.attribute(QLatin1String("static"), QLatin1String("0")); +- m_bStatic = (bool)staticScope.toInt(); +- } else { +- QString ownerScope = element.attribute(QLatin1String("ownerScope"), QLatin1String("instance")); +- m_bStatic = (ownerScope == QLatin1String("classifier")); +- } +- +- // If the node has child nodes, check whether attributes can be +- // extracted from them. +- if (element.hasChildNodes()) { +- QDomNode node = element.firstChild(); +- if (node.isComment()) +- node = node.nextSibling(); +- QDomElement elem = node.toElement(); +- while (!elem.isNull()) { +- QString tag = elem.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("name"))) { +- m_name = elem.attribute(QLatin1String("xmi.value")); +- if (m_name.isEmpty()) +- m_name = elem.text(); +- } else if (UMLDoc::tagEq(tag, QLatin1String("visibility"))) { +- QString vis = elem.attribute(QLatin1String("xmi.value")); +- if (vis.isEmpty()) +- vis = elem.text(); +- if (vis == QLatin1String("private") || vis == QLatin1String("private_vis")) +- m_visibility = Uml::Visibility::Private; +- else if (vis == QLatin1String("protected") || vis == QLatin1String("protected_vis")) +- m_visibility = Uml::Visibility::Protected; +- else if (vis == QLatin1String("implementation")) +- m_visibility = Uml::Visibility::Implementation; +- } else if (UMLDoc::tagEq(tag, QLatin1String("isAbstract"))) { +- QString isAbstract = elem.attribute(QLatin1String("xmi.value")); +- if (isAbstract.isEmpty()) +- isAbstract = elem.text(); +- m_bAbstract = (isAbstract == QLatin1String("true")); +- } else if (UMLDoc::tagEq(tag, QLatin1String("ownerScope"))) { +- QString ownerScope = elem.attribute(QLatin1String("xmi.value")); +- if (ownerScope.isEmpty()) +- ownerScope = elem.text(); +- m_bStatic = (ownerScope == QLatin1String("classifier")); +- } else { +- loadStereotype(elem); +- } +- node = node.nextSibling(); +- if (node.isComment()) +- node = node.nextSibling(); +- elem = node.toElement(); +- } +- } +- +- // Operations, attributes, enum literals, templates, stereotypes, +- // and association role objects get added and signaled elsewhere. +- if (m_BaseType != ot_Operation && m_BaseType != ot_Attribute && +- m_BaseType != ot_EnumLiteral && m_BaseType != ot_EntityAttribute && +- m_BaseType != ot_Template && m_BaseType != ot_Stereotype && +- m_BaseType != ot_Role && m_BaseType != ot_UniqueConstraint && +- m_BaseType != ot_ForeignKeyConstraint && m_BaseType != ot_CheckConstraint) { +- if (m_pUMLPackage) { +- m_pUMLPackage->addObject(this); +- } else if (umldoc->rootFolderType(this) == Uml::ModelType::N_MODELTYPES) { +- // m_pUMLPackage is not set on the root folders. +- uDebug() << m_name << ": m_pUMLPackage is not set"; +- } +- } +- return load(element); +-} +- +-/** +- * Helper function for debug output. +- * Returns the given enum value as string. +- * @param ot ObjectType of which a string representation is wanted +- * @return the ObjectType as string +- */ +-QString UMLObject::toString(ObjectType ot) +-{ +- return QLatin1String(ENUM_NAME(UMLObject, ObjectType, ot)); +-} +- +-/** +- * Returns the given object type value as localized string. +- * @param ot ObjectType of which a string representation is wanted +- * @return the ObjectType as localized string +- */ +-QString UMLObject::toI18nString(ObjectType t) +-{ +- QString name; +- +- switch (t) { +- case UMLObject::ot_Actor: +- name = i18n("Actor &name:"); +- break; +- case UMLObject::ot_Artifact: +- name = i18n("Artifact &name:"); +- break; +- case UMLObject::ot_Class: +- name = i18n("Class &name:"); +- break; +- case UMLObject::ot_Component: +- name = i18n("Component &name:"); +- break; +- case UMLObject::ot_Datatype: +- name = i18n("Datatype &name:"); +- break; +- case UMLObject::ot_Entity: +- name = i18n("Entity &name:"); +- break; +- case UMLObject::ot_Enum: +- name = i18n("Enum &name:"); +- break; +- case UMLObject::ot_Folder: +- name = i18n("Folder &name:"); +- break; +- case UMLObject::ot_Interface: +- name = i18n("Interface &name:"); +- break; +- case UMLObject::ot_Node: +- name = i18n("Node &name:"); +- break; +- case UMLObject::ot_Package: +- name = i18n("Package &name:"); +- break; +- case UMLObject::ot_Port: +- name = i18n("Port &name:"); +- break; +- case UMLObject::ot_Stereotype: +- name = i18n("Stereotype &name:"); +- break; +- case UMLObject::ot_UseCase: +- name = i18n("Use case &name:"); +- break; +- default: +- name = QLatin1String(" &name:"); +- uWarning() << "unknown object type"; +- break; +- } +- return name; +-} +- +-/** +- * Print UML Object to debug output stream, so it can be used like +- * uDebug() << "This object shouldn't be here: " << illegalObject; +- */ +-QDebug operator<<(QDebug out, const UMLObject& obj) +-{ +- out.nospace() << "UMLObject: name= " << obj.name() +- << ", type= " << UMLObject::toString(obj.m_BaseType); +- return out.space(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobject.h umbrello-kf6-15.08.1/umbrello/umlobject.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlobject.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlobject.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,198 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLOBJECT_H +-#define UMLOBJECT_H +- +-#include "basictypes.h" +-#include "umlpackagelist.h" +- +-//qt includes +-#include +-#include +-#include +-#include +-#include +- +-class UMLStereotype; +- +-/** +- * This class is the non-graphical version of @ref UMLWidget. These are +- * created and maintained in the class @ref UMLDoc. This class holds all +- * the generic information needed for all UML objects. +- * +- * @ref clone needs to be implemented by each child class. +- * +- * @ref saveToXMI saves the XMI attributes of each specific model class. +- * It needs to be implemented by each child class. +- * For creating the QDomElement and saving the common XMI parts, +- * it can use the save() method. +- * +- * @short The base class for UML objects. +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLObject : public QObject +-{ +- Q_OBJECT +- Q_ENUMS(ObjectType) +- +-public: +- enum ObjectType +- { +- ot_Unknown = -1, +- ot_UMLObject = 100, +- ot_Actor, +- ot_UseCase, +- ot_Package, +- ot_Interface, +- ot_Datatype, +- ot_Enum, +- ot_Class, +- ot_Association, +- ot_Attribute, +- ot_Operation, +- ot_EnumLiteral, +- ot_Template, +- ot_Component, +- ot_Artifact, +- ot_Node, +- ot_Stereotype, +- ot_Role, +- ot_Entity, +- ot_EntityAttribute, +- ot_Folder, +- ot_EntityConstraint, +- ot_UniqueConstraint, +- ot_ForeignKeyConstraint, +- ot_CheckConstraint, +- ot_Category, +- ot_Port +- }; +- +- static QString toString(ObjectType ot); +- static QString toI18nString(ObjectType t); +- +- explicit UMLObject(const UMLObject& other); +- explicit UMLObject(UMLObject* parent, const QString& name, Uml::ID::Type id = Uml::ID::None); +- explicit UMLObject(UMLObject* parent); +- explicit UMLObject(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~UMLObject(); +- +- bool operator==(const UMLObject & rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- virtual void setBaseType(ObjectType ot); +- ObjectType baseType() const; +- QLatin1String baseTypeStr() const; +- +- virtual void setID(Uml::ID::Type NewID); +- virtual Uml::ID::Type id() const; +- +- QString doc() const; +- bool hasDoc() const; +- void setDoc(const QString &d); +- +- void setVisibility(Uml::Visibility::Enum visibility); +- void setVisibilityCmd(Uml::Visibility::Enum visibility); +- Uml::Visibility::Enum visibility() const; +- +- void setStereotype(const QString &_name); +- void setStereotypeCmd(const QString &_name); +- QString stereotype(bool includeAdornments = false) const; +- +- void setUMLStereotype(UMLStereotype *stereo); +- UMLStereotype *umlStereotype(); +- +- QString package(const QString& separator = QString(), +- bool includeRoot = false); +- +- bool setUMLPackage(UMLPackage* pPkg); +- UMLPackage* umlPackage(); +- +- UMLPackageList packages(bool includeRoot = false) const; +- +- virtual void setName(const QString &strName); +- void setNameCmd(const QString &strName) ; +- QString name() const; +- +- virtual QString fullyQualifiedName(const QString& separator = QString(), +- bool includeRoot = false) const; +- +- void setAbstract(bool bAbstract); +- bool isAbstract() const; +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +- virtual bool resolveRef(); +- +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- virtual bool loadFromXMI(QDomElement & element); +- +- bool loadStereotype(QDomElement & element); +- +- void setStatic(bool bStatic); +- bool isStatic() const; +- +- virtual bool acceptAssociationType(Uml::AssociationType::Enum); //:TODO: check if this is really needed here +- +- void setSecondaryId(const QString& id); +- QString secondaryId() const; +- +- void setSecondaryFallback(const QString& id); +- QString secondaryFallback() const; +- +- QDomElement save(const QString &tag, QDomDocument & qDoc); +- +- friend QDebug operator<< (QDebug out, const UMLObject& obj); +- +-public slots: +- void emitModified(); +- +-signals: +- void modified(); +- +-protected: +- void init(); +- +- void maybeSignalObjectCreated(); +- +- virtual bool load(QDomElement& element); +- +- Uml::ID::Type m_nId; ///< object's id +- QString m_Doc; ///< object's documentation +- UMLPackage* m_pUMLPackage; ///< package the object belongs to if applicable +- UMLStereotype* m_pStereotype; ///< stereotype of the object if applicable +- QString m_name; ///< objects name +- ObjectType m_BaseType; ///< objects type +- Uml::Visibility::Enum m_visibility; ///< objects visibility +- bool m_bAbstract; ///< state of whether the object is abstract or not +- bool m_bStatic; ///< flag for instance scope +- bool m_bInPaste; ///< caller sets this true when in paste operation +- bool m_bCreationWasSignalled; ///< auxiliary to maybeSignalObjectCreated() +- QPointer m_pSecondary; ///< pointer to an associated object +- ///< Only a few of the classes inheriting from UMLObject use this. +- ///< However, it needs to be here because of inheritance graph +- ///< disjunctness. +- QString m_SecondaryId; ///< xmi.id of the secondary object for intermediate use during +- ///< loading. The secondary ID is resolved to the m_pSecondary +- ///< in the course of resolveRef() at the end of loading. +- QString m_SecondaryFallback; ///< Last-chance backup for when m_SecondaryId is not found. +- ///< Used by Rose import: MDL files specify both a "quidu" +- ///< (which corresponds to m_SecondaryId) and the human readable +- ///< fully qualified target name of a reference. +- ///< In case the quidu is not found, the human readable name is +- ///< used which we store in m_SecondaryFallback. +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.cpp umbrello-kf6-15.08.1/umbrello/umlobjectlist.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlobjectlist.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,53 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "umlobjectlist.h" +-#include "umlobject.h" +- +-UMLObjectList::UMLObjectList() +-{ +-} +- +-UMLObjectList::~UMLObjectList() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the new +- * object. +- */ +-void UMLObjectList::copyInto(UMLObjectList *rhs) const +-{ +- // Don't copy yourself. +- if (rhs == this) return; +- +- rhs->clear(); +- +- // Suffering from const; we shall not modify our object. +- UMLObjectList *tmp = new UMLObjectList(*this); +- +- UMLObject *item = NULL; +- for (UMLObjectListIt oit(*tmp); oit.hasNext() ;) +- { +- item = oit.next(); +- rhs->append(item->clone()); +- } +- delete tmp; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObjectList* UMLObjectList::clone() const +-{ +- UMLObjectList *clone = new UMLObjectList(); +- copyInto(clone); +- return clone; +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.h umbrello-kf6-15.08.1/umbrello/umlobjectlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlobjectlist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,40 +0,0 @@ +-/*************************************************************************** +- * 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) 2001 Gustavo Madrigal gmadrigal@nextphere.com * +- * copyright (C) 2002-2014 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLOBJECTLIST_H +-#define UMLOBJECTLIST_H +- +-#include +-#include +- +-// forward declarations +-class UMLObject; +- +-typedef QListIterator > +-UMLObjectListIt; +- +-/** +- * This sub-class adds copyInto and clone to the QList +- * base class. +- */ +-class UMLObjectList : public QList > +-{ +-public: +- +- UMLObjectList(); +- virtual ~UMLObjectList(); +- +- virtual void copyInto(UMLObjectList *rhs) const; +- +- virtual UMLObjectList* clone() const; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umloperationlist.h umbrello-kf6-15.08.1/umbrello/umloperationlist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umloperationlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umloperationlist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,23 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-2007 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLOPERATIONLIST_H +-#define UMLOPERATIONLIST_H +- +-#include +- +-// forward declaration +-class UMLOperation; +- +-typedef QList UMLOperationList; +-typedef QListIterator UMLOperationListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlpackagelist.h umbrello-kf6-15.08.1/umbrello/umlpackagelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlpackagelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlpackagelist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,22 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-2007 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLPACKAGELIST_H +-#define UMLPACKAGELIST_H +- +-#include +- +-class UMLPackage; +- +-typedef QList UMLPackageList; +-typedef QListIterator UMLPackageListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlrole.cpp umbrello-kf6-15.08.1/umbrello/umlrole.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlrole.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlrole.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,415 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "umlrole.h" +- +-// local includes +-#include "association.h" +-#include "debug_utils.h" +-#include "umldoc.h" +-#include "umlroledialog.h" +-#include "uml.h" +- +-// qt includes +-#include +-#include +- +-/** +- * Sets up an association. +- * +- * @param parent The parent (association) of this UMLRole. +- * @param parentObj The Parent UML Object of this UMLRole +- * @param role The Uml::RoleType::Enum of this UMLRole +- */ +-UMLRole::UMLRole(UMLAssociation * parent, UMLObject * parentObj, Uml::RoleType::Enum role) +- : UMLObject(const_cast(parent)), +- m_pAssoc(parent), +- m_role(role), +- m_Multi(QString()), +- m_Changeability(Uml::Changeability::Changeable) +-{ +- m_BaseType = UMLObject::ot_Role; +- m_name.clear(); +- m_pSecondary = parentObj; +- +- // connect this up to parent +- connect(this, SIGNAL(modified()), parent, SIGNAL(modified())); +-} +- +-/** +- * Standard destructor. +- */ +-UMLRole::~UMLRole() +-{ +-} +- +-/** +- * Overloaded '==' operator. +- */ +-bool UMLRole::operator==(const UMLRole &rhs) const +-{ +- if (this == &rhs) { +- return true; +- } +- return (UMLObject::operator==(rhs) && +- m_Changeability == rhs.m_Changeability && +- m_Multi == rhs.m_Multi && +- m_name == rhs.m_name +- ); +-} +- +-UMLAssociation * UMLRole::parentAssociation() const +-{ +- return m_pAssoc; +-} +- +-/** +- * Returns the UMLObject assigned to the role. +- * @return Pointer to the UMLObject in role. +- */ +-UMLObject* UMLRole::object() const +-{ +- return m_pSecondary; +-} +- +-/** +- * Returns the Changeablity of the role. +- * +- * @return Changeability of role. +- */ +-Uml::Changeability::Enum UMLRole::changeability() const +-{ +- return m_Changeability; +-} +- +-/** +- * Returns the multiplicity assigned to the role. +- * +- * @return The multiplicity assigned to the role. +- */ +-QString UMLRole::multiplicity() const +-{ +- return m_Multi; +-} +- +-/** +- * Sets the UMLObject playing the role in the association. +- * +- * @param obj Pointer to the UMLObject of role. +- */ +-void UMLRole::setObject(UMLObject *obj) +-{ +- // because we will get the id of this role from the parent +- // object, we CANT allow UMLRoles to take other UMLRoles as +- // parent objects. In fact, there is probably good reason +- // to only take UMLClassifiers here, but I'll leave it more open +- // for the time being. -b.t. +- if (obj && dynamic_cast(obj)) { +- uError() << "UMLRole(" << Uml::ID::toString(m_nId) << ") cannot setObject() to another UMLRole(" +- << Uml::ID::toString(obj->id()) << ")"; +- return; +- } +- +- m_pSecondary = obj; +- UMLObject::emitModified(); +-} +- +-/** +- * Sets the changeability of the role. +- * +- * @param value Changeability::Enum of role. +- */ +-void UMLRole::setChangeability(Uml::Changeability::Enum value) +-{ +- m_Changeability = value; +- UMLObject::emitModified(); +-} +- +-/** +- * Sets the multiplicity of the role. +- * +- * @param multi The multiplicity of role. +- */ +-void UMLRole::setMultiplicity(const QString &multi) +-{ +- m_Multi = multi; +- UMLObject::emitModified(); +-} +- +-/** +- * Get the 'id' of the role (NOT the parent object). This could be +- * either Uml::RoleType::A or Uml::RoleType::B. Yes, it would be better if we +- * could get along without this, but we need it to distinguish saved +- * umlrole objects in the XMI for 'self' associations where both roles +- * will point to the same underlying UMLObject. +- */ +-Uml::RoleType::Enum UMLRole::role() const +-{ +- return m_role; +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLRole::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement roleElement = UMLObject::save(QLatin1String("UML:AssociationEnd"), qDoc); +- if (m_pSecondary) +- roleElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); +- else +- uError() << "id " << Uml::ID::toString(m_nId) << ": m_pSecondary is NULL"; +- if (!m_Multi.isEmpty()) +- roleElement.setAttribute(QLatin1String("multiplicity"), m_Multi); +- if (m_role == Uml::RoleType::A) { // role aggregation based on parent type +- // role A +- switch (m_pAssoc->getAssocType()) { +- case Uml::AssociationType::Composition: +- roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("composite")); +- break; +- case Uml::AssociationType::Aggregation: +- roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("aggregate")); +- break; +- default: +- roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); +- break; +- } +- if (m_pAssoc->getAssocType() == Uml::AssociationType::UniAssociation) { +- // Normally the isNavigable attribute is "true". +- // We set it to false on role A to indicate that +- // role B gets an explicit arrowhead. +- roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("false")); +- } else { +- roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); +- } +- } else { +- roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); +- roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); +- //FIXME obviously this isn't standard XMI +- if (m_pAssoc->getAssocType() == Uml::AssociationType::Relationship) { +- roleElement.setAttribute(QLatin1String("relationship"), QLatin1String("true")); +- } +- } +- +- roleElement.setAttribute(QLatin1String("visibility"), Uml::Visibility::toString(visibility(), false)); +- +- switch (m_Changeability) { +- case Uml::Changeability::Frozen: +- roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("frozen")); +- break; +- case Uml::Changeability::AddOnly: +- roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("addOnly")); +- break; +- case Uml::Changeability::Changeable: +- roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("changeable")); +- break; +- } +- qElement.appendChild(roleElement); +-} +- +-/** +- * Display the properties configuration dialog for the object. +- * +- * @param parent The parent widget. +- * @return True for success of this operation. +- */ +-bool UMLRole::showPropertiesDialog(QWidget *parent) +-{ +- QPointer dlg = new UMLRoleDialog(parent, this); +- bool modified = false; +- if (dlg->exec() == QDialog::Accepted) { +- modified = true; +- } +- delete dlg; +- return modified; +-} +- +-/** +- * Loads the XMI element. +- * Auxiliary to UMLObject::loadFromXMI. +- */ +-bool UMLRole::load(QDomElement & element) +-{ +- UMLDoc * doc = UMLApp::app()->document(); +- QString type = element.attribute(QLatin1String("type")); +- if (!type.isEmpty()) { +- if (!m_SecondaryId.isEmpty()) +- uWarning() << "overwriting old m_SecondaryId \"" << m_SecondaryId +- << " with new value \"" << type << "\""; +- m_SecondaryId = type; +- } +- // Inspect child nodes - for multiplicity (and type if not set above.) +- for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { +- if (node.isComment()) +- continue; +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("name"))) { +- m_name = tempElement.text(); +- } else if (UMLDoc::tagEq(tag, QLatin1String("AssociationEnd.multiplicity"))) { +- /* +- * There are different ways in which the multiplicity might be given: +- * - direct value in the tag, +- * - attributes "lower" and "upper" of a subordinate , +- * - direct value in subordinate and +- * tags +- */ +- QDomNode n = tempElement.firstChild(); +- if (node.isNull() || tempElement.isNull() || n.isNull() || +- n.toElement().isNull()) { +- m_Multi = tempElement.text().trimmed(); +- continue; +- } +- tempElement = n.toElement(); +- tag = tempElement.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity"))) { +- m_Multi = tempElement.text().trimmed(); +- continue; +- } +- n = tempElement.firstChild(); +- tempElement = n.toElement(); +- tag = tempElement.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity.range"))) { +- m_Multi = tempElement.text().trimmed(); +- continue; +- } +- n = tempElement.firstChild(); +- tempElement = n.toElement(); +- tag = tempElement.tagName(); +- if (!UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange"))) { +- m_Multi = tempElement.text().trimmed(); +- continue; +- } +- QString multiUpper; +- if (tempElement.hasAttribute(QLatin1String("lower"))) { +- m_Multi = tempElement.attribute(QLatin1String("lower")); +- multiUpper = tempElement.attribute(QLatin1String("upper")); +- if (!multiUpper.isEmpty()) { +- if (!m_Multi.isEmpty()) +- m_Multi.append(QLatin1String("..")); +- m_Multi.append(multiUpper); +- } +- continue; +- } +- n = tempElement.firstChild(); +- while (!n.isNull()) { +- tempElement = n.toElement(); +- tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.lower"))) { +- m_Multi = tempElement.text(); +- } else if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.upper"))) { +- multiUpper = tempElement.text(); +- } +- n = n.nextSibling(); +- } +- if (!multiUpper.isEmpty()) { +- if (!m_Multi.isEmpty()) +- m_Multi.append(QLatin1String("..")); +- m_Multi.append(multiUpper); +- } +- } else if (m_SecondaryId.isEmpty() && +- (UMLDoc::tagEq(tag, QLatin1String("type")) || +- UMLDoc::tagEq(tag, QLatin1String("participant")))) { +- m_SecondaryId = tempElement.attribute(QLatin1String("xmi.id")); +- if (m_SecondaryId.isEmpty()) +- m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); +- if (m_SecondaryId.isEmpty()) { +- QDomNode inner = tempElement.firstChild(); +- QDomElement innerElem = inner.toElement(); +- m_SecondaryId = innerElem.attribute(QLatin1String("xmi.id")); +- if (m_SecondaryId.isEmpty()) +- m_SecondaryId = innerElem.attribute(QLatin1String("xmi.idref")); +- } +- } +- } +- if (!m_Multi.isEmpty()) +- uDebug() << name() << ": m_Multi is " << m_Multi; +- if (m_SecondaryId.isEmpty()) { +- uError() << name() << ": type not given or illegal"; +- return false; +- } +- UMLObject * obj; +- obj = doc->findObjectById(Uml::ID::fromString(m_SecondaryId)); +- if (obj) { +- m_pSecondary = obj; +- m_SecondaryId = QString(); +- } +- +- // block signals to prevent needless updating +- blockSignals(true); +- // Here comes the handling of the association type. +- // This is open for discussion - I'm pretty sure there are better ways.. +- +- // Yeah, for one, setting the *parent* object parameters from here is sucky +- // as hell. Why are we using roleA to store what is essentially a parent (association) +- // parameter, eh? The UML13.dtd is pretty silly, but since that is what +- // is driving us to that point, we have to go with it. Some analysis of +- // the component roles/linked items needs to be done in order to get things +- // right. *sigh* -b.t. +- +- // Setting association type from the role (A) +- // Determination of the "aggregation" attribute used to be done only +- // when (m_role == Uml::RoleType::A) but some XMI writers (e.g. StarUML) place +- // the aggregation attribute at role B. +- // The role end with the aggregation unequal to "none" wins. +- QString aggregation = element.attribute(QLatin1String("aggregation"), QLatin1String("none")); +- if (aggregation == QLatin1String("composite")) +- m_pAssoc->setAssociationType(Uml::AssociationType::Composition); +- else if (aggregation == QLatin1String("shared") // UML1.3 +- || aggregation == QLatin1String("aggregate")) // UML1.4 +- m_pAssoc->setAssociationType(Uml::AssociationType::Aggregation); +- +- if (!element.hasAttribute(QLatin1String("isNavigable"))) { +- // Backward compatibility mode: In umbrello-kf6 version 1.3.x the +- // logic for saving the isNavigable flag was wrong. +- // May happen on loading role A. +- m_pAssoc->setOldLoadMode(true); +- } else if (m_pAssoc->getOldLoadMode() == true) { +- // Here is the original logic: +- // "Role B: +- // If isNavigable is not given, we make no change to the +- // association type. +- // If isNavigable is given, and is "true", then we assume that +- // the association's other end (role A) is not navigable, and +- // therefore we change the association type to UniAssociation. +- // The case that isNavigable is given as "false" is ignored. +- // Combined with the association type logic for role A, this +- // allows us to support at_Association and at_UniAssociation." +- if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("true")) +- m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); +- } else if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("false")) { +- m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); +- } +- +- //FIXME not standard XMI +- if (element.hasAttribute(QLatin1String("relationship"))) { +- if (element.attribute(QLatin1String("relationship")) == QLatin1String("true")) { +- m_pAssoc->setAssociationType(Uml::AssociationType::Relationship); +- } +- } +- +- if (m_Multi.isEmpty()) +- m_Multi = element.attribute(QLatin1String("multiplicity")); +- +- // Changeability defaults to Changeable if it cant set it here.. +- m_Changeability = Uml::Changeability::Changeable; +- QString changeability = element.attribute(QLatin1String("changeability")); +- if (changeability.isEmpty()) +- element.attribute(QLatin1String("changeable")); // for backward compatibility +- if (changeability == QLatin1String("frozen")) +- m_Changeability = Uml::Changeability::Frozen; +- else if (changeability == QLatin1String("addOnly")) +- m_Changeability = Uml::Changeability::AddOnly; +- +- // finished config, now unblock +- blockSignals(false); +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlrole.h umbrello-kf6-15.08.1/umbrello/umlrole.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlrole.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlrole.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,65 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLROLE_H +-#define UMLROLE_H +- +-#include "umlobject.h" +- +-class UMLAssociation; +- +-/** +- * This class contains the non-graphic representation of an association role. +- * +- * @author Brian Thomas +- * @see UMLObject +- */ +-class UMLRole : public UMLObject +-{ +- Q_OBJECT +-public: +- +- UMLRole(UMLAssociation * parent, UMLObject * parentUMLObject, Uml::RoleType::Enum role); +- virtual ~UMLRole(); +- +- bool operator==(const UMLRole & rhs) const; +- +- void setObject(UMLObject *obj); +- UMLObject* object() const; +- +- void setChangeability(Uml::Changeability::Enum value); +- Uml::Changeability::Enum changeability() const; +- +- void setMultiplicity(const QString &multi); +- QString multiplicity() const; +- +- UMLAssociation * parentAssociation() const; +- +- Uml::RoleType::Enum role() const; +- +- UMLObject* clone() const { return NULL; } +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual bool showPropertiesDialog(QWidget *parent = 0); +- +-protected: +- +- bool load(QDomElement& element); +- +-private: +- +- UMLAssociation * m_pAssoc; +- Uml::RoleType::Enum m_role; +- QString m_Multi; +- Uml::Changeability::Enum m_Changeability; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlstereotypelist.h umbrello-kf6-15.08.1/umbrello/umlstereotypelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlstereotypelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umlstereotypelist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,22 +0,0 @@ +-/*************************************************************************** +- * 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-2012 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLSTEREOTYPELIST_H +-#define UMLSTEREOTYPELIST_H +- +-#include +- +-// forward declaration +-class UMLStereotype; +- +-typedef QList UMLStereotypeList; +-typedef QListIterator UMLStereotypeListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umltemplatelist.h umbrello-kf6-15.08.1/umbrello/umltemplatelist.h +--- umbrello-kf6-15.08.1.orig/umbrello/umltemplatelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/umltemplatelist.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,23 +0,0 @@ +-/*************************************************************************** +- * * +- * 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-2007 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLTEMPLATELIST_H +-#define UMLTEMPLATELIST_H +- +-#include +- +-// forward declaration +-class UMLTemplate; +- +-typedef QList UMLTemplateList; +-typedef QListIterator UMLTemplateListIt; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,457 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "activitywidget.h" ++ ++// app includes ++#include "activitydialog.h" ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "listpopupmenu.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#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. ++ */ ++void ActivityWidget::showPropertiesDialog() ++{ ++ 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); ++ } ++ delete dialog; ++} ++ ++/** ++ * 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::loadFromXMI(QDomElement& qElement) ++{ ++ if(!UMLWidget::loadFromXMI(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::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement activityElement = qDoc.createElement(QLatin1String("activitywidget")); ++ UMLWidget::saveToXMI(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: ++ { ++ bool ok = false; ++ QString n = name(); ++#if QT_VERSION >= 0x050000 ++ n = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter Activity Name"), ++ i18n("Enter the name of the new activity:"), ++ QLineEdit::Normal, ++ n, &ok); ++#else ++ n = KInputDialog::getText(i18n("Enter Activity Name"), ++ i18n("Enter the name of the new activity:"), ++ n, &ok); ++#endif ++ 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,98 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ACTIVITYWIDGET_H ++#define ACTIVITYWIDGET_H ++ ++#include "umlwidget.h" ++#include "worktoolbar.h" ++ ++#define ACTIVITY_MARGIN 5 ++#define ACTIVITY_WIDTH 30 ++#define ACTIVITY_HEIGHT 10 ++ ++/** ++ * This class is the graphical version of a UML Activity. A ActivityWidget is created ++ * by a @ref UMLView. An ActivityWidget belongs to only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. ++ * ++ * The ActivityWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @short A graphical version of a UML Activity. ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ActivityWidget : public UMLWidget ++{ ++ Q_OBJECT ++ Q_ENUMS(ActivityType) ++public: ++ enum ActivityType ++ { ++ Initial = 0, ++ Normal, ++ End, ++ Final, ++ Branch, ++ Invok, ++ Param ++ }; ++ ++ explicit ActivityWidget(UMLScene * scene, ActivityType activityType = Normal, Uml::ID::Type id = Uml::ID::None); ++ virtual ~ActivityWidget(); ++ ++ ActivityType activityType() const; ++ QString activityTypeStr() const; ++ void setActivityType(ActivityType activityType); ++ ++ static bool isActivity(WorkToolBar::ToolBar_Buttons tbb, ++ ActivityType& resultType); ++ ++ QString preconditionText() const; ++ void setPreconditionText(const QString&); ++ ++ QString postconditionText() const; ++ void setPostconditionText(const QString&); ++ ++ virtual void showPropertiesDialog(); ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ virtual void moveWidgetBy(qreal diffX, qreal diffY); ++ ++ virtual bool loadFromXMI(QDomElement & qElement); ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ void constrain(qreal& width, qreal& height); ++ ++signals: ++ /** ++ * Emitted when the activity widget is moved. ++ * Provides the delta X and delta Y amount by which the widget was moved ++ * relative to the previous position. ++ * Slots into PinWidget::slotActMoved() ++ * @param diffX The difference between previous and new X value. ++ * @param diffY The difference between previous and new Y value. ++ */ ++ void sigActMoved(qreal diffX, qreal diffY); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++protected: ++ virtual QSizeF minimumSize() const; ++ virtual QSizeF maximumSize(); ++ ++ ActivityType m_activityType; ///< Type of activity. ++ ++ QString m_preconditionText; ++ QString m_postconditionText; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,104 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header file ++#include "actorwidget.h" ++ ++// local includes ++#include "actor.h" ++#include "umlview.h" ++ ++/** ++ * Constructs an ActorWidget. ++ * ++ * @param scene The parent of this ActorWidget. ++ * @param a The Actor class this ActorWidget will display. ++ */ ++ActorWidget::ActorWidget(UMLScene * scene, UMLActor *a) ++ : UMLWidget(scene, WidgetBase::wt_Actor, a) ++{ ++ setFixedAspectRatio(true); ++} ++ ++/** ++ * Destructor. ++ */ ++ActorWidget::~ActorWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void ActorWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ UMLWidget::setPenFromSettings(painter); ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ const int w = width(); ++ const int h = height(); ++ painter->setFont(UMLWidget::font()); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); ++ const int a_height = h - (drawStereotype ? 2 * fontHeight : fontHeight) - A_MARGIN; ++ const int h2 = a_height / 2; ++ const int a_width = (h2); ++ const int middleX = w / 2; ++ const int thirdY = a_height / 3; ++ ++ //draw actor ++ painter->drawEllipse(middleX - a_width / 2, 0, a_width, thirdY); //head ++ painter->drawLine(middleX, thirdY, ++ middleX, thirdY * 2); //body ++ painter->drawLine(middleX, 2 * thirdY, ++ middleX - a_width / 2, a_height); //left leg ++ painter->drawLine(middleX, 2 * thirdY, ++ middleX + a_width / 2, a_height); //right leg ++ painter->drawLine(middleX - a_width / 2, thirdY + thirdY / 2, ++ middleX + a_width / 2, thirdY + thirdY / 2); //arms ++ //draw text ++ painter->setPen(textColor()); ++ if (drawStereotype) ++ painter->drawText(A_MARGIN, h - 2 * fontHeight, w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); ++ painter->drawText(A_MARGIN, h - fontHeight, ++ w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Saves the widget to the "actorwidget" XMI element. ++ * Note: For loading from XMI, the inherited parent method is used. ++ */ ++void ActorWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement actorElement = qDoc.createElement(QLatin1String("actorwidget")); ++ UMLWidget::saveToXMI(qDoc, actorElement); ++ qElement.appendChild(actorElement); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF ActorWidget::minimumSize() const ++{ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int textWidth = fm.width(name()); ++ bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); ++ int width = textWidth > A_WIDTH ? textWidth : A_WIDTH; ++ int height = A_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + A_MARGIN; ++ width += A_MARGIN * 2; ++ return QSizeF(width, height); ++} ++ ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,55 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ACTORWIDGET_H ++#define ACTORWIDGET_H ++ ++#include "umlwidget.h" ++ ++#define A_WIDTH 20 ++#define A_HEIGHT 40 ++#define A_MARGIN 5 ++ ++class UMLActor; ++ ++/** ++ * This class is the graphical version of a UML Actor. ++ * An ActorWidget is created by a @ref UMLView. An ActorWidget belongs to only ++ * one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to is destroyed, the ++ * ActorWidget will be automatically deleted. ++ * ++ * If the UMLActor class that this ActorWidget is displaying is deleted, the ++ * @ref UMLView will make sure that this instance is also deleted. ++ * ++ * The ActorWidget class inherits from the @ref UMLWidget class ++ * which adds most of the functionality to this class. ++ * ++ * @short A graphical version of a UML Actor. ++ * @author Paul Hensgen ++ * @see UMLWidget ++ * @see UMLView ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ActorWidget : public UMLWidget ++{ ++public: ++ ActorWidget(UMLScene * scene, UMLActor *o); ++ virtual ~ActorWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,293 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "artifactwidget.h" ++ ++// app includes ++#include "artifact.h" ++#include "debug_utils.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++/** ++ * Constructs a ArtifactWidget. ++ * ++ * @param scene The parent of this ArtifactWidget. ++ * @param a The Artifact this widget will be representing. ++ */ ++ArtifactWidget::ArtifactWidget(UMLScene *scene, UMLArtifact *a) ++ : UMLWidget(scene, WidgetBase::wt_Artifact, a) ++{ ++ setSize(100, 30); ++} ++ ++/** ++ * Destructor. ++ */ ++ArtifactWidget::~ArtifactWidget() ++{ ++} ++ ++/** ++ * Reimplemented to paint the articraft widget. Some part of specific ++ * drawing is delegeted to private method like drawAsFile.. ++ */ ++void ArtifactWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ UMLWidget::setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } else { ++ painter->setBrush(m_scene->backgroundColor()); ++ } ++ ++ if (umlObject()) { ++ UMLArtifact *umlart = static_cast(m_umlObject); ++ UMLArtifact::Draw_Type drawType = umlart->getDrawAsType(); ++ switch (drawType) { ++ case UMLArtifact::defaultDraw: ++ paintAsNormal(painter, option); ++ break; ++ case UMLArtifact::file: ++ paintAsFile(painter, option); ++ break; ++ case UMLArtifact::library: ++ paintAsLibrary(painter, option); ++ break; ++ case UMLArtifact::table: ++ paintAsTable(painter, option); ++ break; ++ default: ++ uWarning() << "Artifact drawn as unknown type"; ++ break; ++ } ++ } ++ else { ++ uWarning() << "Cannot draw as there is no UMLArtifact for this widget."; ++ } ++} ++ ++/** ++ * Reimplemented from WidgetBase::saveToXMI to save the widget to ++ * the "artifactwidget" XMI element. ++ */ ++void ArtifactWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("artifactwidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF ArtifactWidget::minimumSize() const ++{ ++ if (!m_umlObject) { ++ return UMLWidget::minimumSize(); ++ } ++ UMLArtifact *umlart = static_cast(m_umlObject); ++ if (umlart->getDrawAsType() == UMLArtifact::defaultDraw) { ++ return calculateNormalSize(); ++ } else { ++ return calculateIconSize(); ++ } ++} ++ ++/** ++ * calculates the size when drawing as an icon (it's the same size for all icons) ++ */ ++QSize ArtifactWidget::calculateIconSize() const ++{ ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); ++ const int fontHeight = fm.lineSpacing(); ++ ++ int width = fm.width(m_umlObject->name()); ++ ++ width = width<50 ? 50 : width; ++ ++ int height = 50 + fontHeight; ++ ++ return QSize(width, height); ++} ++ ++/** ++ * calculates the size for drawing as a box ++ */ ++QSize ArtifactWidget::calculateNormalSize() const ++{ ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); ++ const int fontHeight = fm.lineSpacing(); ++ ++ int width = fm.width(m_umlObject->name()); ++ ++ int tempWidth = 0; ++ if(!m_umlObject->stereotype().isEmpty()) { ++ tempWidth = fm.width(m_umlObject->stereotype(true)); ++ } ++ width = tempWidth>width ? tempWidth : width; ++ width += ARTIFACT_MARGIN * 2; ++ ++ int height = (2*fontHeight) + (ARTIFACT_MARGIN * 2); ++ ++ return QSize(width, height); ++} ++ ++/** ++ * draw as a file icon ++ */ ++void ArtifactWidget::paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ const int w = width(); ++ const int h = height(); ++ QFont font = UMLWidget::font(); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ ++ int startX = (w/2) - 25; ++ int iconHeight = h - fontHeight; ++ QPolygon pointArray(5); ++ pointArray.setPoint(0, startX, 0); ++ pointArray.setPoint(1, startX + 40, 0); ++ pointArray.setPoint(2, startX + 50, 10); ++ pointArray.setPoint(3, startX + 50, iconHeight); ++ pointArray.setPoint(4, startX, iconHeight); ++ painter->drawPolygon(pointArray); ++ ++ painter->drawLine(startX + 40, 0, startX + 40, 10); ++ painter->drawLine(startX + 40, 10, startX + 50, 10); ++ painter->drawLine(startX + 40, 0, startX + 50, 10); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ painter->drawText(0, h - fontHeight, ++ w, fontHeight, Qt::AlignCenter, name()); ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * draw as a library file icon ++ */ ++void ArtifactWidget::paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ //FIXME this should have gears on it ++ const int w = width(); ++ const int h = height(); ++ const QFont font = UMLWidget::font(); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ ++ const int startX = (w/2) - 25; ++ const int iconHeight = h - fontHeight; ++ QPolygon pointArray(5); ++ pointArray.setPoint(0, startX, 0); ++ pointArray.setPoint(1, startX + 40, 0); ++ pointArray.setPoint(2, startX + 50, 10); ++ pointArray.setPoint(3, startX + 50, iconHeight); ++ pointArray.setPoint(4, startX, iconHeight); ++ painter->drawPolygon(pointArray); ++ ++ painter->drawLine(startX + 40, 0, startX + 40, 10); ++ painter->drawLine(startX + 40, 10, startX + 50, 10); ++ painter->drawLine(startX + 40, 0, startX + 50, 10); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ painter->drawText(0, h - fontHeight, ++ w, fontHeight, Qt::AlignCenter, name()); ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * draw as a database table icon ++ */ ++void ArtifactWidget::paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ const int w = width(); ++ const int h = height(); ++ const QFont font = UMLWidget::font(); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ ++ const int startX = (w/2) - 25; ++ const int iconHeight = h - fontHeight; ++ ++ painter->drawRect(startX, 0, 50, h - fontHeight + 1); ++ painter->drawLine(startX + 20, 0, startX + 20, iconHeight); ++ painter->drawLine(startX + 30, 0, startX + 30, iconHeight); ++ painter->drawLine(startX + 40, 0, startX + 40, iconHeight); ++ painter->drawLine(startX, (iconHeight/2), startX + 49, (iconHeight/2)); ++ painter->drawLine(startX, (iconHeight/2) + (iconHeight/4), ++ startX + 49, (iconHeight/2) + (iconHeight/4)); ++ ++ QPen thickerPen = painter->pen(); ++ thickerPen.setWidth(2); ++ painter->setPen(thickerPen); ++ painter->drawLine(startX + 10, 0, startX + 10, iconHeight); ++ painter->drawLine(startX, (iconHeight/4), startX + 50, (iconHeight/4)); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ painter->drawText(0, h - fontHeight, ++ w, fontHeight, Qt::AlignCenter, name()); ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * draw as a box ++ */ ++void ArtifactWidget::paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ int w = width(); ++ int h = height(); ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ QString stereotype = m_umlObject->stereotype(); ++ ++ painter->drawRect(0, 0, w, h); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ if (!stereotype.isEmpty()) { ++ painter->drawText(ARTIFACT_MARGIN, (h/2) - fontHeight, ++ w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); ++ } ++ ++ int lines; ++ if (!stereotype.isEmpty()) { ++ lines = 2; ++ } else { ++ lines = 1; ++ } ++ ++ if (lines == 1) { ++ painter->drawText(0, (h/2) - (fontHeight/2), ++ w, fontHeight, Qt::AlignCenter, name()); ++ } else { ++ painter->drawText(0, (h/2), ++ w, fontHeight, Qt::AlignCenter, name()); ++ } ++ ++ UMLWidget::paint(painter, option); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,55 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ARTIFACTWIDGET_H ++#define ARTIFACTWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLScene; ++class UMLArtifact; ++ ++#define ARTIFACT_MARGIN 5 ++ ++/** ++ * Defines a graphical version of the @ref UMLArtifact. ++ * Most of the functionality will come from the @ref UMLWidget class. ++ * ++ * @short A graphical version of a Artifact. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ArtifactWidget : public UMLWidget ++{ ++public: ++ ArtifactWidget(UMLScene *scene, UMLArtifact *a); ++ virtual ~ArtifactWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ // Note: For loading from XMI, the inherited parent method is used. ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++private: ++ void paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ ++ QSize calculateIconSize() const; ++ QSize calculateNormalSize() const; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,1404 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "associationline.h" ++ ++// application includes ++#include "associationwidget.h" ++#include "debug_utils.h" ++#include "umlwidget.h" ++ ++// qt includes ++#include ++#include ++ ++// system includes ++#include ++#include ++ ++DEBUG_REGISTER_DISABLED(AssociationLine) ++ ++// Initialize static variables. ++const qreal AssociationLine::Delta = 5; ++const qreal AssociationLine::SelectedPointDiameter = 4; ++const qreal AssociationLine::SelfAssociationMinimumHeight = 30; ++ ++/** ++ * Constructor. ++ * Constructs an AssociationLine item with its parent being \a parent. ++ */ ++AssociationLine::AssociationLine(AssociationWidget *association) ++ : QGraphicsObject(association), ++ m_associationWidget(association), ++ m_activePointIndex(-1), ++ m_activeSegmentIndex(-1), ++ m_startSymbol(0), ++ m_endSymbol(0), ++ m_subsetSymbol(0), ++ m_collaborationLineItem(0), ++ m_collaborationLineHead(0), ++ m_layout(Polyline) ++{ ++ Q_ASSERT(association); ++ setFlag(QGraphicsLineItem::ItemIsSelectable); ++ setAcceptHoverEvents(true); ++ setZValue(3); ++} ++ ++/** ++ * Destructor. ++ */ ++AssociationLine::~AssociationLine() ++{ ++} ++ ++/** ++ * Returns the point at the point index. ++ * @return point at given index ++ */ ++QPointF AssociationLine::point(int index) const ++{ ++ if ((index < 0) | (index >= m_points.size())) { ++ uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; ++ return QPointF(-1.0, -1.0); ++ } ++ return m_points.at(index); ++} ++ ++/** ++ * Sets the point value at given index to \a point. ++ */ ++bool AssociationLine::setPoint(int index, const QPointF &point) ++{ ++ if ((index < 0) | (index >= m_points.size())) { ++ uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; ++ return false; ++ } ++ if (m_points.at(index) == point) { ++ return false; // nothing to change ++ } ++ prepareGeometryChange(); ++ m_points[index] = point; ++ alignSymbols(); ++ return true; ++} ++ ++/** ++ * Shortcut for point(0). ++ */ ++QPointF AssociationLine::startPoint() const ++{ ++ return m_points.at(0); ++} ++ ++/** ++ * Shortcut for end point. ++ */ ++QPointF AssociationLine::endPoint() const ++{ ++ return m_points.at(m_points.size()-1); ++} ++ ++/** ++ * Inserts the passed in \a point at the \a index passed in and ++ * recalculates the bounding rect. ++ */ ++void AssociationLine::insertPoint(int index, const QPointF &point) ++{ ++ prepareGeometryChange(); ++ m_points.insert(index, point); ++ alignSymbols(); ++} ++ ++/** ++ * Removes the point at \a index passed in. ++ * @see removeNonEndPoint ++ */ ++void AssociationLine::removePoint(int index) ++{ ++ prepareGeometryChange(); ++ m_points.remove(index); ++ alignSymbols(); ++} ++ ++/** ++ * Returns the amount of POINTS on the line. ++ * Includes start and end points. ++ * @return number of points in the AssociationLine ++ */ ++int AssociationLine::count() const ++{ ++ return m_points.size(); ++} ++ ++/** ++ * Removes all the points and signals a geometry update. ++ */ ++void AssociationLine::cleanup() ++{ ++ if (!m_points.isEmpty()) { ++ prepareGeometryChange(); ++ m_points.clear(); ++ alignSymbols(); ++ } ++} ++ ++/** ++ * This method optimizes the number of points in the ++ * AssociationLine. This can be used to reduce the clutter caused ++ * due to too many points. ++ * TODO: Use delta comparison 'closestPointIndex' instead of exact comparison. ++ * TODO: Not used anywhere. ++ */ ++void AssociationLine::optimizeLinePoints() ++{ ++ int i = 1; ++ prepareGeometryChange(); ++ while (i < m_points.size()) { ++ if (m_points.at(i) == m_points.at(i-1)) { ++ m_points.remove(i); ++ } ++ else { ++ ++i; ++ } ++ } ++ alignSymbols(); ++} ++ ++/** ++ * Return index of point closer a given delta. ++ * ++ * @param point The point which is to be tested for closeness. ++ * @param delta The distance the point should be closer to. ++ * ++ * @retval "Index" of the first line point closer to the \a point passed. ++ * @retval -1 If no line point is closer to passed in \a point. ++ */ ++int AssociationLine::closestPointIndex(const QPointF &point, qreal delta) const ++{ ++ for(int i = 0; i < m_points.size(); ++i) { ++ const QPointF& linePoint = m_points.at(i); ++ // Apply distance formula to see point closeness. ++ qreal deltaXSquare = (point.x() - linePoint.x()) * (point.x() - linePoint.x()); ++ qreal deltaYSquare = (point.y() - linePoint.y()) * (point.y() - linePoint.y()); ++ ++ qreal lhs = deltaXSquare + deltaYSquare; ++ qreal rhs = delta * delta; ++ ++ if (lhs <= rhs) { ++ return i; ++ } ++ } ++ return -1; ++} ++ ++/** ++ * Return index of closest segment. ++ * ++ * @param point The point which is to be tested for closeness. ++ * ++ * @return Index of the line segment closest to the \a point passed; ++ * -1 if no line segment is closer to passed in \a point. ++ */ ++int AssociationLine::closestSegmentIndex(const QPointF &point, qreal delta) const ++{ ++ QPainterPathStroker stroker; ++ stroker.setWidth(delta); ++ ++ for(int i = 1; i < m_points.size(); ++i) { ++ QLineF segment(m_points[i-1], m_points[i]); ++ ++ QPainterPath path; ++ path.moveTo(segment.p1()); ++ path.lineTo(segment.p2()); ++ ++ path = stroker.createStroke(path); ++ ++ if (path.contains(point)) { ++ return i-1; ++ } ++ } ++ return -1; ++} ++ ++/** ++ * Retval True If point at \a index is start or end. ++ */ ++bool AssociationLine::isEndPointIndex(int index) const ++{ ++ const int size = m_points.size(); ++ Q_ASSERT(index >= 0 && index < size); ++ ++ return (index == 0 || index == (size - 1)); ++} ++ ++/** ++ * Retval True If segment at \a index is start or end. ++ */ ++bool AssociationLine::isEndSegmentIndex(int index) const ++{ ++ // num of seg = num of points - 1 ++ const int size = m_points.size() - 1; ++ Q_ASSERT(index >= 0 && index < size); ++ ++ return (index == 0 || index == (size - 1)); ++} ++ ++/** ++ * Sets the start and end points. ++ */ ++bool AssociationLine::setEndPoints(const QPointF &start, const QPointF &end) ++{ ++ const int size = m_points.size(); ++ ++ prepareGeometryChange(); ++ ++ if (size == 0) { ++ m_points.insert(0, start); ++ m_points.insert(1, end); ++ } ++ else if (size == 1) { ++ m_points[0] = start; ++ m_points.insert(1, end); ++ } ++ else { ++ m_points[0] = start; ++ m_points[size-1] = end; ++ } ++ ++ alignSymbols(); ++ return true; ++} ++ ++/** ++ * Debug helper method to write out the points. ++ */ ++void AssociationLine::dumpPoints() ++{ ++ for (int i = 1; i < m_points.size(); ++i) { ++ QPointF p = m_points.at(i); ++ DEBUG(DBG_SRC) << i << ". point x:" << p.x() << " / y:" << p.y(); ++ } ++} ++ ++/** ++ * Loads AssociationLine information saved in \a qElement XMI element. ++ */ ++bool AssociationLine::loadFromXMI(QDomElement &qElement) ++{ ++ QString layout = qElement.attribute(QLatin1String("layout"), QLatin1String("polyline")); ++ m_layout = fromString(layout); ++ ++ QDomNode node = qElement.firstChild(); ++ ++ m_points.clear(); ++ ++ QDomElement startElement = node.toElement(); ++ if(startElement.isNull() || startElement.tagName() != QLatin1String("startpoint")) { ++ return false; ++ } ++ QString x = startElement.attribute(QLatin1String("startx"), QLatin1String("0")); ++ qreal nX = x.toFloat(); ++ QString y = startElement.attribute(QLatin1String("starty"), QLatin1String("0")); ++ qreal nY = y.toFloat(); ++ QPointF startPoint(nX, nY); ++ ++ node = startElement.nextSibling(); ++ QDomElement endElement = node.toElement(); ++ if(endElement.isNull() || endElement.tagName() != QLatin1String("endpoint")) { ++ return false; ++ } ++ x = endElement.attribute(QLatin1String("endx"), QLatin1String("0")); ++ nX = x.toFloat(); ++ y = endElement.attribute(QLatin1String("endy"), QLatin1String("0")); ++ nY = y.toFloat(); ++ QPointF endPoint(nX, nY); ++ setEndPoints(startPoint, endPoint); ++ QPointF point; ++ node = endElement.nextSibling(); ++ QDomElement element = node.toElement(); ++ int i = 1; ++ while(!element.isNull()) { ++ if(element.tagName() == QLatin1String("point")) { ++ x = element.attribute(QLatin1String("x"), QLatin1String("0")); ++ y = element.attribute(QLatin1String("y"), QLatin1String("0")); ++ point.setX(x.toFloat()); ++ point.setY(y.toFloat()); ++ insertPoint(i++, point); ++ } ++ node = element.nextSibling(); ++ element = node.toElement(); ++ } ++ ++ return true; ++} ++ ++/** ++ * Saves association line information into XMI element named "linepath". ++ * @note Stored as linepath for backwared compatibility ++ */ ++void AssociationLine::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) ++{ ++ QPointF point = m_associationWidget->mapToScene(startPoint()); ++ QDomElement lineElement = qDoc.createElement(QLatin1String("linepath")); ++ lineElement.setAttribute(QLatin1String("layout"), toString(m_layout)); ++ QDomElement startElement = qDoc.createElement(QLatin1String("startpoint")); ++ startElement.setAttribute(QLatin1String("startx"), point.x()); ++ startElement.setAttribute(QLatin1String("starty"), point.y()); ++ lineElement.appendChild(startElement); ++ QDomElement endElement = qDoc.createElement(QLatin1String("endpoint")); ++ point = m_associationWidget->mapToScene(endPoint()); ++ endElement.setAttribute(QLatin1String("endx"), point.x()); ++ endElement.setAttribute(QLatin1String("endy"), point.y()); ++ lineElement.appendChild(endElement); ++ for(int i = 1; i < count()-1; ++i) { ++ QDomElement pointElement = qDoc.createElement(QLatin1String("point")); ++ point = m_associationWidget->mapToScene(this->point(i)); ++ pointElement.setAttribute(QLatin1String("x"), point.x()); ++ pointElement.setAttribute(QLatin1String("y"), point.y()); ++ lineElement.appendChild(pointElement); ++ } ++ qElement.appendChild(lineElement); ++} ++ ++/** ++ * Returns the type of brush to use depending on the type of Association. ++ */ ++QBrush AssociationLine::brush() const ++{ ++ QBrush brush(Qt::solid-kf6Pattern); ++ Uml::AssociationType::Enum type = m_associationWidget->associationType(); ++ if (type == Uml::AssociationType::Aggregation || ++ type == Uml::AssociationType::Generalization || ++ type == Uml::AssociationType::Realization) { ++ brush.setColor(Qt::white); ++ } ++ if (type == Uml::AssociationType::Composition) { ++ brush.setColor(m_associationWidget->lineColor()); ++ } ++ return brush; ++} ++ ++/** ++ * Returns the type of pen to use depending on the type of Association. ++ */ ++QPen AssociationLine::pen() const ++{ ++ QPen pen(m_associationWidget->lineColor(), ++ m_associationWidget->lineWidth(), ++ Qt::solid-kf6Line, ++ Qt::RoundCap, ++ Qt::RoundJoin); ++ Uml::AssociationType::Enum type = m_associationWidget->associationType(); ++ if (type == Uml::AssociationType::Dependency || ++ type == Uml::AssociationType::Realization || ++ type == Uml::AssociationType::Anchor) { ++ pen.setStyle(Qt::DashLine); ++ } ++ return pen; ++} ++ ++/** ++ * This method simply ensures presence of two points and ++ * adds the needed points for self associations. ++ */ ++void AssociationLine::calculateInitialEndPoints() ++{ ++ if (m_associationWidget->isSelf() && count() < 4) { ++ for (int i = count(); i < 4; ++i) { ++ insertPoint(i, QPointF()); ++ } ++ UMLWidget *wid = m_associationWidget->widgetForRole(Uml::RoleType::B); ++ if (!wid) { ++ uError() << "AssociationWidget is partially constructed." ++ "UMLWidget for role B is null."; ++ return; ++ } ++ const QRectF rect = m_associationWidget->mapFromScene( ++ mapToScene(wid->rect()).boundingRect()).boundingRect(); ++ ++ qreal l = rect.left() + .25 * rect.width(); ++ qreal r = rect.left() + .75 * rect.width(); ++ bool drawAbove = rect.top() >= SelfAssociationMinimumHeight; ++ qreal y = drawAbove ? rect.top() : rect.bottom(); ++ qreal yOffset = SelfAssociationMinimumHeight; ++ if (drawAbove) { ++ yOffset *= -1.0; ++ } ++ ++ setPoint(0, QPointF(l, y)); ++ setPoint(1, QPointF(l, y + yOffset)); ++ setPoint(2, QPointF(r, y + yOffset)); ++ setPoint(3, QPointF(r, y)); ++ } else if (!m_associationWidget->isSelf() && count() < 2) { ++ setEndPoints(QPointF(), QPointF()); ++ } ++} ++ ++/** ++ * This method creates, deletes symbols and collaboration lines based on ++ * m_associationWidget->associationType(). ++ * ++ * Call this method when associationType of m_associationWidget changes. ++ */ ++void AssociationLine::reconstructSymbols() ++{ ++ switch( m_associationWidget->associationType() ) { ++ case Uml::AssociationType::State: ++ case Uml::AssociationType::Activity: ++ case Uml::AssociationType::Exception: ++ case Uml::AssociationType::UniAssociation: ++ case Uml::AssociationType::Dependency: ++ setStartSymbol(Symbol::None); ++ setEndSymbol(Symbol::OpenArrow); ++ removeSubsetSymbol(); ++ removeCollaborationLine(); ++ break; ++ ++ case Uml::AssociationType::Relationship: ++ setStartSymbol(Symbol::None); ++ setEndSymbol(Symbol::CrowFeet); ++ removeSubsetSymbol(); ++ removeCollaborationLine(); ++ break; ++ ++ case Uml::AssociationType::Generalization: ++ case Uml::AssociationType::Realization: ++ setStartSymbol(Symbol::None); ++ setEndSymbol(Symbol::ClosedArrow); ++ removeSubsetSymbol(); ++ removeCollaborationLine(); ++ break; ++ ++ case Uml::AssociationType::Composition: ++ case Uml::AssociationType::Aggregation: ++ setStartSymbol(Symbol::Diamond); ++ setEndSymbol(Symbol::None); ++ removeSubsetSymbol(); ++ removeCollaborationLine(); ++ break; ++ ++ case Uml::AssociationType::Containment: ++ setStartSymbol(Symbol::Circle); ++ setEndSymbol(Symbol::None); ++ removeSubsetSymbol(); ++ removeCollaborationLine(); ++ break; ++ ++ case Uml::AssociationType::Child2Category: ++ setStartSymbol(Symbol::None); ++ setEndSymbol(Symbol::None); ++ createSubsetSymbol(); ++ removeCollaborationLine(); ++ break; ++ ++ case Uml::AssociationType::Coll_Message_Synchronous: ++ case Uml::AssociationType::Coll_Message_Asynchronous: ++ case Uml::AssociationType::Coll_Message_Self: ++ setStartSymbol(Symbol::None); ++ setEndSymbol(Symbol::None); ++ removeSubsetSymbol(); ++ createCollaborationLine(); ++ break; ++ ++ default: ++ break; ++ } ++ alignSymbols(); ++} ++ ++/** ++ * Sets the Symbol to appear at the first line segment to \a symbol. ++ * ++ * If symbol == Symbol::None , then it deletes the symbol item. ++ */ ++void AssociationLine::setStartSymbol(Symbol::SymbolType symbolType) ++{ ++ Q_ASSERT(symbolType != Symbol::Count); ++ if (symbolType == Symbol::None) { ++ delete m_startSymbol; ++ m_startSymbol = 0; ++ return; ++ } ++ ++ if (m_startSymbol) { ++ m_startSymbol->setSymbolType(symbolType); ++ } ++ else { ++ m_startSymbol = new Symbol(symbolType, m_associationWidget); ++ } ++ m_startSymbol->setPen(pen()); ++ m_startSymbol->setBrush(brush()); ++} ++ ++/** ++ * Sets the Symbol to appear at the last line segment to \a symbol. ++ * ++ * If symbol == Symbol::None , then it deletes the symbol item. ++ */ ++void AssociationLine::setEndSymbol(Symbol::SymbolType symbolType) ++{ ++ Q_ASSERT(symbolType != Symbol::Count); ++ if (symbolType == Symbol::None) { ++ delete m_endSymbol; ++ m_endSymbol = 0; ++ return; ++ } ++ ++ if (m_endSymbol) { ++ m_endSymbol->setSymbolType(symbolType); ++ } ++ else { ++ m_endSymbol = new Symbol(symbolType, m_associationWidget); ++ } ++ m_endSymbol->setPen(pen()); ++ m_endSymbol->setBrush(brush()); ++} ++ ++/** ++ * Constructs a new subset symbol. ++ */ ++void AssociationLine::createSubsetSymbol() ++{ ++ delete m_subsetSymbol; // recreate ++ m_subsetSymbol = new Symbol(Symbol::Subset, m_associationWidget); ++ m_subsetSymbol->setPen(pen()); ++ m_subsetSymbol->setBrush(brush()); ++} ++ ++/** ++ * Removes the subset symbol if it existed by deleting appropriate items. ++ */ ++void AssociationLine::removeSubsetSymbol() ++{ ++ delete m_subsetSymbol; ++ m_subsetSymbol = 0; ++} ++ ++/** ++ * Constructs the open arrow symbol and arrow line, that would represent Collaboration line. ++ */ ++void AssociationLine::createCollaborationLine() ++{ ++ const QPen p = pen(); ++ ++ // recreate ++ delete m_collaborationLineItem; ++ delete m_collaborationLineHead; ++ ++ m_collaborationLineItem = new QGraphicsLineItem(m_associationWidget); ++ m_collaborationLineItem->setPen(p); ++ ++ if (m_associationWidget->associationType() == Uml::AssociationType::Coll_Message_Synchronous) { ++ m_collaborationLineHead = new Symbol(Symbol::ClosedArrow, m_associationWidget); ++ m_collaborationLineHead->setBrush(p.color()); ++ } ++ else ++ m_collaborationLineHead = new Symbol(Symbol::OpenArrow, m_associationWidget); ++ m_collaborationLineHead->setPen(p); ++} ++ ++/** ++ * Removes collaboration line by deleting the head and line item. ++ */ ++void AssociationLine::removeCollaborationLine() ++{ ++ delete m_collaborationLineItem; ++ m_collaborationLineItem = 0; ++ ++ delete m_collaborationLineHead; ++ m_collaborationLineHead = 0; ++} ++ ++/** ++ * This method aligns both the \b "start" and \b "end" symbols to ++ * the current angles of the \b "first" and the \b "last" line ++ * segment respectively. ++ */ ++void AssociationLine::alignSymbols() ++{ ++ const int sz = m_points.size(); ++ if (sz < 2) { ++ // cannot align if there is no line (one line = 2 points) ++ return; ++ } ++ ++ QList polygons = path().toSubpathPolygons(); ++ ++ if (m_startSymbol) { ++ QPolygonF firstLine = polygons.first(); ++ QLineF segment(firstLine.at(1), firstLine.at(0)); ++ m_startSymbol->alignTo(segment); ++ } ++ ++ if (m_endSymbol) { ++ QPolygonF lastLine = polygons.last(); ++ int maxIndex = lastLine.size(); ++ QLineF segment(lastLine.at(maxIndex-2), lastLine.at(maxIndex-1)); ++ m_endSymbol->alignTo(segment); ++ } ++ ++ if (m_subsetSymbol) { ++ QPointF p1 = path().pointAtPercent(0.4); ++ QPointF p2 = path().pointAtPercent(0.5); ++ QLineF segment(p1, p2); ++ m_subsetSymbol->alignTo(segment); ++ } ++ ++ if (m_collaborationLineItem) { ++ const qreal distance = 10; ++ const int midSegmentIndex = (sz - 1) / 2; ++ ++ const QPointF a = m_points.at(midSegmentIndex); ++ const QPointF b = m_points.at(midSegmentIndex + 1); ++ ++ if (a == b) ++ return; ++ ++ const QPointF p1 = (a + b) / 2.0; ++ const QPointF p2 = (p1 + b) / 2.0; ++ ++ // Reversed line as we want normal in opposite direction. ++ QLineF segment(p2, p1); ++ QLineF normal = segment.normalVector().unitVector(); ++ normal.setLength(distance); ++ ++ QLineF actualLine; ++ actualLine.setP2(normal.p2()); ++ ++ normal.translate(p1 - p2); ++ actualLine.setP1(normal.p2()); ++ ++ m_collaborationLineItem->setLine(actualLine); ++ m_collaborationLineHead->alignTo(actualLine); ++ } ++} ++ ++/** ++ * @return The path of the AssociationLine. ++ */ ++QPainterPath AssociationLine::path() const ++{ ++ if (m_points.count() > 0) { ++ QPainterPath path; ++ switch (m_layout) { ++ case Direct: ++ path.moveTo(m_points.first()); ++ path.lineTo(m_points.last()); ++ break; ++ ++ case Spline: ++ path = createBezierCurve(m_points); ++ break; ++ ++ case Orthogonal: ++ path = createOrthogonalPath(m_points); ++ break; ++ ++ case Polyline: ++ default: ++ QPolygonF polygon(m_points); ++ path.addPolygon(polygon); ++ break; ++ } ++ return path; ++ } ++ else { ++ return QPainterPath(); ++ } ++} ++ ++/** ++ * The points are used for the bounding rect. The reason is, ++ * that for splines the control points are further away from the path. ++ * @return The bounding rectangle for the AssociationLine. ++ */ ++QRectF AssociationLine::boundingRect() const ++{ ++ QPolygonF polygon(m_points); ++ QRectF rect = polygon.boundingRect(); ++ const qreal margin(5.0); ++ rect.adjust(-margin, -margin, margin, margin); ++ return rect; ++} ++ ++/** ++ * @return The shape of the AssociationLine. ++ */ ++QPainterPath AssociationLine::shape() const ++{ ++ QPainterPathStroker stroker; ++ stroker.setWidth(qMax(2*SelectedPointDiameter, pen().widthF()) + 2.0); // allow delta region ++ stroker.setCapStyle(Qt::FlatCap); ++ return stroker.createStroke(path()); ++} ++ ++/** ++ * Convert enum LayoutType to string. ++ */ ++QString AssociationLine::toString(LayoutType layout) ++{ ++ return QLatin1String(ENUM_NAME(AssociationLine, LayoutType, layout)); ++} ++ ++/** ++ * Convert string to enum LayoutType. ++ */ ++AssociationLine::LayoutType AssociationLine::fromString(const QString &layout) ++{ ++ if (layout == QLatin1String("Direct")) ++ return Direct; ++ if (layout == QLatin1String("Spline")) ++ return Spline; ++ if (layout == QLatin1String("Orthogonal")) ++ return Orthogonal; ++ return Polyline; ++} ++ ++/** ++ * Return the layout type of the association line. ++ * @return the currently used layout ++ */ ++AssociationLine::LayoutType AssociationLine::layout() const ++{ ++ return m_layout; ++} ++ ++/** ++ * Set the layout type of the association line. ++ * @param layout the desired layout to set ++ */ ++void AssociationLine::setLayout(LayoutType layout) ++{ ++ prepareGeometryChange(); ++ m_layout = layout; ++ DEBUG(DBG_SRC) << "new layout = " << toString(m_layout); ++ if (m_layout == Spline) { ++ createSplinePoints(); ++ } ++ alignSymbols(); ++} ++ ++/** ++ * For a cubic Bezier curve at least four points are needed. ++ * If there are less, the missing points will be created. ++ * Note: Implementation is only for two points. ++ */ ++void AssociationLine::createSplinePoints() ++{ ++ if (m_points.size() == 2) { // create two points ++ QPointF p1 = m_points.first(); // start point ++ QPointF p2 = m_points.last(); // end point ++ qreal dx = p2.x() - p1.x(); ++ qreal dy = p2.y() - p1.y(); ++ qreal oneThirdX = 0.33 * dx; ++ qreal oneThirdY = 0.33 * dy; ++ QPointF c1(p1.x() + oneThirdX, // control point 1 ++ p1.y() - oneThirdY); ++ QPointF c2(p2.x() - oneThirdX, // control point 2 ++ p2.y() + oneThirdY); ++ insertPoint(1, c1); ++ insertPoint(2, c2); ++ } ++ if (m_points.size() == 3) { // create one point ++ // insertPoint(1 or 2, ); ++ // Note: For now we use a quadratic Bezier curve in createBezierCurve(...). ++ } ++} ++ ++/** ++ * Returns a Bézier path from given points. ++ * @param points points which define the Bézier curve ++ * @return cubic Bézier spline ++ */ ++QPainterPath AssociationLine::createBezierCurve(QVector points) ++{ ++ QPainterPath path; ++ if (points.size() > 3) { // cubic Bezier curve(s) ++ path.moveTo(points.at(0)); ++ int i = 1; ++ while (i + 2 < points.size()) { ++ path.cubicTo(points.at(i), points.at(i+1), points.at(i+2)); ++ i += 3; ++ } ++ while (i < points.size()) { // draw a line if points are not modulo 3 ++ path.lineTo(points.at(i)); ++ ++i; ++ } ++ } ++ else { ++ if (points.size() == 3) { // quadratic Bezier curve ++ path.moveTo(points.at(0)); ++ path.quadTo(points.at(1), points.at(2)); ++ } ++ else { // should not be reached ++ QPolygonF polygon(points); ++ path.addPolygon(polygon); ++ } ++ } ++ return path; ++} ++ ++/** ++ * Returns an orthogonal path constructed of vertical and horizontal segments ++ * through the given points. ++ * @param points base points for the path ++ * @return orthogonal path ++ */ ++QPainterPath AssociationLine::createOrthogonalPath(QVector points) ++{ ++ QPainterPath path; ++ if (points.size() > 1) { ++ QPointF start = points.first(); ++ QPointF end = points.last(); ++ qreal deltaX = fabs(start.x() - end.x()); ++ qreal deltaY = fabs(start.y() - end.y()); ++ // DEBUG("AssociationLine") << "start=" << start << " / end=" << end ++ // << " / deltaX=" << deltaX << " / deltaY=" << deltaY; ++ QVector vector; ++ for (int i = 0; i < points.size() - 1; ++i) { ++ QPointF curr = points.at(i); ++ QPointF next = points.at(i+1); ++ QPointF center = (next + curr)/2.0; ++ ++ vector.append(curr); ++ if (deltaX < deltaY) { ++ // go vertical first ++ vector.append(QPointF(curr.x(), center.y())); ++ vector.append(QPointF(next.x(), center.y())); ++ } ++ else { ++ // go horizontal first ++ vector.append(QPointF(center.x(), curr.y())); ++ vector.append(QPointF(center.x(), next.y())); ++ } ++ vector.append(next); ++ } ++ ++ QPolygonF rectLine(vector); ++ path.addPolygon(rectLine); ++ } ++ else { ++ QPolygonF polygon(points); ++ path.addPolygon(polygon); ++ } ++ return path; ++} ++ ++/** ++ * Reimplemented from QGraphicsItem::paint. ++ * Draws the AssociationLine and also takes care of highlighting active point or line. ++ */ ++void AssociationLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) ++{ ++ Q_UNUSED(widget) ++ QPen _pen = pen(); ++ const QColor orig = _pen.color().lighter(); ++ QColor invertedColor(orig.green(), orig.blue(), orig.red()); ++ if (invertedColor == _pen.color()) { ++ // Ensure different color. ++ invertedColor.setRed((invertedColor.red() + 50) % 256); ++ } ++ invertedColor.setAlpha(150); ++ ++ int sz = m_points.size(); ++ if (sz < 1) { ++ // not enough points - do nothing ++ return; ++ } ++ ++ QPointF savedStart = m_points.first(); ++ QPointF savedEnd = m_points.last(); ++ ++ // modify the m_points array not to include the Symbol, the value depends on Symbol ++ if (m_startSymbol) { ++ QPointF newStart = m_startSymbol->mapToParent(m_startSymbol->symbolEndPoints().first); ++ m_points[0] = newStart; ++ } ++ ++ if (m_endSymbol) { ++ QPointF newEnd = m_endSymbol->mapToParent(m_endSymbol->symbolEndPoints().first); ++ m_points[sz - 1] = newEnd; ++ } ++ ++ painter->setPen(_pen); ++ painter->setBrush(Qt::NoBrush); ++ painter->drawPath(path()); ++ ++ if (option->state & QStyle::State_Selected) { ++ // make the association broader in the selected state ++ QPainterPathStroker stroker; ++ stroker.setWidth(3.0); ++ QPainterPath outline = stroker.createStroke(path()); ++ QColor shadowColor(Qt::lightGray); ++ shadowColor.setAlpha(80); ++ QBrush shadowBrush(shadowColor); ++ painter->setBrush(shadowBrush); ++ painter->setPen(Qt::NoPen); ++ painter->drawPath(outline); ++ ++ // set color for selected painting ++ _pen.setColor(Qt::blue); ++ QRectF circle(0, 0, SelectedPointDiameter, SelectedPointDiameter); ++ painter->setBrush(_pen.color()); ++ painter->setPen(Qt::NoPen); ++ ++ // draw points ++ circle.moveCenter(savedStart); ++ painter->drawRect(circle); ++ for (int i = 1; i < sz-1; ++i) { ++ if (i != m_activePointIndex) { ++ circle.moveCenter(m_points.at(i)); ++ painter->drawRect(circle); ++ } ++ } ++ circle.moveCenter(savedEnd); ++ painter->drawRect(circle); ++ ++ if (m_activePointIndex != -1) { ++ painter->setBrush(invertedColor); ++ painter->setPen(Qt::NoPen); ++ circle.setWidth(1.5*SelectedPointDiameter); ++ circle.setHeight(1.5*SelectedPointDiameter); ++ circle.moveCenter(m_points.at(m_activePointIndex)); ++ painter->drawEllipse(circle); ++ } ++ else if (m_activeSegmentIndex != -1) { ++ if (m_layout == Polyline) { ++ painter->setPen(QPen(invertedColor, _pen.widthF() + 1)); ++ painter->setBrush(Qt::NoBrush); ++ ++ QLineF segmentLine(m_points[m_activeSegmentIndex], m_points[m_activeSegmentIndex + 1]); ++ painter->drawLine(segmentLine); ++ } ++ } ++ // debug info ++ if (Tracer::instance()->isEnabled(QString::fromLatin1(metaObject()->className()))) { ++ painter->setPen(Qt::green); ++ painter->setBrush(Qt::NoBrush); ++ painter->drawPath(shape()); ++ painter->setPen(Qt::red); ++ painter->drawRect(boundingRect()); ++ // origin ++ painter->drawLine(-10, 0, 10, 0); ++ painter->drawLine(0, -10, 0, 10); ++ } ++ ++ } ++ ++ // now restore the points array ++ m_points[0] = savedStart; ++ m_points[sz - 1] = savedEnd; ++} ++ ++/** ++ * Determines the active point or segment, the latter being given more priority. ++ */ ++void AssociationLine::mousePressEvent(QGraphicsSceneMouseEvent *event) ++{ ++ DEBUG(DBG_SRC) << "at " << event->scenePos(); ++ if (event->buttons() & Qt::LeftButton) { ++ m_activePointIndex = closestPointIndex(event->scenePos()); ++ if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { ++ // end points are not drawn and hence not active ++ m_activePointIndex = -1; ++ } ++ // calculate only if active point index is -1 ++ m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); ++ } ++ else if (event->buttons() & Qt::RightButton) { ++ DEBUG(DBG_SRC) << "call context menu of association widget at " << event->scenePos(); ++ } ++ else { ++ m_activePointIndex = -1; ++ m_activeSegmentIndex = -1; ++ } ++} ++ ++/** ++ * Moves the point or line if active. ++ */ ++void AssociationLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) ++{ ++ UMLScene* scene = m_associationWidget->umlScene(); ++ ++ QPointF oldPos = event->scenePos(); ++ QPointF newPos( ++ scene->snappedX(oldPos.x()), ++ scene->snappedY(oldPos.y()) ++ ); ++ ++ // Prevent the moving vertex from disappearing underneath a widget ++ // (else there's no way to get it back.) ++ UMLWidget *onW = scene->widgetAt(newPos); ++ if (onW && onW->baseType() != WidgetBase::wt_Box) { // boxes are transparent ++ const qreal pX = newPos.x(); ++ const qreal pY = newPos.y(); ++ const qreal wX = onW->x(); ++ const qreal wY = onW->y(); ++ const qreal wWidth = onW->width(); ++ const qreal wHeight = onW->height(); ++ if (pX > wX && pX < wX + wWidth) { ++ const qreal midX = wX + wWidth / 2.0; ++ if (pX <= midX) ++ newPos.setX(wX); ++ else ++ newPos.setX(wX + wWidth); ++ } ++ if (pY > wY && pY < wY + wHeight) { ++ const qreal midY = wY + wHeight / 2.0; ++ if (pY <= midY) ++ newPos.setY(wY); ++ else ++ newPos.setY(wY + wHeight); ++ } ++ } ++ ++ if (m_activePointIndex != -1) { ++ // Move a single point (snap behaviour) ++ setPoint(m_activePointIndex, newPos); ++ } ++ else if (m_activeSegmentIndex != -1 && !isEndSegmentIndex(m_activeSegmentIndex)) { ++ // Move a segment (between two points, snap behaviour not implemented) ++ QPointF delta = event->scenePos() - event->lastScenePos(); ++ setPoint(m_activeSegmentIndex, m_points[m_activeSegmentIndex] + delta); ++ setPoint(m_activeSegmentIndex + 1, m_points[m_activeSegmentIndex + 1] + delta); ++ } ++} ++ ++/** ++ * Reset active indices and also push undo command. ++ */ ++void AssociationLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) ++{ ++ if (event->buttons() & Qt::LeftButton) { ++ m_activeSegmentIndex = -1; ++ m_activePointIndex = -1; ++ } ++} ++ ++/** ++ * Calculates the "to be highlighted" point and segment indicies ++ * and updates if necessary. ++ */ ++void AssociationLine::hoverEnterEvent(QGraphicsSceneHoverEvent *event) ++{ ++ DEBUG(DBG_SRC) << "at " << event->scenePos(); ++ int oldPointIndex = m_activePointIndex; ++ int oldSegmentIndex = m_activeSegmentIndex; ++ ++ m_activePointIndex = closestPointIndex(event->scenePos()); ++ // End points are not drawn and hence not active. ++ if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { ++ m_activePointIndex = -1; ++ } ++ // Activate segment index only if point index is -1 ++ m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); ++ ++ bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); ++ if (isChanged) { ++ m_associationWidget->update(); ++ } ++} ++ ++/** ++ * Calculates the "to be highlighted" point and segment indicies ++ * and updates if necessary. ++ */ ++void AssociationLine::hoverMoveEvent(QGraphicsSceneHoverEvent *event) ++{ ++ int oldPointIndex = m_activePointIndex; ++ int oldSegmentIndex = m_activeSegmentIndex; ++ ++ m_activePointIndex = closestPointIndex(event->scenePos()); ++ // End points are not drawn and hence not active. ++ if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { ++ m_activePointIndex = -1; ++ } ++ // Activate segment index only if point index is -1 ++ m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); ++ ++ bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); ++ if (isChanged) { ++ m_associationWidget->update(); ++ } ++} ++ ++/** ++ * Reset active indicies and updates. ++ */ ++void AssociationLine::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) ++{ ++ DEBUG(DBG_SRC) << "at " << event->scenePos(); ++ //Q_UNUSED(event) ++ m_activePointIndex = -1; ++ m_activeSegmentIndex = -1; ++ m_associationWidget->update(); ++} ++ ++//----------------------------------------------------------------------------- ++ ++/** ++ * SymbolEndPoints: ++ * The first point is where the AssociationLine's visible line is ++ * supposed to end. ++ * The second points is where the actual symbol part is to appear. ++ */ ++Symbol::SymbolProperty Symbol::symbolTable[Count] = ++{ ++ { ++ QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), ++ SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) ++ }, ++ { ++ QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), ++ SymbolEndPoints(QPointF(0, 0), QPointF(0, 10)) ++ }, ++ { ++ QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), ++ SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) ++ }, ++ { ++ QRectF(-5, -10, 10, 20), QPainterPath(), QLineF(0, -10, 0, 10), ++ SymbolEndPoints(QPointF(0, -10), QPointF(0, 10)) ++ }, ++ { ++ QRectF(-15, -10, 30, 20), QPainterPath(), QLineF(-10, 0, 0, 0), ++ SymbolEndPoints(QPointF(0, 0), QPointF(0, 0)) ++ }, ++ { ++ QRectF(-8, -8, 16, 16), QPainterPath(), QLineF(0, -8, 0, 8), ++ SymbolEndPoints(QPointF(0, -8), QPointF(0, 8)) ++ } ++ ++}; ++ ++/** ++ * @internal A convenience method to setup shapes of all symbols. ++ */ ++void Symbol::setupSymbolTable() ++{ ++ SymbolProperty &openArrow = symbolTable[OpenArrow]; ++ if (openArrow.shape.isEmpty()) { ++ QRectF rect = openArrow.boundRect; ++ // Defines a 'V' shape arrow fitting in the bound rect. ++ openArrow.shape.moveTo(rect.topLeft()); ++ openArrow.shape.lineTo(rect.center().x(), rect.bottom()); ++ openArrow.shape.lineTo(rect.topRight()); ++ } ++ ++ SymbolProperty &closedArrow = symbolTable[ClosedArrow]; ++ if (closedArrow.shape.isEmpty()) { ++ QRectF rect = closedArrow.boundRect; ++ // Defines a 'V' shape arrow fitting in the bound rect. ++ closedArrow.shape.moveTo(rect.topLeft()); ++ closedArrow.shape.lineTo(rect.center().x(), rect.bottom()); ++ closedArrow.shape.lineTo(rect.topRight()); ++ closedArrow.shape.lineTo(rect.topLeft()); ++ } ++ ++ SymbolProperty &crowFeet = symbolTable[CrowFeet]; ++ if (crowFeet.shape.isEmpty()) { ++ QRectF rect = crowFeet.boundRect; ++ // Defines a crowFeet fitting in the bound rect. ++ QPointF topMid(rect.center().x(), rect.top()); ++ ++ // left leg ++ crowFeet.shape.moveTo(rect.bottomLeft()); ++ crowFeet.shape.lineTo(topMid); ++ ++ // middle leg ++ crowFeet.shape.moveTo(rect.center().x(), rect.bottom()); ++ crowFeet.shape.lineTo(topMid); ++ ++ // right leg ++ crowFeet.shape.moveTo(rect.bottomRight()); ++ crowFeet.shape.lineTo(topMid); ++ } ++ ++ SymbolProperty &diamond = symbolTable[Diamond]; ++ if (diamond.shape.isEmpty()) { ++ QRectF rect = diamond.boundRect; ++ // Defines a 'diamond' shape fitting in the bound rect. ++ diamond.shape.moveTo(rect.center().x(), rect.top()); ++ diamond.shape.lineTo(rect.left(), rect.center().y()); ++ diamond.shape.lineTo(rect.center().x(), rect.bottom()); ++ diamond.shape.lineTo(rect.right(), rect.center().y()); ++ diamond.shape.lineTo(rect.center().x(), rect.top()); ++ } ++ ++ SymbolProperty &subset = symbolTable[Subset]; ++ if (subset.shape.isEmpty()) { ++ QRectF rect = subset.boundRect; ++ // Defines an arc fitting in bound rect. ++ qreal start = 90, span = 180; ++ subset.shape.arcMoveTo(rect, start); ++ subset.shape.arcTo(rect, start, span); ++ } ++ ++ SymbolProperty &circle = symbolTable[Circle]; ++ if (circle.shape.isEmpty()) { ++ QRectF rect = circle.boundRect; ++ // Defines a circle with a horizontal-vertical cross lines. ++ circle.shape.addEllipse(rect); ++ ++ circle.shape.moveTo(rect.center().x(), rect.top()); ++ circle.shape.lineTo(rect.center().x(), rect.bottom()); ++ ++ circle.shape.moveTo(rect.left(), rect.center().y()); ++ circle.shape.lineTo(rect.right(), rect.center().y()); ++ } ++ ++} ++ ++/** ++ * Constructs a Symbol with current symbol being \a symbol and ++ * parented to \a parent. ++ */ ++Symbol::Symbol(SymbolType symbolType, QGraphicsItem *parent) ++ : QGraphicsItem(parent), ++ m_symbolType(symbolType) ++{ ++ // ensure SymbolTable is validly initialized ++ setupSymbolTable(); ++} ++ ++/** ++ * Destructor. ++ */ ++Symbol::~Symbol() ++{ ++} ++ ++/** ++ * @return The current symbol being represented. ++ */ ++Symbol::SymbolType Symbol::symbolType() const ++{ ++ return m_symbolType; ++} ++ ++/** ++ * Sets the current symbol type to \a symbol and updates the geometry. ++ */ ++void Symbol::setSymbolType(SymbolType symbolType) ++{ ++ prepareGeometryChange(); // calls update implicitly ++ m_symbolType = symbolType; ++} ++ ++/** ++ * Draws the current symbol using the QPainterPath stored for the current ++ * symbol. ++ */ ++void Symbol::paint(QPainter *painter, const QStyleOptionGraphicsItem * option, QWidget * widget) ++{ ++ Q_UNUSED(option) Q_UNUSED(widget) ++ painter->setPen(m_pen); ++ switch (m_symbolType) { ++ case ClosedArrow: ++ case CrowFeet: ++ case Diamond: ++ painter->setBrush(m_brush); ++ break; ++ default: ++ break; ++ } ++ painter->drawPath(Symbol::symbolTable[m_symbolType].shape); ++} ++ ++/** ++ * @return The bound rectangle for this based on current symbol. ++ */ ++QRectF Symbol::boundingRect() const ++{ ++ const qreal adj = .5 * m_pen.widthF(); ++ return Symbol::symbolTable[m_symbolType].boundRect. ++ adjusted(-adj, -adj, adj, adj); ++} ++ ++/** ++ * @return The path for this based on current symbol. ++ */ ++QPainterPath Symbol::shape() const ++{ ++ QPainterPath path; ++ path.addRect(boundingRect()); ++ return path; ++} ++ ++/** ++ * This method aligns *this* Symbol to the line being ++ * passed. That is, it ensures that the axis of this symbol aligns ++ * exactly with the \a "to" line passed. ++ * ++ * Also this item is moved such that the second end point of the ++ * SymbolEndPoints for the current symbol *collides* with the second end ++ * point of \a "to" line. ++ */ ++void Symbol::alignTo(const QLineF& to) ++{ ++ QLineF toMapped(mapFromParent(to.p1()), mapFromParent(to.p2())); ++ ++ QLineF origAxis = Symbol::symbolTable[m_symbolType].axisLine; ++ QLineF translatedAxis = origAxis.translated(toMapped.p2() - origAxis.p2()); ++ ++ qreal angle = translatedAxis.angleTo(toMapped); ++ setRotation(rotation() - angle); ++ ++ QPointF delta = to.p2() - mapToParent(symbolEndPoints().second); ++ moveBy(delta.x(), delta.y()); ++} ++ ++/** ++ * @return The end points for the symbol. ++ */ ++Symbol::SymbolEndPoints Symbol::symbolEndPoints() const ++{ ++ return Symbol::symbolTable[m_symbolType].endPoints; ++} ++ ++/** ++ * @return The pen used to draw symbol. ++ */ ++QPen Symbol::pen() const ++{ ++ return m_pen; ++} ++ ++/** ++ * Sets the pen used to draw the symbol. ++ */ ++void Symbol::setPen(const QPen& pen) ++{ ++ prepareGeometryChange(); ++ m_pen = pen; ++ if (m_symbolType == ClosedArrow) ++ m_pen.setStyle(Qt::solid-kf6Line); ++} ++ ++/** ++ * @return The brush used to fill symbol. ++ */ ++QBrush Symbol::brush() const ++{ ++ return m_brush; ++} ++ ++/** ++ * Sets the brush used to fill symbol. ++ */ ++void Symbol::setBrush(const QBrush &brush) ++{ ++ m_brush = brush; ++ update(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.h umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,207 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ASSOCIATIONLINE_H ++#define ASSOCIATIONLINE_H ++ ++#include "basictypes.h" ++ ++#include ++#include ++#include ++#include ++ ++// forward declarations ++class AssociationWidget; ++class QDomDocument; ++class QDomElement; ++class QPainter; ++ ++/** ++ * This class provides with various symbols that can be embedded in ++ * AssociationLine. It also provides with convenience methods to align ++ * the symbol to AssociationLine. ++ */ ++class Symbol : public QGraphicsItem ++{ ++ public: ++ typedef QPair SymbolEndPoints; ++ ++ /** ++ * This enumeration lists all the symbols that can be used as ++ * embedded on AssociationLine. ++ */ ++ enum SymbolType { ++ None = -1, ++ OpenArrow, ++ ClosedArrow, ++ CrowFeet, ++ Diamond, ++ Subset, ++ Circle, ++ Count ++ }; ++ ++ explicit Symbol(SymbolType symbolType, QGraphicsItem *parent = 0); ++ virtual ~Symbol(); ++ ++ SymbolType symbolType() const; ++ void setSymbolType(SymbolType symbolType); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); ++ ++ virtual QRectF boundingRect() const; ++ virtual QPainterPath shape() const; ++ ++ void alignTo(const QLineF& line); ++ SymbolEndPoints symbolEndPoints() const; ++ ++ QPen pen() const; ++ void setPen(const QPen &pen); ++ ++ QBrush brush() const; ++ void setBrush(const QBrush& brush); ++ ++ private: ++ QPen m_pen; ///< pen used to draw Symbol ++ QBrush m_brush; ///< brush used to fill Symbol ++ SymbolType m_symbolType; ///< current symbol being represented by this item ++ ++ /// A structure to hold a table of values for all symbols. ++ struct SymbolProperty { ++ QRectF boundRect; ++ QPainterPath shape; ++ QLineF axisLine; ++ SymbolEndPoints endPoints; ++ }; ++ ++ static SymbolProperty symbolTable[Symbol::Count]; ///< a table which stores all symbol properties ++ static void setupSymbolTable(); ++}; ++ ++/** ++ * A convenience class that encapsulates geometry management, handles ++ * mouse and hover events, embeds and aligns symbols and finally draws the ++ * lines and points. ++ * Context menu events are handled in AssociationWidget. ++ * ++ * This class is infact a draw and event handling proxy for ++ * AssociationWidget. ++ * ++ * @note m_activePointIndex and m_activeSegmentIndex can't be ++ * active at same time! ++ * ++ * @author Gopala Krishna ++ * @author Andi Fischer ++ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org ++ */ ++class AssociationLine : public QGraphicsObject ++{ ++ Q_OBJECT ++ Q_ENUMS(LayoutType) ++public: ++ enum LayoutType { ++ Direct = 1, ++ Orthogonal, ++ Polyline, ++ Spline ++ }; ++ ++ static QString toString(LayoutType layout); ++ static LayoutType fromString(const QString& layout); ++ ++ explicit AssociationLine(AssociationWidget *association); ++ virtual ~AssociationLine(); ++ ++ QPointF point(int index) const; ++ bool setPoint(int index, const QPointF& point); ++ QPointF startPoint() const; ++ QPointF endPoint() const; ++ ++ void insertPoint(int index, const QPointF& point); ++ void removePoint(int index); ++ ++ int count() const; ++ void cleanup(); ++ ++ void optimizeLinePoints(); ++ ++ int closestPointIndex(const QPointF& point, qreal delta = Delta) const; ++ int closestSegmentIndex(const QPointF& point, qreal delta = Delta) const; ++ ++ bool isEndPointIndex(int index) const; ++ bool isEndSegmentIndex(int index) const; ++ ++ bool setEndPoints(const QPointF &start, const QPointF &end); ++ ++ void dumpPoints(); ++ ++ bool loadFromXMI(QDomElement &qElement); ++ void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); ++ ++ QBrush brush() const; ++ QPen pen() const; ++ ++ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); ++ ++ QPainterPath path() const; ++ ++ QRectF boundingRect() const; ++ QPainterPath shape() const; ++ ++ LayoutType layout() const; ++ void setLayout(LayoutType layout); ++ ++ void mousePressEvent(QGraphicsSceneMouseEvent *event); ++ void mouseMoveEvent(QGraphicsSceneMouseEvent *event); ++ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); ++ ++ void hoverEnterEvent(QGraphicsSceneHoverEvent *event); ++ void hoverMoveEvent(QGraphicsSceneHoverEvent *event); ++ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); ++ ++ void calculateInitialEndPoints(); ++ ++ void reconstructSymbols(); ++ ++private: ++ void setStartSymbol(Symbol::SymbolType symbolType); ++ void setEndSymbol(Symbol::SymbolType symbolType); ++ ++ void createSubsetSymbol(); ++ void removeSubsetSymbol(); ++ ++ void createCollaborationLine(); ++ void removeCollaborationLine(); ++ ++ void alignSymbols(); ++ ++ void createSplinePoints(); ++ ++ AssociationWidget *m_associationWidget; ///< association widget for which this line represents ++ QVector m_points; ///< points representing the association line ++ int m_activePointIndex; ///< index of active point which can be dragged to modify association line ++ int m_activeSegmentIndex; ///< index of active segment ++ Symbol *m_startSymbol; ///< symbol drawn at the end of "first" line segment ++ Symbol *m_endSymbol; ///< symbol drawn at the end of "last" line segment ++ Symbol *m_subsetSymbol; ///< subset symbol ++ QGraphicsLineItem *m_collaborationLineItem; ///< parallel arrow line drawn in case of collaboration message ++ Symbol *m_collaborationLineHead; ///< arrow head drawn at end of m_collaborationLineItem ++ LayoutType m_layout; ++ ++ static QPainterPath createBezierCurve(QVector points); ++ static QPainterPath createOrthogonalPath(QVector points); ++ ++ static const qreal Delta; ///< default delta for fuzzy recognition of points closer to point ++ static const qreal SelectedPointDiameter; ///< radius of circles drawn to show "selection" ++ static const qreal SelfAssociationMinimumHeight; ///< minimum height for self association's loop ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,4407 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "associationwidget.h" ++ ++// app includes ++#include "association.h" ++#include "associationline.h" ++#include "associationpropertiesdialog.h" ++#include "assocrules.h" ++#include "attribute.h" ++#include "classifier.h" ++#include "classifierwidget.h" ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "entity.h" ++#include "floatingtextwidget.h" ++#include "listpopupmenu.h" ++#include "messagewidget.h" ++#include "objectwidget.h" ++#include "operation.h" ++#include "optionstate.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "umlwidget.h" ++#include "widget_utils.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#include ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++// system includes ++#include ++ ++#define DBG_AW() DEBUG(QLatin1String("AssociationWidget")) ++DEBUG_REGISTER_DISABLED(AssociationWidget) ++ ++using namespace Uml; ++ ++/** ++ * Constructor is private because the static create() methods shall ++ * be used for constructing AssociationWidgets. ++ * ++ * @param scene The parent view of this widget. ++ */ ++AssociationWidget::AssociationWidget(UMLScene *scene) ++ : WidgetBase(scene, WidgetBase::wt_Association), ++ m_positions_len(0), ++ m_activated(false), ++ m_unNameLineSegment(-1), ++ m_nLinePathSegmentIndex(-1), ++ m_pAssocClassLine(0), ++ m_pAssocClassLineSel0(0), ++ m_pAssocClassLineSel1(0), ++ m_associationLine(new AssociationLine(this)), ++ m_associationClass(0), ++ m_associationType(Uml::AssociationType::Association), ++ m_nameWidget(0) ++{ ++ // floating text widgets objects owned by this association ++ m_role[RoleType::A].changeabilityWidget = 0; ++ m_role[RoleType::B].changeabilityWidget = 0; ++ m_role[RoleType::A].multiplicityWidget = 0; ++ m_role[RoleType::B].multiplicityWidget = 0; ++ m_role[RoleType::A].roleWidget = 0; ++ m_role[RoleType::B].roleWidget = 0; ++ m_role[RoleType::A].umlWidget = 0; ++ m_role[RoleType::B].umlWidget = 0; ++ ++ // associationwidget attributes ++ m_role[RoleType::A].m_WidgetRegion = Uml::Region::Error; ++ m_role[RoleType::B].m_WidgetRegion = Uml::Region::Error; ++ m_role[RoleType::A].m_nIndex = 0; ++ m_role[RoleType::B].m_nIndex = 0; ++ m_role[RoleType::A].m_nTotalCount = 0; ++ m_role[RoleType::B].m_nTotalCount = 0; ++ m_role[RoleType::A].visibility = Uml::Visibility::Public; ++ m_role[RoleType::B].visibility = Uml::Visibility::Public; ++ m_role[RoleType::A].changeability = Uml::Changeability::Changeable; ++ m_role[RoleType::B].changeability = Uml::Changeability::Changeable; ++ ++ setFlag(QGraphicsLineItem::ItemIsSelectable); ++ setAcceptHoverEvents(true); ++} ++ ++/** ++ * This constructor is really only for loading from XMI, otherwise it ++ * should not be allowed as it creates an incomplete associationwidget. ++ * ++ * @param scene The parent view of this widget. ++ */ ++AssociationWidget* AssociationWidget::create(UMLScene *scene) ++{ ++ AssociationWidget* instance = new AssociationWidget(scene); ++ return instance; ++} ++ ++/** ++ * Preferred constructor (static factory method.) ++ * ++ * @param scene The parent view of this widget. ++ * @param pWidgetA Pointer to the role A widget for the association. ++ * @param assocType The AssociationType::Enum for this association. ++ * @param pWidgetB Pointer to the role B widget for the association. ++ * @param umlobject Pointer to the underlying UMLObject (if applicable.) ++ */ ++AssociationWidget* AssociationWidget::create ++ (UMLScene *scene, UMLWidget* pWidgetA, ++ Uml::AssociationType::Enum assocType, UMLWidget* pWidgetB, ++ UMLObject *umlobject /* = NULL */) ++{ ++ AssociationWidget* instance = new AssociationWidget(scene); ++ if (umlobject) { ++ instance->setUMLObject(umlobject); ++ } else { ++ // set up UMLAssociation obj if assoc is represented and both roles are UML objects ++ if (Uml::AssociationType::hasUMLRepresentation(assocType)) { ++ UMLObject* umlRoleA = pWidgetA->umlObject(); ++ UMLObject* umlRoleB = pWidgetB->umlObject(); ++ if (umlRoleA != NULL && umlRoleB != NULL) { ++ bool swap; ++ ++ // This is not correct. We could very easily have more than one ++ // of the same type of association between the same two objects. ++ // Just create the association. This search should have been ++ // done BEFORE creation of the widget, if it mattered to the code. ++ // But lets leave check in here for the time being so that debugging ++ // output is shown, in case there is a collision with code elsewhere. ++ UMLDoc *doc = UMLApp::app()->document(); ++ UMLAssociation *myAssoc = doc->findAssociation(assocType, umlRoleA, umlRoleB, &swap); ++ if (myAssoc != NULL) { ++ switch (assocType) { ++ case Uml::AssociationType::Generalization: ++ case Uml::AssociationType::Dependency: ++ case Uml::AssociationType::Association_Self: ++ case Uml::AssociationType::Coll_Message_Self: ++ case Uml::AssociationType::Seq_Message_Self: ++ case Uml::AssociationType::Containment: ++ case Uml::AssociationType::Realization: ++ DBG_AW() << "Ignoring second construction of same assoctype " ++ << assocType << " between " << umlRoleA->name() ++ << " and " << umlRoleB->name(); ++ break; ++ default: ++ DBG_AW() << "constructing a similar or exact same assoctype " ++ << assocType << " between " << umlRoleA->name() << " and " ++ << umlRoleB->name() << "as an already existing assoc (swap=" ++ << swap << ")"; ++ // now, just create a new association anyways ++ myAssoc = NULL; ++ break; ++ } ++ } ++ if (myAssoc == NULL) { ++ myAssoc = new UMLAssociation(assocType, umlRoleA, umlRoleB); ++ // CHECK: myAssoc is not yet inserted at any parent UMLPackage - ++ // need to check carefully that all callers do this, lest it be ++ // orphaned. ++ // ToolBarStateAssociation::addAssociationInViewAndDoc() is ++ // okay in this regard. ++ } ++ instance->setUMLAssociation(myAssoc); ++ } ++ } ++ } ++ ++ instance->setWidgetForRole(pWidgetA, RoleType::A); ++ instance->setWidgetForRole(pWidgetB, RoleType::B); ++ ++ instance->setAssociationType(assocType); ++ ++ instance->calculateEndingPoints(); ++ ++ instance->associationLine()->calculateInitialEndPoints(); ++ instance->associationLine()->reconstructSymbols(); ++ ++ //The AssociationWidget is set to Activated because it already has its side widgets ++ instance->setActivated(true); ++ ++ // sync UML meta-data to settings here ++ instance->mergeAssociationDataIntoUMLRepresentation(); ++ ++ // Collaboration messages need a name label because it's that ++ // which lets operator== distinguish them, which in turn ++ // permits us to have more than one message between two objects. ++ if (instance->isCollaboration()) { ++ // Create a temporary name to bring on setName() ++ int collabID = instance->m_scene->generateCollaborationId(); ++ instance->setName(QLatin1Char('m') + QString::number(collabID)); ++ } ++ ++ return instance; ++} ++ ++/** ++ * Destructor. ++ */ ++AssociationWidget::~AssociationWidget() ++{ ++ delete m_associationLine; ++} ++ ++/** ++ * Overriding the method from WidgetBase because we need to do ++ * something extra in case this AssociationWidget represents ++ * an attribute of a classifier. ++ */ ++void AssociationWidget::setUMLObject(UMLObject *obj) ++{ ++ WidgetBase::setUMLObject(obj); ++ if (obj == NULL) ++ return; ++ UMLClassifier *klass = NULL; ++ UMLAttribute *attr = NULL; ++ UMLEntity *ent = NULL; ++ const UMLObject::ObjectType ot = obj->baseType(); ++ switch (ot) { ++ case UMLObject::ot_Association: ++ setUMLAssociation(dynamic_cast(obj)); ++ break; ++ case UMLObject::ot_Operation: ++ setOperation(dynamic_cast(obj)); ++ break; ++ case UMLObject::ot_Attribute: ++ klass = static_cast(obj->parent()); ++ connect(klass, SIGNAL(attributeRemoved(UMLClassifierListItem*)), ++ this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); ++ attr = static_cast(obj); ++ connect(attr, SIGNAL(attributeChanged()), this, SLOT(slotAttributeChanged())); ++ break; ++ case UMLObject::ot_EntityAttribute: ++ ent = static_cast(obj->parent()); ++ connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), ++ this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); ++ break; ++ case UMLObject::ot_ForeignKeyConstraint: ++ ent = static_cast(obj->parent()); ++ connect(ent, SIGNAL(entityConstraintRemoved(UMLClassifierListItem*)), ++ this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); ++ break; ++ default: ++ uError() << "cannot associate UMLObject of type " << UMLObject::toString(ot); ++ break; ++ } ++} ++ ++/** ++ * Set all 'owned' child widgets to this font. ++ */ ++void AssociationWidget::lwSetFont (QFont font) ++{ ++ if (m_nameWidget) { ++ m_nameWidget->setFont(font); ++ } ++ if (m_role[RoleType::A].roleWidget) { ++ m_role[RoleType::A].roleWidget->setFont(font); ++ } ++ if (m_role[RoleType::B].roleWidget) { ++ m_role[RoleType::B].roleWidget->setFont(font); ++ } ++ if (m_role[RoleType::A].multiplicityWidget) { ++ m_role[RoleType::A].multiplicityWidget->setFont(font); ++ } ++ if (m_role[RoleType::B].multiplicityWidget) { ++ m_role[RoleType::B].multiplicityWidget->setFont(font); ++ } ++ if (m_role[RoleType::A].changeabilityWidget) ++ m_role[RoleType::A].changeabilityWidget->setFont(font); ++ if (m_role[RoleType::B].changeabilityWidget) ++ m_role[RoleType::B].changeabilityWidget->setFont(font); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * @todo Move to LinkWidget. ++ */ ++UMLClassifier *AssociationWidget::operationOwner() ++{ ++ Uml::RoleType::Enum role = (isCollaboration() ? Uml::RoleType::B : Uml::RoleType::A); ++ UMLObject *o = widgetForRole(role)->umlObject(); ++ if (!o) { ++ return 0; ++ } ++ UMLClassifier *c = dynamic_cast(o); ++ if (!c) { ++ uError() << "widgetForRole(" << role << ") is not a classifier"; ++ } ++ return c; ++} ++ ++/** ++ * Implements operation from LinkWidget. ++ * Motivated by FloatingTextWidget. ++ */ ++UMLOperation *AssociationWidget::operation() ++{ ++ return dynamic_cast(m_umlObject); ++} ++ ++/** ++ * Implements operation from LinkWidget. ++ * Motivated by FloatingTextWidget. ++ */ ++void AssociationWidget::setOperation(UMLOperation *op) ++{ ++ if (m_umlObject) ++ disconnect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); ++ m_umlObject = op; ++ if (m_umlObject) ++ connect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); ++ if (m_nameWidget) ++ m_nameWidget->setMessageText(); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++QString AssociationWidget::customOpText() ++{ ++ return name(); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++void AssociationWidget::setCustomOpText(const QString &opText) ++{ ++ setName(opText); ++} ++ ++/** ++ * Calls setTextPosition on all the labels. ++ * Overrides operation from LinkWidget. ++ */ ++void AssociationWidget::resetTextPositions() ++{ ++ if (m_role[RoleType::A].multiplicityWidget) { ++ setTextPosition(TextRole::MultiA); ++ } ++ if (m_role[RoleType::B].multiplicityWidget) { ++ setTextPosition(Uml::TextRole::MultiB); ++ } ++ if (m_role[RoleType::A].changeabilityWidget) { ++ setTextPosition(Uml::TextRole::ChangeA); ++ } ++ if (m_role[RoleType::B].changeabilityWidget) { ++ setTextPosition(Uml::TextRole::ChangeB); ++ } ++ if (m_nameWidget) { ++ setTextPosition(Uml::TextRole::Name); ++ } ++ if (m_role[RoleType::A].roleWidget) { ++ setTextPosition(Uml::TextRole::RoleAName); ++ } ++ if (m_role[RoleType::B].roleWidget) { ++ setTextPosition(Uml::TextRole::RoleBName); ++ } ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @param ft The text widget which to update. ++ */ ++void AssociationWidget::setMessageText(FloatingTextWidget *ft) ++{ ++ if (isCollaboration()) { ++ ft->setSequenceNumber(m_SequenceNumber); ++ if (m_umlObject != NULL) { ++ ft->setText(operationText(m_scene)); ++ } else { ++ ft->setText(name()); ++ } ++ } else { ++ ft->setText(name()); ++ } ++} ++ ++/** ++ * Sets the text of the given FloatingTextWidget. ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++void AssociationWidget::setText(FloatingTextWidget *ft, const QString &text) ++{ ++ Uml::TextRole::Enum role = ft->textRole(); ++ switch (role) { ++ case Uml::TextRole::Name: ++ setName(text); ++ break; ++ case Uml::TextRole::RoleAName: ++ setRoleName(text, RoleType::A); ++ break; ++ case Uml::TextRole::RoleBName: ++ setRoleName(text, RoleType::B); ++ break; ++ case Uml::TextRole::MultiA: ++ setMultiplicity(text, RoleType::A); ++ break; ++ case Uml::TextRole::MultiB: ++ setMultiplicity(text, RoleType::B); ++ break; ++ default: ++ uWarning() << "Unhandled TextRole: " << Uml::TextRole::toString(role); ++ break; ++ } ++} ++ ++/** ++ * Shows the association properties dialog and updates the ++ * corresponding texts if its execution is successful. ++ */ ++void AssociationWidget::showPropertiesDialog() ++{ ++ UMLApp::app()->docWindow()->updateDocumentation(); ++ QPointer dlg = new AssociationPropertiesDialog(static_cast(m_scene->activeView()), this); ++ if (dlg->exec()) { ++ //rules built into these functions to stop updating incorrect values ++ setName(name()); ++ ++ setRoleName(roleName(RoleType::A), RoleType::A); ++ setRoleName(roleName(RoleType::B), RoleType::B); ++ ++ setDocumentation(documentation()); ++ ++ setRoleDocumentation(roleDocumentation(RoleType::A), RoleType::A); ++ setRoleDocumentation(roleDocumentation(RoleType::B), RoleType::B); ++ ++ setMultiplicity(multiplicity(RoleType::A), RoleType::A); ++ setMultiplicity(multiplicity(RoleType::B), RoleType::B); ++ ++ setVisibility(visibility(RoleType::A), RoleType::A); ++ setVisibility(visibility(RoleType::B), RoleType::B); ++ ++ setChangeability(changeability(RoleType::A), RoleType::A); ++ setChangeability(changeability(RoleType::B), RoleType::B); ++ ++ UMLApp::app()->docWindow()->showDocumentation(this, true); ++ } ++ delete dlg; ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @param op Return this AssociationWidget's operation string. ++ */ ++QString AssociationWidget::lwOperationText() ++{ ++ return name(); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @return classifier ++ */ ++UMLClassifier* AssociationWidget::lwClassifier() ++{ ++ UMLObject *o = widgetForRole(RoleType::B)->umlObject(); ++ UMLClassifier *c = dynamic_cast(o); ++ return c; ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @param op The new operation string to set. ++ */ ++void AssociationWidget::setOperationText(const QString &op) ++{ ++ if (!op.isEmpty()) { ++ setName(op); ++ } ++} ++ ++/** ++ * Calculates the m_unNameLineSegment value according to the new ++ * NameText topleft corner PT. ++ * It iterates through all AssociationLine's segments and for each one ++ * calculates the sum of PT's distance to the start point + PT's ++ * distance to the end point. The segment with the smallest sum will ++ * be the RoleTextSegment (if this segment moves then the RoleText ++ * will move with it). It sets m_unNameLineSegment to the start point ++ * of the chosen segment. ++ * ++ * Overrides operation from LinkWidget (i.e. this method is also ++ * required by FloatingTextWidget.) ++ */ ++void AssociationWidget::calculateNameTextSegment() ++{ ++ if (!m_nameWidget) { ++ return; ++ } ++ //changed to use the middle of the text ++ //i think this will give a better result. ++ //never know what sort of lines people come up with ++ //and text could be long to give a false reading ++ qreal xt = m_nameWidget->x(); ++ qreal yt = m_nameWidget->y(); ++ xt += m_nameWidget->width() / 2; ++ yt += m_nameWidget->height() / 2; ++ int size = m_associationLine->count(); ++ //sum of length(PTP1) and length(PTP2) ++ qreal total_length = 0; ++ qreal smallest_length = 0; ++ for (int i = 0; i < size - 1; ++i) { ++ QPointF pi = m_associationLine->point( i ); ++ QPointF pj = m_associationLine->point( i+1 ); ++ qreal xtiDiff = xt - pi.x(); ++ qreal xtjDiff = xt - pj.x(); ++ qreal ytiDiff = yt - pi.y(); ++ qreal ytjDiff = yt - pj.y(); ++ total_length = sqrt( double(xtiDiff * xtiDiff + ytiDiff * ytiDiff) ) ++ + sqrt( double(xtjDiff * xtjDiff + ytjDiff * ytjDiff) ); ++ //this gives the closest point ++ if (total_length < smallest_length || i == 0) { ++ smallest_length = total_length; ++ m_unNameLineSegment = i; ++ } ++ } ++} ++ ++/** ++ * Returns the UMLAssociation representation of this object. ++ * ++ * @return Pointer to the UMLAssociation that is represented by ++ * this AsociationWidget. ++ */ ++UMLAssociation* AssociationWidget::association() const ++{ ++ if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) ++ return NULL; ++ return static_cast(m_umlObject); ++} ++ ++/** ++ * Returns the UMLAttribute representation of this object. ++ * ++ * @return Pointer to the UMLAttribute that is represented by ++ * this AsociationWidget. ++ */ ++UMLAttribute* AssociationWidget::attribute() const ++{ ++ if (m_umlObject == NULL) ++ return NULL; ++ UMLObject::ObjectType ot = m_umlObject->baseType(); ++ if (ot != UMLObject::ot_Attribute && ot != UMLObject::ot_EntityAttribute) ++ return NULL; ++ return static_cast(m_umlObject); ++} ++ ++#if 0 //:TODO: ++/** ++ * Overrides the assignment operator. ++ */ ++AssociationWidget& AssociationWidget::operator=(const AssociationWidget& other) ++{ ++ *m_associationLine = *other.m_associationLine; ++ ++ if (other.m_nameWidget) { ++ m_nameWidget = new FloatingTextWidget(m_scene); ++ *m_nameWidget = *(other.m_nameWidget); ++ } else { ++ m_nameWidget = NULL; ++ } ++ ++ for (unsigned r = (unsigned)A; r <= (unsigned)B; ++r) { ++ WidgetRole& lhs = m_role[r]; ++ const WidgetRole& rhs = other.m_role[r]; ++ lhs.m_nIndex = rhs.m_nIndex; ++ lhs.m_nTotalCount = rhs.m_nTotalCount; ++ ++ if (rhs.multiplicityWidget) { ++ lhs.multiplicityWidget = new FloatingTextWidget(m_scene); ++ *(lhs.multiplicityWidget) = *(rhs.multiplicityWidget); ++ } else { ++ lhs.multiplicityWidget = NULL; ++ } ++ ++ if (rhs.roleWidget) { ++ lhs.roleWidget = new FloatingTextWidget(m_scene); ++ *(lhs.roleWidget) = *(rhs.roleWidget); ++ } else { ++ lhs.roleWidget = NULL; ++ } ++ ++ if (rhs.changeabilityWidget) { ++ lhs.changeabilityWidget = new FloatingTextWidget(m_scene); ++ *(lhs.changeabilityWidget) = *(rhs.changeabilityWidget); ++ } else { ++ lhs.changeabilityWidget = NULL; ++ } ++ ++ lhs.umlWidget = rhs.umlWidget; ++ lhs.m_WidgetRegion = rhs.m_WidgetRegion; ++ } ++ ++ m_activated = other.m_activated; ++ m_unNameLineSegment = other.m_unNameLineSegment; ++ m_pMenu = other.m_pMenu; ++ setUMLAssociation(other.association()); ++ setSelected(other.isSelected()); ++ ++ return *this; ++} ++#endif //:TODO: ++ ++/** ++ * Overrides the equality test operator. ++ */ ++bool AssociationWidget::operator==(const AssociationWidget& other) const ++{ ++ if (this == &other) ++ return true; ++ ++ // if no model representation exists, then the widgets are not equal ++ if (association() == NULL && other.association() == NULL) ++ return false; ++ ++ if (!m_umlObject || !other.m_umlObject ) { ++ if (!other.m_umlObject && m_umlObject) ++ return false; ++ if (other.m_umlObject && !m_umlObject) ++ return false; ++ ++ } else if (m_umlObject != other.m_umlObject) ++ return false; ++ ++ if (associationType() != other.associationType()) ++ return false; ++ ++ if (widgetIDForRole(RoleType::A) != other.widgetIDForRole(RoleType::A)) ++ return false; ++ ++ if (widgetIDForRole(RoleType::B) != other.widgetIDForRole(RoleType::B)) ++ return false; ++ ++ if (widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object && ++ other.widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object) { ++ ObjectWidget *ownA = static_cast(widgetForRole(RoleType::A)); ++ ObjectWidget *otherA = static_cast(other.widgetForRole(RoleType::A)); ++ if (ownA->localID() != otherA->localID()) ++ return false; ++ } ++ ++ if (widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object && ++ other.widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object) { ++ ObjectWidget *ownB = static_cast(widgetForRole(RoleType::B)); ++ ObjectWidget *otherB = static_cast(other.widgetForRole(RoleType::B)); ++ if (ownB->localID() != otherB->localID()) ++ return false; ++ } ++ ++ // Two objects in a collaboration can have multiple messages between each other. ++ // Here we depend on the messages having names, and the names must be different. ++ // That is the reason why collaboration messages have strange initial names like ++ // "m29997" or similar. ++ return (name() == other.name()); ++} ++ ++/** ++ * Overrides the != operator. ++ */ ++bool AssociationWidget::operator!=(AssociationWidget& other) const ++{ ++ return !(*this == other); ++} ++ ++/** ++ * Returns a pointer to the association widget's line path. ++ */ ++AssociationLine* AssociationWidget::associationLine() const ++{ ++ return m_associationLine; ++} ++ ++/** ++ * Activates the AssociationWidget after a load. ++ * ++ * @return true for success ++ */ ++bool AssociationWidget::activate() ++{ ++ if (m_umlObject == NULL && ++ AssociationType::hasUMLRepresentation(m_associationType)) { ++ UMLObject *myObj = umlDoc()->findObjectById(m_nId); ++ if (myObj == NULL) { ++ uError() << "cannot find UMLObject " << Uml::ID::toString(m_nId); ++ return false; ++ } else { ++ const UMLObject::ObjectType ot = myObj->baseType(); ++ if (ot == UMLObject::ot_Association) { ++ UMLAssociation * myAssoc = static_cast(myObj); ++ setUMLAssociation(myAssoc); ++ } else { ++ setUMLObject(myObj); ++ setAssociationType(m_associationType); ++ } ++ } ++ } ++ ++ if (m_activated) ++ return true; ++ ++ Uml::AssociationType::Enum type = associationType(); ++ ++ if (m_role[RoleType::A].umlWidget == NULL) ++ setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::A)), RoleType::A); ++ if (m_role[RoleType::B].umlWidget == NULL) ++ setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::B)), RoleType::B); ++ ++ if (!m_role[RoleType::A].umlWidget || !m_role[RoleType::B].umlWidget) { ++ DEBUG(DBG_SRC) << "Cannot make association!"; ++ return false; ++ } ++ ++ calculateEndingPoints(); ++ ++ if (AssocRules::allowRole(type)) { ++ for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { ++ WidgetRole& robj = m_role[r]; ++ if (robj.roleWidget == NULL) ++ continue; ++ robj.roleWidget->setLink(this); ++ TextRole::Enum tr = (r == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); ++ robj.roleWidget->setTextRole(tr); ++ Uml::Visibility::Enum vis = visibility(Uml::RoleType::fromInt(r)); ++ robj.roleWidget->setPreText(Uml::Visibility::toString(vis, true)); ++ ++ if (FloatingTextWidget::isTextValid(robj.roleWidget->text())) ++ robj.roleWidget->show(); ++ else ++ robj.roleWidget->hide(); ++ if (m_scene->type() == DiagramType::Collaboration) ++ robj.roleWidget->setUMLObject(robj.umlWidget->umlObject()); ++ robj.roleWidget->activate(); ++ } ++ } ++ ++ if (m_nameWidget != NULL) { ++ m_nameWidget->setLink(this); ++ m_nameWidget->setTextRole(calculateNameType(TextRole::Name)); ++ ++ if (FloatingTextWidget::isTextValid(m_nameWidget->text())) { ++ m_nameWidget->show(); ++ } else { ++ m_nameWidget->hide(); ++ } ++ m_nameWidget->activate(); ++ calculateNameTextSegment(); ++ } ++ ++ for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { ++ WidgetRole& robj = m_role[r]; ++ ++ FloatingTextWidget* pMulti = robj.multiplicityWidget; ++ if (pMulti != NULL && ++ AssocRules::allowMultiplicity(type, robj.umlWidget->baseType())) { ++ pMulti->setLink(this); ++ TextRole::Enum tr = (r == RoleType::A ? TextRole::MultiA : TextRole::MultiB); ++ pMulti->setTextRole(tr); ++ if (FloatingTextWidget::isTextValid(pMulti->text())) ++ pMulti->show(); ++ else ++ pMulti->hide(); ++ pMulti->activate(); ++ } ++ ++ FloatingTextWidget* pChangeWidget = robj.changeabilityWidget; ++ if (pChangeWidget != NULL) { ++ pChangeWidget->setLink(this); ++ TextRole::Enum tr = (r == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); ++ pChangeWidget->setTextRole(tr); ++ if (FloatingTextWidget::isTextValid(pChangeWidget->text())) ++ pChangeWidget->show(); ++ else ++ pChangeWidget->hide (); ++ pChangeWidget->activate(); ++ } ++ } ++ ++ // Prepare the association class line if needed. ++ if (m_associationClass && !m_pAssocClassLine) { ++ createAssocClassLine(); ++ } ++ ++ m_activated = true; ++ return true; ++} ++ ++/** ++ * Set the widget of the given role. ++ * Add this AssociationWidget at the widget. ++ * If this AssociationWidget has an underlying UMLAssociation then set ++ * the widget's underlying UMLObject at the UMLAssociation's role object. ++ * ++ * @param widget Pointer to the UMLWidget. ++ * @param role Role for which to set the widget. ++ */ ++void AssociationWidget::setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role) ++{ ++ m_role[role].umlWidget = widget; ++ if (widget) { ++ m_role[role].umlWidget->addAssoc(this); ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) ++ association()->setObject(widget->umlObject(), role); ++ } ++} ++ ++/** ++ * Return the multiplicity FloatingTextWidget widget of the given role. ++ * ++ * @return Pointer to the multiplicity FloatingTextWidget object. ++ */ ++FloatingTextWidget* AssociationWidget::multiplicityWidget(Uml::RoleType::Enum role) const ++{ ++ return m_role[role].multiplicityWidget; ++} ++ ++/** ++ * Read property of FloatingTextWidget* m_nameWidget. ++ * ++ * @return Pointer to the FloatingTextWidget name widget. ++ */ ++FloatingTextWidget* AssociationWidget::nameWidget() const ++{ ++ return m_nameWidget; ++} ++ ++/** ++ * Return the given role's FloatingTextWidget object. ++ * ++ * @return Pointer to the role's FloatingTextWidget widget. ++ */ ++FloatingTextWidget* AssociationWidget::roleWidget(Uml::RoleType::Enum role) const ++{ ++ return m_role[role].roleWidget; ++} ++ ++/** ++ * Return the given role's changeability FloatingTextWidget widget. ++ */ ++FloatingTextWidget* AssociationWidget::changeabilityWidget(Uml::RoleType::Enum role) const ++{ ++ return m_role[role].changeabilityWidget; ++} ++ ++/** ++ * Return the FloatingTextWidget object indicated by the given TextRole::Enum. ++ * ++ * @return Pointer to the text role's FloatingTextWidget widget. ++ */ ++FloatingTextWidget* AssociationWidget::textWidgetByRole(Uml::TextRole::Enum tr) const ++{ ++ switch (tr) { ++ case Uml::TextRole::MultiA: ++ return m_role[RoleType::A].multiplicityWidget; ++ case Uml::TextRole::MultiB: ++ return m_role[RoleType::B].multiplicityWidget; ++ case Uml::TextRole::Name: ++ case Uml::TextRole::Coll_Message: ++ return m_nameWidget; ++ case Uml::TextRole::RoleAName: ++ return m_role[RoleType::A].roleWidget; ++ case Uml::TextRole::RoleBName: ++ return m_role[RoleType::B].roleWidget; ++ case Uml::TextRole::ChangeA: ++ return m_role[RoleType::A].changeabilityWidget; ++ case Uml::TextRole::ChangeB: ++ return m_role[RoleType::B].changeabilityWidget; ++ default: ++ break; ++ } ++ return NULL; ++} ++ ++/** ++ * Returns the m_nameWidget's text. ++ * ++ * @return Text of the FloatingTextWidget name widget. ++ */ ++QString AssociationWidget::name() const ++{ ++ if (m_nameWidget == NULL) ++ return QString(); ++ return m_nameWidget->text(); ++} ++ ++/** ++ * Sets the text in the FloatingTextWidget widget representing the Name ++ * of this association. ++ */ ++void AssociationWidget::setName(const QString &strName) ++{ ++ // set attribute of UMLAssociation associated with this associationwidget ++ UMLAssociation *umla = association(); ++ if (umla) ++ umla->setName(strName); ++ ++ bool newLabel = false; ++ if (!m_nameWidget) { ++ // Don't construct the FloatingTextWidget if the string is empty. ++ if (! FloatingTextWidget::isTextValid(strName)) ++ return; ++ ++ newLabel = true; ++ m_nameWidget = new FloatingTextWidget(m_scene, calculateNameType(Uml::TextRole::Name), strName); ++ m_nameWidget->setParentItem(this); ++ m_nameWidget->setLink(this); ++ } else { ++ m_nameWidget->setText(strName); ++ if (! FloatingTextWidget::isTextValid(strName)) { ++ //m_nameWidget->hide(); ++ m_scene->removeWidget(m_nameWidget); ++ m_nameWidget = NULL; ++ return; ++ } ++ } ++ ++ setTextPosition(Uml::TextRole::Name); ++ if (newLabel) { ++ m_nameWidget->setActivated(); ++ m_scene->addFloatingTextWidget(m_nameWidget); ++ } ++ ++ m_nameWidget->show(); ++} ++ ++void AssociationWidget::setStereotype(const QString &stereo) { ++ UMLAssociation *umlassoc = association(); ++ if (umlassoc) { ++ umlassoc->setStereotype(stereo); ++ if (m_nameWidget) { ++ m_nameWidget->setText(umlassoc->stereotype(true)); ++ } else { ++ uDebug() << "not setting " << stereo << " because m_nameWidget is NULL"; ++ } ++ } else { ++ uDebug() << "not setting " << stereo << " because association is NULL"; ++ } ++} ++ ++/** ++ * Return the given role's FloatingTextWidget widget text. ++ * ++ * @return The name set at the FloatingTextWidget. ++ */ ++QString AssociationWidget::roleName(Uml::RoleType::Enum role) const ++{ ++ if (m_role[role].roleWidget == NULL) ++ return QString(); ++ return m_role[role].roleWidget->text(); ++} ++ ++/** ++ * Sets the text to the FloatingTextWidget that display the Role text of this ++ * association. ++ * For this function to work properly, the associated widget ++ * should already be set. ++ */ ++void AssociationWidget::setRoleName(const QString &strRole, Uml::RoleType::Enum role) ++{ ++ Uml::AssociationType::Enum type = associationType(); ++ //if the association is not supposed to have a Role FloatingTextWidget ++ if (!AssocRules::allowRole(type)) { ++ return; ++ } ++ ++ TextRole::Enum tr = (role == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); ++ setFloatingText(tr, strRole, m_role[role].roleWidget); ++ if (m_role[role].roleWidget) { ++ Uml::Visibility::Enum vis = visibility(role); ++ if (FloatingTextWidget::isTextValid(m_role[role].roleWidget->text())) { ++ m_role[role].roleWidget->setPreText(Uml::Visibility::toString(vis, true)); ++ //m_role[role].roleWidget->show(); ++ } else { ++ m_role[role].roleWidget->setPreText(QString()); ++ //m_role[role].roleWidget->hide(); ++ } ++ } ++ ++ // set attribute of UMLAssociation associated with this associationwidget ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) ++ association()->setRoleName(strRole, role); ++} ++ ++/** ++ * Set the documentation on the given role. ++ */ ++void AssociationWidget::setRoleDocumentation(const QString &doc, Uml::RoleType::Enum role) ++{ ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) ++ association()->setRoleDoc(doc, role); ++ else ++ m_role[role].roleDocumentation = doc; ++} ++ ++/** ++ * Returns the given role's documentation. ++ */ ++QString AssociationWidget::roleDocumentation(Uml::RoleType::Enum role) const ++{ ++ if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) ++ return QString(); ++ UMLAssociation *umla = static_cast(m_umlObject); ++ return umla->getRoleDoc(role); ++} ++ ++/** ++ * Change, create, or delete the FloatingTextWidget indicated by the given TextRole::Enum. ++ * ++ * @param tr TextRole::Enum of the FloatingTextWidget to change or create. ++ * @param text Text string that controls the action: ++ * If empty and ft is NULL then setFloatingText() is a no-op. ++ * If empty and ft is non-NULL then the existing ft is deleted. ++ * If non-empty and ft is NULL then a new FloatingTextWidget is created ++ * and returned in ft with the text set. ++ * If non-empty and ft is non-NULL then the existing ft text is modified. ++ * @param ft Reference to the pointer to FloatingTextWidget to change or create. ++ * On creation/deletion, the pointer value will be changed. ++ */ ++void AssociationWidget::setFloatingText(Uml::TextRole::Enum role, ++ const QString &text, ++ FloatingTextWidget* &ft) ++{ ++ if (! FloatingTextWidget::isTextValid(text)) { ++ if (ft) { ++ // Remove preexisting FloatingTextWidget ++ m_scene->removeWidget(ft); // physically deletes ft ++ ft = NULL; ++ } ++ return; ++ } ++ ++ if (ft == NULL) { ++ ft = new FloatingTextWidget(m_scene, role, text); ++ ft->setParentItem(this); ++ ft->setLink(this); ++ ft->activate(); ++ setTextPosition(role); ++ m_scene->addFloatingTextWidget(ft); ++ } else { ++ bool newLabel = ft->text().isEmpty(); ++ ft->setText(text); ++ if (newLabel) ++ setTextPosition(role); ++ } ++ ++ ft->show(); ++} ++ ++/** ++ * Return the given role's multiplicity text. ++ * ++ * @return Text of the given role's multiplicity widget. ++ */ ++QString AssociationWidget::multiplicity(Uml::RoleType::Enum role) const ++{ ++ if (m_role[role].multiplicityWidget == NULL) ++ return QString(); ++ return m_role[role].multiplicityWidget->text(); ++} ++ ++/** ++ * Sets the text in the FloatingTextWidget representing the multiplicity ++ * at the given side of the association. ++ */ ++void AssociationWidget::setMultiplicity(const QString& text, Uml::RoleType::Enum role) ++{ ++ TextRole::Enum tr = (role == RoleType::A ? TextRole::MultiA : TextRole::MultiB); ++ ++ setFloatingText(tr, text, m_role[role].multiplicityWidget); ++ ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) ++ association()->setMultiplicity(text, role); ++} ++ ++/** ++ * Gets the visibility on the given role of the association. ++ */ ++Visibility::Enum AssociationWidget::visibility(Uml::RoleType::Enum role) const ++{ ++ const UMLAssociation *assoc = association(); ++ if (assoc) ++ return assoc->visibility(role); ++ const UMLAttribute *attr = attribute(); ++ if (attr) ++ return attr->visibility(); ++ return m_role[role].visibility; ++} ++ ++/** ++ * Sets the visibility on the given role of the association. ++ */ ++void AssociationWidget::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) ++{ ++ if (value == visibility(role)) { ++ return; ++ } ++ if (m_umlObject) { ++ // update our model object ++ const UMLObject::ObjectType ot = m_umlObject->baseType(); ++ if (ot == UMLObject::ot_Association) ++ association()->setVisibility(value, role); ++ else if (ot == UMLObject::ot_Attribute) ++ attribute()->setVisibility(value); ++ } ++ m_role[role].visibility = value; ++ // update role pre-text attribute as appropriate ++ if (m_role[role].roleWidget) { ++ QString scopeString = Visibility::toString(value, true); ++ m_role[role].roleWidget->setPreText(scopeString); ++ } ++} ++ ++/** ++ * Gets the changeability on the given end of the Association. ++ */ ++Uml::Changeability::Enum AssociationWidget::changeability(Uml::RoleType::Enum role) const ++{ ++ if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) ++ return m_role[role].changeability; ++ UMLAssociation *umla = static_cast(m_umlObject); ++ return umla->changeability(role); ++} ++ ++/** ++ * Sets the changeability on the given end of the Association. ++ */ ++void AssociationWidget::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) ++{ ++ if (value == changeability(role)) ++ return; ++ QString changeString = Uml::Changeability::toString(value); ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) // update our model object ++ association()->setChangeability(value, role); ++ m_role[role].changeability = value; ++ // update our string representation ++ setChangeWidget(changeString, role); ++} ++ ++/** ++ * For internal purpose-kf6s only. ++ * Other classes/users should use setChangeability() instead. ++ */ ++void AssociationWidget::setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role) ++{ ++ bool newLabel = false; ++ TextRole::Enum tr = (role == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); ++ ++ if (!m_role[role].changeabilityWidget) { ++ // Don't construct the FloatingTextWidget if the string is empty. ++ if (strChangeWidget.isEmpty()) ++ return; ++ ++ newLabel = true; ++ m_role[role].changeabilityWidget = new FloatingTextWidget(m_scene, tr, strChangeWidget); ++ m_role[role].changeabilityWidget->setParentItem(this); ++ m_role[role].changeabilityWidget->setLink(this); ++ m_scene->addFloatingTextWidget(m_role[role].changeabilityWidget); ++ m_role[role].changeabilityWidget->setPreText(QLatin1String("{")); // all types have this ++ m_role[role].changeabilityWidget->setPostText(QLatin1String("}")); // all types have this ++ } else { ++ if (m_role[role].changeabilityWidget->text().isEmpty()) { ++ newLabel = true; ++ } ++ m_role[role].changeabilityWidget->setText(strChangeWidget); ++ } ++ m_role[role].changeabilityWidget->setActivated(); ++ ++ if (newLabel) { ++ setTextPosition(tr); ++ } ++ ++ if (FloatingTextWidget::isTextValid(m_role[role].changeabilityWidget->text())) ++ m_role[role].changeabilityWidget->show(); ++ else ++ m_role[role].changeabilityWidget->hide(); ++} ++ ++/** ++ * Returns true if the line path starts at the given widget. ++ */ ++bool AssociationWidget::linePathStartsAt(const UMLWidget* widget) ++{ ++//:TODO: ++// QPointF lpStart = m_associationLine->point(0); ++// int startX = lpStart.x(); ++// int startY = lpStart.y(); ++// int wX = widget->x(); ++// int wY = widget->y(); ++// int wWidth = widget->width(); ++// int wHeight = widget->height(); ++// bool result = (startX >= wX && startX <= wX + wWidth && ++// startY >= wY && startY <= wY + wHeight); ++// return result; ++ bool result = widget->contains(m_associationLine->point(0)); ++ DEBUG(DBG_SRC) << "widget=" << widget->name() << " / result=" << result; ++ return result; ++} ++ ++/** ++ * This function calculates which role should be set for the m_nameWidget FloatingTextWidget. ++ */ ++Uml::TextRole::Enum AssociationWidget::calculateNameType(Uml::TextRole::Enum defaultRole) ++{ ++ TextRole::Enum result = defaultRole; ++ if (m_scene->type() == DiagramType::Collaboration) { ++ if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { ++ result = TextRole::Coll_Message;//for now same as other Coll_Message ++ } else { ++ result = TextRole::Coll_Message; ++ } ++ } else if (m_scene->type() == DiagramType::Sequence) { ++ if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { ++ result = TextRole::Seq_Message_Self; ++ } else { ++ result = TextRole::Seq_Message; ++ } ++ } ++ ++ return result; ++} ++ ++/** ++ * Gets the given role widget. ++ * ++ * @return Pointer to the role's UMLWidget. ++ */ ++UMLWidget* AssociationWidget::widgetForRole(Uml::RoleType::Enum role) const ++{ ++ return m_role[role].umlWidget; ++} ++ ++/** ++ * Sets the associated widgets. ++ * ++ * @param widgetA Pointer the role A widget for the association. ++ * @param assocType The AssociationType::Enum for this association. ++ * @param widgetB Pointer the role B widget for the association. ++ */ ++bool AssociationWidget::setWidgets(UMLWidget* widgetA, ++ Uml::AssociationType::Enum assocType, ++ UMLWidget* widgetB) ++{ ++ //if the association already has a WidgetB or WidgetA associated, then ++ //it cannot be changed to other widget, that would require a deletion ++ //of the association and the creation of a new one ++ if ((m_role[RoleType::A].umlWidget && (m_role[RoleType::A].umlWidget != widgetA)) || ++ (m_role[RoleType::B].umlWidget && (m_role[RoleType::B].umlWidget != widgetB))) { ++ return false; ++ } ++ setWidgetForRole(widgetA, RoleType::A); ++ setAssociationType(assocType); ++ setWidgetForRole(widgetB, RoleType::B); ++ ++ calculateEndingPoints(); ++ return true; ++} ++ ++/** ++ * CleansUp all the association's data in the related widgets. ++ */ ++void AssociationWidget::cleanup() ++{ ++ //let any other associations know we are going so they can tidy their positions up ++ if (m_role[RoleType::A].m_nTotalCount > 2) ++ updateAssociations(m_role[RoleType::A].m_nTotalCount - 1, m_role[RoleType::A].m_WidgetRegion, RoleType::A); ++ if (m_role[RoleType::B].m_nTotalCount > 2) ++ updateAssociations(m_role[RoleType::B].m_nTotalCount - 1, m_role[RoleType::B].m_WidgetRegion, RoleType::B); ++ ++ for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { ++ WidgetRole& robj = m_role[r]; ++ ++ if (robj.umlWidget) { ++ robj.umlWidget->removeAssoc(this); ++ robj.umlWidget = 0; ++ } ++ if (robj.roleWidget) { ++ m_scene->removeWidget(robj.roleWidget); ++ robj.roleWidget = 0; ++ } ++ if (robj.multiplicityWidget) { ++ m_scene->removeWidget(robj.multiplicityWidget); ++ robj.multiplicityWidget = 0; ++ } ++ if (robj.changeabilityWidget) { ++ m_scene->removeWidget(robj.changeabilityWidget); ++ robj.changeabilityWidget = 0; ++ } ++ } ++ ++ if (m_nameWidget) { ++ m_scene->removeWidget(m_nameWidget); ++ m_nameWidget = 0; ++ } ++ ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { ++ /* ++ We do not remove the UMLAssociation from the document. ++ Why? - Well, for example we might be in the middle of ++ a cut/paste. If the UMLAssociation is removed by the cut ++ then upon pasteing we have a problem. ++ This is not quite clean yet - there should be a way to ++ explicitly delete a UMLAssociation. The Right Thing would ++ be to have a ListView representation for UMLAssociation. ++ ` ++ IF we are cut n pasting, why are we handling this association as a pointer? ++ We should be using the XMI representation for a cut and paste. This ++ allows us to be clean here, AND a choice of recreating the object ++ w/ same id IF its a "cut", or a new object if its a "copy" operation ++ (in which case we wouldnt be here, in cleanup()). ++ */ ++ setUMLAssociation(0); ++ } ++ ++ m_associationLine->cleanup(); ++ removeAssocClassLine(); ++} ++ ++/** ++ * @brief Return state if the assocation line point in the near of the last context ++ * menu event position is addable or not. ++ * A point is addable if the association is not an Exception and there is no point in the near. ++ * ++ * @return true if point is addable ++ */ ++bool AssociationWidget::isPointAddable() ++{ ++ if (!isSelected() || associationType() == Uml::AssociationType::Exception) ++ return false; ++ int i = m_associationLine->closestPointIndex(m_eventScenePos); ++ return i == -1; ++} ++ ++/** ++ * @brief Return state if the assocation line point in the near of the last context ++ * menu event position is removable or not. ++ * A point is removable if the association is not an Exception and is not the start or end point. ++ * ++ * @return true if point is removable ++ */ ++bool AssociationWidget::isPointRemovable() ++{ ++ if (!isSelected() || associationType() == Uml::AssociationType::Exception || m_associationLine->count() <= 2) ++ return false; ++ int i = m_associationLine->closestPointIndex(m_eventScenePos); ++ return i > 0 && i < m_associationLine->count() - 1; ++} ++ ++/** ++ * Set our internal umlAssociation. ++ */ ++void AssociationWidget::setUMLAssociation (UMLAssociation * assoc) ++{ ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { ++ UMLAssociation *umla = association(); ++ ++ // safety check. Did some num-nuts try to set the existing ++ // association again? If so, just bail here ++ if (umla == assoc) ++ return; ++ ++ //umla->disconnect(this); //Qt does disconnect automatically upon destruction. ++ umla->nrof_parent_widgets--; ++ ++ // ANSWER: This is the wrong treatment of cut and paste. Associations that ++ // are being cut/n pasted should be serialized to XMI, then reconstituted ++ // (IF a paste operation) rather than passing around object pointers. Its ++ // just too hard otherwise to prevent problems in the code. Bottom line: we need to ++ // delete orphaned associations or we well get code crashes and memory leaks. ++ if (umla->nrof_parent_widgets <= 0) { ++ //umla->deleteLater(); ++ } ++ ++ m_umlObject = NULL; ++ } ++ ++ if (assoc) { ++ m_umlObject = assoc; ++ ++ // move counter to "0" from "-1" (which means, no assocwidgets) ++ if (assoc->nrof_parent_widgets < 0) ++ assoc->nrof_parent_widgets = 0; ++ ++ assoc->nrof_parent_widgets++; ++ connect(assoc, SIGNAL(modified()), this, SLOT(syncToModel())); ++ } ++ ++} ++ ++/** ++ * Returns true if the Widget is either at the starting or ending side of the association. ++ */ ++bool AssociationWidget::containsAsEndpoint(UMLWidget* widget) ++{ ++ return (widget == m_role[RoleType::A].umlWidget || widget == m_role[RoleType::B].umlWidget); ++} ++ ++/** ++ * Returns true if this AssociationWidget represents a collaboration message. ++ */ ++bool AssociationWidget::isCollaboration() const ++{ ++ Uml::AssociationType::Enum at = associationType(); ++ return (at == AssociationType::Coll_Message_Synchronous ++ || at == AssociationType::Coll_Message_Asynchronous ++ || at == AssociationType::Coll_Message_Self); ++} ++ ++/** ++ * Returns true if this AssociationWidget represents a self message. ++ */ ++bool AssociationWidget::isSelf() const ++{ ++ return widgetForRole(Uml::RoleType::A) == widgetForRole(Uml::RoleType::B); ++} ++ ++/** ++ * Gets the association's type. ++ * ++ * @return This AssociationWidget's AssociationType::Enum. ++ */ ++Uml::AssociationType::Enum AssociationWidget::associationType() const ++{ ++ if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) ++ return m_associationType; ++ UMLAssociation *umla = static_cast(m_umlObject); ++ return umla->getAssocType(); ++} ++ ++/** ++ * Sets the association's type. ++ * ++ * @param type The AssociationType::Enum to set. ++ */ ++void AssociationWidget::setAssociationType(Uml::AssociationType::Enum type) ++{ ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { ++ association()->setAssociationType(type); ++ } ++ m_associationType = type; ++ // If the association new type is not supposed to have Multiplicity ++ // FloatingTexts and a Role FloatingTextWidget then set the texts ++ // to empty. ++ // NB We do not physically delete the floatingtext widgets here because ++ // those widgets are also stored in the UMLView::m_WidgetList. ++ if (!AssocRules::allowMultiplicity(type, widgetForRole(RoleType::A)->baseType())) { ++ if (m_role[RoleType::A].multiplicityWidget) { ++ m_role[RoleType::A].multiplicityWidget->setName(QString()); ++ } ++ if (m_role[RoleType::B].multiplicityWidget) { ++ m_role[RoleType::B].multiplicityWidget->setName(QString()); ++ } ++ } ++ if (!AssocRules::allowRole(type)) { ++ if (m_role[RoleType::A].roleWidget) { ++ m_role[RoleType::A].roleWidget->setName(QString()); ++ } ++ if (m_role[RoleType::B].roleWidget) { ++ m_role[RoleType::B].roleWidget->setName(QString()); ++ } ++ setRoleDocumentation(QString(), RoleType::A); ++ setRoleDocumentation(QString(), RoleType::B); ++ } ++ m_associationLine->reconstructSymbols(); ++} ++ ++/** ++ * Gets the ID of the given role widget. ++ */ ++Uml::ID::Type AssociationWidget::widgetIDForRole(Uml::RoleType::Enum role) const ++{ ++ if (m_role[role].umlWidget == NULL) { ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { ++ UMLAssociation *umla = static_cast(m_umlObject); ++ return umla->getObjectId(role); ++ } ++ uError() << "umlWidget is NULL"; ++ return Uml::ID::None; ++ } ++ if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) ++ return static_cast(m_role[role].umlWidget)->localID(); ++ Uml::ID::Type id = m_role[role].umlWidget->id(); ++ return id; ++} ++ ++/** ++ * Gets the local ID of the given role widget. ++ */ ++Uml::ID::Type AssociationWidget::widgetLocalIDForRole(Uml::RoleType::Enum role) const ++{ ++ if (m_role[role].umlWidget == NULL) { ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { ++ UMLAssociation *umla = static_cast(m_umlObject); ++ return umla->getObjectId(role); ++ } ++ uError() << "umlWidget is NULL"; ++ return Uml::ID::None; ++ } ++ if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) ++ return static_cast(m_role[role].umlWidget)->localID(); ++ Uml::ID::Type id = m_role[role].umlWidget->localID(); ++ return id; ++} ++ ++/** ++ * Returns a QString Object representing this AssociationWidget. ++ */ ++QString AssociationWidget::toString() const ++{ ++ QString string; ++ static const QChar colon(QLatin1Char(':')); ++ ++ if (widgetForRole(RoleType::A)) { ++ string = widgetForRole(RoleType::A)->name(); ++ } ++ string.append(colon); ++ ++ if (m_role[RoleType::A].roleWidget) { ++ string += m_role[RoleType::A].roleWidget->text(); ++ } ++ string.append(colon); ++ string.append(Uml::AssociationType::toStringI18n(associationType())); ++ string.append(colon); ++ ++ if (widgetForRole(RoleType::B)) { ++ string += widgetForRole(RoleType::B)->name(); ++ } ++ ++ string.append(colon); ++ if (m_role[RoleType::B].roleWidget) { ++ string += m_role[RoleType::B].roleWidget->text(); ++ } ++ ++ return string; ++} ++ ++/** ++ * Adds a break point (if left mouse button). ++ */ ++void AssociationWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) ++{ ++ if (event->button() == Qt::LeftButton) { ++ uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); ++ showPropertiesDialog(); ++ event->accept(); ++ } ++} ++ ++/** ++ * Overrides moveEvent. ++ */ ++void AssociationWidget::moveEvent(QGraphicsSceneMouseEvent *me) ++{ ++ // 2004-04-30: Achim Spangler ++ // Simple Approach to block moveEvent during load of XMI ++ /// @todo avoid trigger of this event during load ++ ++ if (umlDoc()->loading()) { ++ // hmmh - change of position during load of XMI ++ // -> there is something wrong ++ // -> avoid movement during opening ++ // -> print warn and stay at old position ++ uWarning() << "called during load of XMI for ViewType: " ++ << m_scene->type() << ", and BaseType: " << baseType(); ++ return; ++ } ++ /*to be here a line segment has moved. ++ we need to see if the three text widgets needs to be moved. ++ there are a few things to check first though: ++ ++ 1) Do they exist ++ 2) does it need to move: ++ 2a) for the multi widgets only move if they changed region, otherwise they are close enough ++ 2b) for role name move if the segment it is on moves. ++ */ ++ //first see if either the first or last segments moved, else no need to recalculate their point positions ++ ++ QPointF oldNamePoint = calculateTextPosition(TextRole::Name); ++ QPointF oldMultiAPoint = calculateTextPosition(TextRole::MultiA); ++ QPointF oldMultiBPoint = calculateTextPosition(TextRole::MultiB); ++ QPointF oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); ++ QPointF oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); ++ QPointF oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); ++ QPointF oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); ++ ++ int movingPoint = m_associationLine->closestPointIndex(me->scenePos()); ++ if (movingPoint != -1) ++ m_associationLine->setPoint(movingPoint, me->scenePos()); ++ int pos = m_associationLine->count() - 1;//set to last point for widget b ++ ++ if ( movingPoint == 1 || (movingPoint == pos-1) ) { ++ calculateEndingPoints(); ++ } ++ if (m_role[RoleType::A].changeabilityWidget && (movingPoint == 1)) { ++ setTextPositionRelatively(TextRole::ChangeA, oldChangeAPoint); ++ } ++ if (m_role[RoleType::B].changeabilityWidget && (movingPoint == 1)) { ++ setTextPositionRelatively(TextRole::ChangeB, oldChangeBPoint); ++ } ++ if (m_role[RoleType::A].multiplicityWidget && (movingPoint == 1)) { ++ setTextPositionRelatively(TextRole::MultiA, oldMultiAPoint); ++ } ++ if (m_role[RoleType::B].multiplicityWidget && (movingPoint == pos-1)) { ++ setTextPositionRelatively(TextRole::MultiB, oldMultiBPoint); ++ } ++ ++ if (m_nameWidget) { ++ if (movingPoint == m_unNameLineSegment || ++ movingPoint - 1 == m_unNameLineSegment) { ++ setTextPositionRelatively(TextRole::Name, oldNamePoint); ++ } ++ } ++ ++ if (m_role[RoleType::A].roleWidget) { ++ setTextPositionRelatively(TextRole::RoleAName, oldRoleAPoint); ++ } ++ if (m_role[RoleType::B].roleWidget) { ++ setTextPositionRelatively(TextRole::RoleBName, oldRoleBPoint); ++ } ++ ++ if (m_pAssocClassLine) { ++ computeAssocClassLine(); ++ } ++} ++ ++/** ++ * Calculates and sets the first and last point in the Association's AssociationLine. ++ * Each point is a middle point of its respecting UMLWidget's Bounding rectangle ++ * or a corner of it. ++ * This method picks which sides to use for the association. ++ */ ++void AssociationWidget::calculateEndingPoints() ++{ ++ /* ++ * For each UMLWidget the diagram is divided in four regions by its diagonals ++ * as indicated below ++ * Region 2 ++ * \ / ++ * \ / ++ * +--------+ ++ * | \ / | ++ * Region 1 | >< | Region 3 ++ * | / \ | ++ * +--------+ ++ * / \ ++ * / \ ++ * Region 4 ++ * ++ * Each diagonal is defined by two corners of the bounding rectangle ++ * ++ * To calculate the first point in the AssociationLine we have to find out in which ++ * Region (defined by WidgetA's diagonals) is WidgetB's center ++ * (let's call it Region M.) After that the first point will be the middle ++ * point of the rectangle's side contained in Region M. ++ * ++ * To calculate the last point in the AssociationLine we repeat the above but ++ * in the opposite direction (from widgetB to WidgetA) ++ */ ++ ++ UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; ++ UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; ++ if (!pWidgetA || !pWidgetB) { ++ uWarning() << "Returning - one of the role widgets is not set."; ++ return; ++ } ++ ++ int size = m_associationLine->count(); ++ if (size < 2) { ++ QPointF pA = pWidgetA->pos(); ++ QPointF pB = pWidgetB->pos(); ++ QPolygonF polyA = pWidgetA->shape().toFillPolygon().translated(pA); ++ QPolygonF polyB = pWidgetB->shape().toFillPolygon().translated(pB); ++ QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); ++ if (nearestPoints.isNull()) { ++ uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; ++ } else { ++ pA = nearestPoints.p1(); ++ pB = nearestPoints.p2(); ++ } ++ m_associationLine->setEndPoints(pA, pB); ++ } ++ ++ // See if an association to self. ++ // See if it needs to be set up before we continue: ++ // If self association/message and doesn't have the minimum 4 points ++ // then create it. Make sure no points are out of bounds of viewing area. ++ // This only happens on first time through that we are worried about. ++ if (isSelf() && size < 4) { ++ createPointsSelfAssociation(); ++ return; ++ } ++ ++ if (associationType() == AssociationType::Exception && size < 4) { ++ createPointsException(); ++ updatePointsException(); ++ return; ++ } ++ ++ // If the line has more than one segment change the values to calculate ++ // from widget to point 1. ++ qreal xB = pWidgetB->x() + pWidgetB->width() / 2; ++ qreal yB = pWidgetB->y() + pWidgetB->height() / 2; ++ if (size > 2) { ++ QPointF p = m_associationLine->point(1); ++ xB = p.x(); ++ yB = p.y(); ++ } ++ doUpdates(QPointF(xB, yB), RoleType::A); ++ ++ // Now do the same for widgetB. ++ // If the line has more than one segment change the values to calculate ++ // from widgetB to the last point away from it. ++ qreal xA = pWidgetA->x() + pWidgetA->width() / 2; ++ qreal yA = pWidgetA->y() + pWidgetA->height() / 2; ++ if (size > 2 ) { ++ QPointF p = m_associationLine->point(size - 2); ++ xA = p.x(); ++ yA = p.y(); ++ } ++ doUpdates(QPointF(xA, yA), RoleType::B); ++ ++ computeAssocClassLine(); ++} ++ ++/** ++ * Used by @ref calculateEndingPoints. ++ */ ++void AssociationWidget::doUpdates(const QPointF &otherP, RoleType::Enum role) ++{ ++ // Find widget region. ++ Uml::Region::Enum oldRegion = m_role[role].m_WidgetRegion; ++ UMLWidget *pWidget = m_role[role].umlWidget; ++ QRectF rc(pWidget->x(), pWidget->y(), ++ pWidget->width(), pWidget->height()); ++ Uml::Region::Enum region = m_role[role].m_WidgetRegion; // alias for brevity ++ region = findPointRegion(rc, otherP); ++ // Move some regions to the standard ones. ++ switch( region ) { ++ case Uml::Region::NorthWest: ++ region = Uml::Region::North; ++ break; ++ case Uml::Region::NorthEast: ++ region = Uml::Region::East; ++ break; ++ case Uml::Region::SouthEast: ++ region = Uml::Region::South; ++ break; ++ case Uml::Region::SouthWest: ++ case Uml::Region::Center: ++ region = Uml::Region::West; ++ break; ++ default: ++ break; ++ } ++ int regionCount = getRegionCount(region, role) + 2; //+2 = (1 for this one and one to halve it) ++ int totalCount = m_role[role].m_nTotalCount; ++ if (oldRegion != region) { ++ updateRegionLineCount(regionCount - 1, regionCount, region, role); ++ updateAssociations(totalCount - 1, oldRegion, role); ++ } else if (totalCount != regionCount) { ++ updateRegionLineCount(regionCount - 1, regionCount, region, role); ++ } else { ++ updateRegionLineCount(m_role[role].m_nIndex, totalCount, region, role); ++ } ++ updateAssociations(regionCount, region, role); ++} ++ ++/** ++ * Read property of bool m_activated. ++ */ ++bool AssociationWidget::isActivated() const ++{ ++ return m_activated; ++} ++ ++/** ++ * Set the m_activated flag of a widget but does not perform the Activate method. ++ */ ++void AssociationWidget::setActivated(bool active) ++{ ++ m_activated = active; ++} ++ ++/** ++ * Synchronize this widget from the UMLAssociation. ++ */ ++void AssociationWidget::syncToModel() ++{ ++ UMLAssociation *uml = association(); ++ ++ if (uml == NULL) { ++ UMLAttribute *attr = attribute(); ++ if (attr == NULL) ++ return; ++ setVisibility(attr->visibility(), RoleType::B); ++ setRoleName(attr->name(), RoleType::B); ++ return; ++ } ++ // block signals until finished ++ uml->blockSignals(true); ++ ++ setName(uml->name()); ++ setRoleName(uml->getRoleName(RoleType::A), RoleType::A); ++ setRoleName(uml->getRoleName(RoleType::B), RoleType::B); ++ setVisibility(uml->visibility(RoleType::A), RoleType::A); ++ setVisibility(uml->visibility(RoleType::B), RoleType::B); ++ setChangeability(uml->changeability(RoleType::A), RoleType::A); ++ setChangeability(uml->changeability(RoleType::B), RoleType::B); ++ setMultiplicity(uml->getMultiplicity(RoleType::A), RoleType::A); ++ setMultiplicity(uml->getMultiplicity(RoleType::B), RoleType::B); ++ ++ uml->blockSignals(false); ++} ++ ++/** ++ * Merges/syncs the association widget data into UML object ++ * representation. ++ * This will synchronize UMLAssociation w/ this new Widget ++ * CHECK: Can we get rid of this. ++ */ ++void AssociationWidget::mergeAssociationDataIntoUMLRepresentation() ++{ ++ UMLAssociation *umlassoc = association(); ++ UMLAttribute *umlattr = attribute(); ++ if (umlassoc == NULL && umlattr == NULL) ++ return; ++ ++ // block emit modified signal, or we get a horrible loop ++ m_umlObject->blockSignals(true); ++ ++ // would be desirable to do the following ++ // so that we can be sure its back to initial state ++ // in case we missed something here. ++ //uml->init(); ++ ++ // floating text widgets ++ FloatingTextWidget *text = nameWidget(); ++ if (text) ++ m_umlObject->setName(text->text()); ++ ++ text = roleWidget(RoleType::A); ++ if (text && umlassoc) ++ umlassoc->setRoleName(text->text(), RoleType::A); ++ ++ text = roleWidget(RoleType::B); ++ if (text) { ++ if (umlassoc) ++ umlassoc->setRoleName(text->text(), RoleType::B); ++ else if (umlattr) ++ umlattr->setName(text->text()); ++ } ++ ++ text = multiplicityWidget(RoleType::A); ++ if (text && umlassoc) ++ umlassoc->setMultiplicity(text->text(), RoleType::A); ++ ++ text = multiplicityWidget(RoleType::B); ++ if (text && umlassoc) ++ umlassoc->setMultiplicity(text->text(), RoleType::B); ++ ++ // unblock ++ m_umlObject->blockSignals(false); ++} ++ ++/** ++ * Auxiliary method for widgetMoved(): ++ * Saves all ideally computed floatingtext positions before doing any ++ * kind of change. This is necessary because a single invocation of ++ * calculateEndingPoints() modifies the AssociationLine ending points on ALL ++ * AssociationWidgets. This means that if we don't save the old ideal ++ * positions then they are irretrievably lost as soon as ++ * calculateEndingPoints() is invoked. ++ */ ++void AssociationWidget::saveIdealTextPositions() ++{ ++ m_oldNamePoint = calculateTextPosition(TextRole::Name); ++ m_oldMultiAPoint = calculateTextPosition(TextRole::MultiA); ++ m_oldMultiBPoint = calculateTextPosition(TextRole::MultiB); ++ m_oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); ++ m_oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); ++ m_oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); ++ m_oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); ++} ++ ++/** ++ * Adjusts the ending point of the association that connects to Widget. ++ */ ++void AssociationWidget::widgetMoved(UMLWidget* widget, qreal dx, qreal dy) ++{ ++ Q_UNUSED(dx); Q_UNUSED(dy); ++ ++ // Simple Approach to block moveEvent during load of XMI ++ /// @todo avoid trigger of this event during load ++ if (umlDoc()->loading()) { ++ // change of position during load of XMI ++ // -> there is something wrong ++ // -> avoid movement during opening ++ // -> print warn and stay at old position ++ DEBUG(DBG_SRC) << "called during load of XMI for ViewType: " << m_scene->type() ++ << ", and BaseType: " << baseTypeStr(); ++ return; ++ } ++ ++ DEBUG(DBG_SRC) << "association type=" << Uml::AssociationType::toString(associationType()); ++ if (associationType() == AssociationType::Exception) { ++ updatePointsException(); ++ setTextPosition(TextRole::Name); ++ } ++ else { ++ calculateEndingPoints(); ++ computeAssocClassLine(); ++ } ++ ++ // Assoc to self - move all points: ++ if (isSelf()) { ++ updatePointsSelfAssociation(); ++ ++ if (m_nameWidget && !m_nameWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::Name, m_oldNamePoint); ++ } ++ ++ }//end if widgetA = widgetB ++ else if (m_role[RoleType::A].umlWidget == widget) { ++ if (m_nameWidget && m_unNameLineSegment == 0 && !m_nameWidget->isSelected() ) { ++ //only calculate position and move text if the segment it is on is moving ++ setTextPositionRelatively(TextRole::Name, m_oldNamePoint); ++ } ++ }//end if widgetA moved ++ else if (m_role[RoleType::B].umlWidget == widget) { ++ const int size = m_associationLine->count(); ++ if (m_nameWidget && (m_unNameLineSegment == size-2) && !m_nameWidget->isSelected() ) { ++ //only calculate position and move text if the segment it is on is moving ++ setTextPositionRelatively(TextRole::Name, m_oldNamePoint); ++ } ++ }//end if widgetB moved ++ ++ if (m_role[RoleType::A].roleWidget && !m_role[RoleType::A].roleWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::RoleAName, m_oldRoleAPoint); ++ } ++ if (m_role[RoleType::B].roleWidget && !m_role[RoleType::B].roleWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::RoleBName, m_oldRoleBPoint); ++ } ++ if (m_role[RoleType::A].multiplicityWidget && !m_role[RoleType::A].multiplicityWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::MultiA, m_oldMultiAPoint); ++ } ++ if (m_role[RoleType::B].multiplicityWidget && !m_role[RoleType::B].multiplicityWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::MultiB, m_oldMultiBPoint); ++ } ++ if (m_role[RoleType::A].changeabilityWidget && !m_role[RoleType::A].changeabilityWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::ChangeA, m_oldChangeAPoint); ++ } ++ if (m_role[RoleType::B].changeabilityWidget && !m_role[RoleType::B].changeabilityWidget->isSelected()) { ++ setTextPositionRelatively(TextRole::ChangeB, m_oldChangeBPoint); ++ } ++} ++ ++/** ++ * Creates the points of the self association. ++ * Method called when a widget end points are calculated by calculateEndingPoints(). ++ */ ++void AssociationWidget::createPointsSelfAssociation() ++{ ++ UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; ++ ++ const int DISTANCE = 50; ++ qreal x = pWidgetA->x(); ++ qreal y = pWidgetA->y(); ++ qreal h = pWidgetA->height(); ++ qreal w = pWidgetA->width(); ++ // see if above widget ok to start ++ if (y - DISTANCE > 0) { ++ m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); ++ m_associationLine->insertPoint(1, QPointF(x + w / 4, y - DISTANCE)); ++ m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); ++ m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; ++ } else { ++ m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); ++ m_associationLine->insertPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); ++ m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); ++ m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; ++ } ++} ++ ++/** ++ * Adjusts the points of the self association. ++ * Method called when a widget was moved by widgetMoved(widget, x, y). ++ */ ++void AssociationWidget::updatePointsSelfAssociation() ++{ ++ UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; ++ ++ const int DISTANCE = 50; ++ qreal x = pWidgetA->x(); ++ qreal y = pWidgetA->y(); ++ qreal h = pWidgetA->height(); ++ qreal w = pWidgetA->width(); ++ // see if above widget ok to start ++ if (y - DISTANCE > 0) { ++ m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); ++ m_associationLine->setPoint(1, QPointF(x + w / 4, y - DISTANCE)); ++ m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); ++ m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; ++ } else { ++ m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); ++ m_associationLine->setPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); ++ m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); ++ m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; ++ } ++} ++ ++/** ++ * Creates the points of the association exception. ++ * Method called when a widget end points are calculated by calculateEndingPoints(). ++ */ ++void AssociationWidget::createPointsException() ++{ ++ UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; ++ UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; ++ ++ qreal xa = pWidgetA->x(); ++ qreal ya = pWidgetA->y(); ++ qreal ha = pWidgetA->height(); ++ qreal wa = pWidgetA->width(); ++ ++ qreal xb = pWidgetB->x(); ++ qreal yb = pWidgetB->y(); ++ qreal hb = pWidgetB->height(); ++ //qreal wb = pWidgetB->width(); ++ ++ m_associationLine->setEndPoints(QPointF(xa + wa , ya + ha/2) , QPointF(xb , yb + hb/2)); ++ m_associationLine->insertPoint(1, QPointF(xa + wa , ya + ha/2)); ++ m_associationLine->insertPoint(2, QPointF(xb , yb + hb/2)); ++} ++ ++/** ++ * Adjusts the points of the association exception. ++ * Method called when a widget was moved by widgetMoved(widget, x, y). ++ */ ++void AssociationWidget::updatePointsException() ++{ ++ UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; ++ UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; ++ ++ qreal xa = pWidgetA->x(); ++ qreal ya = pWidgetA->y(); ++ qreal ha = pWidgetA->height(); ++ qreal wa = pWidgetA->width(); ++ ++ qreal xb = pWidgetB->x(); ++ qreal yb = pWidgetB->y(); ++ qreal hb = pWidgetB->height(); ++ qreal wb = pWidgetB->width(); ++ qreal xmil, ymil; ++ qreal xdeb, ydeb; ++ qreal xfin, yfin; ++ qreal ESPACEX, ESPACEY; ++ QPointF p1; ++ QPointF p2; ++ //calcul des coordonnées au milieu de la flèche eclair ++ if (xb - xa - wa >= 45) { ++ ESPACEX = 0; ++ xdeb = xa + wa; ++ xfin = xb; ++ } else if (xa - xb - wb > 45) { ++ ESPACEX = 0; ++ xdeb = xa; ++ xfin = xb + wb; ++ } else { ++ ESPACEX = 15; ++ xdeb = xa + wa/2; ++ xfin = xb + wb/2; ++ } ++ ++ xmil = xdeb + (xfin - xdeb)/2; ++ ++ if (yb - ya - ha >= 45) { ++ ESPACEY = 0; ++ ydeb = ya + ha; ++ yfin = yb; ++ } else if (ya - yb - hb > 45) { ++ ESPACEY = 0; ++ ydeb = ya; ++ yfin = yb + hb; ++ } else { ++ ESPACEY = 15; ++ ydeb = ya + ha/2; ++ yfin = yb + hb/2; ++ } ++ ++ ymil = ydeb + (yfin - ydeb)/2; ++ ++ p1.setX(xmil + (xfin - xmil)*1/2); p1.setY(ymil + (yfin - ymil)*1/3); ++ p2.setX(xmil - (xmil - xdeb)*1/2); p2.setY(ymil - (ymil - ydeb)*1/3); ++ ++ if (abs(p1.x() - p2.x()) <= 10) ++ ESPACEX = 15; ++ if (abs(p1.y() - p2.y()) <= 10) ++ ESPACEY = 15; ++ ++ m_associationLine->setEndPoints(QPointF(xdeb, ydeb), QPointF(xfin, yfin)); ++ m_associationLine->setPoint(1, QPointF(p1.x() + ESPACEX, p1.y() + ESPACEY)); ++ m_associationLine->setPoint(2, QPointF(p2.x() - ESPACEX, p2.y() - ESPACEY)); ++ ++ m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; ++} ++ ++/** ++ * Finds out which region of rectangle 'rect' contains the point 'pos' and returns the region ++ * number: ++ * 1 = Region 1 ++ * 2 = Region 2 ++ * 3 = Region 3 ++ * 4 = Region 4 ++ * 5 = On diagonal 2 between Region 1 and 2 ++ * 6 = On diagonal 1 between Region 2 and 3 ++ * 7 = On diagonal 2 between Region 3 and 4 ++ * 8 = On diagonal 1 between Region 4 and 1 ++ * 9 = On diagonal 1 and On diagonal 2 (the center) ++ */ ++Uml::Region::Enum AssociationWidget::findPointRegion(const QRectF& rect, const QPointF &pos) ++{ ++ qreal w = rect.width(); ++ qreal h = rect.height(); ++ qreal x = rect.x(); ++ qreal y = rect.y(); ++ qreal slope2 = w / h; ++ qreal slope1 = slope2 *(-1.0); ++ qreal b1 = x + w - (slope1 * y); ++ qreal b2 = x - (slope2 * y); ++ ++ qreal eval1 = slope1 * pos.y() + b1; ++ qreal eval2 = slope2 * pos.y() + b2; ++ ++ Uml::Region::Enum result = Uml::Region::Error; ++ //if inside region 1 ++ if (eval1 > pos.x() && eval2 > pos.x()) { ++ result = Uml::Region::West; ++ } ++ //if inside region 2 ++ else if (eval1 > pos.x() && eval2 < pos.x()) { ++ result = Uml::Region::North; ++ } ++ //if inside region 3 ++ else if (eval1 < pos.x() && eval2 < pos.x()) { ++ result = Uml::Region::East; ++ } ++ //if inside region 4 ++ else if (eval1 < pos.x() && eval2 > pos.x()) { ++ result = Uml::Region::South; ++ } ++ //if inside region 5 ++ else if (eval1 == pos.x() && eval2 < pos.x()) { ++ result = Uml::Region::NorthWest; ++ } ++ //if inside region 6 ++ else if (eval1 < pos.x() && eval2 == pos.x()) { ++ result = Uml::Region::NorthEast; ++ } ++ //if inside region 7 ++ else if (eval1 == pos.x() && eval2 > pos.x()) { ++ result = Uml::Region::SouthEast; ++ } ++ //if inside region 8 ++ else if (eval1 > pos.x() && eval2 == pos.x()) { ++ result = Uml::Region::SouthWest; ++ } ++ //if inside region 9 ++ else if (eval1 == pos.x() && eval2 == pos.x()) { ++ result = Uml::Region::Center; ++ } ++ return result; ++} ++ ++/** ++ * Returns a point with interchanged X and Y coordinates. ++ */ ++QPointF AssociationWidget::swapXY(const QPointF &p) ++{ ++ QPointF swapped( p.y(), p.x() ); ++ return swapped; ++} ++ ++#if 0 // not used at the moment ++/** ++ * Calculates which point of segment P1P2 has a distance equal to ++ * Distance from P1. ++ * Let's say such point is PX, the distance from P1 to PX must be equal ++ * to Distance and if PX is not a point of the segment P1P2 then the ++ * function returns (-1, -1). ++ */ ++QPointF AssociationWidget::calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance) ++{ ++ /* ++ the distance D between points (x1, y1) and (x3, y3) has the following formula: ++ --- ------------------------------ ++ D = \ / 2 2 ++ \ / (x3 - x1) + (y3 - y1) ++ ++ D, x1 and y1 are known and the point (x3, y3) is inside line (x1, y1)(x2, y2), so if the ++ that line has the formula y = mx + b ++ then y3 = m*x3 + b ++ ++ 2 2 2 ++ D = (x3 - x1) + (y3 - y1) ++ ++ 2 2 2 2 2 ++ D = x3 - 2*x3*x1 + x1 + y3 - 2*y3*y1 + y1 ++ ++ 2 2 2 2 2 ++ D - x1 - y1 = x3 - 2*x3*x1 + y3 - 2*y3*y1 ++ ++ 2 2 2 2 2 ++ D - x1 - y1 = x3 - 2*x3*x1 + (m*x3 + b) - 2*(m*x3 + b)*y1 ++ ++ 2 2 2 2 2 2 ++ D - x1 - y1 + 2*b*y1 - b = (m + 1)*x3 + (-2*x1 + 2*m*b -2*m*y1)*x3 ++ ++ 2 2 2 2 ++ C = - D + x1 + y1 - 2*b*y1 + b ++ ++ ++ 2 ++ A = (m + 1) ++ ++ B = (-2*x1 + 2*m*b -2*m*y1) ++ ++ and we have ++ 2 ++ A * x3 + B * x3 - C = 0 ++ ++ --------------- ++ -B + --- / 2 ++ \/ B - 4*A*C ++ sol_1 = -------------------------------- ++ 2*A ++ ++ ++ --------------- ++ -B - --- / 2 ++ \/ B - 4*A*C ++ sol_2 = -------------------------------- ++ 2*A ++ ++ ++ then in the distance formula we have only one variable x3 and that is easy ++ to calculate ++ */ ++ int x1 = P1.y(); ++ int y1 = P1.x(); ++ int x2 = P2.y(); ++ int y2 = P2.x(); ++ ++ if (x2 == x1) { ++ return QPointF(x1, y1 + (int)Distance); ++ } ++ float slope = ((float)y2 - (float)y1) / ((float)x2 - (float)x1); ++ float b = (y1 - slope*x1); ++ float A = (slope * slope) + 1; ++ float B = (2*slope*b) - (2*x1) - (2*slope*y1); ++ float C = (b*b) - (Distance*Distance) + (x1*x1) + (y1*y1) - (2*b*y1); ++ float t = B*B - 4*A*C; ++ ++ if (t < 0) { ++ return QPointF(-1, -1); ++ } ++ float sol_1 = ((-1* B) + sqrt(t)) / (2*A); ++ float sol_2 = ((-1*B) - sqrt(t)) / (2*A); ++ ++ if (sol_1 < 0.0 && sol_2 < 0.0) { ++ return QPointF(-1, -1); ++ } ++ QPointF sol1Point((int)(slope*sol_1 + b), (int)(sol_1)); ++ QPointF sol2Point((int)(slope*sol_2 + b), (int)(sol_2)); ++ if (sol_1 < 0 && sol_2 >=0) { ++ if (x2 > x1) { ++ if (x1 <= sol_2 && sol_2 <= x2) ++ return sol2Point; ++ } else { ++ if (x2 <= sol_2 && sol_2 <= x1) ++ return sol2Point; ++ } ++ } else if (sol_1 >= 0 && sol_2 < 0) { ++ if (x2 > x1) { ++ if (x1 <= sol_1 && sol_1 <= x2) ++ return sol1Point; ++ } else { ++ if (x2 <= sol_1 && sol_1 <= x1) ++ return sol1Point; ++ } ++ } else { ++ if (x2 > x1) { ++ if (x1 <= sol_1 && sol_1 <= x2) ++ return sol1Point; ++ if (x1 <= sol_2 && sol_2 <= x2) ++ return sol2Point; ++ } else { ++ if (x2 <= sol_1 && sol_1 <= x1) ++ return sol1Point; ++ if (x2 <= sol_2 && sol_2 <= x1) ++ return sol2Point; ++ } ++ } ++ return QPointF(-1, -1); ++} ++ ++/** ++ * Calculates which point of a perpendicular line to segment P1P2 that contains P2 ++ * has a distance equal to Distance from P2, ++ * Lets say such point is P3, the distance from P2 to P3 must be equal to Distance ++ */ ++QPointF AssociationWidget::calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance) ++{ ++ /* ++ the distance D between points (x2, y2) and (x3, y3) has the following formula: ++ ++ --- ------------------------------ ++ D = \ / 2 2 ++ \ / (x3 - x2) + (y3 - y2) ++ ++ D, x2 and y2 are known and line P2P3 is perpendicular to line (x1, y1)(x2, y2), so if the ++ line P1P2 has the formula y = m*x + b, ++ then (x1 - x2) ++ m = -----------, because it is perpendicular to line P1P2 ++ (y2 - y1) ++ ++ also y2 = m*x2 + b ++ => b = y2 - m*x2 ++ ++ then P3 = (x3, m*x3 + b) ++ ++ 2 2 2 ++ D = (x3 - x2) + (y3 - y2) ++ ++ 2 2 2 2 2 ++ D = x3 - 2*x3*x2 + x2 + y3 - 2*y3*y2 + y2 ++ ++ 2 2 2 2 2 ++ D - x2 - y2 = x3 - 2*x3*x2 + y3 - 2*y3*y2 ++ ++ ++ ++ 2 2 2 2 2 ++ D - x2 - y2 = x3 - 2*x3*x2 + (m*x3 + b) - 2*(m*x3 + b)*y2 ++ ++ 2 2 2 2 2 2 ++ D - x2 - y2 + 2*b*y2 - b = (m + 1)*x3 + (-2*x2 + 2*m*b -2*m*y2)*x3 ++ ++ 2 2 2 2 ++ C = - D + x2 + y2 - 2*b*y2 + b ++ ++ 2 ++ A = (m + 1) ++ ++ B = (-2*x2 + 2*m*b -2*m*y2) ++ ++ and we have ++ 2 ++ A * x3 + B * x3 - C = 0 ++ ++ ++ --------------- ++ --- / 2 ++ -B + \/ B - 4*A*C ++ sol_1 = -------------------------------- ++ 2*A ++ ++ ++ --------------- ++ --- / 2 ++ -B - \/ B - 4*A*C ++ sol_2 = -------------------------------- ++ 2*A ++ ++ then in the distance formula we have only one variable x3 and that is easy ++ to calculate ++ */ ++ if (P1.x() == P2.x()) { ++ return QPointF((int)(P2.x() + Distance), P2.y()); ++ } ++ const int x1 = P1.y(); ++ const int y1 = P1.x(); ++ const int x2 = P2.y(); ++ const int y2 = P2.x(); ++ ++ float slope = ((float)x1 - (float)x2) / ((float)y2 - (float)y1); ++ float b = (y2 - slope*x2); ++ float A = (slope * slope) + 1; ++ float B = (2*slope*b) - (2*x2) - (2*slope*y2); ++ float C = (b*b) - (Distance*Distance) + (x2*x2) + (y2*y2) - (2*b*y2); ++ float t = B*B - 4*A*C; ++ if (t < 0) { ++ return QPointF(-1, -1); ++ } ++ float sol_1 = ((-1* B) + sqrt(t)) / (2*A); ++ ++ float sol_2 = ((-1*B) - sqrt(t)) / (2*A); ++ ++ if (sol_1 < 0 && sol_2 < 0) { ++ return QPointF(-1, -1); ++ } ++ QPointF sol1Point((int)(slope*sol_1 + b), (int)sol_1); ++ QPointF sol2Point((int)(slope*sol_2 + b), (int)sol_2); ++ if (sol_1 < 0 && sol_2 >=0) { ++ return sol2Point; ++ } else if (sol_1 >= 0 && sol_2 < 0) { ++ return sol1Point; ++ } else { // Choose one solution, either will work fine ++ if (slope >= 0) { ++ if (sol_1 <= sol_2) ++ return sol2Point; ++ else ++ return sol1Point; ++ } else { ++ if (sol_1 <= sol_2) ++ return sol1Point; ++ else ++ return sol2Point; ++ } ++ ++ } ++ return QPointF(-1, -1); // never reached, just keep compilers happy ++} ++ ++/** ++ * Calculates the intersection (PS) between line P1P2 and a perpendicular line containing ++ * P3, the result is returned in ResultingPoint. and result value represents the distance ++ * between ResultingPoint and P3; if this value is negative an error ocurred. ++ */ ++float AssociationWidget::perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, ++ QPointF& ResultingPoint) ++{ ++ //line P1P2 is Line 1 = y=slope1*x + b1 ++ ++ //line P3PS is Line 1 = y=slope2*x + b2 ++ ++ float slope2 = 0; ++ float slope1 = 0; ++ float sx = 0, sy = 0; ++ int y2 = P2.x(); ++ int y1 = P1.x(); ++ int x2 = P2.y(); ++ int x1 = P1.y(); ++ int y3 = P3.x(); ++ int x3 = P3.y(); ++ float distance = 0; ++ float b1 = 0; ++ ++ float b2 = 0; ++ ++ if (x2 == x1) { ++ sx = x2; ++ sy = y3; ++ } else if (y2 == y1) { ++ sy = y2; ++ sx = x3; ++ } else { ++ slope1 = (y2 - y1)/ (x2 - x1); ++ slope2 = (x1 - x2)/ (y2 - y1); ++ b1 = y2 - (slope1 * x2); ++ b2 = y3 - (slope2 * x3); ++ sx = (b2 - b1) / (slope1 - slope2); ++ sy = slope1*sx + b1; ++ } ++ distance = (int)(sqrt(((x3 - sx)*(x3 - sx)) + ((y3 - sy)*(y3 - sy)))); ++ ++ ResultingPoint.setX((int)sy); ++ ResultingPoint.setY((int)sx); ++ ++ return distance; ++} ++#endif ++ ++/** ++ * Calculates the position of the text widget depending on the role ++ * that widget is playing. ++ * Returns the point at which to put the widget. ++ */ ++QPointF AssociationWidget::calculateTextPosition(Uml::TextRole::Enum role) ++{ ++ const int SPACE = 2; ++ QPointF p(-1, -1), q(-1, -1); ++ ++ // used to find out if association end point (p) ++ // is at top or bottom edge of widget. ++ ++ if (role == TextRole::MultiA || role == TextRole::ChangeA || role == TextRole::RoleAName) { ++ p = m_associationLine->point(0); ++ q = m_associationLine->point(1); ++ } else if (role == TextRole::MultiB || role == TextRole::ChangeB || role == TextRole::RoleBName) { ++ const int lastSegment = m_associationLine->count() - 1; ++ p = m_associationLine->point(lastSegment); ++ q = m_associationLine->point(lastSegment - 1); ++ } else if (role != TextRole::Name) { ++ uError() << "called with unsupported TextRole::Enum " << role; ++ return QPointF(-1, -1); ++ } ++ ++ FloatingTextWidget *text = textWidgetByRole(role); ++ int textW = 0, textH = 0; ++ if (text) { ++ textW = text->width(); ++ textH = text->height(); ++ } ++ ++ qreal x = 0.0, y = 0.0; ++ ++ if (role == TextRole::MultiA || role == TextRole::MultiB) { ++ const bool isHorizontal = (p.y() == q.y()); ++ const int atBottom = p.y() + SPACE; ++ const int atTop = p.y() - SPACE - textH; ++ const int atLeft = p.x() - SPACE - textW; ++ const int atRight = p.x() + SPACE; ++ y = (p.y() > q.y()) == isHorizontal ? atBottom : atTop; ++ x = (p.x() < q.x()) == isHorizontal ? atRight : atLeft; ++ ++ } else if (role == TextRole::ChangeA || role == TextRole::ChangeB) { ++ ++ if (p.y() > q.y()) ++ y = p.y() - SPACE - (textH * 2); ++ else ++ y = p.y() + SPACE + textH; ++ ++ if (p.x() < q.x()) ++ x = p.x() + SPACE; ++ else ++ x = p.x() - SPACE - textW; ++ ++ } else if (role == TextRole::RoleAName || role == TextRole::RoleBName) { ++ ++ if (p.y() > q.y()) ++ y = p.y() - SPACE - textH; ++ else ++ y = p.y() + SPACE; ++ ++ if (p.x() < q.x()) ++ x = p.x() + SPACE; ++ else ++ x = p.x() - SPACE - textW; ++ ++ } else if (role == TextRole::Name) { ++ ++ calculateNameTextSegment(); ++ if (m_unNameLineSegment == -1) { ++ uWarning() << "TODO:negative line segment index"; ++ m_unNameLineSegment = 0; ++ } ++ x = ( m_associationLine->point(m_unNameLineSegment).x() + ++ m_associationLine->point(m_unNameLineSegment + 1).x() ) / 2; ++ y = ( m_associationLine->point(m_unNameLineSegment).y() + ++ m_associationLine->point(m_unNameLineSegment + 1).y() ) / 2; ++ } ++ ++ if (text) { ++ constrainTextPos(x, y, textW, textH, role); ++ } ++ p = QPointF( x, y ); ++ return p; ++} ++ ++/** ++ * Return the mid point between p0 and p1 ++ */ ++QPointF AssociationWidget::midPoint(const QPointF& p0, const QPointF& p1) ++{ ++ QPointF midP; ++ if (p0.x() < p1.x()) ++ midP.setX(p0.x() + (p1.x() - p0.x()) / 2); ++ else ++ midP.setX(p1.x() + (p0.x() - p1.x()) / 2); ++ if (p0.y() < p1.y()) ++ midP.setY(p0.y() + (p1.y() - p0.y()) / 2); ++ else ++ midP.setY(p1.y() + (p0.y() - p1.y()) / 2); ++ return midP; ++} ++ ++/** ++ * Constrains the FloatingTextWidget X and Y values supplied. ++ * Implements the abstract operation from LinkWidget. ++ * ++ * @param textX Candidate X value (may be modified by the constraint.) ++ * @param textY Candidate Y value (may be modified by the constraint.) ++ * @param textWidth Width of the text. ++ * @param textHeight Height of the text. ++ * @param tr Uml::Text_Role of the text. ++ */ ++void AssociationWidget::constrainTextPos(qreal &textX, qreal &textY, ++ qreal textWidth, qreal textHeight, ++ Uml::TextRole::Enum tr) ++{ ++ const int textCenterX = textX + textWidth / 2; ++ const int textCenterY = textY + textHeight / 2; ++ const int lastSegment = m_associationLine->count() - 1; ++ QPointF p0, p1; ++ switch (tr) { ++ case TextRole::RoleAName: ++ case TextRole::MultiA: ++ case TextRole::ChangeA: ++ p0 = m_associationLine->point(0); ++ p1 = m_associationLine->point(1); ++ // If we are dealing with a single line then tie the ++ // role label to the proper half of the line, i.e. ++ // the role label must be closer to the "other" ++ // role object. ++ if (lastSegment == 1) ++ p1 = midPoint(p0, p1); ++ break; ++ case TextRole::RoleBName: ++ case TextRole::MultiB: ++ case TextRole::ChangeB: ++ p0 = m_associationLine->point(lastSegment - 1); ++ p1 = m_associationLine->point(lastSegment); ++ if (lastSegment == 1) ++ p0 = midPoint(p0, p1); ++ break; ++ case TextRole::Name: ++ case TextRole::Coll_Message: // CHECK: collab.msg texts seem to be TextRole::Name ++ case TextRole::State: // CHECK: is this used? ++ // Find the linepath segment to which the (textX, textY) is closest ++ // and constrain to the corridor of that segment (see farther below) ++ { ++ int minDistSquare = 100000; // utopian initial value ++ int lpIndex = 0; ++ for (int i = 0; i < lastSegment; ++i) { ++ p0 = m_associationLine->point(i); ++ p1 = m_associationLine->point(i + 1); ++ QPointF midP = midPoint(p0, p1); ++ const int deltaX = textCenterX - midP.x(); ++ const int deltaY = textCenterY - midP.y(); ++ const int cSquare = deltaX * deltaX + deltaY * deltaY; ++ if (cSquare < minDistSquare) { ++ minDistSquare = cSquare; ++ lpIndex = i; ++ } ++ } ++ p0 = m_associationLine->point(lpIndex); ++ p1 = m_associationLine->point(lpIndex + 1); ++ } ++ break; ++ default: ++ uError() << "unexpected TextRole::Enum " << tr; ++ return; ++ break; ++ } ++ /* Constraint: ++ The midpoint between p0 and p1 is taken to be the center of a circle ++ with radius D/2 where D is the distance between p0 and p1. ++ The text center needs to be within this circle else it is constrained ++ to the nearest point on the circle. ++ */ ++ p0 = swapXY(p0); // go to the natural coordinate system ++ p1 = swapXY(p1); // with (0,0) in the lower left corner ++ QPointF midP = midPoint(p0, p1); ++ // If (textX,textY) is not inside the circle around midP then ++ // constrain (textX,textY) to the nearest point on that circle. ++ const int x0 = p0.x(); ++ const int y0 = p0.y(); ++ const int x1 = p1.x(); ++ const int y1 = p1.y(); ++ double r = sqrt((double)((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0))) / 2; ++ if (textWidth > r) ++ r = textWidth; ++ // swap textCenter{X,Y} to convert from Qt coord.system. ++ const QPointF origTextCenter(textCenterY, textCenterX); ++ const int relX = abs(origTextCenter.x() - midP.x()); ++ const int relY = abs(origTextCenter.y() - midP.y()); ++ const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r; ++ if (negativeWhenInsideCircle <= 0.0) { ++ return; ++ } ++ /* ++ The original constraint was to snap the text position to the ++ midpoint but that creates unpleasant visual jitter: ++ textX = midP.y() - textWidth / 2; // go back to Qt coord.sys. ++ textY = midP.x() - textHeight / 2; // go back to Qt coord.sys. ++ ++ Rather, we project the text position onto the closest point ++ on the circle: ++ ++ Circle equation: ++ relX^2 + relY^2 - r^2 = 0, or in other words ++ relY^2 = r^2 - relX^2, or ++ relY = sqrt(r^2 - relX^2) ++ Line equation: ++ relY = a * relX + b ++ We can omit "b" because relX and relY are already relative to ++ the circle origin, therefore we can also write: ++ a = relY / relX ++ To obtain the point of intersection between the circle of radius r ++ and the line connecting the circle origin with the point (relX, relY), ++ we equate the relY: ++ a * x = sqrt(r^2 - x^2), or in other words ++ a^2 * x^2 = r^2 - x^2, or ++ x^2 * (a^2 + 1) = r^2, or ++ x^2 = r^2 / (a^2 + 1), or ++ x = sqrt(r^2 / (a^2 + 1)) ++ and then ++ y = a * x ++ The resulting x and y are relative to the circle origin so we just add ++ the circle origin (X, Y) to obtain the constrained (textX, textY). ++ */ ++ // Handle the special case, relX = 0. ++ if (relX == 0) { ++ if (origTextCenter.y() > midP.y()) ++ textX = midP.y() + (int)r; // go back to Qt coord.sys. ++ else ++ textX = midP.y() - (int)r; // go back to Qt coord.sys. ++ textX -= textWidth / 2; ++ return; ++ } ++ const double a = (double)relY / (double)relX; ++ const double x = sqrt(r*r / (a*a + 1)); ++ const double y = a * x; ++ if (origTextCenter.x() > midP.x()) ++ textY = midP.x() + (int)x; // go back to Qt coord.sys. ++ else ++ textY = midP.x() - (int)x; // go back to Qt coord.sys. ++ textY -= textHeight / 2; ++ if (origTextCenter.y() > midP.y()) ++ textX = midP.y() + (int)y; // go back to Qt coord.sys. ++ else ++ textX = midP.y() - (int)y; // go back to Qt coord.sys. ++ textX -= textWidth / 2; ++} ++ ++/** ++ * Puts the text widget with the given role at the given position. ++ * This method calls @ref calculateTextPostion to get the needed position. ++ * I.e. the line segment it is on has moved and it should move the same ++ * amount as the line. ++ */ ++void AssociationWidget::setTextPosition(Uml::TextRole::Enum role) ++{ ++ bool startMove = false; ++ if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) ++ startMove = true; ++ else if (m_nameWidget && m_nameWidget->getStartMove()) ++ startMove = true; ++ if (startMove) { ++ return; ++ } ++ FloatingTextWidget *ft = textWidgetByRole(role); ++ if (ft == NULL) ++ return; ++ QPointF pos = calculateTextPosition(role); ++ ft->setX(pos.x()); ++ ft->setY(pos.y()); ++} ++ ++/** ++ * Moves the text widget with the given role by the difference between ++ * the two points. ++ */ ++void AssociationWidget::setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition) ++{ ++ bool startMove = false; ++ if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) ++ startMove = true; ++ else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) ++ startMove = true; ++ else if (m_nameWidget && m_nameWidget->getStartMove()) ++ startMove = true; ++ ++ if (startMove) { ++ return; ++ } ++ FloatingTextWidget *ft = textWidgetByRole(role); ++ if (ft == NULL) ++ return; ++ qreal ftX = ft->x(); ++ qreal ftY = ft->y(); ++ ++ QPointF pos = calculateTextPosition(role); ++ int relX = pos.x() - oldPosition.x(); ++ int relY = pos.y() - oldPosition.y(); ++ qreal ftNewX = ftX + relX; ++ qreal ftNewY = ftY + relY; ++ ++ bool oldIgnoreSnapToGrid = ft->getIgnoreSnapToGrid(); ++ ft->setIgnoreSnapToGrid(true); ++ ft->setX(ftNewX); ++ ft->setY(ftNewY); ++ ft->setIgnoreSnapToGrid(oldIgnoreSnapToGrid); ++} ++ ++/** ++ * Remove dashed connecting line for association class. ++ */ ++void AssociationWidget::removeAssocClassLine() ++{ ++ delete m_pAssocClassLineSel0; ++ m_pAssocClassLineSel0 = 0; ++ delete m_pAssocClassLineSel1; ++ m_pAssocClassLineSel1 = 0; ++ delete m_pAssocClassLine; ++ m_pAssocClassLine = 0; ++ if (m_associationClass) { ++ m_associationClass->setClassAssociationWidget(0); ++ m_associationClass = 0; ++ } ++} ++ ++/** ++ * Creates the association class connecting line. ++ */ ++void AssociationWidget::createAssocClassLine() ++{ ++ if (m_pAssocClassLine == NULL) { ++ m_pAssocClassLine = new QGraphicsLineItem(this); ++ } ++ QPen pen(lineColor(), lineWidth(), Qt::DashLine); ++ m_pAssocClassLine->setPen(pen); ++ // decoration points ++ m_pAssocClassLineSel0 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p1(), ++ m_pAssocClassLine); ++ m_pAssocClassLineSel1 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p2(), ++ m_pAssocClassLine); ++ computeAssocClassLine(); ++ selectAssocClassLine(false); ++} ++ ++/** ++ * Creates the association class connecting line using the specified ++ * ClassifierWidget. ++ * ++ * @param classifier The ClassifierWidget to use. ++ * @param linePathSegmentIndex The index of the segment where the ++ * association class is created. ++ */ ++void AssociationWidget::createAssocClassLine(ClassifierWidget* classifier, ++ int linePathSegmentIndex) ++{ ++ m_nLinePathSegmentIndex = linePathSegmentIndex; ++ ++ if (m_nLinePathSegmentIndex < 0) { ++ return; ++ } ++ ++ m_associationClass = classifier; ++ m_associationClass->setClassAssociationWidget(this); ++ m_associationClass->addAssoc(this); // to get widgetMoved(...) for association classes ++ ++ createAssocClassLine(); ++} ++ ++/** ++ * Compute the end points of m_pAssocClassLine in case this ++ * association has an attached association class. ++ * TODO: The decoration points make no sense for now, because they are not movable. ++ */ ++void AssociationWidget::computeAssocClassLine() ++{ ++ if (m_associationClass == NULL || m_pAssocClassLine == NULL) { ++ return; ++ } ++ if (m_nLinePathSegmentIndex < 0) { ++ uError() << "m_nLinePathSegmentIndex is not set"; ++ return; ++ } ++ ++ QPointF segStart = m_associationLine->point(m_nLinePathSegmentIndex); ++ QPointF segEnd = m_associationLine->point(m_nLinePathSegmentIndex + 1); ++ const qreal midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2.0; ++ const qreal midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2.0; ++ QPointF segmentMidPoint(midSegX, midSegY); ++ ++ QLineF possibleAssocLine = QLineF(segmentMidPoint, ++ m_associationClass->mapRectToScene(m_associationClass->rect()).center()); ++ QPointF intersectionPoint; ++ QLineF::IntersectType type = intersect(m_associationClass->mapRectToScene(m_associationClass->boundingRect()), ++ possibleAssocLine, ++ &intersectionPoint); ++ // DEBUG(DBG_SRC) << "intersect type=" << type << " / point=" << intersectionPoint; ++ ++ if (type == QLineF::BoundedIntersection) { ++ m_pAssocClassLine->setLine(midSegX, midSegY, ++ intersectionPoint.x(), intersectionPoint.y()); ++ ++ if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { ++ m_pAssocClassLineSel0->setPos(m_pAssocClassLine->line().p1()); ++ m_pAssocClassLineSel1->setPos(m_pAssocClassLine->line().p2()); ++ } ++ } ++} ++ ++/** ++ * Renders the association class connecting line selected. ++ */ ++void AssociationWidget::selectAssocClassLine(bool sel) ++{ ++ if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { ++ m_pAssocClassLineSel0->setVisible(sel); ++ m_pAssocClassLineSel1->setVisible(sel); ++ } ++} ++ ++/** ++ * Sets the association to be selected. ++ */ ++void AssociationWidget::mousePressEvent(QGraphicsSceneMouseEvent * me) ++{ ++ // clear other selected stuff on the screen of ShiftKey ++ if (me->modifiers() != Qt::ShiftModifier) { ++ m_scene->clearSelected(); ++ } ++ ++ if (me->button() == Qt::LeftButton && me->modifiers() == Qt::ControlModifier) { ++ if (checkRemovePoint(me->scenePos())) ++ return; ++ } ++ ++ // make sure we should be here depending on the button ++ if (me->button() != Qt::RightButton && me->button() != Qt::LeftButton) { ++ return; ++ } ++ QPointF mep = me->scenePos(); ++ // see if `mep' is on the connecting line to the association class ++ if (onAssocClassLine(mep)) { ++ setSelected(true); ++ selectAssocClassLine(); ++ return; ++ } ++ setSelected(!isSelected()); ++ associationLine()->mousePressEvent(me); ++} ++ ++/** ++ * Displays the right mouse buttom menu if right button is pressed. ++ */ ++void AssociationWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent * me) ++{ ++ associationLine()->mouseReleaseEvent(me); ++} ++ ++/** ++ * Handles the selection from the popup menu. ++ */ ++void AssociationWidget::slotMenuSelection(QAction* action) ++{ ++ QString oldText, newText; ++ QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); ++ Uml::AssociationType::Enum atype = associationType(); ++ Uml::RoleType::Enum r = RoleType::B; ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ DEBUG(DBG_SRC) << "menu selection = " << ListPopupMenu::toString(sel); ++ ++ // if it's a collaboration message we now just use the code in floatingtextwidget ++ // this means there's some redundant code below but that's better than duplicated code ++ if (isCollaboration() && sel != ListPopupMenu::mt_Delete) { ++ m_nameWidget->slotMenuSelection(action); ++ return; ++ } ++ ++ switch(sel) { ++ case ListPopupMenu::mt_Properties: ++ if (atype == AssociationType::Seq_Message || atype == AssociationType::Seq_Message_Self) { ++ // show op dlg for seq. diagram here ++ // don't worry about here, I don't think it can get here as ++ // line is widget on seq. diagram ++ // here just in case - remove later after testing ++ DEBUG(DBG_SRC) << "mt_Properties: assoctype is " << atype; ++ } else { //standard assoc dialog ++ UMLApp::app()->docWindow()->updateDocumentation(false); ++ showPropertiesDialog(); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Add_Point: ++ checkAddPoint(m_eventScenePos); ++ break; ++ ++ case ListPopupMenu::mt_Delete_Point: ++ checkRemovePoint(m_eventScenePos); ++ break; ++ ++ case ListPopupMenu::mt_Delete: ++ if (m_pAssocClassLineSel0) ++ removeAssocClassLine(); ++ else if (association()) ++ m_scene->removeAssocInViewAndDoc(this); ++ else ++ m_scene->removeAssoc(this); ++ break; ++ ++ case ListPopupMenu::mt_Rename_MultiA: ++ r = RoleType::A; // fall through ++ case ListPopupMenu::mt_Rename_MultiB: ++ if (m_role[r].multiplicityWidget) ++ oldText = m_role[r].multiplicityWidget->text(); ++ else ++ oldText = QString(); ++#if QT_VERSION >= 0x050000 ++ newText = QInputDialog::getText(m_scene->activeView(), ++ i18n("Multiplicity"), ++ i18n("Enter multiplicity:"), ++ QLineEdit::Normal, ++ oldText, NULL); ++#else ++ newText = KInputDialog::getText(i18n("Multiplicity"), ++ i18n("Enter multiplicity:"), ++ oldText, NULL, m_scene->activeView(), &v); ++#endif ++ if (newText != oldText) { ++ if (FloatingTextWidget::isTextValid(newText)) { ++ setMultiplicity(newText, r); ++ } else { ++ m_scene->removeWidget(m_role[r].multiplicityWidget); ++ m_role[r].multiplicityWidget = NULL; ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Rename_Name: ++ if (m_nameWidget) ++ oldText = m_nameWidget->text(); ++ else ++ oldText = QString(); ++#if QT_VERSION >= 0x050000 ++ newText = QInputDialog::getText(m_scene->activeView(), ++ i18n("Association Name"), ++ i18n("Enter association name:"), ++ QLineEdit::Normal, ++ oldText, NULL); ++#else ++ newText = KInputDialog::getText(i18n("Association Name"), ++ i18n("Enter association name:"), ++ oldText, NULL, m_scene->activeView(), &v); ++#endif ++ if (newText != oldText) { ++ if (FloatingTextWidget::isTextValid(newText)) { ++ setName(newText); ++ } else if (m_nameWidget) { ++ m_scene->removeWidget(m_nameWidget); ++ m_nameWidget = NULL; ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Rename_RoleAName: ++ r = RoleType::A; // fall through ++ case ListPopupMenu::mt_Rename_RoleBName: ++ if (m_role[r].roleWidget) ++ oldText = m_role[r].roleWidget->text(); ++ else ++ oldText = QString(); ++#if QT_VERSION >= 0x050000 ++ newText = QInputDialog::getText(m_scene->activeView(), ++ i18n("Role Name"), ++ i18n("Enter role name:"), ++ QLineEdit::Normal, ++ oldText, NULL); ++#else ++ newText = KInputDialog::getText(i18n("Role Name"), ++ i18n("Enter role name:"), ++ oldText, NULL, m_scene->activeView(), &v); ++#endif ++ if (newText != oldText) { ++ if (FloatingTextWidget::isTextValid(newText)) { ++ setRoleName(newText, r); ++ } else { ++ m_scene->removeWidget(m_role[r].roleWidget); ++ m_role[r].roleWidget = NULL; ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Change_Font: ++ { ++#if QT_VERSION >= 0x050000 ++ bool ok = false; ++ QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); ++ if (ok) ++#else ++ QFont fnt = font(); ++ if (KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) ++#endif ++ lwSetFont(fnt); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Line_Color: ++ { ++#if QT_VERSION >= 0x050000 ++ QColor newColor = QColorDialog::getColor(lineColor()); ++ if (newColor != lineColor()) { ++#else ++ QColor newColor; ++ if (KColorDialog::getColor(newColor)) { ++#endif ++ m_scene->selectionSetLineColor(newColor); ++ umlDoc()->setModified(true); ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Cut: ++ m_scene->setStartedCut(); ++ UMLApp::app()->slotEditCut(); ++ break; ++ ++ case ListPopupMenu::mt_Copy: ++ UMLApp::app()->slotEditCopy(); ++ break; ++ ++ case ListPopupMenu::mt_Paste: ++ UMLApp::app()->slotEditPaste(); ++ break; ++ ++ case ListPopupMenu::mt_Reset_Label_Positions: ++ resetTextPositions(); ++ break; ++ ++ case ListPopupMenu::mt_LayoutDirect: ++ m_associationLine->setLayout(AssociationLine::Direct); ++ break; ++ case ListPopupMenu::mt_LayoutSpline: ++ m_associationLine->setLayout(AssociationLine::Spline); ++ break; ++ case ListPopupMenu::mt_LayoutOrthogonal: ++ m_associationLine->setLayout(AssociationLine::Orthogonal); ++ break; ++ case ListPopupMenu::mt_LayoutPolyline: ++ m_associationLine->setLayout(AssociationLine::Polyline); ++ break; ++ ++ default: ++ DEBUG(DBG_SRC) << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; ++ break; ++ }//end switch ++} ++ ++/** ++ * Return the first font found being used by any child widget. (They ++ * could be different fonts, so this is a slightly misleading method.) ++ */ ++QFont AssociationWidget::font() const ++{ ++ //:TODO: find a general font for the association ++ QFont font; ++ ++ if (m_role[RoleType::A].roleWidget) ++ font = m_role[RoleType::A].roleWidget->font(); ++ else if (m_role[RoleType::B].roleWidget) ++ font = m_role[RoleType::B].roleWidget->font(); ++ else if (m_role[RoleType::A].multiplicityWidget) ++ font = m_role[RoleType::A].multiplicityWidget->font(); ++ else if (m_role[RoleType::B].multiplicityWidget) ++ font = m_role[RoleType::B].multiplicityWidget->font(); ++ else if (m_role[RoleType::A].changeabilityWidget) ++ font = m_role[RoleType::A].changeabilityWidget->font(); ++ else if (m_role[RoleType::B].changeabilityWidget) ++ font = m_role[RoleType::B].changeabilityWidget->font(); ++ else if (m_nameWidget) ++ font = m_nameWidget->font(); ++ else ++ font = m_role[RoleType::A].umlWidget->font(); ++ ++ return font; ++} ++ ++/** ++ * Set all 'owned' child widgets to this text color. ++ */ ++void AssociationWidget::setTextColor(const QColor &color) ++{ ++ WidgetBase::setTextColor(color); ++ if (m_nameWidget) { ++ m_nameWidget->setTextColor(color); ++ } ++ if (m_role[RoleType::A].roleWidget) { ++ m_role[RoleType::A].roleWidget->setTextColor(color); ++ } ++ if (m_role[RoleType::B].roleWidget) { ++ m_role[RoleType::B].roleWidget->setTextColor(color); ++ } ++ if (m_role[RoleType::A].multiplicityWidget) { ++ m_role[RoleType::A].multiplicityWidget->setTextColor(color); ++ } ++ if (m_role[RoleType::B].multiplicityWidget) { ++ m_role[RoleType::B].multiplicityWidget->setTextColor(color); ++ } ++ if (m_role[RoleType::A].changeabilityWidget) ++ m_role[RoleType::A].changeabilityWidget->setTextColor(color); ++ if (m_role[RoleType::B].changeabilityWidget) ++ m_role[RoleType::B].changeabilityWidget->setTextColor(color); ++} ++ ++bool AssociationWidget::checkAddPoint(const QPointF &scenePos) ++{ ++ if (associationType() == AssociationType::Exception) { ++ return false; ++ } ++ ++ // if there is no point around the mouse pointer, we insert a new one ++ if (m_associationLine->closestPointIndex(scenePos) < 0) { ++ int i = m_associationLine->closestSegmentIndex(scenePos); ++ if (i < 0) { ++ DEBUG(DBG_SRC) << "no closest segment found!"; ++ return false; ++ } ++ m_associationLine->insertPoint(i + 1, scenePos); ++ if (m_nLinePathSegmentIndex == i) { ++ QPointF segStart = m_associationLine->point(i); ++ QPointF segEnd = m_associationLine->point(i + 2); ++ const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2; ++ const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2; ++ /* ++ DEBUG(DBG_SRC) << "segStart=" << segStart << ", segEnd=" << segEnd ++ << ", midSeg=(" << midSegX << "," << midSegY ++ << "), mp=" << mp; ++ */ ++ if (midSegX > scenePos.x() || midSegY < scenePos.y()) { ++ m_nLinePathSegmentIndex++; ++ DEBUG(DBG_SRC) << "setting m_nLinePathSegmentIndex to " ++ << m_nLinePathSegmentIndex; ++ computeAssocClassLine(); ++ } ++ m_associationLine->update(); ++ calculateNameTextSegment(); ++ umlDoc()->setModified(true); ++ setSelected(true); ++ } ++ return true; ++ } ++ else { ++ DEBUG(DBG_SRC) << "found point already close enough!"; ++ return false; ++ } ++} ++ ++/** ++ * Remove point close to the given point and redraw the association. ++ * @param scenePos point which should be removed ++ * @return success status of the remove action ++ */ ++bool AssociationWidget::checkRemovePoint(const QPointF &scenePos) ++{ ++ int i = m_associationLine->closestPointIndex(scenePos); ++ if (i == -1) ++ return false; ++ ++ m_associationLine->setSelected(false); ++ ++ // there was a point so we remove the point ++ m_associationLine->removePoint(i); ++ ++ // Maybe reattach association class connecting line ++ // to different association linepath segment. ++ const int numberOfLines = m_associationLine->count() - 1; ++ if (m_nLinePathSegmentIndex >= numberOfLines) { ++ m_nLinePathSegmentIndex = numberOfLines - 1; ++ } ++ calculateEndingPoints(); ++ ++ // select the line path ++ m_associationLine->setSelected(true); ++ ++ m_associationLine->update(); ++ ++ calculateNameTextSegment(); ++ umlDoc()->setModified(true); ++ return true; ++} ++ ++/** ++ * Moves the break point being dragged. ++ */ ++void AssociationWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) ++{ ++ if (me->buttons() != Qt::LeftButton) { ++ return; ++ } ++ ++ setSelected(true); ++ ++ associationLine()->mouseMoveEvent(me); ++ moveEvent(me); ++ m_scene->resizeSceneToItems(); ++} ++ ++/** ++ * Returns the Region the widget to line intersection is for the given ++ * widget in this Association. If the given widget is not in the ++ * Association then Region::Error is returned. ++ * Used by @ref calculateEndingPoints to work these positions out for ++ * another Association - since the number of Associations on the same ++ * region for the same widget will mean the lines will need to be ++ * spread out across the region. ++ */ ++//Uml::Region::Enum AssociationWidget::getWidgetRegion(AssociationWidget * widget) const ++//{ ++// if (widget->widgetForRole(RoleType::A) == m_role[RoleType::A].umlWidget) ++// return m_role[RoleType::A].m_WidgetRegion; ++// if (widget->widgetForRole(RoleType::B) == m_role[RoleType::B].umlWidget) ++// return m_role[RoleType::B].m_WidgetRegion; ++// return Uml::Region::Error; ++//} ++ ++/** ++ * Returns the number of lines there are on the given region for ++ * either widget A or B of the association. ++ */ ++int AssociationWidget::getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role) ++{ ++ if ((region == Uml::Region::Error) | (umlScene() == NULL)) { ++ return 0; ++ } ++ int widgetCount = 0; ++ AssociationWidgetList list = m_scene->associationList(); ++ foreach (AssociationWidget* assocwidget, list) { ++ //don't count this association ++ if (assocwidget == this) ++ continue; ++ const WidgetRole& otherA = assocwidget->m_role[RoleType::A]; ++ const WidgetRole& otherB = assocwidget->m_role[RoleType::B]; ++ const UMLWidget *a = otherA.umlWidget; ++ const UMLWidget *b = otherB.umlWidget; ++ /* ++ //don't count associations to self if both of their end points are on the same region ++ //they are different and placement won't interfere with them ++ if (a == b && otherA.m_WidgetRegion == otherB.m_WidgetRegion) ++ continue; ++ */ ++ if (m_role[role].umlWidget == a && region == otherA.m_WidgetRegion) ++ widgetCount++; ++ else if (m_role[role].umlWidget == b && region == otherB.m_WidgetRegion) ++ widgetCount++; ++ }//end foreach ++ return widgetCount; ++} ++ ++/** ++ * Find the border point of the given rect when a line is drawn from the ++ * given point to the rect. ++ * @param rect rect of a classifier ++ * @param line a line to the rect ++ * @param intersectionPoint the intercept point on the border of the rect ++ * @return the type of the intersection @ref QLineF::IntersectType ++ */ ++QLineF::IntersectType AssociationWidget::intersect(const QRectF &rect, const QLineF &line, ++ QPointF* intersectionPoint) ++{ ++ QList lines; ++ lines << QLineF(rect.topLeft(), rect.topRight()); ++ lines << QLineF(rect.topRight(), rect.bottomRight()); ++ lines << QLineF(rect.bottomRight(), rect.bottomLeft()); ++ lines << QLineF(rect.bottomLeft(), rect.topLeft()); ++ foreach (const QLineF& rectLine, lines) { ++ QLineF::IntersectType type = rectLine.intersect(line, intersectionPoint); ++ if (type == QLineF::BoundedIntersection) { ++ return type; ++ } ++ } ++ return QLineF::NoIntersection; ++} ++ ++/** ++ * Given a rectangle and a point, findInterceptOnEdge computes the ++ * connecting line between the middle point of the rectangle and ++ * the point, and returns the intercept of this line with the ++ * the edge of the rectangle identified by `region'. ++ * When the region is North or South, the X value is returned (Y is ++ * constant.) ++ * When the region is East or West, the Y value is returned (X is ++ * constant.) ++ * @todo This is buggy. Try replacing by intersect() ++ */ ++qreal AssociationWidget::findInterceptOnEdge(const QRectF &rect, ++ Uml::Region::Enum region, ++ const QPointF &point) ++{ ++ // The Qt coordinate system has (0, 0) in the top left corner. ++ // In order to go to the regular XY coordinate system with (0, 0) ++ // in the bottom left corner, we swap the X and Y axis. ++ // That's why the following assignments look twisted. ++ const qreal rectHalfWidth = rect.height() / 2.0; ++ const qreal rectHalfHeight = rect.width() / 2.0; ++ const qreal rectMidX = rect.y() + rectHalfWidth; ++ const qreal rectMidY = rect.x() + rectHalfHeight; ++ const qreal dX = rectMidX - point.y(); ++ const qreal dY = rectMidY - point.x(); ++ switch (region) { ++ case Uml::Region::West: ++ region = Uml::Region::South; ++ break; ++ case Uml::Region::North: ++ region = Uml::Region::West; ++ break; ++ case Uml::Region::East: ++ region = Uml::Region::North; ++ break; ++ case Uml::Region::South: ++ region = Uml::Region::East; ++ break; ++ default: ++ break; ++ } ++ // Now we have regular coordinates with the point (0, 0) in the ++ // bottom left corner. ++ if (region == Uml::Region::North || region == Uml::Region::South) { ++ if (dX == 0) ++ return rectMidY; ++ // should be rectMidX, but we go back to Qt coord.sys. ++ if (dY == 0) { ++ uError() << "usage error: " << "North/South (dY == 0)"; ++ return -1.0; ++ } ++ const qreal m = dY / dX; ++ qreal relativeX; ++ if (region == Uml::Region::North) ++ relativeX = rectHalfHeight / m; ++ else ++ relativeX = -rectHalfHeight / m; ++ return (rectMidY + relativeX); ++ // should be rectMidX, but we go back to Qt coord.sys. ++ } else { ++ if (dY == 0) ++ return rectMidX; ++ // should be rectMidY, but we go back to Qt coord.sys. ++ if (dX == 0) { ++ uError() << "usage error: " << "East/West (dX == 0)"; ++ return -1.0; ++ } ++ const qreal m = dY / dX; ++ qreal relativeY = m * rectHalfWidth; ++ if (region == Uml::Region::West) ++ relativeY = -relativeY; ++ return (rectMidX + relativeY); ++ // should be rectMidY, but we go back to Qt coord.sys. ++ } ++} ++ ++/** ++ * Auxiliary method for updateAssociations(): ++ * Put position into m_positions and assoc into m_ordered at the ++ * correct index. ++ * m_positions and m_ordered move in parallel and are sorted by ++ * ascending position. ++ */ ++void AssociationWidget::insertIntoLists(qreal position, const AssociationWidget* assoc) ++{ ++ bool did_insertion = false; ++ for (int index = 0; index < m_positions_len; ++index) { ++ if (position < m_positions[index]) { ++ for (int moveback = m_positions_len; moveback > index; moveback--) ++ m_positions[moveback] = m_positions[moveback - 1]; ++ m_positions[index] = position; ++ m_ordered.insert(index, const_cast(assoc)); ++ did_insertion = true; ++ break; ++ } ++ } ++ if (! did_insertion) { ++ m_positions[m_positions_len] = position; ++ m_ordered.append(const_cast(assoc)); ++ } ++ m_positions_len++; ++} ++ ++/** ++ * Tells all the other view associations the new count for the ++ * given widget on a certain region. And also what index they should be. ++ */ ++void AssociationWidget::updateAssociations(int totalCount, ++ Uml::Region::Enum region, ++ Uml::RoleType::Enum role) ++{ ++ if ((region == Uml::Region::Error) | (umlScene() == NULL)) { ++ return; ++ } ++ AssociationWidgetList list = m_scene->associationList(); ++ ++ UMLWidget *ownWidget = m_role[role].umlWidget; ++ m_positions_len = 0; ++ m_ordered.clear(); ++ // we order the AssociationWidget list by region and x/y value ++ foreach (AssociationWidget* assocwidget, list) { ++ WidgetRole *roleA = &assocwidget->m_role[RoleType::A]; ++ WidgetRole *roleB = &assocwidget->m_role[RoleType::B]; ++ UMLWidget *wA = roleA->umlWidget; ++ UMLWidget *wB = roleB->umlWidget; ++ // Skip self associations. ++ if (wA == wB) ++ continue; ++ // Now we must find out with which end the assocwidget connects ++ // to the input widget (ownWidget). ++ bool inWidgetARegion = (ownWidget == wA && ++ region == roleA->m_WidgetRegion); ++ bool inWidgetBRegion = (ownWidget == wB && ++ region == roleB->m_WidgetRegion); ++ if (!inWidgetARegion && !inWidgetBRegion) ++ continue; ++ // Determine intercept position on the edge indicated by `region'. ++ UMLWidget * otherWidget = (inWidgetARegion ? wB : wA); ++ AssociationLine *linepath = assocwidget->associationLine(); ++ QPointF refpoint; ++ if (assocwidget->linePathStartsAt(otherWidget)) ++ refpoint = linepath->point(linepath->count() - 2); ++ else ++ refpoint = linepath->point(1); ++ // The point is authoritative if we're called for the second time ++ // (i.e. role==B) or it is a waypoint on the line path. ++ bool pointIsAuthoritative = (role == RoleType::B || linepath->count() > 2); ++ if (! pointIsAuthoritative) { ++ // If the point is not authoritative then we use the other ++ // widget's center. ++ refpoint.setX(otherWidget->x() + otherWidget->width() / 2); ++ refpoint.setY(otherWidget->y() + otherWidget->height() / 2); ++ } ++ qreal intercept = findInterceptOnEdge(ownWidget->rect(), region, refpoint); ++ if (intercept < 0) { ++ DEBUG(DBG_SRC) << "error from findInterceptOnEdge for" ++ << " assocType=" << assocwidget->associationType() ++ << " ownWidget=" << ownWidget->name() ++ << " otherWidget=" << otherWidget->name(); ++ continue; ++ } ++ insertIntoLists(intercept, assocwidget); ++ } // while ((assocwidget = assoc_it.current())) ++ ++ // we now have an ordered list and we only have to call updateRegionLineCount ++ int index = 1; ++ foreach (AssociationWidget* assocwidget, m_ordered ) { ++ if (ownWidget == assocwidget->widgetForRole(RoleType::A)) { ++ assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::A); ++ } else if (ownWidget == assocwidget->widgetForRole(RoleType::B)) { ++ assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::B); ++ } ++ } // for (assocwidget = ordered.first(); ...) ++} ++ ++/** ++ * Called to tell the association that another association has added ++ * a line to the region of one of its widgets. The widget is identified ++ * by its role (A or B). ++ * ++ * Called by @ref updateAssociations which is called by ++ * @ref calculateEndingPoints when required. ++ */ ++void AssociationWidget::updateRegionLineCount(int index, int totalCount, ++ Uml::Region::Enum region, ++ Uml::RoleType::Enum role) ++{ ++ if ((region == Uml::Region::Error) | (umlScene() == NULL)) { ++ return; ++ } ++ // If the association is to self and the line ends are on the same region then ++ // use a different calculation. ++ if (isSelf() && ++ m_role[RoleType::A].m_WidgetRegion == m_role[RoleType::B].m_WidgetRegion) { ++ UMLWidget * pWidget = m_role[RoleType::A].umlWidget; ++ qreal x = pWidget->x(); ++ qreal y = pWidget->y(); ++ qreal wh = pWidget->height(); ++ qreal ww = pWidget->width(); ++ int size = m_associationLine->count(); ++ // See if above widget ok to place assoc. ++ switch( m_role[RoleType::A].m_WidgetRegion ) { ++ case Uml::Region::North: ++ m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y ) ); ++ m_associationLine->setPoint( size - 1, QPointF(x + ( ww * 3 / 4 ), y ) ); ++ break; ++ ++ case Uml::Region::South: ++ m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y + wh ) ); ++ m_associationLine->setPoint( size - 1, QPointF( x + ( ww * 3 / 4 ), y + wh ) ); ++ break; ++ ++ case Uml::Region::East: ++ m_associationLine->setPoint( 0, QPointF( x + ww, y + ( wh / 4 ) ) ); ++ m_associationLine->setPoint( size - 1, QPointF( x + ww, y + ( wh * 3 / 4 ) ) ); ++ break; ++ ++ case Uml::Region::West: ++ m_associationLine->setPoint( 0, QPointF( x, y + ( wh / 4 ) ) ); ++ m_associationLine->setPoint( size - 1, QPointF( x, y + ( wh * 3 / 4 ) ) ); ++ break; ++ default: ++ break; ++ }//end switch ++ ++ return; ++ } ++ ++ WidgetRole& robj = m_role[role]; ++ UMLWidget * pWidget = robj.umlWidget; ++ ++ robj.m_nIndex = index; ++ robj.m_nTotalCount = totalCount; ++ qreal x = pWidget->x(); ++ qreal y = pWidget->y(); ++ qreal ww = pWidget->width(); ++ qreal wh = pWidget->height(); ++ const bool angular = Settings::optionState().generalState.angularlines; ++ qreal ch = 0; ++ qreal cw = 0; ++ if (angular) { ++ uint nind = (role == RoleType::A ? 1 : m_associationLine->count() - 2); ++ QPointF neighbour = m_associationLine->point(nind); ++ if (neighbour.x() < x) ++ cw = 0; ++ else if (neighbour.x() > x + ww) ++ cw = 0 + ww; ++ else ++ cw = neighbour.x() - x; ++ if (neighbour.y() < y) ++ ch = 0; ++ else if (neighbour.y() > y + wh) ++ ch = 0 + wh; ++ else ++ ch = neighbour.y() - y; ++ } else { ++ ch = wh * index / totalCount; ++ cw = ww * index / totalCount; ++ } ++ ++ qreal newX = x + cw; ++ qreal newY = y + ch; ++ ++ QPointF pt; ++ if (angular) { ++ pt = QPointF(newX, newY); ++ } else { ++ UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; ++ UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; ++ QList polyListA = pWidgetA->shape().toSubpathPolygons(); ++ QPolygonF polyA = polyListA.at(0); ++ if (polyListA.size() > 1) { ++ for (int i = 1; i < polyListA.size(); i++) { ++ polyA = polyA.united(polyListA.at(i)); ++ } ++ } ++ polyA = polyA.translated(pWidgetA->pos()); ++ QList polyListB = pWidgetB->shape().toSubpathPolygons(); ++ QPolygonF polyB = polyListB.at(0); ++ if (polyListB.size() > 1) { ++ for (int i = 1; i < polyListB.size(); i++) { ++ polyB = polyB.united(polyListB.at(i)); ++ } ++ } ++ polyB = polyB.translated(pWidgetB->pos()); ++ QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); ++ if (nearestPoints.isNull()) { ++ uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; ++ switch(region) { ++ case Uml::Region::West: ++ pt.setX(x); ++ pt.setY(newY); ++ break; ++ case Uml::Region::North: ++ pt.setX(newX); ++ pt.setY(y); ++ break; ++ case Uml::Region::East: ++ pt.setX(x + ww); ++ pt.setY(newY); ++ break; ++ case Uml::Region::South: ++ pt.setX(newX); ++ pt.setY(y + wh); ++ break; ++ case Uml::Region::Center: ++ pt.setX(x + ww / 2); ++ pt.setY(y + wh / 2); ++ break; ++ default: ++ break; ++ } ++ } else { ++ if (role == RoleType::A) ++ pt = nearestPoints.p1(); ++ else ++ pt = nearestPoints.p2(); ++ } ++ } ++ if (role == RoleType::A) { ++ m_associationLine->setPoint(0, pt); ++ } ++ else { ++ m_associationLine->setPoint(m_associationLine->count() - 1, pt); ++ } ++} ++ ++/** ++ * Sets the state of whether the widget is selected. ++ * ++ * @param _select The state of whether the widget is selected. ++ */ ++void AssociationWidget::setSelected(bool _select /* = true */) ++{ ++ WidgetBase::setSelected(_select); ++ if ( m_nameWidget) ++ m_nameWidget->setSelected( _select ); ++ if ( m_role[RoleType::A].roleWidget ) ++ m_role[RoleType::A].roleWidget->setSelected( _select ); ++ if ( m_role[RoleType::B].roleWidget ) ++ m_role[RoleType::B].roleWidget->setSelected( _select ); ++ if ( m_role[RoleType::A].multiplicityWidget ) ++ m_role[RoleType::A].multiplicityWidget->setSelected( _select ); ++ if ( m_role[RoleType::B].multiplicityWidget ) ++ m_role[RoleType::B].multiplicityWidget->setSelected( _select ); ++ if ( m_role[RoleType::A].changeabilityWidget) ++ m_role[RoleType::A].changeabilityWidget->setSelected( _select ); ++ if ( m_role[RoleType::B].changeabilityWidget) ++ m_role[RoleType::B].changeabilityWidget->setSelected( _select ); ++ ++ // Update the docwindow for this association. ++ // This is done last because each of the above setSelected calls ++ // overwrites the docwindow, but we want the main association doc ++ // to win. ++ if (_select) { ++ if (m_scene->selectedCount() == 0) ++ UMLApp::app()->docWindow()->showDocumentation(this, false); ++ } else ++ UMLApp::app()->docWindow()->updateDocumentation(true); ++ ++ m_associationLine->setSelected(_select); ++ if (! _select) { ++ // For now, if _select is true we don't make the assoc class line ++ // selected. But that's certainly open for discussion. ++ // At any rate, we need to deselect the assoc class line ++ // if _select is false. ++ selectAssocClassLine(false); ++ } ++ UMLApp::app()->document()->writeToStatusBar(_select ? i18n("Press Ctrl with left mouse click to delete a point") : QString()); ++} ++ ++/** ++ * Reimplement method from WidgetBase in order to check owned floating texts. ++ * ++ * @param p Point to be checked. ++ * ++ * @return m_nameWidget if m_nameWidget is non NULL and m_nameWidget->onWidget(p) returns non NULL; ++ * m_role[0].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and ++ * its onWidget(p) returns non NULL; ++ * m_role[1].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and ++ * its onWidget(p) returns non NULL; ++ * else NULL. ++ */ ++UMLWidget* AssociationWidget::onWidget(const QPointF &p) ++{ ++ if (m_nameWidget && m_nameWidget->onWidget(p)) { ++ return m_nameWidget; ++ } ++ for (int i = 0; i <= 1; i++) { ++ const WidgetRole& r = m_role[i]; ++ if (r.multiplicityWidget && r.multiplicityWidget->onWidget(p)) ++ return r.multiplicityWidget; ++ if (r.changeabilityWidget && r.changeabilityWidget->onWidget(p)) ++ return r.changeabilityWidget; ++ if (r.roleWidget && r.roleWidget->onWidget(p)) ++ return r.roleWidget; ++ } ++ return NULL; ++} ++ ++/** ++ * Returns true if the given point is on the connecting line to ++ * the association class. Returns false if there is no association ++ * class attached, or if the given point is not on the connecting ++ * line. ++ */ ++bool AssociationWidget::onAssocClassLine(const QPointF &point) ++{ ++ bool onLine = false; ++ if (m_pAssocClassLine) { ++//:TODO: ++// const QPointF mapped = m_pAssocClassLine->mapFromParent(point); ++// bool onLine = m_pAssocClassLine->contains(mapped); ++// return onLine; ++ UMLSceneItemList list = m_scene->collisions(point); ++ UMLSceneItemList::iterator end(list.end()); ++ for (UMLSceneItemList::iterator item_it(list.begin()); item_it != end; ++item_it) { ++ if (*item_it == m_pAssocClassLine) { ++ onLine = true; ++ break; ++ } ++ } ++ } ++ DEBUG(DBG_SRC) << onLine; ++ return onLine; ++} ++ ++/** ++ * Returns true if the given point is on the association line. ++ * A circle (rectangle) around the point is used to obtain more tolerance. ++ * @param point the point to check ++ * @return flag whether point is on association line ++ */ ++bool AssociationWidget::onAssociation(const QPointF& point) ++{ ++ // check the path ++ const qreal diameter(4.0); ++ QPainterPath path = m_associationLine->shape(); ++ if (path.contains(point)) { ++ DEBUG(DBG_SRC) << "on path"; ++ return true; ++ } ++ // check also the points ++ if (m_associationLine->layout() == AssociationLine::Spline) { ++ if (m_associationLine->closestPointIndex(point, diameter) > -1) { ++ DEBUG(DBG_SRC) << "on spline point"; ++ return true; ++ } ++ } ++ return onAssocClassLine(point); ++} ++ ++/** ++ * Set all association points to x coordinate. ++ */ ++void AssociationWidget::setXEntireAssoc(qreal x) ++{ ++ for (int i = 0; i < m_associationLine->count(); ++i) { ++ QPointF p = m_associationLine->point(i); ++ p.setX(x); ++ m_associationLine->setPoint(i, p); ++ } ++} ++ ++/** ++ * Set all association points to y coordinate. ++ */ ++void AssociationWidget::setYEntireAssoc(qreal y) ++{ ++ for (int i = 0; i < m_associationLine->count(); ++i) { ++ QPointF p = m_associationLine->point(i); ++ p.setY(y); ++ m_associationLine->setPoint(i, p); ++ } ++} ++ ++/** ++ * Moves all the mid points (all expcept start /end) by the given amount. ++ */ ++void AssociationWidget::moveMidPointsBy(qreal x, qreal y) ++{ ++ int pos = m_associationLine->count() - 1; ++ for (int i = 1; i < (int)pos; ++i) { ++ QPointF p = m_associationLine->point( i ); ++ qreal newX = p.x() + x; ++ qreal newY = p.y() + y; ++ p.setX( newX ); ++ p.setY( newY ); ++ m_associationLine->setPoint( i, p ); ++ } ++} ++ ++/** ++ * Moves the entire association by the given offset. ++ */ ++void AssociationWidget::moveEntireAssoc(qreal x, qreal y) ++{ ++ //TODO: ADD SUPPORT FOR ASSOC. ON SEQ. DIAGRAMS WHEN NOTES BACK IN. ++ moveMidPointsBy(x, y); ++ calculateEndingPoints(); ++ calculateNameTextSegment(); ++ resetTextPositions(); ++} ++ ++/** ++ * Returns the bounding rectangle of all segments of the association. ++ */ ++QRectF AssociationWidget::boundingRect() const ++{ ++ return m_associationLine->boundingRect(); ++} ++ ++/** ++ * Returns the shape of all segments of the association. ++ */ ++QPainterPath AssociationWidget::shape() const ++{ ++ return m_associationLine->shape(); ++} ++ ++/** ++ * Connected to UMLClassifier::attributeRemoved() or UMLEntity::constraintRemoved() ++ * in case this AssociationWidget is linked to a clasifier list item ++ * (an attribute or a foreign key constraint) ++ * ++ * @param obj The UMLClassifierListItem removed. ++ */ ++void AssociationWidget::slotClassifierListItemRemoved(UMLClassifierListItem* obj) ++{ ++ if (obj != m_umlObject) { ++ DEBUG(DBG_SRC) << "obj=" << obj << ": m_umlObject=" << m_umlObject; ++ return; ++ } ++ m_umlObject = 0; ++ m_scene->removeAssoc(this); ++} ++ ++/** ++ * Connected to UMLObject::modified() in case this ++ * AssociationWidget is linked to a classifer's attribute type. ++ */ ++void AssociationWidget::slotAttributeChanged() ++{ ++ UMLAttribute *attr = attribute(); ++ if (attr == NULL) { ++ uError() << "attribute() returns NULL"; ++ return; ++ } ++ setVisibility(attr->visibility(), RoleType::B); ++ setRoleName(attr->name(), RoleType::B); ++} ++ ++void AssociationWidget::clipSize() ++{ ++ if (m_nameWidget) ++ m_nameWidget->clipSize(); ++ ++ if (m_role[RoleType::A].multiplicityWidget) ++ m_role[RoleType::A].multiplicityWidget->clipSize(); ++ ++ if (m_role[RoleType::B].multiplicityWidget) ++ m_role[RoleType::B].multiplicityWidget->clipSize(); ++ ++ if (m_role[RoleType::A].roleWidget) ++ m_role[RoleType::A].roleWidget->clipSize(); ++ ++ if (m_role[RoleType::B].roleWidget) ++ m_role[RoleType::B].roleWidget->clipSize(); ++ ++ if (m_role[RoleType::A].changeabilityWidget) ++ m_role[RoleType::A].changeabilityWidget->clipSize(); ++ ++ if (m_role[RoleType::B].changeabilityWidget) ++ m_role[RoleType::B].changeabilityWidget->clipSize(); ++ ++ if (m_associationClass) ++ m_associationClass->clipSize(); ++} ++ ++/** ++ * Event handler for context menu events, called from the line segments. ++ */ ++void AssociationWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) ++{ ++ const Uml::AssociationType::Enum type = associationType(); ++ ListPopupMenu::MenuType menuType = ListPopupMenu::mt_Association_Selected; ++ if ((type == Uml::AssociationType::Anchor) || ++ onAssocClassLine(event->scenePos())) { ++ menuType = ListPopupMenu::mt_Anchor; ++ } else if (isCollaboration()) { ++ menuType = ListPopupMenu::mt_Collaboration_Message; ++ } else if (!association()) { ++ menuType = ListPopupMenu::mt_AttributeAssociation; ++ } else if (AssocRules::allowRole(type)) { ++ menuType = ListPopupMenu::mt_FullAssociation; ++ } ++ ++ event->accept(); ++ DEBUG(DBG_SRC) << "menue type = " << ListPopupMenu::toString(menuType) ++ << " / association = " << Uml::AssociationType::toString(type); ++ ++ UMLScene *scene = umlScene(); ++ QWidget *parent = 0; ++ if (scene) { ++ parent = scene->activeView(); ++ } ++ ++ if (!isSelected() && scene && !scene->selectedItems().isEmpty()) { ++ Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); ++ if ((event->modifiers() & forSelection) == 0) { ++ scene->clearSelection(); ++ } ++ } ++ setSelected(true); ++ m_eventScenePos = event->scenePos(); ++ ListPopupMenu popup(parent, menuType, this); ++ QAction *triggered = popup.exec(event->screenPos()); ++ ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); ++ ++ if (!parentMenu) { ++ uWarning() << "Action's data field does not contain ListPopupMenu pointer"; ++ return; ++ } ++ ++ WidgetBase *ownerWidget = parentMenu->ownerWidget(); ++ // assert because logic is based on only WidgetBase being the owner of ++ // ListPopupMenu actions executed in this context menu. ++ Q_ASSERT_X(ownerWidget != 0, "AssociationWidget::contextMenuEvent", ++ "ownerWidget is null which means action belonging to UMLView, UMLScene" ++ " or UMLObject is the one triggered in ListPopupMenu"); ++ ++ ownerWidget->slotMenuSelection(triggered); ++} ++ ++/** ++ * Reimplemented event handler for hover enter events. ++ */ ++void AssociationWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) ++{ ++ associationLine()->hoverEnterEvent(event); ++} ++ ++/** ++ * Reimplemented event handler for hover leave events. ++ */ ++void AssociationWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) ++{ ++ associationLine()->hoverLeaveEvent(event); ++} ++ ++/** ++ * Reimplemented event handler for hover move events. ++ */ ++void AssociationWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) ++{ ++ associationLine()->hoverMoveEvent(event); ++} ++ ++/** ++ * Saves this widget to the "assocwidget" XMI element. ++ */ ++void AssociationWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) ++{ ++ QDomElement assocElement = qDoc.createElement(QLatin1String("assocwidget")); ++ ++ WidgetBase::saveToXMI(qDoc, assocElement); ++ LinkWidget::saveToXMI(qDoc, assocElement); ++ if (m_umlObject) { ++ assocElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_umlObject->id())); ++ } ++ assocElement.setAttribute(QLatin1String("type"), associationType()); ++ if (!association()) { ++ assocElement.setAttribute(QLatin1String("visibilityA"), visibility(RoleType::A)); ++ assocElement.setAttribute(QLatin1String("visibilityB"), visibility(RoleType::B)); ++ assocElement.setAttribute(QLatin1String("changeabilityA"), changeability(RoleType::A)); ++ assocElement.setAttribute(QLatin1String("changeabilityB"), changeability(RoleType::B)); ++ if (m_umlObject == NULL) { ++ assocElement.setAttribute(QLatin1String("roleAdoc"), roleDocumentation(RoleType::A)); ++ assocElement.setAttribute(QLatin1String("roleBdoc"), roleDocumentation(RoleType::B)); ++ assocElement.setAttribute(QLatin1String("documentation"), documentation()); ++ } ++ } ++ assocElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(widgetIDForRole(RoleType::A))); ++ assocElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(widgetIDForRole(RoleType::B))); ++ assocElement.setAttribute(QLatin1String("indexa"), m_role[RoleType::A].m_nIndex); ++ assocElement.setAttribute(QLatin1String("indexb"), m_role[RoleType::B].m_nIndex); ++ assocElement.setAttribute(QLatin1String("totalcounta"), m_role[RoleType::A].m_nTotalCount); ++ assocElement.setAttribute(QLatin1String("totalcountb"), m_role[RoleType::B].m_nTotalCount); ++ m_associationLine->saveToXMI(qDoc, assocElement); ++ ++ if (m_nameWidget) { ++ m_nameWidget->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (multiplicityWidget(RoleType::A)) { ++ multiplicityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (multiplicityWidget(RoleType::B)) { ++ multiplicityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (roleWidget(RoleType::A)) { ++ roleWidget(RoleType::A)->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (roleWidget(RoleType::B)) { ++ roleWidget(RoleType::B)->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (changeabilityWidget(RoleType::A)) { ++ changeabilityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (changeabilityWidget(RoleType::B)) { ++ changeabilityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); ++ } ++ ++ if (m_associationClass) { ++ QString acid = Uml::ID::toString(m_associationClass->id()); ++ assocElement.setAttribute(QLatin1String("assocclass"), acid); ++ assocElement.setAttribute(QLatin1String("aclsegindex"), m_nLinePathSegmentIndex); ++ } ++ ++ qElement.appendChild(assocElement); ++} ++ ++/** ++ * Uses the supplied widgetList for resolving ++ * the role A and role B widgets. (The other loadFromXMI() queries ++ * the UMLView for these widgets.) ++ * Required for clipboard operations. ++ */ ++bool AssociationWidget::loadFromXMI(QDomElement& qElement, ++ const UMLWidgetList& widgets, ++ const MessageWidgetList* messages) ++{ ++ if (!WidgetBase::loadFromXMI(qElement)) { ++ return false; ++ } ++ ++ if (!LinkWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ ++ // load child widgets first ++ QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); ++ QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); ++ Uml::ID::Type aId = Uml::ID::fromString(widgetaid); ++ Uml::ID::Type bId = Uml::ID::fromString(widgetbid); ++ UMLWidget *pWidgetA = Widget_Utils::findWidget(aId, widgets, messages); ++ if (!pWidgetA) { ++ uError() << "cannot find widget for roleA id " << Uml::ID::toString(aId); ++ return false; ++ } ++ UMLWidget *pWidgetB = Widget_Utils::findWidget(bId, widgets, messages); ++ if (!pWidgetB) { ++ uError() << "cannot find widget for roleB id " << Uml::ID::toString(bId); ++ return false; ++ } ++ setWidgetForRole(pWidgetA, RoleType::A); ++ setWidgetForRole(pWidgetB, RoleType::B); ++ ++ QString type = qElement.attribute(QLatin1String("type"), QLatin1String("-1")); ++ Uml::AssociationType::Enum aType = Uml::AssociationType::fromInt(type.toInt()); ++ ++ QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); ++ bool oldStyleLoad = false; ++ if (id == QLatin1String("-1")) { ++ // xmi.id not present, ergo either a pure widget association, ++ // or old (pre-1.2) style: ++ // Everything is loaded from the AssociationWidget. ++ // UMLAssociation may or may not be saved - if it is, it's a dummy. ++ // Create the UMLAssociation if both roles are UML objects; ++ // else load the info locally. ++ ++ if (Uml::AssociationType::hasUMLRepresentation(aType)) { ++ // lack of an association in our widget AND presence of ++ // both uml objects for each role clearly identifies this ++ // as reading in an old-school file. Note it as such, and ++ // create, and add, the UMLAssociation for this widget. ++ // Remove this special code when backwards compatibility ++ // with older files isn't important anymore. -b.t. ++ UMLObject* umlRoleA = pWidgetA->umlObject(); ++ UMLObject* umlRoleB = pWidgetB->umlObject(); ++ if (!m_umlObject && umlRoleA && umlRoleB) { ++ oldStyleLoad = true; // flag for further special config below ++ if (aType == AssociationType::Aggregation || aType == AssociationType::Composition) { ++ uWarning()<<" Old Style save file? swapping roles on association widget"<umlObject(); ++ umlRoleB = pWidgetB->umlObject(); ++ } ++ ++ setUMLAssociation(umlDoc()->createUMLAssociation(umlRoleA, umlRoleB, aType)); ++ } ++ } ++ ++ setDocumentation(qElement.attribute(QLatin1String("documentation"))); ++ setRoleDocumentation(qElement.attribute(QLatin1String("roleAdoc")), RoleType::A); ++ setRoleDocumentation(qElement.attribute(QLatin1String("roleBdoc")), RoleType::B); ++ ++ // visibility defaults to Public if it cant set it here.. ++ QString visibilityA = qElement.attribute(QLatin1String("visibilityA"), QLatin1String("0")); ++ int vis = visibilityA.toInt(); ++ if (vis >= 200) { // bkwd compat. ++ vis -= 200; ++ } ++ setVisibility((Uml::Visibility::Enum)vis, RoleType::A); ++ ++ QString visibilityB = qElement.attribute(QLatin1String("visibilityB"), QLatin1String("0")); ++ vis = visibilityB.toInt(); ++ if (vis >= 200) { // bkwd compat. ++ vis -= 200; ++ } ++ setVisibility((Uml::Visibility::Enum)vis, RoleType::B); ++ ++ // Changeability defaults to "Changeable" if it cant set it here.. ++ QString changeabilityA = qElement.attribute(QLatin1String("changeabilityA"), QLatin1String("0")); ++ if (changeabilityA.toInt() > 0) ++ setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); ++ ++ QString changeabilityB = qElement.attribute(QLatin1String("changeabilityB"), QLatin1String("0")); ++ if (changeabilityB.toInt() > 0) ++ setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); ++ ++ } else { ++ ++ // we should disconnect any prior association (can this happen??) ++ if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { ++ UMLAssociation *umla = association(); ++ umla->disconnect(this); ++ umla->nrof_parent_widgets--; ++ } ++ ++ // New style: The xmi.id is a reference to the UMLAssociation. ++ // If the UMLObject is not found right now, we try again later ++ // during the type resolution pass - see activate(). ++ m_nId = Uml::ID::fromString(id); ++ UMLObject *myObj = umlDoc()->findObjectById(m_nId); ++ if (myObj) { ++ const UMLObject::ObjectType ot = myObj->baseType(); ++ if (ot != UMLObject::ot_Association) { ++ setUMLObject(myObj); ++ } else { ++ UMLAssociation * myAssoc = static_cast(myObj); ++ setUMLAssociation(myAssoc); ++ if (type == QLatin1String("-1")) ++ aType = myAssoc->getAssocType(); ++ } ++ } ++ } ++ ++ setAssociationType(aType); ++ ++ QString indexa = qElement.attribute(QLatin1String("indexa"), QLatin1String("0")); ++ QString indexb = qElement.attribute(QLatin1String("indexb"), QLatin1String("0")); ++ QString totalcounta = qElement.attribute(QLatin1String("totalcounta"), QLatin1String("0")); ++ QString totalcountb = qElement.attribute(QLatin1String("totalcountb"), QLatin1String("0")); ++ m_role[RoleType::A].m_nIndex = indexa.toInt(); ++ m_role[RoleType::B].m_nIndex = indexb.toInt(); ++ m_role[RoleType::A].m_nTotalCount = totalcounta.toInt(); ++ m_role[RoleType::B].m_nTotalCount = totalcountb.toInt(); ++ ++ QString assocclassid = qElement.attribute(QLatin1String("assocclass")); ++ if (! assocclassid.isEmpty()) { ++ Uml::ID::Type acid = Uml::ID::fromString(assocclassid); ++ UMLWidget *w = Widget_Utils::findWidget(acid, widgets); ++ if (w) { ++ ClassifierWidget* aclWidget = static_cast(w); ++ QString aclSegIndex = qElement.attribute(QLatin1String("aclsegindex"), QLatin1String("0")); ++ createAssocClassLine(aclWidget, aclSegIndex.toInt()); ++ } else { ++ uError() << "cannot find assocclass " << assocclassid; ++ } ++ } ++ ++ //now load child elements ++ QDomNode node = qElement.firstChild(); ++ QDomElement element = node.toElement(); ++ while (!element.isNull()) { ++ QString tag = element.tagName(); ++ if (tag == QLatin1String("linepath")) { ++ if (!m_associationLine->loadFromXMI(element)) { ++ return false; ++ } ++ } else if (tag == QLatin1String("floatingtext") || ++ tag == QLatin1String("UML:FloatingTextWidget")) { // for bkwd compatibility ++ QString r = element.attribute(QLatin1String("role"), QLatin1String("-1")); ++ if (r == QLatin1String("-1")) ++ return false; ++ Uml::TextRole::Enum role = Uml::TextRole::fromInt(r.toInt()); ++ FloatingTextWidget *ft = new FloatingTextWidget(m_scene, role, QString(), Uml::ID::Reserved); ++ if (! ft->loadFromXMI(element)) { ++ // Most likely cause: The FloatingTextWidget is empty. ++ delete ft; ++ node = element.nextSibling(); ++ element = node.toElement(); ++ continue; ++ } ++ // always need this ++ ft->setParentItem(this); ++ ft->setLink(this); ++ ft->setSequenceNumber(m_SequenceNumber); ++ ft->setFontCmd(ft->font()); ++ ++ switch(role) { ++ case Uml::TextRole::MultiA: ++ m_role[RoleType::A].multiplicityWidget = ft; ++ if (oldStyleLoad) ++ setMultiplicity(m_role[RoleType::A].multiplicityWidget->text(), RoleType::A); ++ break; ++ ++ case Uml::TextRole::MultiB: ++ m_role[RoleType::B].multiplicityWidget = ft; ++ if (oldStyleLoad) ++ setMultiplicity(m_role[RoleType::B].multiplicityWidget->text(), RoleType::B); ++ break; ++ ++ case Uml::TextRole::ChangeA: ++ m_role[RoleType::A].changeabilityWidget = ft; ++ break; ++ ++ case Uml::TextRole::ChangeB: ++ m_role[RoleType::B].changeabilityWidget = ft; ++ break; ++ ++ case Uml::TextRole::Name: ++ m_nameWidget = ft; ++ if (oldStyleLoad) ++ setName(m_nameWidget->text()); ++ break; ++ ++ case Uml::TextRole::Coll_Message: ++ case Uml::TextRole::Coll_Message_Self: ++ m_nameWidget = ft; ++ ft->setLink(this); ++ ft->setActivated(); ++ if (FloatingTextWidget::isTextValid(ft->text())) ++ ft->show(); ++ else ++ ft->hide(); ++ break; ++ ++ case Uml::TextRole::RoleAName: ++ m_role[RoleType::A].roleWidget = ft; ++ setRoleName(ft->text(), RoleType::A); ++ break; ++ case Uml::TextRole::RoleBName: ++ m_role[RoleType::B].roleWidget = ft; ++ setRoleName(ft->text(), RoleType::B); ++ break; ++ default: ++ DEBUG(DBG_SRC) << "unexpected FloatingTextWidget (TextRole::Enum " << role << ")"; ++ delete ft; ++ break; ++ } ++ } ++ node = element.nextSibling(); ++ element = node.toElement(); ++ } ++ ++ return true; ++} ++ ++/** ++ * Queries the UMLView for resolving the role A and role B widgets. ++ * .... ++ */ ++bool AssociationWidget::loadFromXMI(QDomElement& qElement) ++{ ++ UMLScene *scene = umlScene(); ++ if (scene) { ++ const UMLWidgetList& widgetList = scene->widgetList(); ++ const MessageWidgetList& messageList = scene->messageList(); ++ return loadFromXMI(qElement, widgetList, &messageList); ++ } ++ else { ++ DEBUG(DBG_SRC) << "This isn't on UMLScene yet, so can neither fetch" ++ "messages nor widgets on umlscene"; ++ return false; ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,328 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ASSOCIATIONWIDGET_H ++#define ASSOCIATIONWIDGET_H ++ ++#include "associationwidgetlist.h" ++#include "linkwidget.h" ++#include "messagewidgetlist.h" ++#include "umlwidgetlist.h" ++#include "widgetbase.h" ++ ++class AssociationLine; ++class ClassifierWidget; ++class UMLScene; ++class UMLAssociation; ++class UMLAttribute; ++class UMLClassifierListItem; ++class UMLOperation; ++ ++/** ++ * This class represents an association inside a diagram. ++ * ++ * Constructor is made non accessible: ++ * Users shall use the static create() methods for constructing AssociationWidgets. ++ * ++ * Associations exist not only between UML objects. For example, when a Note is ++ * attached to a UML object, the Note itself is not a UML object. ++ * This class supports both kinds of associations. An association where one or ++ * both roles are not a UML object is called a "pure widget association". ++ * ++ * An AssociationWidget where both roles are UML objects has a corresponding ++ * UMLAssociation. The UMLAssociation can be retrieved using the getAssociation ++ * method. ++ * A pure widget association does not have a corresponding UMLAssociation. ++ * The getAssociation method returns NULL in this case. ++ * ++ * @author Gustavo Madrigal ++ * @author Gopala Krishna ++ * @short This class represents an association inside a diagram. ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class AssociationWidget : public WidgetBase, public LinkWidget ++{ ++ Q_OBJECT ++public: ++ static AssociationWidget* create(UMLScene *scene); ++ static AssociationWidget* create ++ (UMLScene *scene, UMLWidget* WidgetA, ++ Uml::AssociationType::Enum assocType, UMLWidget* WidgetB, ++ UMLObject *umlobject = NULL); ++ ++ virtual ~AssociationWidget(); ++ ++ virtual void setUMLObject(UMLObject *obj); ++ ++ //---------- LinkWidget Interface methods implementation from now on. ++ ++ virtual void lwSetFont(QFont font); ++ virtual UMLClassifier *operationOwner(); ++ ++ virtual UMLOperation *operation(); ++ virtual void setOperation(UMLOperation *op); ++ ++ virtual QString customOpText(); ++ virtual void setCustomOpText(const QString &opText); ++ ++ virtual void resetTextPositions(); ++ ++ virtual void setMessageText(FloatingTextWidget *ft); ++ virtual void setText(FloatingTextWidget *ft, const QString &newText); ++ ++ virtual void showPropertiesDialog(); ++ ++ virtual QString lwOperationText(); ++ virtual UMLClassifier *lwClassifier(); ++ virtual void setOperationText(const QString &op); ++ ++ virtual void constrainTextPos(qreal &textX, qreal &textY, ++ qreal textWidth, qreal textHeight, ++ Uml::TextRole::Enum tr); ++ ++ virtual void calculateNameTextSegment(); ++ ++ //---------- End LinkWidget Interface methods implementation. ++ ++ UMLAssociation* association() const; ++ UMLAttribute* attribute() const; ++ ++// AssociationWidget& operator=(const AssociationWidget& other); ++ bool operator==(const AssociationWidget& other) const; ++ bool operator!=(AssociationWidget& other) const; ++ ++ FloatingTextWidget* textWidgetByRole(Uml::TextRole::Enum tr) const; ++ ++ FloatingTextWidget* nameWidget() const; ++ QString name() const; ++ void setName(const QString &strRole); ++ void setStereotype(const QString &stereo); ++ ++ FloatingTextWidget* roleWidget(Uml::RoleType::Enum role) const; ++ QString roleName(Uml::RoleType::Enum role) const; ++ void setRoleName(const QString &strRole, Uml::RoleType::Enum role); ++ ++ QString roleDocumentation(Uml::RoleType::Enum role) const; ++ void setRoleDocumentation(const QString& doc, Uml::RoleType::Enum role); ++ ++ FloatingTextWidget* multiplicityWidget(Uml::RoleType::Enum role) const; ++ QString multiplicity(Uml::RoleType::Enum role) const; ++ void setMultiplicity(const QString& text, Uml::RoleType::Enum role); ++ ++ Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; ++ void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); ++ ++ FloatingTextWidget* changeabilityWidget(Uml::RoleType::Enum role) const; ++ Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; ++ void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); ++ ++ Uml::ID::Type widgetIDForRole(Uml::RoleType::Enum role) const; ++ Uml::ID::Type widgetLocalIDForRole(Uml::RoleType::Enum role) const; ++ UMLWidget* widgetForRole(Uml::RoleType::Enum role) const; ++ void setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role); ++ ++ bool setWidgets(UMLWidget* widgetA, Uml::AssociationType::Enum assocType, UMLWidget* widgetB); ++ ++ bool containsAsEndpoint(UMLWidget* widget); ++ ++ Uml::AssociationType::Enum associationType() const; ++ void setAssociationType(Uml::AssociationType::Enum type); ++ ++ bool isCollaboration() const; ++ bool isSelf() const; ++ ++ QString toString() const; ++ ++ bool isActivated() const; ++ void setActivated(bool active); ++ ++ AssociationLine* associationLine() const; ++ ++ virtual bool activate(); ++ virtual QRectF boundingRect() const; ++ virtual QPainterPath shape() const; ++ ++ void widgetMoved(UMLWidget* widget, qreal x, qreal y); ++ ++ void saveIdealTextPositions(); ++ ++ UMLWidget* onWidget(const QPointF &p); ++ bool onAssociation(const QPointF& point); ++ bool onAssocClassLine(const QPointF& point); ++ ++ void createAssocClassLine(); ++ void createAssocClassLine(ClassifierWidget* classifierWidget, ++ int linePathSegmentIndex); ++ ++ void selectAssocClassLine(bool sel = true); ++ void removeAssocClassLine(); ++ void computeAssocClassLine(); ++ ++ void setXEntireAssoc(qreal x); ++ void setYEntireAssoc(qreal y); ++ ++ void moveMidPointsBy(qreal x, qreal y); ++ void moveEntireAssoc(qreal x, qreal y); ++ ++ QFont font() const; ++ ++ virtual void setTextColor(const QColor &color); ++ ++ void calculateEndingPoints(); ++ ++ void clipSize(); ++ ++ bool loadFromXMI(QDomElement& qElement, const UMLWidgetList& widgets, ++ const MessageWidgetList* messages); ++ virtual bool loadFromXMI(QDomElement& qElement); ++ virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); ++ ++ void cleanup(); ++ ++ bool isPointAddable(); ++ bool isPointRemovable(); ++ ++ //:TODO: the following four methods should be protected ++ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); ++ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); ++ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); ++ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); ++ ++ virtual void setSelected(bool _select); ++public Q_SLOTS: //:TODO: all virtual? ++ virtual void slotMenuSelection(QAction* action); ++ void slotClassifierListItemRemoved(UMLClassifierListItem* obj); ++ void slotAttributeChanged(); ++ ++ void syncToModel(); ++ ++protected: ++ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); ++ ++ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); ++ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); ++ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); ++ ++private: ++ QPointF calculateTextPosition(Uml::TextRole::Enum role); ++ void setTextPosition(Uml::TextRole::Enum role); ++ void setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition); ++ void setFloatingText(Uml::TextRole::Enum role, const QString& text, FloatingTextWidget* &ft); ++ ++ AssociationWidget(UMLScene *scene); ++ ++ void setUMLAssociation(UMLAssociation * assoc); ++ ++ void mergeAssociationDataIntoUMLRepresentation(); ++ ++ static Uml::Region::Enum findPointRegion(const QRectF& rect, const QPointF& pos); ++ static qreal findInterceptOnEdge(const QRectF &rect, Uml::Region::Enum region, const QPointF &point); ++ static QLineF::IntersectType intersect(const QRectF &rect, const QLineF &line, ++ QPointF* intersectionPoint); ++ ++ void moveEvent(QGraphicsSceneMouseEvent *me); ++ ++ Uml::TextRole::Enum calculateNameType(Uml::TextRole::Enum defaultRoleType); ++ ++ static QPointF swapXY(const QPointF &p); ++ ++ // not used at the moment ++ // static QPointF calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance); ++ // static QPointF calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance); ++ // static float perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, QPointF& ResultingPoint); ++ ++ static QPointF midPoint(const QPointF& p0, const QPointF& p1); ++ ++ void createPointsSelfAssociation(); ++ void updatePointsSelfAssociation(); ++ void createPointsException(); ++ void updatePointsException(); ++ ++ /** ++ * The WidgetRole struct gathers all information pertaining to the role. ++ * The AssociationWidget class contains two WidgetRole objects, one for each ++ * side of the association (A and B). ++ */ ++ struct WidgetRole { ++ ++ FloatingTextWidget* multiplicityWidget; ///< information regarding multiplicity ++ FloatingTextWidget* changeabilityWidget; ///< information regarding changeability ++ FloatingTextWidget* roleWidget; ///< role's label of this association ++ ++ UMLWidget* umlWidget; ///< UMLWidget at this role's side of this association ++ ++ Uml::Region::Enum m_WidgetRegion; ///< region of this role's widget ++ ++ int m_nIndex; ///< the index of where the line is on the region for this role ++ int m_nTotalCount; ///< total amount of associations on the region this role's line is on ++ ++ // The following items are only used if m_pObject is not set. ++ Uml::Visibility::Enum visibility; ++ Uml::Changeability::Enum changeability; ++ QString roleDocumentation; ++ ++ }; ++ ++ void updateRegionLineCount(int index, int totalCount, ++ Uml::Region::Enum region, Uml::RoleType::Enum role); ++ ++ void updateAssociations(int totalCount, Uml::Region::Enum region, Uml::RoleType::Enum role); ++ ++ int getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role); ++ ++ void doUpdates(const QPointF &otherP, Uml::RoleType::Enum role); ++ ++ void setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role); ++ ++ bool checkAddPoint(const QPointF &scenePos); ++ bool checkRemovePoint(const QPointF &scenePos); ++ ++ bool linePathStartsAt(const UMLWidget* widget); ++ ++ void insertIntoLists(qreal position, const AssociationWidget* assoc); ++ ++ qreal m_positions[100]; ///< auxiliary variable for updateAssociations() ++ int m_positions_len; ///< auxiliary variable for updateAssociations() ++ AssociationWidgetList m_ordered; ///< auxiliary variable for updateAssociations() ++ ++ bool m_activated; ///< flag which is true if the activate method has been called for this class instance ++ ++ /** ++ * When the association has a Role Floating Text this text should move ++ * when the AssociationLine moves but only if the closest segment to the ++ * role text moves. ++ * This segment is: ++ * m_associationLine[m_unNameLineSegment] -- m_associationLine[m_unNameLineSegment+1] ++ */ ++ int m_unNameLineSegment; ++ ++ QPointF m_oldNamePoint; ///< Position of name floatingtext saved by saveIdealTextPositions() ++ QPointF m_oldMultiAPoint; ///< Position of role A multiplicity floatingtext saved by saveIdealTextPositions() ++ QPointF m_oldMultiBPoint; ///< Position of role B multiplicity floatingtext saved by saveIdealTextPositions() ++ QPointF m_oldChangeAPoint; ///< Position of role A changeability floatingtext saved by saveIdealTextPositions() ++ QPointF m_oldChangeBPoint; ///< Position of role B changeability floatingtext saved by saveIdealTextPositions() ++ QPointF m_oldRoleAPoint; ///< Position of role A name floatingtext saved by saveIdealTextPositions() ++ QPointF m_oldRoleBPoint; ///< Position of role B name floatingtext saved by saveIdealTextPositions() ++ ++ int m_nLinePathSegmentIndex; ///< anchor for m_pAssocClassLine ++ QGraphicsLineItem *m_pAssocClassLine; ///< used for connecting assoc. class ++ QGraphicsRectItem *m_pAssocClassLineSel0; ///< selection decoration for the start point of the assoc. class line ++ QGraphicsRectItem *m_pAssocClassLineSel1; ///< selection decoration for the end point of the assoc. class line ++ ++ AssociationLine *m_associationLine; ///< the definition points for the association line ++ ClassifierWidget *m_associationClass; ///< used if we have an assoc. class ++ Uml::AssociationType::Enum m_associationType; ///< is only used if m_pObject is not set ++ WidgetRole m_role[2]; ++ FloatingTextWidget* m_nameWidget; ///< displays the name of this association ++ QPointF m_eventScenePos; ///< holds scene pos of contextMenuEvent() ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,79 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "boxwidget.h" ++ ++// app includes ++#include "uml.h" ++#include "umldoc.h" ++ ++// qt includes ++#include ++ ++/** ++ * Constructs a BoxWidget. ++ * ++ * @param scene The parent to this widget. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ * @param type The WidgetType (wt_Box.) ++ */ ++BoxWidget::BoxWidget(UMLScene * scene, Uml::ID::Type id, WidgetType type) ++ : UMLWidget(scene, type, id) ++{ ++ setSize(100, 80); ++ m_usesDiagramLineColor = false; // boxes be black ++ m_lineColor = QColor("black"); ++ setZValue(-10); ++} ++ ++/** ++ * Destructor. ++ */ ++BoxWidget::~BoxWidget() ++{ ++} ++ ++/** ++ * Draws a rectangle. ++ */ ++void BoxWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ setPenFromSettings(painter); ++ painter->drawRect(0, 0, width(), height()); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Saves the widget to the "boxwidget" XMI element. ++ * Note: For loading from XMI, the inherited parent method is used. ++ */ ++void BoxWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement boxElement = qDoc.createElement(QLatin1String("boxwidget")); ++ UMLWidget::saveToXMI(qDoc, boxElement); ++ qElement.appendChild(boxElement); ++} ++ ++/** ++ * Show a properties dialog for a BoxWidget. ++ */ ++void BoxWidget::showPropertiesDialog() ++{ ++ QColor newColor = QColorDialog::getColor(lineColor()); // krazy:exclude=qclasses ++ if (newColor != lineColor()) { ++ setLineColor(newColor); ++ setUsesDiagramLineColor(false); ++ umlDoc()->setModified(true); ++ } ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,39 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef BOXWIDGET_H ++#define BOXWIDGET_H ++ ++//app includes ++#include "umlwidget.h" ++ ++/** ++ * Displays a rectangular box. ++ * These widgets are diagram specific. They will still need a unique id ++ * from the @ref UMLDoc class for deletion and other purpose-kf6s. ++ * ++ * @short Displays a box. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class BoxWidget : public UMLWidget ++{ ++public: ++ explicit BoxWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, WidgetType type = WidgetBase::wt_Box); ++ virtual ~BoxWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ virtual void showPropertiesDialog(); ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,148 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header file ++#include "categorywidget.h" ++ ++// local includes ++#include "category.h" ++#include "debug_utils.h" ++#include "umlview.h" ++#include "listpopupmenu.h" ++ ++// qt includes ++#include ++ ++/** ++ * Creates a Category widget. ++ * ++ * @param scene The parent of the widget. ++ * @param o The UMLCategory to represent. ++ */ ++CategoryWidget::CategoryWidget(UMLScene * scene, UMLCategory *o) ++ : UMLWidget(scene, WidgetBase::wt_Category, o) ++{ ++ m_fixedAspectRatio = true; ++} ++ ++/** ++ * Destructor. ++ */ ++CategoryWidget::~CategoryWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void CategoryWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ UMLWidget::setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ QFont font = UMLWidget::font(); ++ font.setUnderline(false); ++ font.setBold(false); ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ // the height is our radius ++ const int h = height(); ++ const int w = width(); ++ const int r = h > w ? h : w; ++ ++ //int middleX = w / 2; ++ const int textStartY = (r / 2) - (fontHeight / 2); ++ ++ // draw a circle ++ painter->drawEllipse(0, 0, r, r); ++ painter->setPen(textColor()); ++ ++ QString letterType(QLatin1Char('D')); ++ switch(static_cast(m_umlObject)->getType()) { ++ case UMLCategory::ct_Disjoint_Specialisation: ++ letterType = QLatin1Char('D'); ++ break; ++ case UMLCategory::ct_Overlapping_Specialisation: ++ letterType = QLatin1Char('O'); ++ break; ++ case UMLCategory::ct_Union: ++ letterType = QLatin1Char('U'); ++ break; ++ default: ++ break; ++ } ++ ++ painter->drawText(UC_MARGIN, textStartY, r - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, letterType); ++ UMLWidget::setPenFromSettings(painter); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF CategoryWidget::minimumSize() const ++{ ++ const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); ++ const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); ++ const int fontHeight = fm.lineSpacing(); ++ int radius = UC_RADIUS + fontHeight + UC_MARGIN; ++ ++ return QSizeF(radius, radius); ++} ++ ++/** ++ * Saves this Category to file. ++ */ ++void CategoryWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement categoryElement = qDoc.createElement(QLatin1String("categorywidget")); ++ UMLWidget::saveToXMI(qDoc, categoryElement); ++ qElement.appendChild(categoryElement); ++} ++ ++/** ++ * Will be called when a menu selection has been made from the ++ * popup menu. ++ * ++ * @param action The action that has been selected. ++ */ ++void CategoryWidget::slotMenuSelection(QAction* action) ++{ ++ UMLCategory* catObj = static_cast(umlObject()); ++ if (!catObj) { ++ uWarning() << "No UMLCategory for this widget."; ++ return; ++ } ++ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_DisjointSpecialisation: ++ catObj->setType(UMLCategory::ct_Disjoint_Specialisation); ++ break; ++ ++ case ListPopupMenu::mt_OverlappingSpecialisation: ++ catObj->setType(UMLCategory::ct_Overlapping_Specialisation); ++ break; ++ ++ case ListPopupMenu::mt_Union: ++ catObj->setType(UMLCategory::ct_Union); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,56 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef CATEGORYWIDGET_H ++#define CATEGORYWIDGET_H ++ ++#include "umlwidget.h" ++ ++#define UC_MARGIN 5 ++#define UC_RADIUS 30 ++ ++class UMLCategory; ++ ++/** ++ * This class is the graphical version of a UMLCategory. A CategoryWidget is created ++ * by a @ref UMLView. An CategoryWidget belongs to only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. ++ * ++ * If the Category class that this CategoryWidget is displaying is deleted, the @ref UMLView will ++ * make sure that this instance is also deleted. ++ * ++ * The CategoryWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @short A graphical version of a UMLCategory. ++ * @author Sharan Rao ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class CategoryWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ CategoryWidget(UMLScene * scene, UMLCategory *o); ++ virtual ~CategoryWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ // For loading we can use the loadFromXMI() inherited from UMLWidget. ++ ++protected: ++ QSizeF minimumSize() const; ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,1426 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "classifierwidget.h" ++ ++// app includes ++#include "floatingtextwidget.h" ++#include "associationwidget.h" ++#include "associationline.h" ++#include "classifier.h" ++#include "cmds.h" ++#include "debug_utils.h" ++#include "listpopupmenu.h" ++#include "object_factory.h" ++#include "operation.h" ++#include "template.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlview.h" ++ ++#define PACKAGE_MARGIN 5 ++ ++// qt includes ++#include ++ ++DEBUG_REGISTER_DISABLED(ClassifierWidget) ++ ++const int ClassifierWidget::MARGIN = 5; ++const int ClassifierWidget::CIRCLE_SIZE = 30; ++const int ClassifierWidget::SOCKET_INCREMENT = 10; ++ ++/** ++ * Constructs a ClassifierWidget. ++ * ++ * @param scene The parent of this ClassifierWidget. ++ * @param c The UMLClassifier to represent. ++ */ ++ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLClassifier *c) ++ : UMLWidget(scene, WidgetBase::wt_Class, c), ++ m_pAssocWidget(0), m_pInterfaceName(0) ++{ ++ const Settings::OptionState& ops = m_scene->optionState(); ++ setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); ++ setVisualPropertyCmd(ShowOperations, ops.classState.showOps); ++ setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); ++ setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); ++ m_attributeSignature = Uml::SignatureType::ShowSig; ++ /*:TODO: ++ setVisualProperty(ShowOperationSignature, ops.classState.showOpSig); ++ Cannot do that because we get "pure virtual method called". Open code: ++ */ ++ if(!ops.classState.showOpSig) { ++ if (visualProperty(ShowVisibility)) ++ m_operationSignature = Uml::SignatureType::NoSig; ++ else ++ m_operationSignature = Uml::SignatureType::NoSigNoVis; ++ ++ } else if (visualProperty(ShowVisibility)) ++ m_operationSignature = Uml::SignatureType::ShowSig; ++ else ++ m_operationSignature = Uml::SignatureType::SigNoVis; ++ ++ setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); ++ setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); ++ setVisualPropertyCmd(DrawAsCircle, false); ++ ++ setShowAttSigs(ops.classState.showAttSig); ++ ++ if (c && c->isInterface()) { ++ m_baseType = WidgetBase::wt_Interface; ++ m_visualProperties = ShowOperations | ShowVisibility | ShowStereotype; ++ setShowStereotype(true); ++ updateSignatureTypes(); ++ } ++} ++ ++/** ++ * Constructs a ClassifierWidget. ++ * ++ * @param scene The parent of this ClassifierWidget. ++ * @param c The UMLClassifier to represent. ++ */ ++ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLPackage *o) ++ : UMLWidget(scene, WidgetBase::wt_Package, o), ++ m_pAssocWidget(0), ++ m_pInterfaceName(0) ++{ ++ const Settings::OptionState& ops = m_scene->optionState(); ++ setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); ++ setVisualPropertyCmd(ShowOperations, ops.classState.showOps); ++ setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); ++ setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); ++ m_attributeSignature = Uml::SignatureType::ShowSig; ++ ++ if(!ops.classState.showOpSig) { ++ if (visualProperty(ShowVisibility)) ++ m_operationSignature = Uml::SignatureType::NoSig; ++ else ++ m_operationSignature = Uml::SignatureType::NoSigNoVis; ++ ++ } else if (visualProperty(ShowVisibility)) ++ m_operationSignature = Uml::SignatureType::ShowSig; ++ else ++ m_operationSignature = Uml::SignatureType::SigNoVis; ++ ++ setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); ++ setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); ++ setVisualPropertyCmd(DrawAsPackage, true); ++ ++ setShowAttSigs(ops.classState.showAttSig); ++} ++ ++/** ++ * Destructor. ++ */ ++ClassifierWidget::~ClassifierWidget() ++{ ++ if (m_pAssocWidget) ++ m_pAssocWidget->removeAssocClassLine(); ++ if (m_pInterfaceName) { ++ delete m_pInterfaceName; ++ m_pInterfaceName = 0; ++ } ++} ++ ++/** ++ * Return the UMLClassifier which this ClassifierWidget ++ * represents. ++ */ ++UMLClassifier *ClassifierWidget::classifier() const ++{ ++ return dynamic_cast(m_umlObject); ++} ++ ++/** ++ * @return the visual properties ++ */ ++ClassifierWidget::VisualProperties ClassifierWidget::visualProperties() const ++{ ++ return m_visualProperties; ++} ++ ++/** ++ * Set an OR combination of properties stored in \a properties on this ++ * widget. ++ */ ++void ClassifierWidget::setVisualProperties(VisualProperties properties) ++{ ++ // Don't do anything if the argument is equal to current status. ++ if (quint32(m_visualProperties) == quint32(properties)) { ++ return; ++ } ++ ++ m_visualProperties = properties; ++ updateSignatureTypes(); ++} ++ ++/** ++ * @return The status of the property passed in. ++ * ++ * @note Use @ref attributeSignature() and @ref ++ * operationSignature() to get signature status. This ++ * method only indicates whether signature is visible or not. ++ */ ++bool ClassifierWidget::visualProperty(VisualProperty property) const ++{ ++ if (property == ShowAttributeSignature) { ++ return (m_attributeSignature == Uml::SignatureType::ShowSig ++ || m_attributeSignature == Uml::SignatureType::SigNoVis); ++ } ++ ++ else if(property == ShowOperationSignature) { ++ return (m_operationSignature == Uml::SignatureType::ShowSig ++ || m_operationSignature == Uml::SignatureType::SigNoVis); ++ } ++ ++ return m_visualProperties.testFlag(property); ++} ++ ++/** ++ * A convenient method to set and reset individual VisualProperty ++ * ++ * Undo command. ++ * ++ * @param property The property to be set/reset. ++ * @param enable True/false to set/reset. (default = true) ++ * ++ * @note This method handles ShowAttributeSignature and ++ * ShowOperationSignature specially. ++ */ ++void ClassifierWidget::setVisualProperty(VisualProperty property, bool enable) ++{ ++ if (visualProperty(property) != enable) { ++ UMLApp::app()->executeCommand(new Uml::CmdChangeVisualProperty(this, property, enable)); ++ } ++} ++ ++/** ++ * A convenient method to set and reset individual VisualProperty ++ * ++ * @param property The property to be set/reset. ++ * @param enable True/false to set/reset. (default = true) ++ * ++ * @note This method handles ShowAttributeSignature and ++ * ShowOperationSignature specially. ++ */ ++void ClassifierWidget::setVisualPropertyCmd(VisualProperty property, bool enable) ++{ ++ // Handle ShowAttributeSignature and ShowOperationSignature ++ // specially. ++ ++ if (property == ShowAttributeSignature) { ++ if (!enable) { ++ m_attributeSignature = visualProperty(ShowVisibility) ? ++ Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; ++ } else { ++ m_attributeSignature = visualProperty(ShowVisibility) ? ++ Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; ++ } ++ //:TODO: updateTextItemGroups(); ++ updateSignatureTypes(); ++ } ++ ++ else if (property == ShowOperationSignature) { ++ if (!enable) { ++ m_operationSignature = visualProperty(ShowVisibility) ? ++ Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; ++ } else { ++ m_operationSignature = visualProperty(ShowVisibility) ? ++ Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; ++ } ++ //:TODO: updateTextItemGroups(); ++ updateSignatureTypes(); ++ } ++ ++ else if (property == ShowStereotype) { ++ // Now just update flag and use base method for actual work. ++ if (enable) { ++ m_visualProperties |= property; ++ } else { ++ m_visualProperties &= ~property; ++ } ++ setShowStereotype(enable); ++ } ++ ++ else if (property == DrawAsCircle) { ++ // Don't do anything if the flag status is same. ++ if (visualProperty(property) == enable) ++ return; ++ if (enable) { ++ m_visualProperties |= property; ++ } else { ++ m_visualProperties &= ~property; ++ } ++ setDrawAsCircle(enable); ++ } ++ ++ // Some other flag. ++ else { ++ // Don't do anything if the flag status is same. ++ if (visualProperty(property) == enable) { ++ return; ++ } ++ ++ // Call setVisualProperties appropriately based on enbable. ++ if (enable) { ++ setVisualProperties(visualProperties() | property); ++ } else { ++ setVisualProperties(visualProperties() & ~property); ++ } ++ } ++} ++ ++/** ++ * A convenient method to toggle individual VisualProperty of this ++ * widget. ++ * ++ * @param property The property to be toggled. ++ * ++ * @note This method handles ShowAttributeSignature and ++ * ShowOperationSignature specially. ++ */ ++void ClassifierWidget::toggleVisualProperty(VisualProperty property) ++{ ++ bool oppositeStatus; ++ if (property == ShowOperationSignature) { ++ oppositeStatus = !(m_operationSignature == Uml::SignatureType::ShowSig ++ || m_operationSignature == Uml::SignatureType::SigNoVis); ++ } ++ else if (property == ShowAttributeSignature) { ++ oppositeStatus = !(m_attributeSignature == Uml::SignatureType::ShowSig ++ || m_attributeSignature == Uml::SignatureType::SigNoVis); ++ } ++ else { ++ oppositeStatus = !visualProperty(property); ++ } ++ ++ DEBUG(DBG_SRC) << "VisualProperty: " << property << " to opposite status " << oppositeStatus; ++ setVisualProperty(property, oppositeStatus); ++} ++ ++/** ++ * Updates m_operationSignature to match m_showVisibility. ++ */ ++void ClassifierWidget::updateSignatureTypes() ++{ ++ //turn on scope ++ if (visualProperty(ShowVisibility)) { ++ if (m_operationSignature == Uml::SignatureType::NoSigNoVis) { ++ m_operationSignature = Uml::SignatureType::NoSig; ++ } else if (m_operationSignature == Uml::SignatureType::SigNoVis) { ++ m_operationSignature = Uml::SignatureType::ShowSig; ++ } ++ } ++ //turn off scope ++ else { ++ if (m_operationSignature == Uml::SignatureType::ShowSig) { ++ m_operationSignature = Uml::SignatureType::SigNoVis; ++ } else if (m_operationSignature == Uml::SignatureType::NoSig) { ++ m_operationSignature = Uml::SignatureType::NoSigNoVis; ++ } ++ } ++ if (visualProperty(ShowVisibility)) { ++ if (m_attributeSignature == Uml::SignatureType::NoSigNoVis) ++ m_attributeSignature = Uml::SignatureType::NoSig; ++ else if (m_attributeSignature == Uml::SignatureType::SigNoVis) ++ m_attributeSignature = Uml::SignatureType::ShowSig; ++ } else { ++ if (m_attributeSignature == Uml::SignatureType::ShowSig) ++ m_attributeSignature = Uml::SignatureType::SigNoVis; ++ else if(m_attributeSignature == Uml::SignatureType::NoSig) ++ m_attributeSignature = Uml::SignatureType::NoSigNoVis; ++ } ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Returns whether to show attribute signatures. ++ * Only applies when m_umlObject->getBaseType() is ot_Class. ++ * ++ * @return Status of how attribute signatures are shown. ++ */ ++Uml::SignatureType::Enum ClassifierWidget::attributeSignature() const ++{ ++ return m_attributeSignature; ++} ++ ++/** ++ * Sets the type of signature to display for an attribute. ++ * Only applies when m_umlObject->getBaseType() is ot_Class. ++ * ++ * @param sig Type of signature to display for an attribute. ++ */ ++void ClassifierWidget::setAttributeSignature(Uml::SignatureType::Enum sig) ++{ ++ m_attributeSignature = sig; ++ updateSignatureTypes(); ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * @return The Uml::SignatureType::Enum value for the operations. ++ */ ++Uml::SignatureType::Enum ClassifierWidget::operationSignature() const ++{ ++ return m_operationSignature; ++} ++ ++/** ++ * Set the type of signature to display for an Operation ++ * ++ * @param sig Type of signature to display for an operation. ++ */ ++void ClassifierWidget::setOperationSignature(Uml::SignatureType::Enum sig) ++{ ++ m_operationSignature = sig; ++ updateSignatureTypes(); ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Sets whether to show attribute signature ++ * Only applies when m_umlObject->getBaseType() is ot_Class. ++ * ++ * @param _status True if attribute signatures shall be shown. ++ */ ++void ClassifierWidget::setShowAttSigs(bool _status) ++{ ++ if(!_status) { ++ if (visualProperty(ShowVisibility)) ++ m_attributeSignature = Uml::SignatureType::NoSig; ++ else ++ m_attributeSignature = Uml::SignatureType::NoSigNoVis; ++ } ++ else if (visualProperty(ShowVisibility)) ++ m_attributeSignature = Uml::SignatureType::ShowSig; ++ else ++ m_attributeSignature = Uml::SignatureType::SigNoVis; ++ if (UMLApp::app()->document()->loading()) ++ return; ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Toggles whether to show attribute signatures. ++ * Only applies when m_umlObject->getBaseType() is ot_Class. ++ */ ++void ClassifierWidget::toggleShowAttSigs() ++{ ++ if (m_attributeSignature == Uml::SignatureType::ShowSig || ++ m_attributeSignature == Uml::SignatureType::SigNoVis) { ++ if (visualProperty(ShowVisibility)) { ++ m_attributeSignature = Uml::SignatureType::NoSig; ++ } else { ++ m_attributeSignature = Uml::SignatureType::NoSigNoVis; ++ } ++ } else if (visualProperty(ShowVisibility)) { ++ m_attributeSignature = Uml::SignatureType::ShowSig; ++ } else { ++ m_attributeSignature = Uml::SignatureType::SigNoVis; ++ } ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Return the number of displayed members of the given ObjectType. ++ * Takes into consideration m_showPublicOnly but not other settings. ++ */ ++int ClassifierWidget::displayedMembers(UMLObject::ObjectType ot) const ++{ ++ int count = 0; ++ UMLClassifier *umlc = this->classifier(); ++ if (!umlc) ++ return count; ++ UMLClassifierListItemList list = umlc->getFilteredList(ot); ++ foreach (UMLClassifierListItem *m, list) { ++ if (!(visualProperty(ShowPublicOnly) && m->visibility() != Uml::Visibility::Public)) ++ count++; ++ } ++ return count; ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF ClassifierWidget::minimumSize() const ++{ ++ return calculateSize(); ++} ++ ++/** ++ * Calculate content related size of widget. ++ * Overrides method from UMLWidget. ++ */ ++QSizeF ClassifierWidget::calculateSize(bool withExtensions /* = true */) const ++{ ++ if (!m_umlObject) { ++ return UMLWidget::minimumSize(); ++ } ++ if (m_umlObject->baseType() == UMLObject::ot_Package) { ++ return calculateAsPackageSize(); ++ } ++ UMLClassifier *umlc = this->classifier(); ++ if (!umlc) { ++ uError() << "Internal error - classifier() returns NULL"; ++ return UMLWidget::minimumSize(); ++ } ++ if (umlc->isInterface() && visualProperty(DrawAsCircle)) { ++ return calculateAsCircleSize(); ++ } ++ ++ const bool showNameOnly = !visualProperty(ShowAttributes) && ++ !visualProperty(ShowOperations) && ++ !visualProperty(ShowDocumentation); ++ ++ const QFontMetrics &fm = getFontMetrics(UMLWidget::FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ // width is the width of the longest 'word' ++ int width = 0, height = 0; ++ // consider stereotype ++ if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { ++ height += fontHeight; ++ // ... width ++ const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD); ++ const int stereoWidth = bfm.size(0, m_umlObject->stereotype(true)).width(); ++ if (stereoWidth > width) ++ width = stereoWidth; ++ } else if (showNameOnly) { ++ height += MARGIN; ++ } ++ ++ // consider name ++ height += fontHeight; ++ // ... width ++ QString displayedName; ++ if (visualProperty(ShowPackage)) ++ displayedName = m_umlObject->fullyQualifiedName(); ++ else ++ displayedName = m_umlObject->name(); ++ const UMLWidget::FontType nft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); ++ const int nameWidth = UMLWidget::getFontMetrics(nft).size(0, displayedName).width(); ++ if (nameWidth > width) ++ width = nameWidth; ++ ++#ifdef ENABLE_WIDGET_SHOW_DOC ++ // consider documentation ++ if (visualProperty(ShowDocumentation)) { ++ if (!documentation().isEmpty()) { ++ QRect brect = fm.boundingRect(QRect(0, 0, this->width()-2*MARGIN, this->height()-height), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); ++ height += brect.height(); ++ if (!visualProperty(ShowOperations) && !visualProperty(ShowAttributes)) { ++ if (brect.width() >= width) ++ width = brect.width(); ++ } ++ } ++ else ++ height += fontHeight / 2; ++ } ++#endif ++ ++ // consider attributes ++ if (visualProperty(ShowAttributes)) { ++ const int numAtts = displayedAttributes(); ++ if (numAtts > 0) { ++ height += fontHeight * numAtts; ++ // calculate width of the attributes ++ UMLClassifierListItemList list = umlc->getFilteredList(UMLObject::ot_Attribute); ++ foreach (UMLClassifierListItem *a, list) { ++ if (visualProperty(ShowPublicOnly) && a->visibility() != Uml::Visibility::Public) ++ continue; ++ const int attWidth = fm.size(0, a->toString(m_attributeSignature)).width(); ++ if (attWidth > width) ++ width = attWidth; ++ } ++ } ++ else ++ height += fontHeight / 2; ++ } ++ ++ // consider operations ++ if (visualProperty(ShowOperations)) { ++ const int numOps = displayedOperations(); ++ if (numOps > 0) { ++ height += numOps * fontHeight; ++ // ... width ++ UMLOperationList list(umlc->getOpList()); ++ foreach (UMLOperation* op, list) { ++ if (visualProperty(ShowPublicOnly) && op->visibility() != Uml::Visibility::Public) ++ continue; ++ const QString displayedOp = op->toString(m_operationSignature); ++ UMLWidget::FontType oft; ++ oft = (op->isAbstract() ? UMLWidget::FT_ITALIC : UMLWidget::FT_NORMAL); ++ const int w = UMLWidget::getFontMetrics(oft).size(0, displayedOp).width(); ++ if (w > width) ++ width = w; ++ } ++ } ++ else ++ height += fontHeight / 2; ++ } ++ ++ if (withExtensions) { ++ // consider template box _as last_ ! ++ QSize templatesBoxSize = calculateTemplatesBoxSize(); ++ if (templatesBoxSize.width() != 0) { ++ // add width to largest 'word' ++ width += templatesBoxSize.width() / 2; ++ } ++ if (templatesBoxSize.height() != 0) { ++ height += templatesBoxSize.height() - MARGIN; ++ } ++ } ++ ++ // allow for height margin ++ if (showNameOnly) { ++ height += MARGIN; ++ } ++ ++ // allow for width margin ++ width += MARGIN * 2; ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Calculcates the size of the templates box in the top left ++ * if it exists, returns QSize(0, 0) if it doesn't. ++ * ++ * @return QSize of the templates flap. ++ */ ++QSize ClassifierWidget::calculateTemplatesBoxSize() const ++{ ++ if (!classifier()) ++ return QSize(0, 0); ++ UMLTemplateList list = classifier()->getTemplateList(); ++ int count = list.count(); ++ if (count == 0) { ++ return QSize(0, 0); ++ } ++ ++ QFont font = UMLWidget::font(); ++ font.setItalic(false); ++ font.setUnderline(false); ++ font.setBold(false); ++ const QFontMetrics fm(font); ++ ++ int width = 0; ++ int height = count * fm.lineSpacing() + (MARGIN*2); ++ ++ foreach (UMLTemplate *t, list) { ++ int textWidth = fm.size(0, t->toString()).width(); ++ if (textWidth > width) ++ width = textWidth; ++ } ++ ++ width += (MARGIN*2); ++ return QSize(width, height); ++} ++ ++/** ++ * Return the number of displayed attributes. ++ */ ++int ClassifierWidget::displayedAttributes() const ++{ ++ if (!visualProperty(ShowAttributes)) ++ return 0; ++ return displayedMembers(UMLObject::ot_Attribute); ++} ++ ++/** ++ * Return the number of displayed operations. ++ */ ++int ClassifierWidget::displayedOperations() const ++{ ++ if (!visualProperty(ShowOperations)) ++ return 0; ++ return displayedMembers(UMLObject::ot_Operation); ++} ++ ++/** ++ * Set the AssociationWidget when this ClassWidget acts as ++ * an association class. ++ */ ++void ClassifierWidget::setClassAssociationWidget(AssociationWidget *assocwidget) ++{ ++ if (!classifier()) { ++ uError() << "Class association cannot be applied to package"; ++ return; ++ } ++ m_pAssocWidget = assocwidget; ++ UMLAssociation *umlassoc = NULL; ++ if (assocwidget) ++ umlassoc = assocwidget->association(); ++ classifier()->setClassAssoc(umlassoc); ++} ++ ++/** ++ * Return the AssociationWidget when this classifier acts as ++ * an association class (else return NULL.) ++ */ ++AssociationWidget *ClassifierWidget::classAssociationWidget() const ++{ ++ return m_pAssocWidget; ++} ++ ++/** ++ * Overrides standard method. ++ * Auxiliary to reimplementations in the derived classes. ++ */ ++void ClassifierWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ else { ++ painter->setBrush(m_scene->backgroundColor()); ++ } ++ if (m_umlObject->baseType() == UMLObject::ot_Package) { ++ drawAsPackage(painter, option); ++ UMLWidget::paint(painter, option, widget); ++ return; ++ } ++ UMLClassifier *umlc = this->classifier(); ++ if (!umlc) { ++ uError() << "Internal error - classifier() returns NULL"; ++ return; ++ } ++ if (umlc->isInterface() && visualProperty(DrawAsCircle)) { ++ drawAsCircle(painter, option); ++ UMLWidget::paint(painter, option, widget); ++ return; ++ } ++ ++ // Draw the bounding rectangle ++ QSize templatesBoxSize = calculateTemplatesBoxSize(); ++ int bodyOffsetY = 0; ++ if (templatesBoxSize.height() > 0) ++ bodyOffsetY += templatesBoxSize.height() - MARGIN; ++ int w = width(); ++ if (templatesBoxSize.width() > 0) ++ w -= templatesBoxSize.width() / 2; ++ int h = height(); ++ if (templatesBoxSize.height() > 0) ++ h -= templatesBoxSize.height() - MARGIN; ++ painter->drawRect(0, bodyOffsetY, w, h); ++ ++ QFont font = UMLWidget::font(); ++ font.setUnderline(false); ++ font.setItalic(false); ++ const QFontMetrics &fm = UMLWidget::getFontMetrics(UMLWidget::FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ ++ //If there are any templates then draw them ++ UMLTemplateList tlist = umlc->getTemplateList(); ++ if (tlist.count() > 0) { ++ setPenFromSettings(painter); ++ QPen pen = painter->pen(); ++ pen.setStyle(Qt::DotLine); ++ painter->setPen(pen); ++ painter->drawRect(width() - templatesBoxSize.width(), 0, ++ templatesBoxSize.width(), templatesBoxSize.height()); ++ painter->setPen(QPen(textColor())); ++ font.setBold(false); ++ painter->setFont(font); ++ const int x = width() - templatesBoxSize.width() + MARGIN; ++ int y = MARGIN; ++ foreach (UMLTemplate *t, tlist) { ++ QString text = t->toString(); ++ painter->drawText(x, y, fm.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); ++ y += fontHeight; ++ } ++ } ++ ++ const int textX = MARGIN; ++ const int textWidth = w - MARGIN * 2; ++ ++ painter->setPen(QPen(textColor())); ++ ++ // draw stereotype ++ font.setBold(true); ++ const bool showNameOnly = !visualProperty(ShowAttributes) && ++ !visualProperty(ShowOperations) && ++ !visualProperty(ShowDocumentation); ++ ++ int nameHeight = fontHeight; ++ if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { ++ painter->setFont(font); ++ painter->drawText(textX, bodyOffsetY, textWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); ++ bodyOffsetY += fontHeight; ++ } else if (showNameOnly) { ++ nameHeight = h; ++ } ++ ++ // draw name ++ QString name; ++ if (visualProperty(ShowPackage)) { ++ name = m_umlObject->fullyQualifiedName(); ++ } else { ++ name = this->name(); ++ } ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ painter->drawText(textX, bodyOffsetY, textWidth, nameHeight, Qt::AlignCenter, name); ++ bodyOffsetY += fontHeight; ++ font.setBold(false); ++ font.setItalic(false); ++ painter->setFont(font); ++ ++#ifdef ENABLE_WIDGET_SHOW_DOC ++ // draw documentation ++ if (visualProperty(ShowDocumentation)) { ++ setPenFromSettings(painter); ++ painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); ++ painter->setPen(textColor()); ++ ++ if (!documentation().isEmpty()) { ++ QRect brect = fm.boundingRect(QRect(0, 0, w-2*MARGIN, h-bodyOffsetY), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); ++ if (brect.width() > width() + 2*MARGIN) ++ brect.setWidth(width()-2*MARGIN); ++ brect.adjust(textX, bodyOffsetY, textX, bodyOffsetY); ++ painter->drawText(brect, Qt::AlignCenter | Qt::TextWordWrap, documentation()); ++ bodyOffsetY += brect.height(); ++ } ++ else ++ bodyOffsetY += fontHeight / 2; ++ } ++#endif ++ // draw attributes ++ if (visualProperty(ShowAttributes)) { ++ // draw dividing line between doc/name and attributes ++ setPenFromSettings(painter); ++ painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); ++ painter->setPen(textColor()); ++ ++ const int numAtts = displayedAttributes(); ++ if (numAtts > 0) { ++ drawMembers(painter, UMLObject::ot_Attribute, m_attributeSignature, textX, ++ bodyOffsetY, fontHeight); ++ bodyOffsetY += fontHeight * numAtts; ++ } ++ else ++ bodyOffsetY += fontHeight / 2; ++ } ++ ++ // draw operations ++ if (visualProperty(ShowOperations)) { ++ // draw dividing line between attributes and operations ++ setPenFromSettings(painter); ++ painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); ++ painter->setPen(QPen(textColor())); ++ ++ const int numOps = displayedOperations(); ++ if (numOps >= 0) { ++ drawMembers(painter, UMLObject::ot_Operation, m_operationSignature, textX, ++ bodyOffsetY, fontHeight); ++ } ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * @return The shape of the ClassifierWidget. ++ */ ++QPainterPath ClassifierWidget::shape() const ++{ ++ QPainterPath path; ++ if (classifier() && classifier()->isInterface() && visualProperty(DrawAsCircle)) { ++ path.addEllipse(rect()); ++ return path; ++ } ++#ifdef ENABLE_WIDGET_SHOW_DOC ++ QSizeF mainSize = rect().size(); ++#else ++ QSizeF mainSize = calculateSize(false); ++#endif ++ QSize templatesBoxSize = calculateTemplatesBoxSize(); ++ qreal mainY = 0.0; ++ if (templatesBoxSize.height() > 0) { ++ mainY += templatesBoxSize.height() - MARGIN; ++ path.addRect(QRectF(mainSize.width() - templatesBoxSize.width() / 2, 0.0, ++ templatesBoxSize.width(), templatesBoxSize.height())); ++ } ++ path.addRect(QRectF(0.0, mainY, mainSize.width(), mainSize.height())); ++ return path; ++} ++ ++/** ++ * Draws the interface as a circle. ++ * Only applies when m_umlObject->getBaseType() is ot_Interface. ++ */ ++void ClassifierWidget::drawAsCircle(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ const int w = width(); ++ ++ if (m_Assocs.size() > 1) { ++ painter->drawEllipse(w/2 - CIRCLE_SIZE/2, SOCKET_INCREMENT / 2, CIRCLE_SIZE, CIRCLE_SIZE); ++ // Draw socket for required interface. ++ const qreal angleSpan = 180; // 360.0 / (m_Assocs.size() + 1.0); ++ const int arcDiameter = CIRCLE_SIZE + SOCKET_INCREMENT; ++ QRect requireArc(w/2 - arcDiameter/2, 0, arcDiameter, arcDiameter); ++ const QPointF center(x() + w/2, y() + arcDiameter/2); ++ const qreal cX = center.x(); ++ const qreal cY = center.y(); ++ foreach (AssociationWidget *aw, m_Assocs) { ++ const Uml::AssociationType::Enum aType = aw->associationType(); ++ if (aType == Uml::AssociationType::UniAssociation || ++ aType == Uml::AssociationType::Association) // provider ++ continue; ++ UMLWidget *otherEnd = aw->widgetForRole(Uml::RoleType::A); ++ const WidgetBase::WidgetType oType = otherEnd->baseType(); ++ if (oType != WidgetBase::wt_Component && oType != WidgetBase::wt_Port) ++ continue; ++ ++ AssociationLine *assocLine = aw->associationLine(); ++ const QPointF p(assocLine->endPoint()); ++ const qreal tolerance = 18.0; ++ bool drawArc = true; ++ qreal midAngle; ++ if (p.x() < cX - tolerance) { ++ if (p.y() < cY - tolerance) ++ midAngle = 135; ++ else if (p.y() > cY + tolerance) ++ midAngle = 225; ++ else ++ midAngle = 180; ++ } else if (p.x() > cX + tolerance) { ++ if (p.y() < cY - tolerance) ++ midAngle = 45; ++ else if (p.y() > cY + tolerance) ++ midAngle = 315; ++ else ++ midAngle = 0; ++ } else { ++ if (p.y() < cY - tolerance) ++ midAngle = 90; ++ else if (p.y() > cY + tolerance) ++ midAngle = 270; ++ else ++ drawArc = false; ++ } ++ if (drawArc) { ++ // uDebug() << "number of assocs: " << m_Assocs.size() ++ // << ", p: " << p << ", center: " << center ++ // << ", midAngle: " << midAngle << ", angleSpan: " << angleSpan; ++ painter->drawArc(requireArc, 16 * (midAngle - angleSpan/2), 16 * angleSpan); ++ } else { ++ uError() << "socket: assocLine endPoint " << p ++ << " too close to own center" << center; ++ } ++ } ++ } ++ else ++ painter->drawEllipse(w/2 - CIRCLE_SIZE/2, 0, CIRCLE_SIZE, CIRCLE_SIZE); ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * Calculates the size of the object when drawn as a circle. ++ * Only applies when m_umlObject->getBaseType() is ot_Interface. ++ */ ++QSize ClassifierWidget::calculateAsCircleSize() const ++{ ++ int circleSize = CIRCLE_SIZE; ++ if (m_Assocs.size() > 1) ++ circleSize += SOCKET_INCREMENT; ++ return QSize(circleSize, circleSize); ++} ++ ++void ClassifierWidget::drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ Q_UNUSED(option); ++ ++ int w = width(); ++ int h = height(); ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ //FIXME italic is true when a package is first created until you click elsewhere, not sure why ++ font.setItalic(false); ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ ++ painter->drawRect(0, 0, 50, fontHeight); ++ if (m_umlObject->stereotype() == QLatin1String("subsystem")) { ++ const int fHalf = fontHeight / 2; ++ const int symY = fHalf; ++ const int symX = 38; ++ painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg ++ painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg ++ painter->drawLine(symX, symY, symX + 8, symY); // waist ++ painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head ++ } ++ painter->drawRect(0, fontHeight - 1, w, h - fontHeight); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ int lines = 1; ++ QString stereotype = m_umlObject->stereotype(); ++ if (!stereotype.isEmpty()) { ++ painter->drawText(0, fontHeight + PACKAGE_MARGIN, ++ w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); ++ lines = 2; ++ } ++ ++ painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, ++ w, fontHeight, Qt::AlignCenter, name()); ++} ++ ++QSize ClassifierWidget::calculateAsPackageSize() const ++{ ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); ++ const int fontHeight = fm.lineSpacing(); ++ ++ int lines = 1; ++ ++ int width = fm.width(m_umlObject->name()); ++ ++ int tempWidth = 0; ++ if (!m_umlObject->stereotype().isEmpty()) { ++ tempWidth = fm.width(m_umlObject->stereotype(true)); ++ lines = 2; ++ } ++ if (tempWidth > width) ++ width = tempWidth; ++ width += PACKAGE_MARGIN * 2; ++ if (width < 70) ++ width = 70; // minumin width of 70 ++ ++ int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); ++ ++ return QSize(width, height); ++} ++ ++/** ++ * Auxiliary method for draw() of child classes: ++ * Draw the attributes or operations. ++ * ++ * @param p QPainter to paint to. ++ * @param ot Object type to draw, either ot_Attribute or ot_Operation. ++ * @param sigType Governs details of the member display. ++ * @param x X coordinate at which to draw the texts. ++ * @param y Y coordinate at which text drawing commences. ++ * @param fontHeight The font height. ++ */ ++void ClassifierWidget::drawMembers(QPainter * painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, ++ int x, int y, int fontHeight) ++{ ++ UMLClassifier *umlc = classifier(); ++ if (!umlc) { ++ return; ++ } ++ QFont f = UMLWidget::font(); ++ f.setBold(false); ++ UMLClassifierListItemList list = umlc->getFilteredList(ot); ++ painter->setClipping(true); ++ painter->setClipRect(rect()); ++ foreach (UMLClassifierListItem *obj, list) { ++ if (visualProperty(ShowPublicOnly) && obj->visibility() != Uml::Visibility::Public) ++ continue; ++ QString text = obj->toString(sigType); ++ f.setItalic(obj->isAbstract()); ++ f.setUnderline(obj->isStatic()); ++ painter->setFont(f); ++ QFontMetrics fontMetrics(f); ++ painter->drawText(x, y, fontMetrics.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); ++ f.setItalic(false); ++ f.setUnderline(false); ++ painter->setFont(f); ++ y += fontHeight; ++ } ++ painter->setClipping(false); ++} ++ ++/** ++ * Override method from UMLWidget in order to additionally check m_pInterfaceName. ++ * ++ * @param p Point to be checked. ++ * ++ * @return 'this' if UMLWidget::onWidget(p) returns non NULL; ++ * m_pInterfaceName if m_pName is non NULL and ++ * m_pInterfaceName->onWidget(p) returns non NULL; else NULL. ++ */ ++UMLWidget* ClassifierWidget::onWidget(const QPointF &p) ++{ ++ if (UMLWidget::onWidget(p) != NULL) ++ return this; ++ if (getDrawAsCircle() && m_pInterfaceName) { ++ uDebug() << "floatingtext: " << m_pInterfaceName->text(); ++ return m_pInterfaceName->onWidget(p); ++ } ++ return NULL; ++} ++ ++/** ++ * Reimplement function from UMLWidget. ++ */ ++UMLWidget* ClassifierWidget::widgetWithID(Uml::ID::Type id) ++{ ++ if (UMLWidget::widgetWithID(id)) ++ return this; ++ if (getDrawAsCircle() && m_pInterfaceName && m_pInterfaceName->widgetWithID(id)) ++ return m_pInterfaceName; ++ return NULL; ++} ++ ++void ClassifierWidget::setDocumentation(const QString &doc) ++{ ++ WidgetBase::setDocumentation(doc); ++ updateGeometry(); ++} ++ ++/** ++ * Sets whether to draw as circle. ++ * Only applies when m_umlObject->getBaseType() is ot_Interface. ++ * ++ * @param drawAsCircle True if widget shall be drawn as circle. ++ */ ++void ClassifierWidget::setDrawAsCircle(bool drawAsCircle) ++{ ++ setVisualPropertyCmd(DrawAsCircle, drawAsCircle); ++ const int circleSize = CIRCLE_SIZE + SOCKET_INCREMENT; ++ if (drawAsCircle) { ++ setX(x() + (width()/2 - circleSize/2)); ++ setY(y() + (height()/2 - circleSize/2)); ++ setSize(circleSize, circleSize); ++ if (m_pInterfaceName) { ++ m_pInterfaceName->show(); ++ } else { ++ m_pInterfaceName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); ++ m_pInterfaceName->setParentItem(this); ++ m_pInterfaceName->setText(name()); // to get geometry update ++ m_pInterfaceName->setX(circleSize/2 - m_pInterfaceName->width() / 2); ++ m_pInterfaceName->setY(circleSize + SOCKET_INCREMENT); ++ } ++ m_resizable = false; ++ } else { ++ setSize(ClassifierWidget::minimumSize()); ++ setX(x() - (width()/2 - circleSize/2)); ++ setY(y() - (height()/2 - circleSize/2)); ++ if (m_pInterfaceName) ++ m_pInterfaceName->hide(); ++ m_resizable = true; ++ } ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Returns whether to draw as circle. ++ * Only applies when m_umlObject->getBaseType() is ot_Interface. ++ * ++ * @return True if widget is drawn as circle. ++ */ ++bool ClassifierWidget::getDrawAsCircle() const ++{ ++ return visualProperty(DrawAsCircle); ++} ++ ++/** ++ * Toggles whether to draw as circle. ++ * Only applies when m_umlObject->getBaseType() is ot_Interface. ++ */ ++void ClassifierWidget::toggleDrawAsCircle() ++{ ++ toggleVisualProperty(DrawAsCircle); ++ updateSignatureTypes(); ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Changes this classifier from an interface to a class. ++ * Attributes and stereotype visibility is got from the view OptionState. ++ * This widget is also updated. ++ */ ++void ClassifierWidget::changeToClass() ++{ ++ m_baseType = WidgetBase::wt_Class; ++ m_umlObject->setBaseType(UMLObject::ot_Class); ++ setVisualPropertyCmd(DrawAsCircle, false); ++ const Settings::OptionState& ops = m_scene->optionState(); ++ setVisualProperty(ShowAttributes, ops.classState.showAtts); ++ setVisualProperty(ShowStereotype, ops.classState.showStereoType); ++ ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Changes this classifier from a class to an interface. ++ * Attributes are hidden and stereotype is shown. ++ * This widget is also updated. ++ */ ++void ClassifierWidget::changeToInterface() ++{ ++ m_baseType = WidgetBase::wt_Interface; ++ m_umlObject->setBaseType(UMLObject::ot_Interface); ++ ++ setVisualProperty(ShowAttributes, false); ++ setVisualProperty(ShowStereotype, true); ++ ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Changes this classifier from an "class-or-package" to a package. ++ * This widget is also updated. ++ */ ++void ClassifierWidget::changeToPackage() ++{ ++ m_baseType = WidgetBase::wt_Package; ++ m_umlObject->setBaseType(UMLObject::ot_Package); ++ ++ setVisualProperty(ShowAttributes, false); ++ setVisualProperty(ShowStereotype, true); ++ ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Extends base method to adjust also the association of a class ++ * association. ++ * Executes the base method and then, if file isn't loading and the ++ * classifier acts as a class association, the association position is ++ * updated. ++ * TODO: This is never called. ++ * ++ * param x The x-coordinate. ++ * param y The y-coordinate. ++ */ ++//void ClassifierWidget::adjustAssociations(int x, int y) ++//{ ++// DEBUG(DBG_SRC) << "x=" << x << " / y=" << y; ++// UMLWidget::adjustAssocs(x, y); ++ ++// if (m_doc->loading() || m_pAssocWidget == 0) { ++// return; ++// } ++ ++// //:TODO: the following is also called from UMLWidgetr::ajdustAssocs(...) ++// // and then AssociationWidget::widgetMoved(...) ++// //m_pAssocWidget->computeAssocClassLine(); ++//} ++ ++/** ++ * Loads the "classwidget" or "interfacewidget" XML element. ++ */ ++bool ClassifierWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ ++ QString showatts = qElement.attribute(QLatin1String("showattributes"), QLatin1String("0")); ++ QString showops = qElement.attribute(QLatin1String("showoperations"), QLatin1String("1")); ++ QString showpubliconly = qElement.attribute(QLatin1String("showpubliconly"), QLatin1String("0")); ++ QString showattsigs = qElement.attribute(QLatin1String("showattsigs"), QLatin1String("600")); ++ QString showopsigs = qElement.attribute(QLatin1String("showopsigs"), QLatin1String("600")); ++ QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); ++ QString showscope = qElement.attribute(QLatin1String("showscope"), QLatin1String("0")); ++ QString drawascircle = qElement.attribute(QLatin1String("drawascircle"), QLatin1String("0")); ++#ifdef ENABLE_WIDGET_SHOW_DOC ++ QString showDocumentation = qElement.attribute(QLatin1String("showdocumentation"), QLatin1String("0")); ++#endif ++ ++ setVisualPropertyCmd(ShowAttributes, (bool)showatts.toInt()); ++ setVisualPropertyCmd(ShowOperations, (bool)showops.toInt()); ++ setVisualPropertyCmd(ShowPublicOnly, (bool)showpubliconly.toInt()); ++ setVisualPropertyCmd(ShowPackage, (bool)showpackage.toInt()); ++ setVisualPropertyCmd(ShowVisibility, (bool)showscope.toInt()); ++ setVisualPropertyCmd(DrawAsCircle, (bool)drawascircle.toInt()); ++#ifdef ENABLE_WIDGET_SHOW_DOC ++ setVisualPropertyCmd(ShowDocumentation, (bool)showDocumentation.toInt()); ++#endif ++ ++ m_attributeSignature = Uml::SignatureType::fromInt(showattsigs.toInt()); ++ m_operationSignature = Uml::SignatureType::fromInt(showopsigs.toInt()); ++ ++ if (!getDrawAsCircle()) ++ return true; ++ ++ // Optional child element: floatingtext ++ QDomNode node = qElement.firstChild(); ++ QDomElement element = node.toElement(); ++ if (!element.isNull()) { ++ QString tag = element.tagName(); ++ if (tag == QLatin1String("floatingtext")) { ++ if (m_pInterfaceName == NULL) { ++ m_pInterfaceName = new FloatingTextWidget(m_scene, ++ Uml::TextRole::Floating, ++ name(), Uml::ID::Reserved); ++ m_pInterfaceName->setParentItem(this); ++ } ++ if (!m_pInterfaceName->loadFromXMI(element)) { ++ // Most likely cause: The FloatingTextWidget is empty. ++ delete m_pInterfaceName; ++ m_pInterfaceName = NULL; ++ } else { ++ m_pInterfaceName->activate(); ++ m_pInterfaceName->update(); ++ } ++ } else { ++ uError() << "unknown tag " << tag; ++ } ++ } ++ ++ return true; ++} ++ ++/** ++ * Creates the "classwidget" or "interfacewidget" XML element. ++ */ ++void ClassifierWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement conceptElement; ++ UMLClassifier *umlc = classifier(); ++ if (umlObject() && umlObject()->baseType() == UMLObject::ot_Package) { ++ conceptElement = qDoc.createElement(QLatin1String("packagewidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++ return; ++ } ++ else if (umlc && umlc->isInterface()) ++ conceptElement = qDoc.createElement(QLatin1String("interfacewidget")); ++ else ++ conceptElement = qDoc.createElement(QLatin1String("classwidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ conceptElement.setAttribute(QLatin1String("showoperations"), visualProperty(ShowOperations)); ++ conceptElement.setAttribute(QLatin1String("showpubliconly"), visualProperty(ShowPublicOnly)); ++ conceptElement.setAttribute(QLatin1String("showopsigs"), m_operationSignature); ++ conceptElement.setAttribute(QLatin1String("showpackage"), visualProperty(ShowPackage)); ++ conceptElement.setAttribute(QLatin1String("showscope"), visualProperty(ShowVisibility)); ++ conceptElement.setAttribute(QLatin1String("showattributes"), visualProperty(ShowAttributes)); ++ conceptElement.setAttribute(QLatin1String("showattsigs"), m_attributeSignature); ++#ifdef ENABLE_WIDGET_SHOW_DOC ++ conceptElement.setAttribute(QLatin1String("showdocumentation"),visualProperty(ShowDocumentation)); ++#endif ++ if (umlc && (umlc->isInterface() || umlc->isAbstract())) { ++ conceptElement.setAttribute(QLatin1String("drawascircle"), visualProperty(DrawAsCircle)); ++ if (visualProperty(DrawAsCircle) && m_pInterfaceName) { ++ m_pInterfaceName->saveToXMI(qDoc, conceptElement); ++ } ++ } ++ qElement.appendChild(conceptElement); ++} ++ ++/** ++ * Will be called when a menu selection has been made from the ++ * popup menu. ++ * ++ * @param action The action that has been selected. ++ */ ++void ClassifierWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch (sel) { ++ case ListPopupMenu::mt_Attribute: ++ case ListPopupMenu::mt_Operation: ++ case ListPopupMenu::mt_Template: ++ { ++ UMLObject::ObjectType ot = ListPopupMenu::convert_MT_OT(sel); ++ UMLClassifier *umlc = classifier(); ++ if (!umlc) { ++ uError() << "Internal error - classifier() returns NULL"; ++ return; ++ } ++ if (Object_Factory::createChildObject(umlc, ot)) { ++ updateGeometry(); ++ update(); ++ UMLApp::app()->document()->setModified(); ++ } ++ break; ++ } ++ case ListPopupMenu::mt_Show_Operations: ++ toggleVisualProperty(ShowOperations); ++ break; ++ ++ case ListPopupMenu::mt_Show_Attributes: ++ toggleVisualProperty(ShowAttributes); ++ break; ++ ++ case ListPopupMenu::mt_Show_Documentation: ++ toggleVisualProperty(ShowDocumentation); ++ break; ++ ++ case ListPopupMenu::mt_Show_Public_Only: ++ toggleVisualProperty(ShowPublicOnly); ++ break; ++ ++ case ListPopupMenu::mt_Show_Operation_Signature: ++ toggleVisualProperty(ShowOperationSignature); ++ break; ++ ++ case ListPopupMenu::mt_Show_Attribute_Signature: ++ toggleVisualProperty(ShowAttributeSignature); ++ break; ++ ++ case ListPopupMenu::mt_Visibility: ++ toggleVisualProperty(ShowVisibility); ++ break; ++ ++ case ListPopupMenu::mt_Show_Packages: ++ toggleVisualProperty(ShowPackage); ++ break; ++ ++ case ListPopupMenu::mt_Show_Stereotypes: ++ toggleVisualProperty(ShowStereotype); ++ break; ++ ++ case ListPopupMenu::mt_DrawAsCircle: ++ toggleVisualProperty(DrawAsCircle); ++ break; ++ ++ case ListPopupMenu::mt_ChangeToClass: ++ changeToClass(); ++ break; ++ ++ case ListPopupMenu::mt_ChangeToInterface: ++ changeToInterface(); ++ break; ++ ++ case ListPopupMenu::mt_ChangeToPackage: ++ changeToPackage(); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ break; ++ } ++} ++ ++/** ++ * Slot to show/hide attributes based on \a state. ++ */ ++void ClassifierWidget::slotShowAttributes(bool state) ++{ ++ setVisualProperty(ShowAttributes, state); ++} ++ ++/** ++ * Slot to show/hide operations based on \a state. ++ */ ++void ClassifierWidget::slotShowOperations(bool state) ++{ ++ setVisualProperty(ShowOperations, state); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.h 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,146 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef CLASSIFIERWIDGET_H ++#define CLASSIFIERWIDGET_H ++ ++#include "basictypes.h" ++#include "umlobject.h" ++#include "umlwidget.h" ++ ++class AssociationWidget; ++class FloatingTextWidget; ++class QPainter; ++class UMLClassifier; ++ ++/** ++ * @short Common implementation for class widget and interface widget ++ * ++ * @author Oliver Kellogg ++ * @author Gopala Krishna ++ * ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ClassifierWidget : public UMLWidget ++{ ++ Q_OBJECT ++ Q_ENUMS(VisualProperty) ++public: ++ /** ++ * This enumeration lists the visual properties that can be easily ++ * set, reset and toggled and all these operate on an integer ++ * which stores all the flag status. ++ */ ++ enum VisualProperty { ++ ShowStereotype = 0x1, ++ ShowOperations = 0x2, ++ ShowPublicOnly = 0x4, ++ ShowVisibility = 0x8, ++ ShowPackage = 0x10, ++ ShowAttributes = 0x20, ++ DrawAsCircle = 0x40, ++ ShowOperationSignature = 0x60, ///< only in setter ++ ShowAttributeSignature = 0x80, ///< only in setter ++ DrawAsPackage = 0x100, ++ ShowDocumentation = 0x200, ++ }; ++ ++ Q_DECLARE_FLAGS(VisualProperties, VisualProperty) ++ ++ ClassifierWidget(UMLScene * scene, UMLClassifier * o); ++ ClassifierWidget(UMLScene * scene, UMLPackage * o); ++ virtual ~ClassifierWidget(); ++ ++ UMLClassifier *classifier() const; ++ ++ VisualProperties visualProperties() const; ++ void setVisualProperties(VisualProperties properties); ++ ++ bool visualProperty(VisualProperty property) const; ++ void setVisualProperty(VisualProperty property, bool enable = true); ++ void setVisualPropertyCmd(VisualProperty property, bool enable = true); ++ void toggleVisualProperty(VisualProperty property); ++ ++ int displayedAttributes() const; ++ int displayedOperations() const; ++ ++ Uml::SignatureType::Enum attributeSignature() const; ++ void setAttributeSignature(Uml::SignatureType::Enum sig); ++ ++ Uml::SignatureType::Enum operationSignature() const; ++ void setOperationSignature(Uml::SignatureType::Enum sig); ++ ++ void setShowAttSigs(bool _show); ++ void toggleShowAttSigs(); ++ ++ bool getDrawAsCircle() const; ++ void setDrawAsCircle(bool drawAsCircle); ++ void toggleDrawAsCircle(); ++ ++ void changeToClass(); ++ void changeToInterface(); ++ void changeToPackage(); ++ ++ AssociationWidget *classAssociationWidget() const; ++ void setClassAssociationWidget(AssociationWidget *assocwidget); ++// virtual void adjustAssociations(int x, int y); ++ ++ UMLWidget* onWidget(const QPointF& p); ++ UMLWidget* widgetWithID(Uml::ID::Type id); ++ ++ virtual void setDocumentation(const QString& doc); ++ ++ QSizeF calculateSize(bool withExtensions = true) const; ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ virtual QPainterPath shape() const; ++ ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ virtual bool loadFromXMI(QDomElement & qElement); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++private Q_SLOTS: ++ void slotShowAttributes(bool state); ++ void slotShowOperations(bool state); ++ ++private: ++ void updateSignatureTypes(); ++ QSize calculateTemplatesBoxSize() const; ++ ++ QSizeF minimumSize() const; ++ ++ void drawAsCircle(QPainter *p, const QStyleOptionGraphicsItem *option); ++ QSize calculateAsCircleSize() const; ++ ++ void drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ QSize calculateAsPackageSize() const; ++ ++ int displayedMembers(UMLObject::ObjectType ot) const; ++ void drawMembers(QPainter *painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, ++ int x, int y, int fontHeight); ++ ++ static const int MARGIN; ///< text width margin ++ static const int CIRCLE_SIZE; ///< size of circle when interface is rendered as such ++ static const int SOCKET_INCREMENT; ///< augmentation of circle for socket (required interface) ++ ++ VisualProperties m_visualProperties; ++ Uml::SignatureType::Enum m_attributeSignature; ///< Loaded/saved item. ++ Uml::SignatureType::Enum m_operationSignature; ///< Loaded/saved item. ++ AssociationWidget *m_pAssocWidget; ///< related AssociationWidget in case this classifier acts as an association class ++ FloatingTextWidget *m_pInterfaceName; ///< Separate widget for name in case of interface drawn as circle ++ ++}; ++ ++Q_DECLARE_OPERATORS_FOR_FLAGS(ClassifierWidget::VisualProperties) ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.cpp 2015-10-08 11:48:59.508089026 +0300 +@@ -0,0 +1,477 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "combinedfragmentwidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "dialog_utils.h" ++#include "listpopupmenu.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++#include ++ ++/** ++ * Creates a Combined Fragment widget. ++ * ++ * @param scene The parent of the widget. ++ * @param combinedfragmentType The type of combined fragment. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++CombinedFragmentWidget::CombinedFragmentWidget(UMLScene * scene, CombinedFragmentType combinedfragmentType, Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_CombinedFragment, id) ++{ ++ setCombinedFragmentType(combinedfragmentType); ++} ++ ++/** ++ * Destructor. ++ */ ++CombinedFragmentWidget::~CombinedFragmentWidget() ++{ ++ for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { ++ delete(*it); ++ } ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void CombinedFragmentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ int w = width(); ++ int h = height(); ++ int line_width = 45; ++ int old_Y; ++ ++ setPenFromSettings(painter); ++ ++ if (m_CombinedFragment == Ref) { ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } ++ } ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const QString combined_fragment_value = name(); ++ int textStartY = (h / 2) - (fontHeight / 2); ++ painter->drawRect(0, 0, w, h); ++ ++ painter->setPen(textColor()); ++ painter->setFont(UMLWidget::font()); ++ QString temp = QLatin1String("loop"); ++ ++ switch (m_CombinedFragment) ++ { ++ case Ref : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, textStartY, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignCenter, combined_fragment_value); ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("ref")); ++ break; ++ ++ case Opt : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("opt")); ++ break; ++ ++ case Break : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("break")); ++ break; ++ ++ case Loop : ++ if (combined_fragment_value != QLatin1String("-")) ++ { ++ temp += QLatin1String(" [") + combined_fragment_value + QLatin1Char(']'); ++ line_width += (combined_fragment_value.size() + 2) * 8; ++ } ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); ++ ++ break; ++ ++ case Neg : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("neg")); ++ break; ++ ++ case Crit : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("critical")); ++ break; ++ ++ case Ass : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("assert")); ++ break; ++ ++ case Alt : ++ if (combined_fragment_value != QLatin1String("-")) ++ { ++ temp = QLatin1Char('[') + combined_fragment_value + QLatin1Char(']'); ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 20, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); ++ if (m_dashLines.size() == 1 && m_dashLines.first()->y() < y() + 20 + fontHeight) ++ m_dashLines.first()->setY(y() + h/2); ++ } ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("alt")); ++ // dash lines ++ //m_dashLines.first()->paint(painter); ++ // TODO: move to UMLWidget::calculateSize api ++ for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { ++ (*it)->setX(x()); ++ old_Y = (*it)->getYMin(); ++ (*it)->setYMin(y()); ++ (*it)->setYMax(y() + height()); ++ (*it)->setY(y() + (*it)->y() - old_Y); ++ (*it)->setSize(w, (*it)->height()); ++ (*it)->setLineColor(lineColor()); ++ (*it)->setLineWidth(lineWidth()); ++ } ++ ++ break; ++ ++ case Par : ++ painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, ++ w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("parallel")); ++ // dash lines ++ if (m_dashLines.size() != 0) { ++ //m_dashLines.first()->paint(painter); ++ // TODO: move to UMLWidget::calculateSize api ++ for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { ++ (*it)->setX(x()); ++ old_Y = (*it)->getYMin(); ++ (*it)->setYMin(y()); ++ (*it)->setYMax(y() + height()); ++ (*it)->setY(y() + (*it)->y() - old_Y); ++ (*it)->setSize(w, (*it)->height()); ++ (*it)->setLineColor(lineColor()); ++ (*it)->setLineWidth(lineWidth()); ++ } ++ } ++ break; ++ ++ default : break; ++ } ++ ++ setPenFromSettings(painter); ++ painter->drawLine(0, 20, line_width, 20); ++ painter->drawLine(line_width, 20, line_width + 10, 10); ++ painter->drawLine(line_width + 10, 10, line_width + 10, 0); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF CombinedFragmentWidget::minimumSize() const ++{ ++ int width = 10, height = 10; ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int textWidth = fm.width(name()); ++ height = fontHeight; ++ width = textWidth + 60 > COMBINED_FRAGMENT_WIDTH ? textWidth + 60: COMBINED_FRAGMENT_WIDTH; ++ if (m_CombinedFragment == Loop) ++ width += int((float)textWidth * 0.4f); ++ if (m_CombinedFragment == Alt) ++ height += fontHeight + 40; ++ height = height > COMBINED_FRAGMENT_HEIGHT ? height : COMBINED_FRAGMENT_HEIGHT; ++ width += COMBINED_FRAGMENT_MARGIN * 2; ++ height += COMBINED_FRAGMENT_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Returns the type of combined fragment. ++ */ ++CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType() const ++{ ++ return m_CombinedFragment; ++} ++ ++/** ++ * Sets the type of combined fragment. ++ */ ++void CombinedFragmentWidget::setCombinedFragmentType(CombinedFragmentType combinedfragmentType) ++{ ++ m_CombinedFragment = combinedfragmentType; ++ UMLWidget::m_resizable = true ; //(m_CombinedFragment == Normal); ++ // creates a dash line if the combined fragment type is alternative or parallel ++ if (m_CombinedFragment == Alt && m_dashLines.isEmpty()) ++ { ++ m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); ++ if (m_CombinedFragment == Alt) ++ { ++ m_dashLines.back()->setText(QLatin1String("else")); ++ } ++ // TODO: move to UMLWidget::calculateSize api ++ m_dashLines.back()->setX(x()); ++ m_dashLines.back()->setYMin(y()); ++ m_dashLines.back()->setYMax(y() + height()); ++ m_dashLines.back()->setY(y() + height()/2); ++ m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); ++ m_scene->widgetList().append(m_dashLines.back()); ++ } ++} ++ ++/** ++ * Returns the type of combined fragment. ++ */ ++CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType(const QString& type) const ++{ ++ if (type == QLatin1String("Reference")) ++ return (CombinedFragmentWidget::Ref); ++ if (type == QLatin1String("Option")) ++ return (CombinedFragmentWidget::Opt); ++ if (type == QLatin1String("Break")) ++ return (CombinedFragmentWidget::Break); ++ if (type == QLatin1String("Loop")) ++ return (CombinedFragmentWidget::Loop); ++ if (type == QLatin1String("Negative")) ++ return (CombinedFragmentWidget::Neg); ++ if (type == QLatin1String("Critical")) ++ return (CombinedFragmentWidget::Crit); ++ if (type == QLatin1String("Assertion")) ++ return (CombinedFragmentWidget::Ass); ++ if (type == QLatin1String("Alternative")) ++ return (CombinedFragmentWidget::Alt); ++ if (type == QLatin1String("Parallel")) ++ return (CombinedFragmentWidget::Par); ++ // Shouldn't happen ++ Q_ASSERT(0); ++ return (CombinedFragmentWidget::Ref); ++} ++ ++/** ++ * Sets the type of combined fragment. ++ */ ++void CombinedFragmentWidget::setCombinedFragmentType(const QString& combinedfragmentType) ++{ ++ setCombinedFragmentType(combinedFragmentType(combinedfragmentType)); ++} ++ ++/** ++ * ... ++ */ ++void CombinedFragmentWidget::askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, ++ const QString& dialogPrompt, const QString& defaultName) ++{ ++ Q_UNUSED(defaultName); ++ bool pressedOK = false; ++ const QStringList list = QStringList() ++ << QLatin1String("Reference") ++ << QLatin1String("Option") ++ << QLatin1String("Break") ++ << QLatin1String("Loop") ++ << QLatin1String("Negative") ++ << QLatin1String("Critical") ++ << QLatin1String("Assertion") ++ << QLatin1String("Alternative") ++ << QLatin1String("Parallel") ; ++#if QT_VERSION >= 0x050000 ++ QPointer inputDlg = new QInputDialog(); ++ inputDlg->setComboBoxItems(list); ++ inputDlg->setOptions(QInputDialog::UseListViewForComboBoxItems); ++ inputDlg->setWindowTitle(dialogTitle); ++ inputDlg->setLabelText(dialogPrompt); ++ pressedOK = inputDlg->exec(); ++ QStringList result; ++ result.append(inputDlg->textValue()); ++ delete inputDlg; ++#else ++ const QStringList select = list; ++ QStringList result = KInputDialog::getItemList (dialogTitle, dialogPrompt, list, select, false, &pressedOK, UMLApp::app()); ++#endif ++ if (pressedOK) { ++ QString type = result.join(QString()); ++ dynamic_cast(targetWidget)->setCombinedFragmentType(type); ++ if (type == QLatin1String("Reference")) ++ Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the diagram referenced"), i18n("Enter the name of the diagram referenced"), i18n("Diagram name")); ++ else if (type == QLatin1String(QLatin1String("Loop"))) ++ Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop"), i18n("-")); ++ else if (type == QLatin1String("Alternative")) ++ Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the first alternative name"), i18n("Enter the first alternative name"), i18n("-")); ++ } else { ++ targetWidget->cleanup(); ++ delete targetWidget; ++ targetWidget = NULL; ++ } ++} ++ ++/** ++ * Saves the widget to the "combinedFragmentwidget" XMI element. ++ */ ++void CombinedFragmentWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement combinedFragmentElement = qDoc.createElement(QLatin1String("combinedFragmentwidget")); ++ UMLWidget::saveToXMI(qDoc, combinedFragmentElement); ++ combinedFragmentElement.setAttribute(QLatin1String("combinedFragmentname"), m_Text); ++ combinedFragmentElement.setAttribute(QLatin1String("documentation"), m_Doc); ++ combinedFragmentElement.setAttribute(QLatin1String("CombinedFragmenttype"), m_CombinedFragment); ++ ++ // save the corresponding floating dash lines ++ for (QList::iterator it = m_dashLines.begin() ; it != m_dashLines.end() ; ++it) { ++ (*it)-> saveToXMI(qDoc, combinedFragmentElement); ++ } ++ ++ qElement.appendChild(combinedFragmentElement); ++} ++ ++/** ++ * Loads the widget from the "CombinedFragmentwidget" XMI element. ++ */ ++bool CombinedFragmentWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ m_Text = qElement.attribute(QLatin1String("combinedFragmentname")); ++ m_Doc = qElement.attribute(QLatin1String("documentation")); ++ QString type = qElement.attribute(QLatin1String("CombinedFragmenttype")); ++ ++ //now load child elements ++ QDomNode node = qElement.firstChild(); ++ QDomElement element = node.toElement(); ++ while (!element.isNull()) { ++ QString tag = element.tagName(); ++ if (tag == QLatin1String("floatingdashlinewidget")) { ++ FloatingDashLineWidget * fdlwidget = new FloatingDashLineWidget(m_scene, Uml::ID::None, this); ++ m_dashLines.push_back(fdlwidget); ++ if (!fdlwidget->loadFromXMI(element)) { ++ // Most likely cause: The FloatingTextWidget is empty. ++ delete m_dashLines.back(); ++ return false; ++ } ++ else { ++ m_scene->widgetList().append(fdlwidget); ++ fdlwidget->clipSize(); ++ } ++ } else { ++ uError() << "unknown tag " << tag; ++ } ++ node = node.nextSibling(); ++ element = node.toElement(); ++ } ++ // m_dashLines = listline; ++ setCombinedFragmentType((CombinedFragmentType)type.toInt()); ++ ++ return true; ++} ++ ++void CombinedFragmentWidget::removeDashLine(FloatingDashLineWidget *line) ++{ ++ if (m_dashLines.contains(line)) ++ m_dashLines.removeOne(line); ++} ++ ++/** ++ * Overrides the function from UMLWidget. Deletes all FloatingDashLineWidgets ++ * that are associated with this instance. ++ */ ++void CombinedFragmentWidget::cleanup() ++{ ++ foreach (FloatingDashLineWidget* w, m_dashLines) ++ { ++ if (!w->isSelected()) { ++ // no need to make this undoable, since the dashlines will be ++ // reconstructed when deleting the combined fragment is undone. ++ umlScene()->removeWidgetCmd(w); ++ } ++ } ++} ++ ++/** ++ * Overrides the function from UMLWidget. ++ * ++ * @param action The command to be executed. ++ */ ++void CombinedFragmentWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch (sel) { ++ // for alternative or parallel combined fragments ++ case ListPopupMenu::mt_AddInteractionOperand: ++ m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); ++ if (m_CombinedFragment == Alt) ++ { ++ m_dashLines.back()->setText(QLatin1String("else")); ++ } ++ // TODO: move to UMLWidget::calculateSize api ++ m_dashLines.back()->setX(x()); ++ m_dashLines.back()->setYMin(y()); ++ m_dashLines.back()->setYMax(y() + height()); ++ m_dashLines.back()->setY(y() + height() / 2); ++ m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); ++ m_scene->setupNewWidget(m_dashLines.back()); ++ break; ++ ++ case ListPopupMenu::mt_Rename: ++ { ++ bool ok = false; ++ QString name = m_Text; ++ ++#if QT_VERSION >= 0x050000 ++ if (m_CombinedFragment == Alt) { ++ name = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter first alternative"), i18n("Enter first alternative :"), ++ QLineEdit::Normal, ++ m_Text, &ok); ++ } ++ else if (m_CombinedFragment == Ref) { ++ name = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), ++ QLineEdit::Normal, ++ m_Text, &ok); ++ } ++ else if (m_CombinedFragment == Loop) { ++ name = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), ++ QLineEdit::Normal, ++ m_Text, &ok); ++ } ++#else ++ if (m_CombinedFragment == Alt) { ++ name = KInputDialog::getText(i18n("Enter first alternative"), i18n("Enter first alternative :"), m_Text, &ok); ++ } ++ else if (m_CombinedFragment == Ref) { ++ name = KInputDialog::getText(i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), m_Text, &ok); ++ } ++ else if (m_CombinedFragment == Loop) { ++ name = KInputDialog::getText(i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), m_Text, &ok); ++ } ++#endif ++ if (ok && name.length() > 0) ++ m_Text = name; ++ } ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,91 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef COMBINEDFRAGMENTWIDGET_H ++#define COMBINEDFRAGMENTWIDGET_H ++ ++#include "umlwidget.h" ++#include "worktoolbar.h" ++#include "floatingdashlinewidget.h" ++ ++#include ++ ++#define COMBINED_FRAGMENT_MARGIN 5 ++#define COMBINED_FRAGMENT_WIDTH 100 ++#define COMBINED_FRAGMENT_HEIGHT 50 ++ ++/** ++ * This class is the graphical version of a UML combined fragment. A combinedfragmentWidget is created ++ * by a @ref UMLView. An combinedfragmentWidget belongs to only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. ++ * ++ * The combinedfragmentWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @short A graphical version of a UML combined fragment. ++ * @author Hassan KOUCH ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class CombinedFragmentWidget : public UMLWidget ++{ ++ Q_OBJECT ++ ++public: ++ enum CombinedFragmentType ++ { ++ Ref = 0, ++ Opt, ++ Break, ++ Loop, ++ Neg, ++ Crit, ++ Ass, ++ Alt, ++ Par ++ }; ++ ++ explicit CombinedFragmentWidget(UMLScene * scene, ++ CombinedFragmentType combinedfragmentType = Ref, ++ Uml::ID::Type id = Uml::ID::None); ++ virtual ~CombinedFragmentWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ CombinedFragmentType combinedFragmentType() const; ++ CombinedFragmentType combinedFragmentType(const QString& combinedfragmentType) const; ++ void setCombinedFragmentType(CombinedFragmentType combinedfragmentType); ++ void setCombinedFragmentType(const QString& combinedfragmentType); ++ ++ void askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, ++ const QString& dialogPrompt, const QString& defaultName); ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ bool loadFromXMI(QDomElement & qElement); ++ void removeDashLine(FloatingDashLineWidget *line); ++ ++ virtual void cleanup(); ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ ++ ++protected: ++ QSizeF minimumSize() const; ++ ++ /// Type of CombinedFragment. ++ CombinedFragmentType m_CombinedFragment; ++ ++private: ++ /// Dash lines of an alternative or parallel combined fragment ++ QList m_dashLines ; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,207 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "componentwidget.h" ++ ++// app includes ++#include "component.h" ++#include "debug_utils.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "optionstate.h" ++#include "umldoc.h" ++#include "package.h" ++#include "portwidget.h" ++ ++/** ++ * Constructs a ComponentWidget. ++ * ++ * @param scene The parent of this ComponentWidget. ++ * @param c The UMLComponent this will be representing. ++ */ ++ComponentWidget::ComponentWidget(UMLScene * scene, UMLComponent *c) ++ : UMLWidget(scene, WidgetBase::wt_Component, c) ++{ ++ setSize(100, 30); ++ //set defaults from m_scene ++ if (m_scene) { ++ //check to see if correct ++ const Settings::OptionState& ops = m_scene->optionState(); ++ m_showStereotype = ops.classState.showStereoType; ++ } ++} ++ ++/** ++ * Destructor. ++ */ ++ComponentWidget::~ComponentWidget() ++{ ++} ++ ++/** ++ * Reimplemented from UMLWidget::paint to paint component ++ * widget. ++ */ ++void ComponentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ UMLComponent *umlcomp = static_cast(m_umlObject); ++ if (umlcomp == NULL) ++ return; ++ setPenFromSettings(painter); ++ QPen origPen = painter->pen(); ++ QPen pen = origPen; ++ if (umlcomp->getExecutable()) { ++ pen.setWidth(origPen.width() + 2); ++ painter->setPen(pen); ++ } ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } else { ++ painter->setBrush(m_scene->backgroundColor()); ++ } ++ ++ const int w = width(); ++ const int h = height(); ++ const int halfHeight = h / 2; ++ int textXOffset = 0; ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ QString nameStr = name(); ++ const QString stereotype = m_umlObject->stereotype(); ++ ++ if (Settings::optionState().generalState.uml2) { ++ painter->drawRect(0, 0, w, h); ++ // draw small component symbol in upper right corner ++ painter->setPen(origPen); ++ painter->drawRect(w - 17, 5, 11, 13); ++ painter->drawRect(w - 19, 7, 2, 2); ++ painter->drawRect(w - 19, 11, 2, 2); ++ painter->setPen(pen); ++ } else { ++ painter->drawRect(2*COMPONENT_MARGIN, 0, w - 2*COMPONENT_MARGIN, h); ++ painter->drawRect(0, halfHeight - fontHeight/2 - fontHeight, COMPONENT_MARGIN*4, fontHeight); ++ painter->drawRect(0, halfHeight + fontHeight/2, COMPONENT_MARGIN*4, fontHeight); ++ textXOffset = COMPONENT_MARGIN * 4; ++ } ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ int lines = 1; ++ ++ if (!stereotype.isEmpty()) { ++ painter->drawText(textXOffset, halfHeight - fontHeight, ++ w - textXOffset, fontHeight, Qt::AlignCenter, ++ m_umlObject->stereotype(true)); ++ lines = 2; ++ } ++ ++ if (UMLWidget::isInstance()) { ++ font.setUnderline(true); ++ painter->setFont(font); ++ nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; ++ } ++ ++ if (lines == 1) { ++ painter->drawText(textXOffset, halfHeight - (fontHeight/2), ++ w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); ++ } else { ++ painter->drawText(textXOffset, halfHeight, ++ w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overridden from UMLWidget due to emission of signal sigCompMoved() ++ */ ++void ComponentWidget::moveWidgetBy(qreal diffX, qreal diffY) ++{ ++ UMLWidget::moveWidgetBy(diffX, diffY); ++ emit sigCompMoved(diffX, diffY); ++} ++ ++/** ++ * Override method from UMLWidget for adjustment of attached PortWidgets. ++ */ ++void ComponentWidget::adjustAssocs(qreal dx, qreal dy) ++{ ++ if (m_doc->loading()) { ++ // don't recalculate the assocs during load of XMI ++ // -> return immediately without action ++ return; ++ } ++ UMLWidget::adjustAssocs(dx, dy); ++ UMLPackage *comp = static_cast(m_umlObject); ++ foreach (UMLObject *o, comp->containedObjects()) { ++ uIgnoreZeroPointer(o); ++ if (o->baseType() != UMLObject::ot_Port) ++ continue; ++ UMLWidget *portW = m_scene->widgetOnDiagram(o->id()); ++ if (portW) ++ portW->adjustAssocs(dx, dy); ++ } ++} ++ ++/** ++ * Saves to the "componentwidget" XMI element. ++ */ ++void ComponentWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("componentwidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF ComponentWidget::minimumSize() const ++{ ++ if (!m_umlObject) { ++ return QSizeF(70, 70); ++ } ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); ++ const int fontHeight = fm.lineSpacing(); ++ ++ QString name = m_umlObject->name(); ++ if (UMLWidget::isInstance()) { ++ name = UMLWidget::instanceName() + QLatin1String(" : ") + name; ++ } ++ ++ int width = fm.width(name); ++ ++ int stereoWidth = 0; ++ if (!m_umlObject->stereotype().isEmpty()) { ++ stereoWidth = fm.width(m_umlObject->stereotype(true)); ++ } ++ if (stereoWidth > width) ++ width = stereoWidth; ++ width += COMPONENT_MARGIN * 6; ++ width = 70>width ? 70 : width; //minumin width of 70 ++ ++ int height = (2*fontHeight) + (COMPONENT_MARGIN * 3); ++ ++ UMLComponent *umlcomp = static_cast(m_umlObject); ++ if (umlcomp && umlcomp->getExecutable()) { ++ width += 2; ++ height += 2; ++ } ++ ++ return QSizeF(width, height); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,58 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef COMPONENTWIDGET_H ++#define COMPONENTWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLComponent; ++ ++#define COMPONENT_MARGIN 10 ++ ++/** ++ * Defines a graphical version of the Component. Most of the functionality ++ * will come from the @ref UMLComponent class. ++ * ++ * @short A graphical version of a Component. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ComponentWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ ComponentWidget(UMLScene * scene, UMLComponent *c); ++ virtual ~ComponentWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ virtual void moveWidgetBy(qreal diffX, qreal diffY); ++ virtual void adjustAssocs(qreal dx, qreal dy); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++signals: ++ /** ++ * Emitted when the component widget is moved. ++ * Provides the delta X and delta Y amount by which the widget was moved ++ * relative to the previous position. ++ * Slots into PortWidget::slotCompMoved() ++ * @param diffX The difference between previous and new X value. ++ * @param diffY The difference between previous and new Y value. ++ */ ++ void sigCompMoved(qreal diffX, qreal diffY); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,129 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "datatypewidget.h" ++ ++// app includes ++#include "classifier.h" ++#include "classifierlistitem.h" ++#include "debug_utils.h" ++#include "operation.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// qt includes ++#include ++ ++/** ++ * Constructs an DatatypeWidget. ++ * ++ * @param scene The parent of this DatatypeWidget. ++ * @param d The UMLClassifier this will be representing. ++ */ ++DatatypeWidget::DatatypeWidget(UMLScene *scene, UMLClassifier *d) ++ : UMLWidget(scene, WidgetBase::wt_Datatype, d) ++{ ++ setSize(100, 30); ++} ++ ++/** ++ * Standard deconstructor. ++ */ ++DatatypeWidget::~DatatypeWidget() ++{ ++} ++ ++/** ++ * Overrides standard method. ++ */ ++void DatatypeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } else { ++ painter->setBrush(m_scene->backgroundColor()); ++ } ++ ++ int w = width(); ++ int h = height(); ++ ++ QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ int fontHeight = fm.lineSpacing(); ++ ++ painter->drawRect(0, 0, w, h); ++ painter->setPen(textColor()); ++ ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ painter->setFont(font); ++ painter->drawText(DATATYPE_MARGIN, 0, ++ w - DATATYPE_MARGIN* 2, fontHeight, ++ Qt::AlignCenter, m_umlObject->stereotype(true)); ++ ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ painter->drawText(DATATYPE_MARGIN, fontHeight, ++ w - DATATYPE_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Loads from a "datatypewidget" XMI element. ++ */ ++bool DatatypeWidget::loadFromXMI(QDomElement & qElement) ++{ ++ return UMLWidget::loadFromXMI(qElement); ++} ++ ++/** ++ * Saves to the "datatypewidget" XMI element. ++ */ ++void DatatypeWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("datatypewidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF DatatypeWidget::minimumSize() const ++{ ++ if (!m_umlObject) { ++ return UMLWidget::minimumSize(); ++ } ++ int width, height; ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ ++ int lines = 1;//always have one line - for name ++ lines++; //for the stereotype ++ ++ height = width = 0; ++ height += lines * fontHeight; ++ ++ //now set the width of the concept ++ //set width to name to start with ++ //set width to name to start with ++ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); ++ int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); ++ ++ width = w > width?w:width; ++ ++ //allow for width margin ++ width += DATATYPE_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,48 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef DATATYPEWIDGET_H ++#define DATATYPEWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLClassifier; ++ ++#define DATATYPE_MARGIN 5 ++ ++/** ++ * Defines a graphical version of the datatype. Most of the functionality ++ * will come from the @ref UMLWidget class from which class inherits from. ++ * ++ * @short A graphical version of an datatype. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class DatatypeWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ DatatypeWidget(UMLScene *scene, UMLClassifier *d); ++ virtual ~DatatypeWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ bool loadFromXMI(QDomElement& qElement); ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++public Q_SLOTS: ++ ++protected: ++ QSizeF minimumSize() const; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,246 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "entitywidget.h" ++ ++// app includes ++#include "classifier.h" ++#include "classifierlistitem.h" ++#include "debug_utils.h" ++#include "entity.h" ++#include "entityattribute.h" ++#include "foreignkeyconstraint.h" ++#include "listpopupmenu.h" ++#include "object_factory.h" ++#include "uml.h" ++#include "umlclassifierlistitemlist.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "uniqueconstraint.h" ++ ++/** ++ * Constructs an EntityWidget. ++ * ++ * @param scene The parent of this EntityWidget. ++ * @param o The UMLObject this will be representing. ++ */ ++EntityWidget::EntityWidget(UMLScene *scene, UMLObject* o) ++ : UMLWidget(scene, WidgetBase::wt_Entity, o) ++{ ++ setSize(100, 30); ++} ++ ++/** ++ * Destructor. ++ */ ++EntityWidget::~EntityWidget() ++{ ++} ++ ++/** ++ * Draws the entity as a rectangle with a box underneith with a list of literals ++ */ ++void EntityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ setPenFromSettings(painter); ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ else ++ painter->setBrush(m_scene->backgroundColor()); ++ ++ const int w = width(); ++ const int h = height(); ++ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ int fontHeight = fm.lineSpacing(); ++ const QString name = this->name(); ++ ++ painter->drawRect(0, 0, w, h); ++ painter->setPen(textColor()); ++ ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ painter->setFont(font); ++ int y = 0; ++ if (!m_umlObject->stereotype().isEmpty()) { ++ painter->drawText(ENTITY_MARGIN, 0, ++ w - ENTITY_MARGIN * 2, fontHeight, ++ Qt::AlignCenter, m_umlObject->stereotype(true)); ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ painter->drawText(ENTITY_MARGIN, fontHeight, ++ w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); ++ font.setBold(false); ++ font.setItalic(false); ++ painter->setFont(font); ++ y = fontHeight * 2; ++ } else { ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ painter->drawText(ENTITY_MARGIN, 0, ++ w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); ++ font.setBold(false); ++ font.setItalic(false); ++ painter->setFont(font); ++ ++ y = fontHeight; ++ } ++ ++ setPenFromSettings(painter); ++ ++ painter->drawLine(0, y, w, y); ++ ++ QFontMetrics fontMetrics(font); ++ UMLClassifier *classifier = (UMLClassifier*)m_umlObject; ++ UMLClassifierListItem* entityattribute = 0; ++ UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); ++ foreach (entityattribute, list) { ++ QString text = entityattribute->name(); ++ painter->setPen(textColor()); ++ UMLEntityAttribute* casted = dynamic_cast(entityattribute); ++ if(casted && casted->indexType() == UMLEntityAttribute::Primary) ++ { ++ font.setUnderline(true); ++ painter->setFont(font); ++ font.setUnderline(false); ++ } ++ painter->drawText(ENTITY_MARGIN, y, ++ fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); ++ painter->setFont(font); ++ y+=fontHeight; ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Saves to the "entitywidget" XMI element. ++ */ ++void EntityWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("entitywidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++} ++ ++/** ++ * Will be called when a menu selection has been made from the popup ++ * menu. ++ * ++ * @param action The action that has been selected. ++ */ ++void EntityWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_EntityAttribute: ++ if (Object_Factory::createChildObject(static_cast(m_umlObject), ++ UMLObject::ot_EntityAttribute)) { ++ UMLApp::app()->document()->setModified(); ++ } ++ break; ++ ++ case ListPopupMenu::mt_PrimaryKeyConstraint: ++ case ListPopupMenu::mt_UniqueConstraint: ++ if (UMLObject* obj = Object_Factory::createChildObject(static_cast(m_umlObject), ++ UMLObject::ot_UniqueConstraint)) { ++ UMLApp::app()->document()->setModified(); ++ ++ if (sel == ListPopupMenu::mt_PrimaryKeyConstraint) { ++ UMLUniqueConstraint* uc = static_cast(obj); ++ static_cast(m_umlObject)->setAsPrimaryKey(uc); ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_ForeignKeyConstraint: ++ if (Object_Factory::createChildObject(static_cast(m_umlObject), ++ UMLObject::ot_ForeignKeyConstraint)) { ++ UMLApp::app()->document()->setModified(); ++ ++ } ++ break; ++ ++ case ListPopupMenu::mt_CheckConstraint: ++ if (Object_Factory::createChildObject(static_cast(m_umlObject), ++ UMLObject::ot_CheckConstraint)) { ++ UMLApp::app()->document()->setModified(); ++ ++ } ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF EntityWidget::minimumSize() const ++{ ++ if (!m_umlObject) { ++ return UMLWidget::minimumSize(); ++ } ++ ++ int width, height; ++ QFont font = UMLWidget::font(); ++ font.setItalic(false); ++ font.setUnderline(false); ++ font.setBold(false); ++ const QFontMetrics fm(font); ++ ++ const int fontHeight = fm.lineSpacing(); ++ ++ int lines = 1;//always have one line - for name ++ if (!m_umlObject->stereotype().isEmpty()) { ++ lines++; ++ } ++ ++ const int numberOfEntityAttributes = ((UMLEntity*)m_umlObject)->entityAttributes(); ++ ++ height = width = 0; ++ //set the height of the entity ++ ++ lines += numberOfEntityAttributes; ++ if (numberOfEntityAttributes == 0) { ++ height += fontHeight / 2; //no entity literals, so just add a bit of space ++ } ++ ++ height += lines * fontHeight; ++ ++ //now set the width of the concept ++ //set width to name to start with ++ // FIXME spaces to get round beastie with font width, ++ // investigate UMLWidget::getFontMetrics() ++ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(QLatin1Char(' ') + name() + ++ QLatin1Char(' ')).width(); ++ const int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); ++ ++ width = w > width ? w : width; ++ ++ UMLClassifier* classifier = (UMLClassifier*)m_umlObject; ++ UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); ++ UMLClassifierListItem* listItem = 0; ++ foreach (listItem, list) { ++ int w = fm.width(listItem->name()); ++ width = w > width?w:width; ++ } ++ ++ //allow for width margin ++ width += ENTITY_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,49 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENTITYWIDGET_H ++#define ENTITYWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLScene; ++ ++#define ENTITY_MARGIN 5 ++ ++/** ++ * Defines a graphical version of the entity. Most of the functionality ++ * will come from the @ref UMLWidget class from which class inherits from. ++ * ++ * @short A graphical version of an entity. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class EntityWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ explicit EntityWidget(UMLScene *scene, UMLObject* o); ++ virtual ~EntityWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ // UMLWidget::loadFromXMI is used to load this widget. ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,262 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "enumwidget.h" ++ ++// app includes ++#include "classifier.h" ++#include "classifierlistitem.h" ++#include "debug_utils.h" ++#include "enum.h" ++#include "enumliteral.h" ++#include "listpopupmenu.h" ++#include "object_factory.h" ++#include "uml.h" ++#include "umlclassifierlistitemlist.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++/** ++ * Constructs an instance of EnumWidget. ++ * ++ * @param scene The parent of this EnumWidget. ++ * @param o The UMLObject this will be representing. ++ */ ++EnumWidget::EnumWidget(UMLScene *scene, UMLObject* o) ++ : UMLWidget(scene, WidgetBase::wt_Enum, o), ++ m_showPackage(false) ++{ ++ setSize(100, 30); ++ //set defaults from m_scene ++ if (m_scene) { ++ //check to see if correct ++ const Settings::OptionState& ops = m_scene->optionState(); ++ m_showPackage = ops.classState.showPackage; ++ } else { ++ // For completeness only. Not supposed to happen. ++ m_showPackage = false; ++ } ++} ++ ++/** ++ * Destructor. ++ */ ++EnumWidget::~EnumWidget() ++{ ++} ++ ++/** ++ * Returns the status of whether to show Package. ++ * ++ * @return True if package is shown. ++ */ ++bool EnumWidget::showPackage() const ++{ ++ return m_showPackage; ++} ++ ++/** ++ * Set the status of whether to show Package. ++ * ++ * @param _status True if package shall be shown. ++ */ ++void EnumWidget::setShowPackage(bool _status) ++{ ++ m_showPackage = _status; ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Toggles the status of whether to show package. ++ */ ++void EnumWidget::toggleShowPackage() ++{ ++ m_showPackage = !m_showPackage; ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Draws the enum as a rectangle with a box underneith with a list of literals ++ * Reimplemented from UMLWidget::paint ++ */ ++void EnumWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ setPenFromSettings(painter); ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ else ++ painter->setBrush(m_scene->backgroundColor()); ++ ++ const int w = width(); ++ const int h = height(); ++ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ QString name; ++ if (m_showPackage) { ++ name = m_umlObject->fullyQualifiedName(); ++ } else { ++ name = this->name(); ++ } ++ ++ painter->drawRect(0, 0, w, h); ++ painter->setPen(textColor()); ++ ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ painter->setFont(font); ++ painter->drawText(ENUM_MARGIN, 0, ++ w - ENUM_MARGIN * 2, fontHeight, ++ Qt::AlignCenter, m_umlObject->stereotype(true)); ++ ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ painter->drawText(ENUM_MARGIN, fontHeight, ++ w - ENUM_MARGIN * 2, fontHeight, Qt::AlignCenter, name); ++ font.setBold(false); ++ font.setItalic(false); ++ painter->setFont(font); ++ ++ int y = fontHeight * 2; ++ ++ setPenFromSettings(painter); ++ ++ painter->drawLine(0, y, w, y); ++ ++ QFontMetrics fontMetrics(font); ++ UMLClassifier *classifier = (UMLClassifier*)m_umlObject; ++ UMLClassifierListItem* enumLiteral = 0; ++ UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); ++ foreach (enumLiteral, list) { ++ QString text = enumLiteral->name(); ++ painter->setPen(textColor()); ++ painter->drawText(ENUM_MARGIN, y, ++ fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); ++ y+=fontHeight; ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Loads from an "enumwidget" XMI element. ++ */ ++bool EnumWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); ++ ++ m_showPackage = (bool)showpackage.toInt(); ++ ++ return true; ++} ++ ++/** ++ * Saves to the "enumwidget" XMI element. ++ */ ++void EnumWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("enumwidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ ++ conceptElement.setAttribute(QLatin1String("showpackage"), m_showPackage); ++ qElement.appendChild(conceptElement); ++} ++ ++/** ++ * Will be called when a menu selection has been made from the ++ * popup menu. ++ * ++ * @param action The action that has been selected. ++ */ ++void EnumWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ if (sel == ListPopupMenu::mt_EnumLiteral) { ++ if (Object_Factory::createChildObject(static_cast(m_umlObject), ++ UMLObject::ot_EnumLiteral)) { ++ /* I don't know why it works without these calls: ++ updateComponentSize(); ++ update(); ++ */ ++ UMLApp::app()->document()->setModified(); ++ } ++ return; ++ } ++ UMLWidget::slotMenuSelection(action); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF EnumWidget::minimumSize() const ++{ ++ if (!m_umlObject) { ++ return UMLWidget::minimumSize(); ++ } ++ ++ int width, height; ++ QFont font = UMLWidget::font(); ++ font.setItalic(false); ++ font.setUnderline(false); ++ font.setBold(false); ++ const QFontMetrics fm(font); ++ ++ const int fontHeight = fm.lineSpacing(); ++ ++ int lines = 1;//always have one line - for name ++ lines++; //for the stereotype ++ ++ const int numberOfEnumLiterals = ((UMLEnum*)m_umlObject)->enumLiterals(); ++ ++ height = width = 0; ++ //set the height of the enum ++ ++ lines += numberOfEnumLiterals; ++ if (numberOfEnumLiterals == 0) { ++ height += fontHeight / 2; //no enum literals, so just add a bit of space ++ } ++ ++ height += lines * fontHeight; ++ ++ //now set the width of the concept ++ //set width to name to start with ++ if (m_showPackage) { ++ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); ++ } else { ++ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(name()).width(); ++ } ++ int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); ++ ++ ++ width = w > width?w:width; ++ ++ UMLClassifier *classifier = (UMLClassifier*)m_umlObject; ++ UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); ++ UMLClassifierListItem* listItem = 0; ++ foreach (listItem, list) { ++ int w = fm.width(listItem->name()); ++ width = w > width?w:width; ++ } ++ ++ //allow for width margin ++ width += ENUM_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,52 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef ENUMWIDGET_H ++#define ENUMWIDGET_H ++ ++#include "umlwidget.h" ++ ++#define ENUM_MARGIN 5 ++ ++/** ++ * Defines a graphical version of the enum. Most of the functionality ++ * will come from the @ref UMLWidget class from which class inherits from. ++ * ++ * @short A graphical version of an enum. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class EnumWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ explicit EnumWidget(UMLScene *scene, UMLObject* o); ++ virtual ~EnumWidget(); ++ ++ bool showPackage() const; ++ void setShowPackage(bool _status); ++ void toggleShowPackage(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ virtual bool loadFromXMI(QDomElement& qElement); ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++ bool m_showPackage; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,199 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++// own header ++#include "floatingdashlinewidget.h" ++#include "combinedfragmentwidget.h" ++ ++//kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++ ++//app includes ++#include "debug_utils.h" ++#include "umlview.h" ++#include "widget_utils.h" ++#include "listpopupmenu.h" ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++ ++DEBUG_REGISTER_DISABLED(FloatingDashLineWidget) ++ ++/** ++ * Creates a floating dash line. ++ * @param scene The parent of the widget ++ * @param id The ID to assign (-1 will prompt a new ID) ++ * @param parent The CombinedFragmentWidget which acts as the parent ++ */ ++FloatingDashLineWidget::FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id, CombinedFragmentWidget *parent) ++ : UMLWidget(scene, WidgetBase::wt_FloatingDashLine, id), ++ m_yMin(0), ++ m_yMax(0), ++ m_parent(parent) ++{ ++ m_resizable = false; ++ m_Text = QString(); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ setSize(10, fontHeight); ++} ++ ++/** ++ * Destructor. ++ */ ++FloatingDashLineWidget::~FloatingDashLineWidget() ++{ ++ if (m_parent) ++ m_parent->removeDashLine(this); ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void FloatingDashLineWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ painter->setPen(textColor()); ++ painter->setFont(UMLWidget::font()); ++ painter->drawText(FLOATING_DASH_LINE_TEXT_MARGIN, 0, ++ width() - FLOATING_DASH_LINE_TEXT_MARGIN * 2, fontHeight, ++ Qt::AlignLeft, QLatin1Char('[') + m_Text + QLatin1Char(']')); ++ painter->setPen(QPen(UMLWidget::lineColor(), 0, Qt::DashLine)); ++ painter->drawLine(0, 0, width(), 0); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Sets m_text. ++ */ ++void FloatingDashLineWidget::setText(const QString& text) ++{ ++ m_Text = text; ++} ++ ++/** ++ * Returns true if the given point is near the floatingdashline. ++ */ ++bool FloatingDashLineWidget::onLine(const QPointF& point) ++{ ++ // check if the given point is the start or end point of the line ++ if (((abs((long)(y() + height() - point.y()))) <= POINT_DELTA) || (abs((long)(y() - point.y())) <= POINT_DELTA)) { ++ return true; ++ } ++ // check if the given point is the start or end point of the line ++ return false; ++} ++ ++void FloatingDashLineWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Rename: ++ { ++ bool ok = false; ++ QString name = m_Text; ++#if QT_VERSION >= 0x050000 ++ name = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter alternative Name"), i18n("Enter the alternative:"), ++ QLineEdit::Normal, ++ m_Text, &ok); ++#else ++ name = KInputDialog::getText(i18n("Enter alternative Name"), i18n("Enter the alternative:"), m_Text, &ok); ++#endif ++ if (ok && name.length() > 0) ++ m_Text = name; ++ } ++ break; ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Overrides the setY method. ++ */ ++void FloatingDashLineWidget::setY(qreal y) ++{ ++ if(y >= m_yMin + FLOATING_DASH_LINE_MARGIN && y <= m_yMax - FLOATING_DASH_LINE_MARGIN) ++ UMLWidget::setY(y); ++} ++ ++/** ++ * Sets m_yMin. ++ */ ++void FloatingDashLineWidget::setYMin(qreal yMin) ++{ ++ m_yMin = yMin; ++} ++ ++/** ++ * Sets m_yMax. ++ */ ++void FloatingDashLineWidget::setYMax(qreal yMax) ++{ ++ m_yMax = yMax; ++} ++ ++/** ++ * Returns m_yMin. ++ */ ++qreal FloatingDashLineWidget::getYMin() const ++{ ++ return m_yMin; ++} ++ ++/** ++ * Returns the difference between the y-coordinate of the dash line and m_yMin. ++ */ ++qreal FloatingDashLineWidget::getDiffY() const ++{ ++ return (y() - getYMin()); ++} ++ ++/** ++ * Creates the "floatingdashline" XMI element. ++ */ ++void FloatingDashLineWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement textElement = qDoc.createElement(QLatin1String("floatingdashlinewidget")); ++ UMLWidget::saveToXMI(qDoc, textElement); ++ textElement.setAttribute(QLatin1String("text"), m_Text); ++ textElement.setAttribute(QLatin1String("y"), y()); ++ textElement.setAttribute(QLatin1String("minY"), m_yMin); ++ textElement.setAttribute(QLatin1String("maxY"), m_yMax); ++ ++ qElement.appendChild(textElement); ++} ++ ++/** ++ * Loads the "floatingdashline" XMI element. ++ */ ++bool FloatingDashLineWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if(!UMLWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ DEBUG(DBG_SRC) << "load......."; ++ m_yMax = qElement.attribute(QLatin1String("maxY")).toFloat(); ++ m_yMin = qElement.attribute(QLatin1String("minY")).toFloat(); ++ m_Text = qElement.attribute(QLatin1String("text")); ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,77 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef FLOATINGDASHLINEWIDGET_H ++#define FLOATINGDASHLINEWIDGET_H ++ ++#include "umlwidget.h" ++class CombinedFragmentWidget; ++ ++#define FLOATING_DASH_LINE_MARGIN 25 ++#define FLOATING_DASH_LINE_TEXT_MARGIN 5 ++ ++/* how many pixels a user could click around a point */ ++#define POINT_DELTA 5 ++ ++/** ++ * This class is used to draw dash lines for UML combined fragments. A FloatingDashLineWidget ++ * belongs to one @ref CombinedFragmentWidget instance. ++ * ++ * The FloatingDashLineWidget class inherits from the @ref UMLWidget class. ++ * ++ * @short A dash line for UML combined fragments. ++ * @author Thomas GALLINARI ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class FloatingDashLineWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ explicit FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, CombinedFragmentWidget *parent = 0); ++ ~FloatingDashLineWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option = 0, QWidget *widget = 0); ++ ++ void slotMenuSelection(QAction* action); ++ ++ bool onLine(const QPointF& point); ++ ++ void setText(const QString& text); ++ ++ void setY(qreal y); ++ void setYMin(qreal yMin); ++ void setYMax(qreal yMax); ++ qreal getYMin() const; ++ qreal getDiffY() const; ++ ++ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ bool loadFromXMI(QDomElement & qElement); ++ ++private: ++ /** ++ * Text associated to the dash line ++ */ ++ QString m_text; ++ ++ /** ++ * Minimum value of the Y-coordinate of the dash line ++ * (= y-coordinate of the combined fragment) ++ */ ++ int m_yMin; ++ ++ /** ++ * Maximum value of the Y-coordinate of the dash line ++ * (= y-coordinate of the combined fragment + height of the combined fragment) ++ */ ++ int m_yMax; ++ CombinedFragmentWidget *m_parent; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,854 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "floatingtextwidget.h" ++ ++// local includes ++#include "association.h" ++#include "associationwidget.h" ++#include "associationpropertiesdialog.h" ++#include "classifier.h" ++#include "cmds.h" ++#include "debug_utils.h" ++#include "linkwidget.h" ++#include "classifierwidget.h" ++#include "listpopupmenu.h" ++#include "messagewidget.h" ++#include "model_utils.h" ++#include "object_factory.h" ++#include "operation.h" ++#include "selectoperationdialog.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlview.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++DEBUG_REGISTER_DISABLED(FloatingTextWidget) ++ ++/** ++ * Constructs a FloatingTextWidget instance. ++ * ++ * @param scene The parent of this FloatingTextWidget. ++ * @param role The role this FloatingTextWidget will take up. ++ * @param text The main text to display. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++FloatingTextWidget::FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role, const QString& text, Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_Text, id), ++ m_linkWidget(0), ++ m_preText(QString()), ++ m_postText(QString()), ++ m_textRole(role), ++ m_unconstrainedPositionX(0), ++ m_unconstrainedPositionY(0), ++ m_movementDirectionX(0), ++ m_movementDirectionY(0) ++{ ++ m_Text = text; ++ m_resizable = false; ++ setZValue(10); //make sure always on top. ++} ++ ++/** ++ * Destructor. ++ */ ++FloatingTextWidget::~FloatingTextWidget() ++{ ++} ++ ++/** ++ * Use to get the _main body_ of text (e.g. prepended and appended ++ * text is omitted) as currently displayed by the widget. ++ * ++ * @return The main text currently being displayed by the widget. ++ */ ++QString FloatingTextWidget::text() const ++{ ++ // test to make sure not just the ":" between the seq number and ++ // the actual message widget ++ ++ // hmm. this section looks like it could have been avoided by ++ // using pre-, post- text instead of storing in the main body of ++ // the text -b.t. ++ if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self || ++ m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self) { ++ if (m_Text.length() <= 1 || m_Text == QLatin1String(": ")) ++ return QString(); ++ } ++ return m_Text; ++} ++ ++/** ++ * Set the main body of text to display. ++ * ++ * @param t The text to display. ++ */ ++void FloatingTextWidget::setText(const QString &t) ++{ ++ if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { ++ QString op; ++ if (m_linkWidget) ++ op = m_linkWidget->lwOperationText(); ++ if (op.length() > 0) { ++ if (!m_scene->showOpSig()) ++ op.replace(QRegExp(QLatin1String("\\(.*\\)")), QLatin1String("()")); ++ m_Text = op; ++ } ++ else ++ m_Text = t; ++ } ++ else { ++ m_Text = t; ++ } ++ ++ QSizeF s = minimumSize(); ++ setSize(s.width(), s.height()); ++ ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Set some text to be prepended to the main body of text. ++ * @param t The text to prepend to main body which is displayed. ++ */ ++void FloatingTextWidget::setPreText(const QString &t) ++{ ++ m_preText = t; ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Set some text to be appended to the main body of text. ++ * @param t The text to append to main body which is displayed. ++ */ ++void FloatingTextWidget::setPostText(const QString &t) ++{ ++ m_postText = t; ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * Use to get the total text (prepended + main body + appended) ++ * currently displayed by the widget. ++ * ++ * @return The text currently being displayed by the widget. ++ */ ++QString FloatingTextWidget::displayText() const ++{ ++ QString displayText; ++ if (!m_SequenceNumber.isEmpty()) ++ displayText = m_SequenceNumber + QLatin1String(": ") + m_Text; ++ else ++ displayText = m_Text; ++ displayText.prepend(m_preText); ++ displayText.append(m_postText); ++ return displayText; ++} ++ ++/** ++ * Return state if no pre, post and main text is empty ++ * @return true if widget contains no text ++ */ ++bool FloatingTextWidget::isEmpty() ++{ ++ return m_Text.isEmpty() && m_preText.isEmpty() && m_postText.isEmpty(); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF FloatingTextWidget::minimumSize() const ++{ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ int h = fm.lineSpacing(); ++ int w = fm.width(displayText()); ++ return QSizeF(w + 8, h + 4); // give a small margin ++} ++ ++/** ++ * Method used by setText: its called by cmdsetTxt, Don't use it! ++ * ++ * @param t The text to display. ++ */ ++void FloatingTextWidget::setTextcmd(const QString &t) ++{ ++ UMLApp::app()->executeCommand(new Uml::CmdSetTxt(this, t)); ++} ++ ++/** ++ * Displays a dialog box to change the text. ++ */ ++void FloatingTextWidget::showChangeTextDialog() ++{ ++ bool ok = false; ++#if QT_VERSION >= 0x050000 ++ QString newText = QInputDialog::getText(m_scene->activeView(), ++ i18n("Change Text"), i18n("Enter new text:"), ++ QLineEdit::Normal, ++ text(), &ok); ++#else ++ QString newText = KInputDialog::getText(i18n("Change Text"), i18n("Enter new text:"), text(), &ok, m_scene->activeView()); ++#endif ++ if (ok && newText != text() && isTextValid(newText)) { ++ setText(newText); ++ setVisible(!text().isEmpty()); ++ updateGeometry(); ++ update(); ++ } ++ if (!isTextValid(newText)) ++ hide(); ++} ++ ++/** ++ * Shows an operation dialog box. ++ * ++ * @param enableAutoIncrement Enable auto increment checkbox ++ */ ++void FloatingTextWidget::showOperationDialog(bool enableAutoIncrement) ++{ ++ if (!m_linkWidget) { ++ uError() << "m_linkWidget is NULL"; ++ return; ++ } ++ QString seqNum = m_linkWidget->sequenceNumber(); ++ UMLClassifier* c = m_linkWidget->lwClassifier(); ++ QString opText = m_linkWidget->lwOperationText(); ++ if (!c) { ++ uError() << "m_linkWidget->lwClassifier() returns a NULL classifier"; ++ return; ++ } ++ ++ QPointer selectDialog = new SelectOperationDialog(m_scene->activeView(), c, enableAutoIncrement); ++ if (enableAutoIncrement && m_scene->autoIncrementSequence()) { ++ seqNum = m_scene->autoIncrementSequenceValue(); ++ selectDialog->setAutoIncrementSequence(true); ++ } ++ selectDialog->setSeqNumber(seqNum); ++ if (m_linkWidget->operation() == 0) { ++ selectDialog->setCustomOp(opText); ++ } else { ++ selectDialog->setClassOp(opText); ++ } ++ if (selectDialog->exec()) { ++ seqNum = selectDialog->getSeqNumber(); ++ opText = selectDialog->getOpText(); ++ if (selectDialog->isClassOp()) { ++ Model_Utils::OpDescriptor od; ++ Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, c); ++ if (st == Model_Utils::PS_OK) { ++ UMLClassifierList selfAndAncestors = c->findSuperClassConcepts(); ++ selfAndAncestors.prepend(c); ++ UMLOperation *op = 0; ++ foreach (UMLClassifier *cl, selfAndAncestors) { ++ op = cl->findOperation(od.m_name, od.m_args); ++ if (op) { ++ break; ++ } ++ } ++ if (!op) { ++ // The op does not yet exist. Create a new one. ++ UMLObject *o = c->createOperation(od.m_name, 0, &od.m_args); ++ op = static_cast(o); ++ } ++ if (od.m_pReturnType) { ++ op->setType(od.m_pReturnType); ++ } ++ ++ m_linkWidget->setOperation(op); ++ opText.clear(); ++ } else { ++ m_linkWidget->setOperation(0); ++ } ++ } else { ++ m_linkWidget->setOperation(0); ++ } ++ m_linkWidget->setSequenceNumber(seqNum); ++ m_linkWidget->setOperationText(opText); ++ if (enableAutoIncrement) { ++ m_scene->setAutoIncrementSequence(selectDialog->autoIncrementSequence()); ++ } ++ setMessageText(); ++ } ++ delete selectDialog; ++} ++ ++/** ++ * Show the properties for a FloatingTextWidget. ++ * Depending on the role of the floating text wiget, the options dialog ++ * for the floating text widget, the rename dialog for floating text or ++ * the options dialog for the link widget are shown. ++ */ ++void FloatingTextWidget::showPropertiesDialog() ++{ ++ 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(false); ++ } else if (m_textRole == Uml::TextRole::Floating) { ++ // double clicking on a text line opens the dialog to change the text ++ handleRename(); ++ } else if (m_linkWidget) { ++ m_linkWidget->showPropertiesDialog(); ++ } ++} ++ ++/** ++ * Use to get the pre-text which is prepended to the main body of ++ * text to be displayed. ++ * ++ * @return The pre-text currently displayed by the widget. ++ */ ++QString FloatingTextWidget::preText() const ++{ ++ return m_preText; ++} ++ ++/** ++ * Use to get the post-text which is appended to the main body of ++ * text to be displayed. ++ * ++ * @return The post-text currently displayed by the widget. ++ */ ++QString FloatingTextWidget::postText() const ++{ ++ return m_postText; ++} ++ ++/** ++ * Activate the FloatingTextWidget after the saved data has been loaded ++ * ++ * @param ChangeLog Pointer to the IDChangeLog. ++ * @return true for success ++ */ ++bool FloatingTextWidget::activate(IDChangeLog* ChangeLog /*= 0 */) ++{ ++ if (! UMLWidget::activate(ChangeLog)) ++ return false; ++ update(); ++ return true; ++} ++ ++/** ++ * Set the LinkWidget that this FloatingTextWidget is related to. ++ * ++ * @param l The related LinkWidget. ++ */ ++void FloatingTextWidget::setLink(LinkWidget * l) ++{ ++ m_linkWidget = l; ++} ++ ++/** ++ * Returns the LinkWidget this floating text is related to. ++ * ++ * @return The LinkWidget this floating text is related to. ++ */ ++LinkWidget * FloatingTextWidget::link() const ++{ ++ return m_linkWidget; ++} ++ ++/** ++ * Sets the role type of this FloatingTextWidget. ++ * ++ * @param role The TextRole::Enum of this FloatingTextWidget. ++ */ ++void FloatingTextWidget::setTextRole(Uml::TextRole::Enum role) ++{ ++ m_textRole = role; ++} ++ ++/** ++ * Return the role of the text widget ++ * @return The TextRole::Enum of this FloatingTextWidget. ++ */ ++Uml::TextRole::Enum FloatingTextWidget::textRole() const ++{ ++ return m_textRole; ++} ++ ++/** ++ * Handle the ListPopupMenu::mt_Rename case of the slotMenuSelection. ++ * Given an own method because it requires rather lengthy code. ++ */ ++void FloatingTextWidget::handleRename() ++{ ++ QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); ++ QString t; ++ if (m_textRole == Uml::TextRole::RoleAName || m_textRole == Uml::TextRole::RoleBName) { ++ t = i18n("Enter role name:"); ++ } else if (m_textRole == Uml::TextRole::MultiA || m_textRole == Uml::TextRole::MultiB) { ++ t = i18n("Enter multiplicity:"); ++ /* ++ // NO! shouldn't be allowed ++ } else if (m_textRole == Uml::TextRole::ChangeA || m_textRole == Uml::TextRole::ChangeB) { ++ t = i18n("Enter changeability"); ++ */ ++ } else if (m_textRole == Uml::TextRole::Name) { ++ t = i18n("Enter association name:"); ++ } else if (m_textRole == Uml::TextRole::Floating) { ++ t = i18n("Enter new text:"); ++ } else { ++ t = i18n("ERROR"); ++ } ++ bool ok = false; ++#if QT_VERSION >= 0x050000 ++ QString newText = QInputDialog::getText(m_scene->activeView(), ++ i18n("Rename"), t, ++ QLineEdit::Normal, ++ text(), &ok); ++#else ++ QString newText = KInputDialog::getText(i18n("Rename"), t, text(), &ok, m_scene->activeView(), &v); ++#endif ++ if (!ok || newText == text()) { ++ return; ++ } ++ ++ UMLApp::app()->executeCommand(new Uml::CmdHandleRename(this, newText)); ++} ++ ++/** ++ * Changes the text of linked widget. ++ * @param newText the new text ++ */ ++void FloatingTextWidget::changeName(const QString& newText) ++{ ++ if (m_linkWidget && !isTextValid(newText)) { ++ AssociationWidget *assoc = dynamic_cast(m_linkWidget); ++ if (assoc) { ++ switch (m_textRole) { ++ case Uml::TextRole::MultiA: ++ assoc->setMultiplicity(QString(), Uml::RoleType::A); ++ break; ++ case Uml::TextRole::MultiB: ++ assoc->setMultiplicity(QString(), Uml::RoleType::B); ++ break; ++ case Uml::TextRole::RoleAName: ++ assoc->setRoleName(QString(), Uml::RoleType::A); ++ break; ++ case Uml::TextRole::RoleBName: ++ assoc->setRoleName(QString(), Uml::RoleType::B); ++ break; ++ case Uml::TextRole::ChangeA: ++ assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::A); ++ break; ++ case Uml::TextRole::ChangeB: ++ assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::B); ++ break; ++ default: ++ assoc->setName(QString()); ++ break; ++ } ++ } ++ else { ++ MessageWidget *msg = dynamic_cast(m_linkWidget); ++ if (msg) { ++ msg->setName(QString()); ++ m_scene->removeWidget(this); ++ } ++ } ++ return; ++ } ++ ++ if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message ++ && m_textRole != Uml::TextRole::Seq_Message_Self) { ++ m_linkWidget->setText(this, newText); ++ } ++ else { ++ setText(newText); ++ UMLApp::app()->document()->setModified(true); ++ } ++ ++ setVisible(true); ++ updateGeometry(); ++ update(); ++} ++ ++/** ++ * 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. ++ * ++ * @param text The string to analyze. ++ * @return True if the given text is valid. ++ */ ++bool FloatingTextWidget::isTextValid(const QString &text) ++{ ++ int length = text.length(); ++ if(length < 1) ++ return false; ++ for(int i=0;iconstrainTextPos(newX, newY, width(), height(), textRole()); ++ } ++ ++ return QPointF(newX, newY); ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Moves the widget to a new position using the difference between the ++ * current position and the new position. ++ * If the floating text widget is part of a sequence message, and the ++ * message widget is selected, it does nothing: the message widget will ++ * update the text position when it's moved. ++ * In any other case, the floating text widget constrains its move using ++ * constrainPosition. When the position of the floating text is constrained, ++ * it's kept at that position until it can be moved to another valid ++ * position (m_unconstrainedPositionX/Y and m_movementDirectionX/Y are ++ * used for that). ++ * Moreover, if is part of a sequence message (and the message widget ++ * isn't selected), it updates the position of the message widget. ++ * @see constrainPosition ++ * ++ * @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 FloatingTextWidget::moveWidgetBy(qreal diffX, qreal diffY) ++{ ++ if (textRole() == Uml::TextRole::Seq_Message_Self) ++ return; ++ ++ if (textRole() == Uml::TextRole::Seq_Message ++ && ((MessageWidget*)link())->isSelected()) { ++ return; ++ } ++ ++ m_unconstrainedPositionX += diffX; ++ m_unconstrainedPositionY += diffY; ++ QPointF constrainedPosition = constrainPosition(diffX, diffY); ++ ++ qreal newX = constrainedPosition.x(); ++ qreal newY = constrainedPosition.y(); ++ ++ if (!m_movementDirectionX) { ++ if (m_unconstrainedPositionX != constrainedPosition.x()) { ++ m_movementDirectionX = (diffX > 0)? 1: -1; ++ } ++ } else if ((m_movementDirectionX < 0 && m_unconstrainedPositionX > x()) || ++ (m_movementDirectionX > 0 && m_unconstrainedPositionX < x()) ) { ++ newX = m_unconstrainedPositionX; ++ m_movementDirectionX = 0; ++ } ++ ++ if (!m_movementDirectionY) { ++ if (m_unconstrainedPositionY != constrainedPosition.y()) { ++ m_movementDirectionY = (diffY > 0)? 1: -1; ++ } ++ } else if ((m_movementDirectionY < 0 && m_unconstrainedPositionY > y()) || ++ (m_movementDirectionY > 0 && m_unconstrainedPositionY < y()) ) { ++ newY = m_unconstrainedPositionY; ++ m_movementDirectionY = 0; ++ } ++ ++ setX(newX); ++ setY(newY); ++ ++ if (link()) { ++ link()->calculateNameTextSegment(); ++ if (textRole() == Uml::TextRole::Seq_Message) { ++ MessageWidget* messageWidget = (MessageWidget*)link(); ++ messageWidget->setY(newY + height()); ++ } ++ } ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Modifies the value of the diffX and diffY variables used to move the ++ * widgets. ++ * The values are constrained using constrainPosition. ++ * @see constrainPosition ++ * ++ * @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 FloatingTextWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) ++{ ++ QPointF constrainedPosition = constrainPosition(diffX, diffY); ++ ++ diffX = constrainedPosition.x() - x(); ++ diffY = constrainedPosition.y() - y(); ++} ++ ++/** ++ * Override method from UMLWidget in order to additionally check widget parentage. ++ * ++ * @param p Point to be checked. ++ * ++ * @return 'this' if UMLWidget::onWidget(p) returns non NULL; ++ * else NULL. ++ */ ++UMLWidget* FloatingTextWidget::onWidget(const QPointF &p) ++{ ++ WidgetBase *pw = dynamic_cast(parentItem()); ++ if (pw == NULL) { ++ return WidgetBase::onWidget(p); ++ } ++ const WidgetBase::WidgetType t = pw->baseType(); ++ bool isWidgetChild = false; ++ if (t == WidgetBase::wt_Interface) { ++ ClassifierWidget *cw = static_cast(pw); ++ isWidgetChild = cw->getDrawAsCircle(); ++ } else if (t == wt_Association || ++ t == WidgetBase::wt_Port || t == WidgetBase::wt_Pin) { ++ isWidgetChild = true; ++ } ++ if (!isWidgetChild) { ++ return WidgetBase::onWidget(p); ++ } ++ const qreal w = width(); ++ const qreal h = height(); ++ const qreal left = pw->x() + x(); ++ const qreal right = left + w; ++ const qreal top = pw->y() + y(); ++ const qreal bottom = top + h; ++ // uDebug() << "child_of_pw; p=(" << p.x() << "," << p.y() << "), " ++ // << "x=" << left << ", y=" << top << ", w=" << w << ", h=" << h ++ // << "; right=" << right << ", bottom=" << bottom; ++ if (p.x() >= left && p.x() <= right && ++ p.y() >= top && p.y() <= bottom) { // Qt coord.sys. origin in top left corner ++ // uDebug() << "floatingtext: " << m_Text; ++ return this; ++ } ++ return NULL; ++} ++ ++/** ++ * Overrides default method ++ */ ++void FloatingTextWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ int w = width(); ++ int h = height(); ++ painter->setFont(UMLWidget::font()); ++ painter->setPen(textColor()); ++ painter->drawText(0, 0, w, h, Qt::AlignCenter, displayText()); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Loads the "floatingtext" XMI element. ++ */ ++bool FloatingTextWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if(!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ ++ m_unconstrainedPositionX = x(); ++ m_unconstrainedPositionY = y(); ++ QString role = qElement.attribute(QLatin1String("role")); ++ if(!role.isEmpty()) ++ m_textRole = Uml::TextRole::fromInt(role.toInt()); ++ ++ m_preText = qElement.attribute(QLatin1String("pretext")); ++ m_postText = qElement.attribute(QLatin1String("posttext")); ++ setText(qElement.attribute(QLatin1String("text"))); // use setText for geometry update ++ // If all texts are empty then this is a useless widget. ++ // In that case we return false. ++ // CAVEAT: The caller should not interpret the false return value ++ // as an indication of failure since previous umbrello-kf6 versions ++ // saved lots of these empty FloatingTexts. ++ bool usefulWidget = !isEmpty(); ++ return usefulWidget; ++} ++ ++/** ++ * Reimplemented from UMLWidget::saveToXMI to save the widget ++ * data into XMI 'floatingtext' element. ++ */ ++void FloatingTextWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ if (isEmpty()) ++ return; ++ ++ QDomElement textElement = qDoc.createElement(QLatin1String("floatingtext")); ++ UMLWidget::saveToXMI(qDoc, textElement); ++ textElement.setAttribute(QLatin1String("text"), m_Text); ++ textElement.setAttribute(QLatin1String("pretext"), m_preText); ++ textElement.setAttribute(QLatin1String("posttext"), m_postText); ++ ++ /* No need to save these - the messagewidget already did it. ++ m_Operation = qElement.attribute("operation"); ++ m_SeqNum = qElement.attribute("seqnum"); ++ */ ++ ++ textElement.setAttribute(QLatin1String("role"), m_textRole); ++ qElement.appendChild(textElement); ++} ++ ++/** ++ * Called when a menu selection has been made. ++ * ++ * @param action The action that has been selected. ++ */ ++void FloatingTextWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Properties: ++ showPropertiesDialog(); ++ break; ++ ++ case ListPopupMenu::mt_Delete: ++ hide(); // This is only a workaround; if set then m_linkWidget should ++ // really delete this FloatingTextWidget. ++ update(); ++ m_scene->removeWidget(this); ++ break; ++ ++ case ListPopupMenu::mt_New_Operation: // needed by AssociationWidget ++ case ListPopupMenu::mt_Operation: ++ { ++ if (m_linkWidget == 0) { ++ DEBUG(DBG_SRC) << "mt_Operation: m_linkWidget is NULL"; ++ return; ++ } ++ UMLClassifier* c = m_linkWidget->operationOwner(); ++ if (c == 0) { ++ bool ok = false; ++#if QT_VERSION >= 0x050000 ++ QString opText = QInputDialog::getText(m_scene->activeView(), ++ i18nc("operation name", "Name"), ++ i18n("Enter operation name:"), ++ QLineEdit::Normal, ++ text(), &ok); ++#else ++ QString opText = KInputDialog::getText(i18nc("operation name", "Name"), ++ i18n("Enter operation name:"), ++ text(), &ok, m_scene->activeView()); ++#endif ++ if (ok) ++ m_linkWidget->setCustomOpText(opText); ++ return; ++ } ++ UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, UMLObject::ot_Operation); ++ if (umlObj) { ++ UMLOperation* newOperation = static_cast(umlObj); ++ m_linkWidget->setOperation(newOperation); ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Select_Operation: ++ showOperationDialog(false); ++ break; ++ ++ case ListPopupMenu::mt_Rename: ++ handleRename(); ++ break; ++ ++ case ListPopupMenu::mt_Change_Font: ++ { ++#if QT_VERSION >= 0x050000 ++ bool ok = false; ++ QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); ++ if (ok) { ++#else ++ QFont fnt = font(); ++ if(KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) { ++#endif ++ if(m_textRole == Uml::TextRole::Floating || m_textRole == Uml::TextRole::Seq_Message) { ++ setFont(fnt); ++ } else if (m_linkWidget) { ++ m_linkWidget->lwSetFont(fnt); ++ } ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Reset_Label_Positions: ++ if (m_linkWidget) ++ m_linkWidget->resetTextPositions(); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ break; ++ }//end switch ++} ++ ++/** ++ * Sets the text for this label if it is acting as a sequence diagram ++ * message or a collaboration diagram message. ++ */ ++void FloatingTextWidget::setMessageText() ++{ ++ if (m_linkWidget) { ++ m_linkWidget->setMessageText(this); ++ QSizeF s = minimumSize(); ++ setSize(s.width(), s.height()); ++ ++ } ++ setVisible(!text().isEmpty()); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,131 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef FLOATINGTEXTWIDGET_H ++#define FLOATINGTEXTWIDGET_H ++ ++#include "basictypes.h" ++#include "umlwidget.h" ++ ++class LinkWidget; ++class UMLScene; ++ ++/** ++ * @short Displays a line of text or an operation. ++ * ++ * This is a multipurpose-kf6 class. In its simplest form it will display a ++ * line of text. ++ * It can also be setup to be the text for an operation with regard to the ++ * @ref MessageWidget on the sequence diagram. ++ * It is also used for the text required for an association. ++ * ++ * The differences between all these different uses will be the popup menu ++ * that is associated with it. ++ * ++ * @author Paul Hensgen ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class FloatingTextWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ explicit FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role = Uml::TextRole::Floating, ++ const QString& text = QString(), Uml::ID::Type id = Uml::ID::None); ++ virtual ~FloatingTextWidget(); ++ ++ QString text() const; ++ void setText(const QString &t); ++ ++ void setTextcmd(const QString &t); ++ ++ QString preText() const; ++ void setPreText(const QString &t); ++ ++ QString postText() const; ++ void setPostText(const QString &t); ++ ++ QString displayText() const; ++ ++ bool isEmpty(); ++ ++ void showChangeTextDialog(); ++ void showOperationDialog(bool enableAutoIncrement = true); ++ virtual void showPropertiesDialog(); ++ ++ LinkWidget* link() const; ++ void setLink(LinkWidget * l); ++ ++ bool activate(IDChangeLog* ChangeLog = 0); ++ ++ Uml::TextRole::Enum textRole() const; ++ void setTextRole(Uml::TextRole::Enum role); ++ ++ void handleRename(); ++ void changeName(const QString& newText); ++ ++ void setSequenceNumber(const QString &sequenceNumber); ++ QString sequenceNumber() const; ++ ++ static bool isTextValid(const QString &text); ++ ++ UMLWidget* onWidget(const QPointF& p); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ virtual bool loadFromXMI(QDomElement& qElement); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ void setMessageText(); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++ virtual void moveWidgetBy(qreal diffX, qreal diffY); ++ virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); ++ ++private: ++ QPointF constrainPosition(qreal diffX, qreal diffY); ++ ++ /// The association or message widget we may be linked to. ++ LinkWidget * m_linkWidget; ++ ++ //////////////////// Data loaded/saved: ++ ++ /// Prepended text (such as for scope of association Role or method) ++ QString m_preText; ++ /// Ending text (such as bracket on changability notation for association Role) ++ QString m_postText; ++ /// The role the text widget will enact. ++ Uml::TextRole::Enum m_textRole; ++ ++ //////// ++ ++ /// The horizontal position the widget would have if its move wasn't constrained. ++ qreal m_unconstrainedPositionX; ++ ++ /// The vertical position the widget would have if its move wasn't constrained. ++ qreal m_unconstrainedPositionY; ++ ++ /// The X direction the widget was moved when the constrain was applied. ++ /// -1 means left, 1 means right. ++ int m_movementDirectionX; ++ ++ /// The Y direction the widget was moved when the constrain was applied. ++ /// -1 means up, 1 means down. ++ int m_movementDirectionY; ++ ++ /// Contains sequence number for sequence or collaboration diagram message. ++ QString m_SequenceNumber; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,205 @@ ++/*************************************************************************** ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * copyright (C) 2005-2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "forkjoinwidget.h" ++ ++//app includes ++#include "debug_utils.h" ++#include "umlview.h" ++#include "umldoc.h" ++#include "listpopupmenu.h" ++ ++// qt includes ++#include ++ ++/** ++ * Constructs a ForkJoinWidget. ++ * ++ * @param scene The parent to this widget. ++ * @param ori Whether to draw the plate horizontally or vertically. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++ForkJoinWidget::ForkJoinWidget(UMLScene * scene, Qt::Orientation ori, Uml::ID::Type id) ++ : BoxWidget(scene, id, WidgetBase::wt_ForkJoin), ++ m_orientation(ori) ++{ ++ setSize(10, 40); ++ m_usesDiagramFillColor = false; ++ setFillColorCmd(QColor("black")); ++} ++ ++/** ++ * Destructor. ++ */ ++ForkJoinWidget::~ForkJoinWidget() ++{ ++} ++ ++/** ++ * Get whether to draw the plate vertically or horizontally. ++ */ ++Qt::Orientation ForkJoinWidget::orientation() const ++{ ++ return m_orientation; ++} ++ ++/** ++ * Set whether to draw the plate vertically or horizontally. ++ */ ++void ForkJoinWidget::setOrientation(Qt::Orientation ori) ++{ ++ m_orientation = ori; ++ updateGeometry(); ++ UMLWidget::adjustAssocs(x(), y()); ++} ++ ++/** ++ * Reimplemented from UMLWidget::paint to draw the plate of ++ * fork join. ++ */ ++void ForkJoinWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ painter->fillRect(0, 0, width(), height(), fillColor()); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Reimplemented from UMLWidget::loadFromXMI to load widget ++ * info from XMI element - 'forkjoin'. ++ */ ++bool ForkJoinWidget::loadFromXMI(QDomElement& qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ ++ QString drawVerticalStr = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("0")); ++ bool drawVertical = (bool)drawVerticalStr.toInt(); ++ if (drawVertical) { ++ setOrientation(Qt::Vertical); ++ } ++ else { ++ setOrientation(Qt::Horizontal); ++ } ++ ++ return true; ++} ++ ++/** ++ * Reimplemented from UMLWidget::saveToXMI to save widget info ++ * into XMI element - 'forkjoin'. ++ */ ++void ForkJoinWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement fjElement = qDoc.createElement(QLatin1String("forkjoin")); ++ UMLWidget::saveToXMI(qDoc, fjElement); ++ bool drawVertical = true; ++ if (m_orientation == Qt::Horizontal) { ++ drawVertical = false; ++ } ++ fjElement.setAttribute(QLatin1String("drawvertical"), drawVertical); ++ qElement.appendChild(fjElement); ++} ++ ++/** ++ * Show a properties dialog for a Fork/Join Widget. ++ */ ++void ForkJoinWidget::showPropertiesDialog() ++{ ++ QColor newColor = QColorDialog::getColor(fillColor()); // krazy:exclude=qclasses ++ if (newColor != fillColor()) { ++ setFillColor(newColor); ++ setUsesDiagramFillColor(false); ++ umlDoc()->setModified(true); ++ } ++} ++ ++/** ++ * Reimplemented form UMLWidget::slotMenuSelection to handle ++ * Flip action. ++ */ ++void ForkJoinWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch (sel) { ++ case ListPopupMenu::mt_Fill_Color: ++ showPropertiesDialog(); ++ break; ++ ++ case ListPopupMenu::mt_Flip: ++ switch (m_orientation) { ++ case Qt::Vertical: ++ setOrientation(Qt::Horizontal); ++ break; ++ case Qt::Horizontal: ++ default: ++ setOrientation(Qt::Vertical); ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++/** ++ * Overrides the function from UMLWidget. ++ */ ++QSizeF ForkJoinWidget::minimumSize() const ++{ ++ if (m_orientation == Qt::Vertical) { ++ return QSizeF(4, 40); ++ } else { ++ return QSizeF(40, 4); ++ } ++} ++ ++/** ++ * Reimplement method from UMLWidget to suppress the resize corner. ++ * Although the ForkJoinWidget supports resizing, we suppress the ++ * resize corner because it is too large for this very slim widget. ++ */ ++void ForkJoinWidget::paintSelected(QPainter * p, int offsetX, int offsetY) ++{ ++ Q_UNUSED(p); ++ Q_UNUSED(offsetX); ++ Q_UNUSED(offsetY); ++} ++ ++/** ++ * Reimplement method from UMLWidget. ++ */ ++void ForkJoinWidget::constrain(qreal& width, qreal& height) ++{ ++ if (m_orientation == Qt::Vertical) { ++ if (width < 4) ++ width = 4; ++ else if (width > 10) ++ width = 10; ++ if (height < 40) ++ height = 40; ++ else if (height > 100) ++ height = 100; ++ } else { ++ if (height < 4) ++ height = 4; ++ else if (height > 10) ++ height = 10; ++ if (width < 40) ++ width = 40; ++ else if (width > 100) ++ width = 100; ++ } ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,57 @@ ++/*************************************************************************** ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * copyright (C) 2005-2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef FORKJOINWIDGET_H ++#define FORKJOINWIDGET_H ++ ++//app includes ++#include "boxwidget.h" ++ ++/** ++ * @short Displays a fork/join plate in a state diagram. ++ * ++ * @author Oliver Kellogg ++ * ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ForkJoinWidget : public BoxWidget ++{ ++ Q_OBJECT ++ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) ++public: ++ explicit ForkJoinWidget(UMLScene * scene, Qt::Orientation ori = Qt::Horizontal, Uml::ID::Type id = Uml::ID::None); ++ virtual ~ForkJoinWidget(); ++ ++ Qt::Orientation orientation() const; ++ void setOrientation(Qt::Orientation ori); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ virtual bool loadFromXMI(QDomElement & qElement); ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++ void showPropertiesDialog(); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++ virtual void paintSelected(QPainter * p, int offsetX = 0, int offsetY = 0); ++ ++ void constrain(qreal& width, qreal& height); ++ ++private: ++ Qt::Orientation m_orientation; ///< whether to draw the plate horizontally or vertically ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,113 @@ ++/*************************************************************************** ++ * Copyright (C) 2011 by Andi Fischer * ++ * Copyright (C) 2012 by Ralf Habacker * ++ * * ++ * This 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, or (at your option) * ++ * any later version. * ++ * * ++ * This software is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this package; see the file COPYING. If not, write to * ++ * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * ++ * Boston, MA 02110-1301, USA. * ++ ***************************************************************************/ ++ ++#include "layoutgrid.h" ++ ++#include "debug_utils.h" ++#include "umlscene.h" ++ ++#include ++#include ++ ++#define DBG_LOG() DEBUG(QLatin1String("LayoutGrid")) ++DEBUG_REGISTER_DISABLED(LayoutGrid) ++ ++/** ++ * Constructor. ++ */ ++LayoutGrid::LayoutGrid(UMLScene *scene) ++ : m_scene(scene), ++ m_gridSpacingX(25), ++ m_gridSpacingY(25), ++ m_gridDotColor(Qt::gray), ++ m_isVisible(false) ++{ ++} ++ ++/** ++ * Destructor. ++ */ ++LayoutGrid::~LayoutGrid() ++{ ++} ++ ++void LayoutGrid::paint(QPainter *painter, const QRectF &rect) ++{ ++ if (!isVisible()) ++ return; ++ ++ int gridSizeX = gridSpacingX(); ++ int gridSizeY = gridSpacingY(); ++ ++ qreal left = int(rect.left()) - (int(rect.left()) % gridSizeX); ++ qreal top = int(rect.top()) - (int(rect.top()) % gridSizeY); ++ ++ QVarLengthArray lines; ++ ++ for (qreal x = left; x < rect.right(); x += gridSizeX) ++ lines.append(QLineF(x, rect.top(), x, rect.bottom())); ++ for (qreal y = top; y < rect.bottom(); y += gridSizeY) ++ lines.append(QLineF(rect.left(), y, rect.right(), y)); ++ ++ painter->setPen(m_gridDotColor); ++ painter->drawLines(lines.data(), lines.size()); ++} ++ ++int LayoutGrid::gridSpacingX() const ++{ ++ return m_gridSpacingX; ++} ++ ++int LayoutGrid::gridSpacingY() const ++{ ++ return m_gridSpacingY; ++} ++ ++void LayoutGrid::setGridSpacing(int sizeX, int sizeY) ++{ ++ DBG_LOG() << "x = " << sizeX << " / y = " << sizeY; ++ m_gridSpacingX= sizeX; ++ m_gridSpacingY= sizeY; ++} ++ ++const QColor& LayoutGrid::gridDotColor() const ++{ ++ return m_gridDotColor; ++} ++ ++void LayoutGrid::setGridDotColor(const QColor& color) ++{ ++ DBG_LOG() << "color = " << color; ++ m_gridDotColor = color; ++} ++ ++bool LayoutGrid::isVisible() const ++{ ++ return m_isVisible; ++} ++ ++void LayoutGrid::setVisible(bool visible) ++{ ++ if (m_isVisible != visible) { ++ DBG_LOG() << "visible = " << visible; ++ m_isVisible = visible; ++ m_scene->update(); ++ } ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.h umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,76 @@ ++/*************************************************************************** ++ * Copyright (C) 2011 by Andi Fischer * ++ * Copyright (C) 2012 by Ralf Habacker * ++ * * ++ * This 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, or (at your option) * ++ * any later version. * ++ * * ++ * This software is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this package; see the file COPYING. If not, write to * ++ * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * ++ * Boston, MA 02110-1301, USA. * ++ ***************************************************************************/ ++ ++#ifndef LAYOUTGRID_H ++#define LAYOUTGRID_H ++ ++#include ++#include ++ ++class UMLScene; ++class QRectF; ++ ++/** ++ * @author Andi Fischer ++ * This class handles the layout grid, which is drawn in the background ++ * of the scene. It is used only in UMLScene. ++ */ ++class LayoutGrid ++{ ++public: ++ explicit LayoutGrid(UMLScene *scene); ++ ~LayoutGrid(); ++ ++ void paint(QPainter *painter, const QRectF &rect); ++ ++ QRect gridRect() const; ++ void setGridRect(const QRect& rect); ++ ++ int gridSpacingX() const; ++ int gridSpacingY() const; ++ void setGridSpacing(int sizeX, int sizeY); ++ ++ const QColor& gridDotColor() const; ++ void setGridDotColor(const QColor& color); ++ ++ const QColor& gridCrossColor() const; ++ void setGridCrossColor(const QColor& color); ++ ++ const QColor& textColor() const; ++ void setTextColor(const QColor& color); ++ ++ QFont textFont() const; ++ void setTextFont(const QFont& font); ++ ++ bool isVisible() const; ++ void setVisible(bool visible); ++ ++ bool isTextVisible() const; ++ void setTextVisible(bool visible); ++ ++private: ++ UMLScene *m_scene; ++ int m_gridSpacingX; ++ int m_gridSpacingY; ++ QColor m_gridDotColor; ++ bool m_isVisible; ++}; ++ ++#endif // LAYOUTGRID_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,121 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "linkwidget.h" ++ ++// app includes ++#include "classifier.h" ++#include "operation.h" ++#include "uml.h" ++#include "umlobject.h" ++#include "umlview.h" ++ ++LinkWidget::LinkWidget() ++{ ++} ++ ++LinkWidget::~LinkWidget() ++{ ++} ++ ++/** ++ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) ++ */ ++UMLClassifier *LinkWidget::operationOwner() ++{ ++ UMLOperation *op = operation(); ++ if (op == NULL) ++ return NULL; ++ return static_cast(op->parent()); ++} ++ ++/** ++ * Return the operation text. ++ * When no scene parameter is given, the scene of the current view ++ * is taken instead. ++ * @param scene the given scene ++ * @return the operation text ++ */ ++QString LinkWidget::operationText(UMLScene *scene) ++{ ++ UMLOperation *op = operation(); ++ if (op == NULL) ++ return customOpText(); ++ if (scene == NULL) ++ scene = UMLApp::app()->currentView()->umlScene(); ++ Uml::SignatureType::Enum sigType; ++ if (scene && scene->showOpSig()) ++ sigType = Uml::SignatureType::SigNoVis; ++ else ++ sigType = Uml::SignatureType::NoSigNoVis; ++ QString opText = op->toString(sigType); ++ return opText; ++} ++ ++/** ++ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Reset_Label_Positions) ++ * Only applies to AssociationWidget. ++ */ ++void LinkWidget::resetTextPositions() ++{ ++} ++ ++/** ++ * Motivated by FloatingTextWidget::mouseDoubleClickEvent() ++ * Only applies to AssociationWidget. ++ */ ++void LinkWidget::showPropertiesDialog() ++{ ++} ++ ++/** ++ * Motivated by FloatingTextWidget::setLink(). ++ * Only applies to AssociationWidget. ++ */ ++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(QLatin1String("seqnum")); ++ return true; ++} ++ ++/** ++ * Save data to XMI. ++ */ ++void LinkWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) ++{ ++ Q_UNUSED(qDoc); ++ ++ qElement.setAttribute(QLatin1String("seqnum"), m_SequenceNumber); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,123 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef LINKWIDGET_H ++#define LINKWIDGET_H ++ ++#include "basictypes.h" ++#include "umlscene.h" ++ ++#include ++ ++// forward declarations ++class UMLClassifier; ++class UMLOperation; ++class FloatingTextWidget; ++ ++/** ++ * This is an interface realized by AssociationWidget and MessageWidget. ++ * The design of this interface was driven by the requirements of ++ * class FloatingTextWidget. As the architecture of umbrello-kf6 evolves (for ++ * example, if the class FloatingTextWidget is redesigned), it can be ++ * cleaned up. ++ * ++ * @short Interface to FloatingTextWidget for AssociationWidget and MessageWidget. ++ * @author Oliver Kellogg ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class LinkWidget ++{ ++public: ++ LinkWidget(); ++ virtual ~LinkWidget(); ++ ++ /** ++ * Sets the font the widget is to use. ++ * Abstract operation implemented by inheriting classes. ++ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) ++ * ++ * @param font Font to be set. ++ */ ++ virtual void lwSetFont(QFont font) = 0; ++ ++ virtual UMLClassifier *operationOwner(); ++ ++ /** ++ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) ++ */ ++ virtual UMLOperation *operation() = 0; ++ ++ /** ++ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) ++ */ ++ virtual void setOperation(UMLOperation *op) = 0; ++ ++ /** ++ * Motivated by getOperationText() ++ */ ++ virtual QString customOpText() = 0; ++ ++ /** ++ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) ++ */ ++ virtual void setCustomOpText(const QString &opText) = 0; ++ ++ QString operationText(UMLScene *scene = 0); ++ ++ virtual void resetTextPositions(); ++ ++ /** ++ * Motivated by FloatingTextWidget::setMessageText() ++ */ ++ virtual void setMessageText(FloatingTextWidget *ft) = 0; ++ ++ /** ++ * Motivated by FloatingTextWidget::handleRename() ++ */ ++ virtual void setText(FloatingTextWidget *ft, const QString &newText) = 0; ++ ++ virtual void showPropertiesDialog(); ++ ++ /** ++ * Motivated by FloatingTextWidget::showOpDialog() ++ */ ++ virtual QString lwOperationText() = 0; ++ ++ /** ++ * Motivated by FloatingTextWidget::showOpDialog() ++ */ ++ virtual UMLClassifier *lwClassifier() = 0; ++ ++ /** ++ * Motivated by FloatingTextWidget::showOpDialog() ++ */ ++ virtual void setOperationText(const QString &op) = 0; ++ ++ /** ++ * Abstract operation implemented by inheriting classes. ++ * Motivated by FloatingTextWidget::mouseMoveEvent() ++ */ ++ virtual void constrainTextPos(qreal &textX, qreal &textY, ++ qreal textWidth, qreal textHeight, ++ Uml::TextRole::Enum tr) = 0; ++ ++ 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,1385 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// onw header ++#include "messagewidget.h" ++ ++//app includes ++#include "classifier.h" ++#include "debug_utils.h" ++#include "floatingtextwidget.h" ++#include "listpopupmenu.h" ++#include "objectwidget.h" ++#include "operation.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlview.h" ++#include "uniqueid.h" ++#include "idchangelog.h" ++ ++//qt includes ++#include ++#include ++#include ++#include ++ ++//kde includes ++#include ++ ++DEBUG_REGISTER_DISABLED(MessageWidget) ++ ++static const int circleWidth = 10; ++ ++/** ++ * Constructs a MessageWidget. ++ * ++ * This method is used for creation, synchronous and synchronous message types. ++ * ++ * @param scene The parent to this class. ++ * @param a The role A widget for this message. ++ * @param b The role B widget for this message. ++ * @param y The vertical position to display this message. ++ * @param sequenceMessageType Whether synchronous or asynchronous ++ * @param id A unique id used for deleting this object cleanly. ++ * The default (-1) will prompt generation of a new ID. ++ */ ++MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, ++ int y, Uml::SequenceMessage::Enum sequenceMessageType, ++ Uml::ID::Type id /* = Uml::id_None */) ++ : UMLWidget(scene, WidgetBase::wt_Message, id) ++{ ++ init(); ++ m_pOw[Uml::RoleType::A] = a; ++ m_pOw[Uml::RoleType::B] = b; ++ m_sequenceMessageType = sequenceMessageType; ++ if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { ++ y -= m_pOw[Uml::RoleType::B]->height() / 2; ++ m_pOw[Uml::RoleType::B]->setY(y); ++ } ++ updateResizability(); ++ calculateWidget(); ++ y = y < getMinY() ? getMinY() : y; ++ y = y > getMaxY() ? getMaxY() : y; ++ setY(y); ++ ++ this->activate(); ++} ++ ++/** ++ * Constructs a MessageWidget. ++ * ++ * @param scene The parent to this class. ++ * @param seqMsgType The Uml::SequenceMessage::Enum of this message widget ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++MessageWidget::MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum seqMsgType, ++ Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_Message, id) ++{ ++ init(); ++ m_sequenceMessageType = seqMsgType; ++} ++ ++/** ++ * Constructs a Lost or Found MessageWidget. ++ * ++ * @param scene The parent to this class. ++ * @param a The role A widget for this message. ++ * @param xclick The horizontal position clicked by the user ++ * @param yclick The vertical position clicked by the user ++ * @param sequenceMessageType Whether lost or found ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, ++ Uml::SequenceMessage::Enum sequenceMessageType, ++ Uml::ID::Type id /*= Uml::id_None*/) ++ : UMLWidget(scene, WidgetBase::wt_Message, id) ++{ ++ init(); ++ m_pOw[Uml::RoleType::A] = a; ++ m_pOw[Uml::RoleType::B] = a; ++ ++ m_sequenceMessageType = sequenceMessageType; ++ ++ m_xclicked = xclick; ++ m_yclicked = yclick; ++ ++ updateResizability(); ++ calculateWidget(); ++ yclick = yclick < getMinY() ? getMinY() : yclick; ++ yclick = yclick > getMaxY() ? getMaxY() : yclick; ++ setY(yclick); ++ m_yclicked = yclick; ++ ++ this->activate(); ++} ++ ++/** ++ * Initializes key variables of the class. ++ */ ++void MessageWidget::init() ++{ ++ m_xclicked = -1; ++ m_yclicked = -1; ++ m_ignoreSnapToGrid = true; ++ m_ignoreSnapComponentSizeToGrid = true; ++ m_pOw[Uml::RoleType::A] = m_pOw[Uml::RoleType::B] = NULL; ++ m_pFText = NULL; ++} ++ ++/** ++ * Standard destructor. ++ */ ++MessageWidget::~MessageWidget() ++{ ++} ++ ++/** ++ * Sets the y-coordinate. ++ * Reimplemented from UMLWidget. ++ * ++ * @param y The y-coordinate to be set. ++ */ ++void MessageWidget::setY(qreal y) ++{ ++ if (y < getMinY()) { ++ DEBUG(DBG_SRC) << "got out of bounds y position, check the reason" << this->y() << getMinY(); ++ return; ++ } ++ ++ UMLWidget::setY(y); ++ if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { ++ const qreal objWidgetHalfHeight = m_pOw[Uml::RoleType::B]->height() / 2; ++ m_pOw[Uml::RoleType::B]->setY(y - objWidgetHalfHeight); ++ } ++ ++ if (m_pFText && !UMLApp::app()->document()->loading()) { ++ setTextPosition(); ++ emit sigMessageMoved(); ++ } ++} ++ ++/** ++ * Update the UMLWidget::m_resizable flag according to the ++ * charactersitics of this message. ++ */ ++void MessageWidget::updateResizability() ++{ ++ if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) ++ UMLWidget::m_resizable = true; ++ else ++ UMLWidget::m_resizable = false; ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Returns the cursor to be shown when resizing the widget. ++ * The cursor shown is KCursor::sizeVerCursor(). ++ * ++ * @return The cursor to be shown when resizing the widget. ++ */ ++QCursor MessageWidget::resizeCursor() const ++{ ++ return Qt::SizeVerCursor; ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Resizes the height of the message widget and emits the message moved signal. ++ * Message widgets can only be resized vertically, so width isn't modified. ++ * ++ * @param newW The new width for the widget (isn't used). ++ * @param newH The new height for the widget. ++ */ ++void MessageWidget::resizeWidget(qreal newW, qreal newH) ++{ ++ if (sequenceMessageType() == Uml::SequenceMessage::Creation) ++ setSize(width(), newH); ++ else { ++ qreal x1 = m_pOw[Uml::RoleType::A]->x(); ++ qreal x2 = getxclicked(); ++ qreal diffX = 0; ++ if (x1 < x2) { ++ diffX = x2 + (newW - width()); ++ } ++ else { ++ diffX = x2 - (newW - width()); ++ } ++ if (diffX <= 0 ) ++ diffX = 10; ++ setxclicked (diffX); ++ setSize(newW, newH); ++ calculateWidget(); ++ ++ } ++ emit sigMessageMoved(); ++} ++ ++/** ++ * Constrains the vertical position of the message widget so it doesn't go ++ * upper than the bottom side of the lower object. ++ * The height of the floating text widget in the message is taken in account ++ * if there is any and isn't empty. ++ * ++ * @param diffY The difference between current Y position and new Y position. ++ * @return The new Y position, constrained. ++ */ ++qreal MessageWidget::constrainPositionY(qreal diffY) ++{ ++ qreal newY = y() + diffY; ++ ++ qreal minY = getMinY(); ++ if (m_pFText && !m_pFText->displayText().isEmpty()) { ++ minY += m_pFText->height(); ++ } ++ ++ if (newY < minY) { ++ newY = minY; ++ } ++ ++ return newY; ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Moves the widget to a new position using the difference between the ++ * current position and the new position. X position is ignored, and widget ++ * is only moved along Y axis. If message goes upper than the object, it's ++ * kept at this position until it should be lowered again (the unconstrained ++ * Y position is saved to know when it's the time to lower it again). ++ * If the message is a creation message, the object created is also moved to ++ * the new vertical position. ++ * @see constrainPositionY ++ * ++ * @param diffX The difference between current X position and new X position ++ * (isn't used). ++ * @param diffY The difference between current Y position and new Y position. ++ */ ++void MessageWidget::moveWidgetBy(qreal diffX, qreal diffY) ++{ ++ Q_UNUSED(diffX); ++ qreal newY = constrainPositionY(diffY); ++ setY(newY); ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Modifies the value of the diffX and diffY variables used to move the widgets. ++ * All the widgets are constrained to be moved only in Y axis (diffX is set to 0). ++ * @see constrainPositionY ++ * ++ * @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 MessageWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) ++{ ++ diffX = 0; ++ diffY = constrainPositionY(diffY) - y(); ++} ++ ++/** ++ * Reimplemented from UMLWidget and calls other paint...() methods ++ * depending on the message type. ++ */ ++void MessageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { ++ return; ++ } ++ setPenFromSettings(painter); ++ if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { ++ paintSynchronous(painter, option); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { ++ paintAsynchronous(painter, option); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { ++ paintCreation(painter, option); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { ++ paintLost(painter, option); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { ++ paintFound(painter, option); ++ } else { ++ uWarning() << "Unknown message type"; ++ } ++} ++ ++/** ++ * Draw a solid-kf6 (triangular) arrowhead pointing in the given direction. ++ * The direction can be either Qt::LeftArrow or Qt::RightArrow. ++ */ ++void MessageWidget::paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction) ++{ ++ int arrowheadExtentX = 4; ++ if (direction == Qt::RightArrow) { ++ arrowheadExtentX = -arrowheadExtentX; ++ } ++ QPolygon points; ++ points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3); ++ p->setBrush(QBrush(p->pen().color())); ++ p->drawPolygon(points); ++} ++ ++/** ++ * Draw an arrow pointing in the given direction. ++ * The arrow head is not solid-kf6, i.e. it is made up of two lines ++ * like so: ---> ++ * The direction can be either Qt::LeftArrow or Qt::RightArrow. ++ */ ++void MessageWidget::paintArrow(QPainter *p, int x, int y, int w, ++ Qt::ArrowType direction, bool useDottedLine /* = false */) ++{ ++ if (w > 3) { ++ int arrowheadStartX = x; ++ int arrowheadExtentX = 4; ++ if (direction == Qt::RightArrow) { ++ arrowheadStartX += w; ++ arrowheadExtentX = -arrowheadExtentX; ++ } ++ // draw upper half of arrowhead ++ p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3); ++ // draw lower half of arrowhead ++ p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3); ++ } ++ // draw arrow line ++ if (useDottedLine) { ++ QPen pen = p->pen(); ++ pen.setStyle(Qt::DotLine); ++ p->setPen(pen); ++ } ++ p->drawLine(x, y, x + w, y); ++} ++ ++/** ++ * Draws the calling arrow with filled in arrowhead, the ++ * timeline box and the returning arrow with a dashed line and ++ * stick arrowhead. ++ */ ++void MessageWidget::paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ int x1 = m_pOw[Uml::RoleType::A]->x(); ++ int x2 = m_pOw[Uml::RoleType::B]->x(); ++ int w = width() - 1; ++ int h = height(); ++ int offsetX = 0; ++ int offsetY = 0; ++ ++ bool messageOverlaps = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); ++ const int boxWidth = 17; ++ const int wr = w < boxWidth ? w : boxWidth; ++ const int arrowWidth = 4; ++ ++ if(isSelf()) { ++ painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box ++ painter->drawRect(offsetX, offsetY, wr, h); //box ++ offsetX += wr; ++ w -= wr; ++ offsetY += 3; ++ const int lowerLineY = offsetY + h - 6; ++ // draw upper line segment (leaving the life line) ++ painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); ++ // draw line segment parallel to (and at the right of) the life line ++ painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); ++ // draw lower line segment (back to the life line) ++ paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); ++ offsetX -= wr; ++ offsetY -= 3; ++ } else if(x1 < x2) { ++ if (messageOverlaps) { ++ offsetX += 8; ++ w -= 8; ++ } ++ QPen pen = painter->pen(); ++ int startX = offsetX + w - wr + 1; ++ painter->fillRect(startX, offsetY, wr, h, QBrush(Qt::white)); //box ++ painter->drawRect(startX, offsetY, wr, h); //box ++ painter->drawLine(offsetX, offsetY + arrowWidth, startX, offsetY + arrowWidth); //arrow line ++ if (w > boxWidth + arrowWidth) ++ paintsolid-kf6Arrowhead(painter, startX - 1, offsetY + arrowWidth, Qt::RightArrow); ++ paintArrow(painter, offsetX, offsetY + h - arrowWidth + 1, w - wr + 1, Qt::LeftArrow, true); // return arrow ++ if (messageOverlaps) { ++ offsetX -= 8; //reset for drawSelected() ++ } ++ } else { ++ if (messageOverlaps) { ++ w -=8; ++ } ++ QPen pen = painter->pen(); ++ painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box ++ painter->drawRect(offsetX, offsetY, wr, h); //box ++ painter->drawLine(offsetX + wr + 1, offsetY + arrowWidth, offsetX + w, offsetY + arrowWidth); //arrow line ++ if (w > boxWidth + arrowWidth) ++ paintsolid-kf6Arrowhead(painter, offsetX + wr, offsetY + arrowWidth, Qt::LeftArrow); ++ paintArrow(painter, offsetX + wr + 1, offsetY + h - arrowWidth + 1, w - wr - 1, Qt::RightArrow, true); // return arrow ++ } ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * Draws a solid-kf6 arrow line and a stick arrow head. ++ */ ++void MessageWidget::paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ int x1 = m_pOw[Uml::RoleType::A]->x(); ++ int x2 = m_pOw[Uml::RoleType::B]->x(); ++ int w = width() - 1; ++ int h = height() - 1; ++ int offsetX = 0; ++ int offsetY = 0; ++ bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); ++ //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); ++ ++ if(isSelf()) { ++ if (messageOverlapsA) { ++ offsetX += 7; ++ w -= 7; ++ } ++ const int lowerLineY = offsetY + h - 3; ++ // draw upper line segment (leaving the life line) ++ painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); ++ // draw line segment parallel to (and at the right of) the life line ++ painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); ++ // draw lower line segment (back to the life line) ++ paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); ++ if (messageOverlapsA) { ++ offsetX -= 7; //reset for drawSelected() ++ } ++ } else if(x1 < x2) { ++ if (messageOverlapsA) { ++ offsetX += 7; ++ w -= 7; ++ } ++ paintArrow(painter, offsetX, offsetY + 4, w, Qt::RightArrow); ++ if (messageOverlapsA) { ++ offsetX -= 7; ++ } ++ } else { ++ if (messageOverlapsA) { ++ w -= 7; ++ } ++ paintArrow(painter, offsetX, offsetY + 4, w, Qt::LeftArrow); ++ } ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * Draws a solid-kf6 arrow line and a stick arrow head to the ++ * edge of the target object widget instead of to the ++ * sequence line. ++ */ ++void MessageWidget::paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ int x1 = m_pOw[Uml::RoleType::A]->x(); ++ int x2 = m_pOw[Uml::RoleType::B]->x(); ++ int w = width(); ++ //int h = height() - 1; ++ int offsetX = 0; ++ int offsetY = 0; ++ bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); ++ //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); ++ ++ const int lineY = offsetY + 4; ++ if (x1 < x2) { ++ if (messageOverlapsA) { ++ offsetX += 7; ++ w -= 7; ++ } ++ paintArrow(painter, offsetX, lineY, w, Qt::RightArrow); ++ if (messageOverlapsA) { ++ offsetX -= 7; ++ } ++ } else { ++ if (messageOverlapsA) { ++ w -= 7; ++ } ++ paintArrow(painter, offsetX, lineY, w, Qt::LeftArrow); ++ } ++ ++ UMLWidget::paint(painter, option); ++} ++ ++ ++/** ++ * Draws a solid-kf6 arrow line and a stick arrow head ++ * and a circle ++ */ ++void MessageWidget::paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_xclicked; ++ int w = width(); ++ int h = height(); ++ int offsetX = 0; ++ int offsetY = 0; ++ bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); ++ //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); ++ ++ if(x1 < x2) { ++ if (messageOverlapsA) { ++ offsetX += 7; ++ w -= 7; ++ } ++ ++ setPenFromSettings(painter); ++ painter->setBrush(WidgetBase::lineColor()); ++ painter->drawEllipse(offsetX + w - h, offsetY, h, h); ++ paintArrow(painter, offsetX, offsetY + h/2, w - h, Qt::RightArrow); ++ ++ if (messageOverlapsA) { ++ offsetX -= 7; ++ } ++ } else { ++ setPenFromSettings(painter); ++ painter->setBrush(WidgetBase::lineColor()); ++ painter->drawEllipse(offsetX, offsetY, h, h); ++ paintArrow(painter, offsetX + h, offsetY + h/2, w - h, Qt::LeftArrow); ++ } ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * Draws a circle and a solid-kf6 arrow line and a stick arrow head. ++ */ ++void MessageWidget::paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option) ++{ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_xclicked; ++ int w = width(); ++ int h = height(); ++ int offsetX = 0; ++ int offsetY = 0; ++ bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); ++ //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); ++ ++ if(x1 < x2) { ++ if (messageOverlapsA) { ++ offsetX += 7; ++ w -= 7; ++ } ++ setPenFromSettings(painter); ++ painter->setBrush(WidgetBase::lineColor()); ++ painter->drawEllipse(offsetX + w - h, offsetY, h, h); ++ paintArrow(painter, offsetX, offsetY + h/2, w, Qt::LeftArrow); ++ if (messageOverlapsA) { ++ offsetX -= 7; ++ } ++ } else { ++ if (messageOverlapsA) { ++ w -= 7; ++ } ++ setPenFromSettings(painter); ++ painter->setBrush(WidgetBase::lineColor()); ++ painter->drawEllipse(offsetX, offsetY, h, h); ++ paintArrow(painter, offsetX, offsetY + h/2, w, Qt::RightArrow); ++ } ++ ++ UMLWidget::paint(painter, option); ++} ++ ++/** ++ * Overrides operation from UMLWidget. ++ * ++ * @param p Point to be checked. ++ * ++ * @return 'this' if the point is on a part of the MessageWidget. ++ * NB In case of a synchronous message, the empty space ++ * between call line and return line does not count, i.e. if ++ * the point is located in that space the function returns NULL. ++ */ ++UMLWidget* MessageWidget::onWidget(const QPointF& p) ++{ ++ if (m_sequenceMessageType != Uml::SequenceMessage::Synchronous) { ++ return UMLWidget::onWidget(p); ++ } ++ // Synchronous message: ++ // Consists of top arrow (call) and bottom arrow (return.) ++ if (p.x() < x() || p.x() > x() + width()) ++ return NULL; ++ const int tolerance = 5; // pixels ++ const int pY = p.y(); ++ const int topArrowY = y() + 3; ++ const int bottomArrowY = y() + height() - 3; ++ if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance) ++ return NULL; ++ if (height() <= 2 * tolerance) ++ return this; ++ if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance) ++ return NULL; ++ return this; ++} ++ ++/** ++ * Sets the text position relative to the sequence message. ++ */ ++void MessageWidget::setTextPosition() ++{ ++ if (m_pFText == NULL) { ++ DEBUG(DBG_SRC) << "m_pFText is NULL"; ++ return; ++ } ++ if (m_pFText->displayText().isEmpty()) { ++ return; ++ } ++ m_pFText->updateGeometry(); ++ int ftX = constrainX(m_pFText->x(), m_pFText->width(), m_pFText->textRole()); ++ int ftY = y() - m_pFText->height(); ++ m_pFText->setX(ftX); ++ m_pFText->setY(ftY); ++} ++ ++/** ++ * Returns the textX arg with constraints applied. ++ * Auxiliary to setTextPosition() and constrainTextPos(). ++ */ ++int MessageWidget::constrainX(int textX, int textWidth, Uml::TextRole::Enum tr) ++{ ++ int result = textX; ++ const int minTextX = x() + 5; ++ if (textX < minTextX || tr == Uml::TextRole::Seq_Message_Self) { ++ result = minTextX; ++ } else { ++ ObjectWidget *objectAtRight = NULL; ++ if (m_pOw[Uml::RoleType::B]->x() > m_pOw[Uml::RoleType::A]->x()) ++ objectAtRight = m_pOw[Uml::RoleType::B]; ++ else ++ objectAtRight = m_pOw[Uml::RoleType::A]; ++ const int objRight_seqLineX = objectAtRight->centerX(); ++ const int maxTextX = objRight_seqLineX - textWidth - 5; ++ if (maxTextX <= minTextX) ++ result = minTextX; ++ else if (textX > maxTextX) ++ result = maxTextX; ++ } ++ return result; ++} ++ ++/** ++ * Constrains the FloatingTextWidget X and Y values supplied. ++ * Overrides operation from LinkWidget. ++ * ++ * @param textX candidate X value (may be modified by the constraint) ++ * @param textY candidate Y value (may be modified by the constraint) ++ * @param textWidth width of the text ++ * @param textHeight height of the text ++ * @param tr Uml::TextRole::Enum of the text ++ */ ++void MessageWidget::constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, ++ Uml::TextRole::Enum tr) ++{ ++ textX = constrainX(textX, textWidth, tr); ++ // Constrain Y. ++ const qreal minTextY = getMinY(); ++ const qreal maxTextY = getMaxY() - textHeight - 5; ++ if (textY < minTextY) ++ textY = minTextY; ++ else if (textY > maxTextY) ++ textY = maxTextY; ++// setY(textY + textHeight); // NB: side effect ++} ++ ++/** ++ * Shortcut for calling m_pFText->setLink() followed by ++ * this->setTextPosition(). ++ */ ++void MessageWidget::setLinkAndTextPos() ++{ ++ if (m_pFText) { ++ m_pFText->setLink(this); ++ setTextPosition(); ++ } ++} ++ ++void MessageWidget::resizeEvent(QResizeEvent* /*re*/) ++{ ++} ++ ++/** ++ * Calculate the geometry of the widget. ++ */ ++void MessageWidget::calculateWidget() ++{ ++ setMessageText(m_pFText); ++ calculateDimensions(); ++ setVisible(true); ++} ++ ++void MessageWidget::slotWidgetMoved(Uml::ID::Type id) ++{ ++ const Uml::ID::Type idA = m_pOw[Uml::RoleType::A]->localID(); ++ const Uml::ID::Type idB = m_pOw[Uml::RoleType::B]->localID(); ++ if (idA != id && idB != id) { ++ DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA) ++ << ", idB=" << Uml::ID::toString(idB); ++ return; ++ } ++ qreal y = this->y(); ++ if (y < getMinY()) ++ y = getMinY(); ++ if (y > getMaxY()) ++ y = getMaxY(); ++ setPos(x(), y); ++ calculateWidget(); ++ if(!m_pFText) ++ return; ++ if (m_scene->selectedCount(true) > 1) ++ return; ++ setTextPosition(); ++} ++ ++/** ++ * Check to see if the given ObjectWidget is involved in the message. ++ * ++ * @param w The ObjectWidget to check for. ++ * @return true - if is contained, false - not contained. ++ */ ++bool MessageWidget::hasObjectWidget(ObjectWidget * w) ++{ ++ if(m_pOw[Uml::RoleType::A] == w || m_pOw[Uml::RoleType::B] == w) ++ return true; ++ else ++ return false; ++} ++ ++/** ++ * This method determines whether the message is for "Self" for ++ * an ObjectWidget. ++ * ++ * @retval True If both ObjectWidgets for this widget exists and ++ * are same. ++ */ ++bool MessageWidget::isSelf() const ++{ ++ return (m_pOw[Uml::RoleType::A] && m_pOw[Uml::RoleType::B] && ++ m_pOw[Uml::RoleType::A] == m_pOw[Uml::RoleType::B]); ++} ++ ++void MessageWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ if (sel == ListPopupMenu::mt_Delete) { ++ // This will clean up this widget and the text widget: ++ m_scene->removeWidget(this); ++ } else { ++ ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Activates a MessageWidget. Connects its m_pOw[] pointers ++ * to UMLObjects and also send signals about its FloatingTextWidget. ++ */ ++bool MessageWidget::activate(IDChangeLog * /*Log = 0*/) ++{ ++ m_scene->resetPastep-kf6oint(); ++ // UMLWidget::activate(Log); CHECK: I don't think we need this ? ++ if (m_pOw[Uml::RoleType::A] == NULL) { ++ UMLWidget *pWA = m_scene->findWidget(m_widgetAId); ++ if (pWA == NULL) { ++ DEBUG(DBG_SRC) << "role A object " << Uml::ID::toString(m_widgetAId) << " not found"; ++ return false; ++ } ++ m_pOw[Uml::RoleType::A] = dynamic_cast(pWA); ++ if (m_pOw[Uml::RoleType::A] == NULL) { ++ DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) ++ << " is not an ObjectWidget"; ++ return false; ++ } ++ } ++ if (m_pOw[Uml::RoleType::B] == NULL) { ++ UMLWidget *pWB = m_scene->findWidget(m_widgetBId); ++ if (pWB == NULL) { ++ DEBUG(DBG_SRC) << "role B object " << Uml::ID::toString(m_widgetBId) << " not found"; ++ return false; ++ } ++ m_pOw[Uml::RoleType::B] = dynamic_cast(pWB); ++ if (m_pOw[Uml::RoleType::B] == NULL) { ++ DEBUG(DBG_SRC) << "role B widget " << Uml::ID::toString(m_widgetBId) ++ << " is not an ObjectWidget"; ++ return false; ++ } ++ } ++ updateResizability(); ++ ++ UMLClassifier *c = dynamic_cast(m_pOw[Uml::RoleType::B]->umlObject()); ++ UMLOperation *op = NULL; ++ if (c && !m_CustomOp.isEmpty()) { ++ Uml::ID::Type opId = Uml::ID::fromString(m_CustomOp); ++ op = dynamic_cast(c->findChildObjectById(opId, true)); ++ if (op) { ++ // If the UMLOperation is set, m_CustomOp isn't used anyway. ++ // Just setting it empty for the sake of sanity. ++ m_CustomOp.clear(); ++ } ++ } ++ ++ if(!m_pFText) { ++ Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; ++ if (isSelf()) ++ tr = Uml::TextRole::Seq_Message_Self; ++ m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene)); ++ m_scene->addFloatingTextWidget(m_pFText); ++ m_pFText->setFontCmd(UMLWidget::font()); ++ } ++ if (op) ++ setOperation(op); // This requires a valid m_pFText. ++ setLinkAndTextPos(); ++ m_pFText->setText(QString()); ++ m_pFText->setActivated(); ++ QString messageText = m_pFText->text(); ++ m_pFText->setVisible(messageText.length() > 1); ++ ++ connect(m_pOw[Uml::RoleType::A], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); ++ connect(m_pOw[Uml::RoleType::B], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); ++ ++ connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); ++ connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); ++ m_pOw[Uml::RoleType::A]->messageAdded(this); ++ if (!isSelf()) ++ m_pOw[Uml::RoleType::B]->messageAdded(this); ++ ++ // Calculate the size and position of the message widget ++ calculateDimensions(); ++ ++ // Position the floating text accordingly ++ setTextPosition(); ++ ++ emit sigMessageMoved(); ++ return true; ++} ++ ++/** ++ * Resolve references of this message so they reference the correct ++ * new object widgets after paste. ++ */ ++void MessageWidget::resolveObjectWidget(IDChangeLog* log) { ++ m_widgetAId = log->findNewID(m_widgetAId); ++ m_widgetBId = log->findNewID(m_widgetBId); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @param ft The text widget which to update. ++ */ ++void MessageWidget::setMessageText(FloatingTextWidget *ft) ++{ ++ if (ft == NULL) ++ return; ++ ft->setSequenceNumber(m_SequenceNumber); ++ ft->setText(operationText(m_scene)); ++ setTextPosition(); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @param ft The text widget which to update. ++ * @param newText The new text to set. ++ */ ++void MessageWidget::setText(FloatingTextWidget *ft, const QString &newText) ++{ ++ ft->setText(newText); ++ UMLApp::app()->document()->setModified(true); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * ++ * @param op The new operation string to set. ++ */ ++void MessageWidget::setOperationText(const QString &op) ++{ ++ m_CustomOp = op; ///FIXME m_pOperation ++} ++ ++/** ++ * Implements operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++void MessageWidget::lwSetFont (QFont font) ++{ ++ UMLWidget::setFont(font); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ * @todo Move to LinkWidget. ++ */ ++UMLClassifier *MessageWidget::operationOwner() ++{ ++ UMLObject *pObject = m_pOw[Uml::RoleType::B]->umlObject(); ++ if (pObject == NULL) ++ return NULL; ++ UMLClassifier *c = dynamic_cast(pObject); ++ return c; ++} ++ ++/** ++ * Implements operation from LinkWidget. ++ * Motivated by FloatingTextWidget. ++ */ ++UMLOperation *MessageWidget::operation() ++{ ++ return static_cast(m_umlObject); ++} ++ ++/** ++ * Implements operation from LinkWidget. ++ * Motivated by FloatingTextWidget. ++ */ ++void MessageWidget::setOperation(UMLOperation *op) ++{ ++ if (m_umlObject && m_pFText) ++ disconnect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); ++ m_umlObject = op; ++ if (m_umlObject && m_pFText) { ++ connect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); ++ m_pFText->setMessageText(); ++ } ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++QString MessageWidget::customOpText() ++{ ++ return m_CustomOp; ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++void MessageWidget::setCustomOpText(const QString &opText) ++{ ++ m_CustomOp = opText; ++ m_pFText->setMessageText(); ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++QString MessageWidget::lwOperationText() ++{ ++ UMLOperation *pOperation = operation(); ++ if (pOperation != NULL) { ++ return pOperation->toString(Uml::SignatureType::SigNoVis); ++ } else { ++ return customOpText(); ++ } ++} ++ ++/** ++ * Overrides operation from LinkWidget. ++ * Required by FloatingTextWidget. ++ */ ++UMLClassifier *MessageWidget::lwClassifier() ++{ ++ UMLObject *o = m_pOw[Uml::RoleType::B]->umlObject(); ++ UMLClassifier *c = dynamic_cast(o); ++ return c; ++} ++ ++/** ++ * Calculates the size of the widget by calling ++ * calculateDimensionsSynchronous(), ++ * calculateDimensionsAsynchronous(), or ++ * calculateDimensionsCreation() ++ */ ++void MessageWidget::calculateDimensions() ++{ ++ if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { ++ calculateDimensionsSynchronous(); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { ++ calculateDimensionsAsynchronous(); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { ++ calculateDimensionsCreation(); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { ++ calculateDimensionsLost(); ++ } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { ++ calculateDimensionsFound(); ++ } else { ++ uWarning() << "Unknown message type"; ++ } ++ if (! UMLApp::app()->document()->loading()) { ++ adjustAssocs(x(), y()); // adjust assoc lines ++ } ++} ++ ++/** ++ * Calculates and sets the size of the widget for a synchronous message. ++ */ ++void MessageWidget::calculateDimensionsSynchronous() ++{ ++ int x = 0; ++ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_pOw[Uml::RoleType::B]->centerX(); ++ ++ int widgetWidth = 0; ++ int widgetHeight = 0; ++ if(isSelf()) { ++ widgetWidth = 50; ++ x = x1 - 2; ++ } else if(x1 < x2) { ++ x = x1; ++ widgetWidth = x2 - x1 + 8; ++ } else { ++ x = x2 - 8; ++ widgetWidth = x1 - x2 + 8; ++ } ++ ++ if (height() < 20) { ++ widgetHeight = 20; ++ } else { ++ widgetHeight = height(); ++ } ++ ++ setX(x); ++ setSize(widgetWidth, widgetHeight); ++} ++ ++/** ++ * Calculates and sets the size of the widget for an asynchronous message. ++ */ ++void MessageWidget::calculateDimensionsAsynchronous() ++{ ++ int x = 0; ++ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_pOw[Uml::RoleType::B]->centerX(); ++ ++ int widgetWidth = 0; ++ int widgetHeight = 8; ++ if(isSelf()) { ++ widgetWidth = 50; ++ x = x1; ++ if(height() < 20) { ++ widgetHeight = 20; ++ } else { ++ widgetHeight = height(); ++ } ++ } else if(x1 < x2) { ++ x = x1; ++ widgetWidth = x2 - x1; ++ } else { ++ x = x2; ++ widgetWidth = x1 - x2; ++ } ++ x += 1; ++ widgetWidth -= 2; ++ setX(x); ++ setSize(widgetWidth, widgetHeight); ++} ++ ++/** ++ * Calculates and sets the size of the widget for a creation message. ++ */ ++void MessageWidget::calculateDimensionsCreation() ++{ ++ int x = 0; ++ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_pOw[Uml::RoleType::B]->x(); ++ int w2 = m_pOw[Uml::RoleType::B]->width(); ++ ++ if (x1 > x2) ++ x2 += w2; ++ ++ int widgetWidth = 0; ++ int widgetHeight = 8; ++ if (x1 < x2) { ++ x = x1; ++ widgetWidth = x2 - x1; ++ } else { ++ x = x2; ++ widgetWidth = x1 - x2; ++ } ++ x += 1; ++ widgetWidth -= 2; ++ setPos(x, m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height() / 2); ++ setSize(widgetWidth, widgetHeight); ++} ++ ++/** ++ * Calculates and sets the size of the widget for a lost message. ++ */ ++void MessageWidget::calculateDimensionsLost() ++{ ++ int x = 0; ++ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_xclicked; ++ ++ int widgetWidth = 0; ++ int widgetHeight = 10; ++ if(x1 < x2) { ++ x = x1; ++ widgetWidth = x2 - x1 + circleWidth/2; ++ } else { ++ x = x2 - circleWidth/2; ++ widgetWidth = x1 - x2 + circleWidth/2; ++ } ++ setX(x); ++ setSize(widgetWidth, widgetHeight); ++} ++ ++/** ++ * Calculates and sets the size of the widget for a found message. ++ */ ++void MessageWidget::calculateDimensionsFound() ++{ ++ int x = 0; ++ ++ int x1 = m_pOw[Uml::RoleType::A]->centerX(); ++ int x2 = m_xclicked; ++ ++ int widgetWidth = 0; ++ int widgetHeight = 10; ++ if(x1 < x2) { ++ x = x1; ++ widgetWidth = x2 - x1 + circleWidth/2; ++ } else { ++ x = x2 - circleWidth/2; ++ widgetWidth = x1 - x2 + circleWidth/2; ++ } ++ ++ setX(x); ++ setSize(widgetWidth, widgetHeight); ++} ++ ++/** ++ * Used to cleanup any other widget it may need to delete. ++ */ ++void MessageWidget::cleanup() ++{ ++ if (m_pOw[Uml::RoleType::A]) { ++ disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); ++ m_pOw[Uml::RoleType::A]->messageRemoved(this); ++ } ++ if (m_pOw[Uml::RoleType::B]) { ++ disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); ++ m_pOw[Uml::RoleType::B]->messageRemoved(this); ++ } ++ ++ UMLWidget::cleanup(); ++ if (m_pFText) { ++ m_scene->removeWidgetCmd(m_pFText); ++ m_pFText = NULL; ++ } ++} ++ ++/** ++ * Sets the state of whether the widget is selected. ++ * ++ * @param _select True if the widget is selected. ++ */ ++void MessageWidget::setSelected(bool _select) ++{ ++ UMLWidget::setSelected(_select); ++ if(!m_pFText || m_pFText->displayText().isEmpty()) ++ return; ++ if(isSelected() && m_pFText->isSelected()) ++ return; ++ if(!isSelected() && !m_pFText->isSelected()) ++ return; ++ ++ m_pFText->setSelected(isSelected()); ++} ++ ++/** ++ * 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 MessageWidget::getMinY() ++{ ++ if (!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { ++ return 0; ++ } ++ if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { ++ return m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); ++ } ++ int heightA = m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); ++ int heightB = m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height(); ++ int height = heightA; ++ if(heightA < heightB) { ++ height = heightB; ++ } ++ return height; ++} ++ ++/** ++ * 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 MessageWidget::getMaxY() ++{ ++ if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { ++ return 0; ++ } ++ int heightA = (int)((ObjectWidget*)m_pOw[Uml::RoleType::A])->getEndLineY(); ++ int heightB = (int)((ObjectWidget*)m_pOw[Uml::RoleType::B])->getEndLineY(); ++ int height = heightA; ++ if(heightA > heightB) { ++ height = heightB; ++ } ++ return (height - this->height()); ++} ++ ++/** ++ * Sets the related widget on the given side. ++ * ++ * @param ow The ObjectWidget we are related to. ++ * @param role The Uml::RoleType::Enum to be set for the ObjectWidget ++ */ ++void MessageWidget::setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) ++{ ++ m_pOw[role] = ow; ++ updateResizability(); ++} ++ ++/** ++ * Returns the related widget on the given side. ++ * ++ * @return The ObjectWidget we are related to. ++ */ ++ObjectWidget* MessageWidget::objectWidget(Uml::RoleType::Enum role) ++{ ++ return m_pOw[role]; ++} ++ ++/** ++ * Set the xclicked ++ */ ++void MessageWidget::setxclicked(int xclick) ++{ ++ m_xclicked = xclick; ++} ++ ++/** ++ * Set the yclicked ++ */ ++void MessageWidget::setyclicked(int yclick) ++{ ++ m_yclicked = yclick; ++} ++ ++/** ++ * Event handler for mouse double click events. ++ * @param event QGraphicsSceneMouseEvent which triggered the double click event ++ */ ++void MessageWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) ++{ ++ Q_UNUSED(event) ++ DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET!"; ++ if (m_pFText != NULL) { ++ DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET - on floating text widget!"; ++// QAction* action = m_pMenu->getAction(ListPopupMenu::mt_Select_Operation); ++// m_pFText->slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Saves to the "messagewidget" XMI element. ++ */ ++void MessageWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement messageElement = qDoc.createElement(QLatin1String("messagewidget")); ++ UMLWidget::saveToXMI(qDoc, messageElement); ++ LinkWidget::saveToXMI(qDoc, messageElement); ++ if (m_pOw[Uml::RoleType::A]) ++ messageElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_pOw[Uml::RoleType::A]->localID())); ++ if (m_pOw[Uml::RoleType::B]) ++ messageElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(m_pOw[Uml::RoleType::B]->localID())); ++ UMLOperation *pOperation = operation(); ++ if (pOperation) ++ messageElement.setAttribute(QLatin1String("operation"), Uml::ID::toString(pOperation->id())); ++ else ++ messageElement.setAttribute(QLatin1String("operation"), m_CustomOp); ++ messageElement.setAttribute(QLatin1String("sequencemessagetype"), m_sequenceMessageType); ++ if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { ++ messageElement.setAttribute(QLatin1String("xclicked"), m_xclicked); ++ messageElement.setAttribute(QLatin1String("yclicked"), m_yclicked); ++ } ++ ++ // save the corresponding message text ++ if (m_pFText && !m_pFText->text().isEmpty()) { ++ messageElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pFText->id())); ++ m_pFText->saveToXMI(qDoc, messageElement); ++ } ++ ++ qElement.appendChild(messageElement); ++} ++ ++/** ++ * Loads from the "messagewidget" XMI element. ++ */ ++bool MessageWidget::loadFromXMI(QDomElement& qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ if (!LinkWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); ++ QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); ++ QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); ++ m_CustomOp = qElement.attribute(QLatin1String("operation")); ++ QString sequenceMessageType = qElement.attribute(QLatin1String("sequencemessagetype"), QLatin1String("1001")); ++ m_sequenceMessageType = Uml::SequenceMessage::fromInt(sequenceMessageType.toInt()); ++ if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { ++ m_xclicked = qElement.attribute(QLatin1String("xclicked"), QLatin1String("-1")).toFloat(); ++ m_yclicked = qElement.attribute(QLatin1String("yclicked"), QLatin1String("-1")).toFloat(); ++ } ++ ++ m_widgetAId = Uml::ID::fromString(widgetaid); ++ m_widgetBId = Uml::ID::fromString(widgetbid); ++ m_textId = Uml::ID::fromString(textid); ++ ++ Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; ++ if (m_widgetAId == m_widgetBId) ++ tr = Uml::TextRole::Seq_Message_Self; ++ ++ //now load child elements ++ QDomNode node = qElement.firstChild(); ++ QDomElement element = node.toElement(); ++ if (!element.isNull()) { ++ QString tag = element.tagName(); ++ if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { ++ m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene), m_textId); ++ m_scene->addFloatingTextWidget(m_pFText); ++ if(! m_pFText->loadFromXMI(element)) { ++ // Most likely cause: The FloatingTextWidget is empty. ++ delete m_pFText; ++ m_pFText = NULL; ++ } ++ else ++ m_pFText->setSequenceNumber(m_SequenceNumber); ++ } else { ++ uError() << "unknown tag " << tag; ++ } ++ } ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,212 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef MESSAGEWIDGET_H ++#define MESSAGEWIDGET_H ++ ++#include "umlwidget.h" ++#include "linkwidget.h" ++ ++// forward declarations ++class FloatingTextWidget; ++class ObjectWidget; ++class QResizeEvent; ++class UMLOperation; ++ ++/** ++ * Used to display a message on a sequence diagram. The message ++ * could be between two objects or a message that calls itself on ++ * an object. This class will only display the line that is ++ * required and the text will be setup by the @ref FloatingTextWidget ++ * widget that is passed in the constructor. A message can be ++ * synchronous (calls a method and gains control back on return, ++ * as happens in most programming languages) or asynchronous ++ * (calls a method and gains back control immediately). ++ * ++ * @short Displays a message. ++ * @author Paul Hensgen ++ * @see UMLWidget ++ * @see ObjectWidget ++ * @see FloatingTextWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class MessageWidget : public UMLWidget, public LinkWidget ++{ ++ Q_OBJECT ++public: ++ MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, ++ int y, Uml::SequenceMessage::Enum sequenceMessageType, ++ Uml::ID::Type id = Uml::ID::None); ++ MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum sequenceMessageType, ++ Uml::ID::Type id = Uml::ID::None); ++ MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, ++ Uml::SequenceMessage::Enum sequenceMessageType, ++ Uml::ID::Type id = Uml::ID::None); ++ virtual ~MessageWidget(); ++ ++ virtual void setY(qreal y); ++ ++ //---------- LinkWidget Interface methods implemementation from now on. ++ ++ virtual void lwSetFont (QFont font); ++ virtual UMLClassifier *operationOwner(); ++ ++ virtual UMLOperation *operation(); ++ virtual void setOperation(UMLOperation *op); ++ ++ virtual QString customOpText(); ++ virtual void setCustomOpText(const QString &opText); ++ ++ virtual void setMessageText(FloatingTextWidget *ft); ++ virtual void setText(FloatingTextWidget *ft, const QString &newText); ++ ++ virtual QString lwOperationText(); ++ virtual UMLClassifier *lwClassifier(); ++ virtual void setOperationText(const QString &op); ++ ++ virtual void constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, ++ Uml::TextRole::Enum tr); ++ ++ //---------- End LinkWidget Interface methods implemementation. ++ ++ /// @return Whether the message is synchronous or asynchronous ++ Uml::SequenceMessage::Enum sequenceMessageType() const { ++ return m_sequenceMessageType; ++ } ++ ++ bool hasObjectWidget(ObjectWidget * w); ++ ++ ObjectWidget* objectWidget(Uml::RoleType::Enum role); ++ void setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) ; ++ ++ bool isSelf() const; ++ ++ /** ++ * Returns the text widget it is related to. ++ * ++ * @return The text widget we are related to. ++ */ ++ FloatingTextWidget * floatingTextWidget() { ++ return m_pFText; ++ } ++ ++ /** ++ * Sets the text widget it is related to. ++ * ++ * @param f The text widget we are related to. ++ */ ++ void setFloatingTextWidget(FloatingTextWidget * f) { ++ m_pFText = f; ++ } ++ ++ void calculateWidget(); ++ ++ virtual bool activate(IDChangeLog * Log = 0); ++ void resolveObjectWidget(IDChangeLog* log); ++ ++ void calculateDimensions(); ++ void calculateDimensionsSynchronous(); ++ void calculateDimensionsAsynchronous(); ++ void calculateDimensionsCreation(); ++ void calculateDimensionsLost(); ++ void calculateDimensionsFound(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ void setTextPosition(); ++ ++ void cleanup(); ++ ++ void setSelected(bool _select); ++ ++ int getMinY(); ++ int getMaxY(); ++ ++ UMLWidget* onWidget(const QPointF& p); ++ ++ virtual void resizeWidget(qreal newW, qreal newH); ++ ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ virtual bool loadFromXMI(QDomElement & qElement); ++ ++ void setxclicked(int xclick); ++ void setyclicked(int yclick); ++ ++ /** ++ * Return the xclicked ++ */ ++ int getxclicked() const { ++ return m_xclicked; ++ } ++ ++protected: ++ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); ++ ++ virtual void moveWidgetBy(qreal diffX, qreal diffY); ++ virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); ++ ++ virtual QCursor resizeCursor() const; ++ ++ void setLinkAndTextPos(); ++ ++ int constrainX(int textX, int textWidth, Uml::TextRole::Enum tr); ++ ++ static void paintArrow(QPainter *p, int x, int y, int w, ++ Qt::ArrowType direction, bool useDottedLine = false); ++ static void paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction); ++ ++ void updateResizability(); ++ ++ void paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ void paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option); ++ ++ // Data loaded/saved ++ QString m_CustomOp; ++ /** ++ * Whether the message is synchronous or asynchronous ++ */ ++ Uml::SequenceMessage::Enum m_sequenceMessageType; ++ ++private: ++ void resizeEvent(QResizeEvent *re); ++ ++ qreal constrainPositionY(qreal diffY); ++ ++ void init(); ++ ++ ObjectWidget * m_pOw[2]; ++ FloatingTextWidget * m_pFText; ++ ++ int m_xclicked; ++ int m_yclicked; ++ ++ /** ++ * The following variables are used by loadFromXMI() as an intermediate ++ * store. activate() resolves the IDs, i.e. after activate() the variables ++ * m_pOw[] and m_pFText can be used. ++ */ ++ Uml::ID::Type m_widgetAId, m_widgetBId, m_textId; ++ ++public slots: ++ void slotWidgetMoved(Uml::ID::Type id); ++ void slotMenuSelection(QAction* action); ++ ++signals: ++ /** ++ * emitted when the message widget is moved up or down ++ * slots into ObjectWidget::slotMessageMoved() ++ */ ++ void sigMessageMoved(); ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,156 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "nodewidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "node.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// qt includes ++#include ++#include ++ ++DEBUG_REGISTER_DISABLED(NodeWidget) ++ ++/** ++ * Constructs a NodeWidget. ++ * ++ * @param scene The parent of this NodeWidget. ++ * @param n The UMLNode this will be representing. ++ */ ++NodeWidget::NodeWidget(UMLScene * scene, UMLNode *n) ++ : UMLWidget(scene, WidgetBase::wt_Node, n) ++{ ++ setSize(100, 30); ++ setZValue(1); // above box but below UMLWidget because may embed widgets ++} ++ ++/** ++ * Destructor. ++ */ ++NodeWidget::~NodeWidget() ++{ ++} ++ ++/** ++ * Overrides standard method. ++ */ ++void NodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } else { ++ painter->setBrush(m_scene->backgroundColor()); ++ } ++ const int w = width(); ++ const int h = height(); ++ const int wDepth = (w/3 > DEPTH ? DEPTH : w/3); ++ const int hDepth = (h/3 > DEPTH ? DEPTH : h/3); ++ const int bodyOffsetY = hDepth; ++ const int bodyWidth = w - wDepth; ++ const int bodyHeight = h - hDepth; ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ QString nameStr = name(); ++ ++ QPolygon pointArray(5); ++ pointArray.setPoint(0, 0, bodyOffsetY); ++ pointArray.setPoint(1, wDepth, 0); ++ pointArray.setPoint(2, w, 0); ++ pointArray.setPoint(3, w, bodyHeight); ++ pointArray.setPoint(4, bodyWidth, h); ++ painter->drawPolygon(pointArray); ++ painter->drawRect(0, bodyOffsetY, bodyWidth, bodyHeight); ++ painter->drawLine(w, 0, bodyWidth, bodyOffsetY); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ int lines = 1; ++ if (m_umlObject) { ++ QString stereotype = m_umlObject->stereotype(); ++ if (!stereotype.isEmpty()) { ++ painter->drawText(0, bodyOffsetY + (bodyHeight/2) - fontHeight, ++ bodyWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); ++ lines = 2; ++ } ++ } ++ ++ if (UMLWidget::isInstance()) { ++ font.setUnderline(true); ++ painter->setFont(font); ++ nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; ++ } ++ ++ if (lines == 1) { ++ painter->drawText(0, bodyOffsetY + (bodyHeight/2) - (fontHeight/2), ++ bodyWidth, fontHeight, Qt::AlignCenter, nameStr); ++ } else { ++ painter->drawText(0, bodyOffsetY + (bodyHeight/2), ++ bodyWidth, fontHeight, Qt::AlignCenter, nameStr); ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF NodeWidget::minimumSize() const ++{ ++ if (m_umlObject == NULL) { ++ DEBUG(DBG_SRC) << "m_umlObject is NULL"; ++ return UMLWidget::minimumSize(); ++ } ++ ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); ++ const int fontHeight = fm.lineSpacing(); ++ ++ QString name = m_umlObject->name(); ++ if (UMLWidget::isInstance()) { ++ name = UMLWidget::instanceName() + QLatin1String(" : ") + name; ++ } ++ ++ int width = fm.width(name) + 2 * defaultMargin; ++ ++ int tempWidth = 0; ++ if (!m_umlObject->stereotype().isEmpty()) { ++ tempWidth = fm.width(m_umlObject->stereotype(true)); ++ } ++ if (tempWidth > width) ++ width = tempWidth; ++ width += DEPTH; ++ ++ int height = (2*fontHeight) + DEPTH; ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Saves to the "nodewidget" XMI element. ++ * Note: For loading we use the method inherited from UMLWidget. ++ */ ++void NodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("nodewidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,44 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef NODEWIDGET_H ++#define NODEWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLNode; ++ ++/** ++ * Defines a graphical version of the Node. Most of the functionality ++ * will come from the @ref UMLNode class. ++ * ++ * @short A graphical version of a Node. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class NodeWidget : public UMLWidget ++{ ++public: ++ ++ NodeWidget(UMLScene * scene, UMLNode *n); ++ virtual ~NodeWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++ static const int DEPTH = 30; ///< pixels on Z axis ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,517 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "notewidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "listpopupmenu.h" ++#include "notedialog.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#include ++#endif ++ ++// qt includes ++#include ++#if QT_VERSION >= 0x050000 ++#include ++#include ++#endif ++ ++NoteWidget * NoteWidget::s_pCurrentNote; ++ ++/** ++ * Constructs a NoteWidget. ++ * ++ * @param scene The parent to this widget. ++ * @param noteType The NoteWidget::NoteType of this NoteWidget ++ * @param id The unique id of the widget. ++ * The default (-1) will prompt a new ID. ++ */ ++NoteWidget::NoteWidget(UMLScene * scene, NoteType noteType , Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_Note, id), ++ m_diagramLink(Uml::ID::None), ++ m_noteType(noteType) ++{ ++ setZValue(20); //make sure always on top. ++} ++ ++/** ++ * Destructor. ++ */ ++NoteWidget::~NoteWidget() ++{ ++} ++ ++/** ++ * Override default method. ++ */ ++void NoteWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ const int margin = 10; ++ int w = width(); ++ int h = height(); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ QPolygon poly(6); ++ poly.setPoint(0, 0, 0); ++ poly.setPoint(1, 0, h); ++ poly.setPoint(2, w, h); ++ poly.setPoint(3, w, margin); ++ poly.setPoint(4, w - margin, 0); ++ poly.setPoint(5, 0, 0); ++ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) { ++ QBrush brush(UMLWidget::fillColor()); ++ painter->setBrush(brush); ++ painter->drawPolygon(poly); ++ } else ++ painter->drawPolyline(poly); ++ painter->drawLine(w - margin, 0, w - margin, margin); ++ painter->drawLine(w - margin, margin, w, margin); ++ painter->setPen(textColor()); ++ switch(m_noteType) { ++ case NoteWidget::PreCondition : ++ painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< precondition >>")); ++ break; ++ case NoteWidget::PostCondition : ++ painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< postcondition >>")); ++ break; ++ case NoteWidget::Transformation : ++ painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< transformation >>")); ++ break; ++ case NoteWidget::Normal : ++ default : ++ break; ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++ ++// paintText(&p, 0, 0); ++ paintTextWordWrap(painter); ++} ++ ++/** ++ * Returns the type of note. ++ */ ++NoteWidget::NoteType NoteWidget::noteType() const ++{ ++ return m_noteType; ++} ++ ++/** ++ * Converts a string to NoteWidget::NoteType. ++ */ ++NoteWidget::NoteType NoteWidget::stringToNoteType(const QString& noteType) ++{ ++ if (noteType == QLatin1String("Precondition")) ++ return NoteWidget::PreCondition; ++ else if (noteType == QLatin1String("Postcondition")) ++ return NoteWidget::PostCondition; ++ else if (noteType == QLatin1String("Transformation")) ++ return NoteWidget::Transformation; ++ else ++ return NoteWidget::Normal; ++} ++ ++/** ++ * Sets the type of note. ++ */ ++void NoteWidget::setNoteType(NoteType noteType) ++{ ++ m_noteType = noteType; ++} ++ ++/** ++ * Sets the type of note. ++ */ ++void NoteWidget::setNoteType(const QString& noteType) ++{ ++ setNoteType(stringToNoteType(noteType)); ++} ++ ++/** ++ * Return the ID of the diagram hyperlinked to this note. ++ * ++ * @return ID of an UMLView, or Uml::ID::None if no ++ * hyperlink is set. ++ */ ++Uml::ID::Type NoteWidget::diagramLink() const ++{ ++ return m_diagramLink; ++} ++ ++/** ++ * Set the ID of the diagram hyperlinked to this note. ++ * To switch off the hyperlink, set this to Uml::id_None. ++ * ++ * @param viewID ID of an UMLScene. ++ */ ++void NoteWidget::setDiagramLink(Uml::ID::Type viewID) ++{ ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ UMLView *view = umldoc->findView(viewID); ++ if (view == NULL) { ++ uError() << "no view found for viewID " << Uml::ID::toString(viewID); ++ return; ++ } ++ QString linkText(QLatin1String("Diagram: ") + view->umlScene()->name()); ++ setDocumentation(linkText); ++ m_diagramLink = viewID; ++ update(); ++} ++ ++/** ++ * Display a dialog box to allow the user to choose the note's type. ++ */ ++void NoteWidget::askForNoteType(UMLWidget* &targetWidget) ++{ ++ static const QStringList list = QStringList() << i18n("Precondition") ++ << i18n("Postcondition") ++ << i18n("Transformation"); ++ bool pressedOK = false; ++ ++#if QT_VERSION >= 0x050000 ++ QString type = QInputDialog::getItem (UMLApp::app(), ++ i18n("Note Type"), i18n("Select the Note Type"), list, ++ 0, false, &pressedOK); ++#else ++ QString type = KInputDialog::getItem (i18n("Note Type"), i18n("Select the Note Type"), list, ++ 0, false, &pressedOK, UMLApp::app()); ++#endif ++ ++ if (pressedOK) { ++ dynamic_cast(targetWidget)->setNoteType(type); ++ } else { ++ targetWidget->cleanup(); ++ delete targetWidget; ++ targetWidget = 0; ++ } ++} ++ ++/** ++ * Loads a "notewidget" XMI element. ++ */ ++bool NoteWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ setZValue(20); //make sure always on top. ++ setDocumentation(qElement.attribute(QLatin1String("text"))); ++ QString diagramlink = qElement.attribute(QLatin1String("diagramlink")); ++ if (!diagramlink.isEmpty()) ++ m_diagramLink = Uml::ID::fromString(diagramlink); ++ QString type = qElement.attribute(QLatin1String("noteType")); ++ setNoteType((NoteType)type.toInt()); ++ return true; ++} ++ ++/** ++ * Saves to the "notewidget" XMI element. ++ */ ++void NoteWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement noteElement = qDoc.createElement(QLatin1String("notewidget")); ++ UMLWidget::saveToXMI(qDoc, noteElement); ++ noteElement.setAttribute(QLatin1String("text"), documentation()); ++ if (m_diagramLink != Uml::ID::None) ++ noteElement.setAttribute(QLatin1String("diagramlink"), Uml::ID::toString(m_diagramLink)); ++ noteElement.setAttribute(QLatin1String("noteType"), m_noteType); ++ qElement.appendChild(noteElement); ++} ++ ++/** ++ * Show a properties dialog for a NoteWidget. ++ */ ++void NoteWidget::showPropertiesDialog() ++{ ++ NoteDialog * dlg = 0; ++ UMLApp::app()->docWindow()->updateDocumentation(false); ++ dlg = new NoteDialog(umlScene()->activeView(), this); ++ if (dlg->exec()) { ++ UMLApp::app()->docWindow()->showDocumentation(this, true); ++ UMLApp::app()->document()->setModified(true); ++ update(); ++ } ++ delete dlg; ++} ++ ++/** ++ * Will be called when a menu selection has been made from the popup ++ * menu. ++ * ++ * @param action The action that has been selected. ++ */ ++void NoteWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Rename: ++ showPropertiesDialog(); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ break; ++ } ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF NoteWidget::minimumSize() const ++{ ++ int width = 60; ++ int height = 30; ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int textWidth = fm.width(documentation()); ++ if (m_noteType == PreCondition) { ++ const int widthtemp = fm.width(QLatin1String("<< precondition >>")); ++ width = textWidth > widthtemp ? textWidth : widthtemp; ++ width += 10; ++ } ++ else if (m_noteType == PostCondition) { ++ const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); ++ width = textWidth > widthtemp ? textWidth : widthtemp; ++ width += 10; ++ } ++ else if (m_noteType == Transformation) { ++ const int widthtemp = fm.width(QLatin1String("<< transformation >>")); ++ width = textWidth > widthtemp ? textWidth : widthtemp; ++ width += 10; ++ } ++ return QSizeF(width, height); ++} ++ ++/** ++ * Calculate content related size of widget. ++ * Overrides method from UMLWidget. ++ */ ++QSizeF NoteWidget::calculateSize(bool withExtensions /* = true */) const ++{ ++ Q_UNUSED(withExtensions) ++ int width = this->width(); ++ int height = this->height(); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int margin = fm.width(QLatin1String("W")); ++ QSize size = fm.size (0, documentation()); ++ const int textWidth = size.width(); ++ if (m_noteType == PreCondition) { ++ const int widthtemp = fm.width(QLatin1String("<< precondition >>")); ++ width = textWidth > widthtemp ? textWidth : widthtemp; ++ width += 2 * margin; ++ } ++ else if (m_noteType == PostCondition) { ++ const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); ++ width = textWidth > widthtemp ? textWidth : widthtemp; ++ width += 2 * margin; ++ } ++ else if (m_noteType == Transformation) { ++ const int widthtemp = fm.width(QLatin1String("<< transformation >>")); ++ width = textWidth > widthtemp ? textWidth : widthtemp; ++ width += 2 * margin; ++ } ++ return QSizeF(width, height); ++} ++ ++/** ++ * Paints the text. Auxiliary to paint(). ++ * Implemented without word wrap. ++ */ ++void NoteWidget::paintText(QPainter *painter) ++{ ++ if (painter == 0) { ++ return; ++ } ++ ++ QString text = documentation(); ++ if (text.length() == 0) { ++ return; ++ } ++ ++ painter->setPen(Qt::black); ++ QFont font = UMLWidget::font(); ++ painter->setFont(font); ++ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int margin = fm.width(QLatin1String("W")); ++ const QSize textSize = fm.size(Qt::TextExpandTabs, text); ++ ++ const int width = this->width() - margin * 2; ++ const int height = this->height() - fontHeight; ++ int textY = fontHeight / 2; ++ int textX = margin; ++ ++ if ((textSize.width() < width) && (textSize.height() < height)) { ++ // the entire text is small enough - draw it ++ painter->drawText(textX, textY, ++ textSize.width(), textSize.height(), ++ Qt::AlignLeft, text); ++ } ++ else { ++ // not all text can be drawn ++ QStringList lines = text.split(QLatin1Char('\n')); ++ foreach(const QString& line, lines) { ++ int lineWidth = fm.width(line); ++ if (lineWidth < width) { ++ // line is small enough - draw it ++ painter->drawText(textX, textY, ++ textSize.width(), fontHeight, ++ Qt::AlignLeft, line); ++ } ++ else { ++ // draw a smaller line ++ for(int len = line.length(); len > 0; --len) { ++ QString smallerLine = line.left(len); ++ int smallerLineWidth = fm.width(smallerLine); ++ if (smallerLineWidth < width) { ++ // line is small enough - draw it ++ painter->drawText(textX, textY, ++ width, fontHeight, ++ Qt::AlignLeft, smallerLine); ++ } ++ } ++ } ++ textY += fontHeight; ++ if (textY > height) { ++ // skip the next lines - size is not enough ++ break; ++ } ++ } ++ } ++} ++ ++/** ++ * Paints the text. Auxiliary to paint(). ++ * Implemented with word wrap. ++ */ ++void NoteWidget::paintTextWordWrap(QPainter *painter) ++{ ++ if (painter == 0) { ++ return; ++ } ++ QString text = documentation(); ++ if (text.length() == 0) { ++ return; ++ } ++ // Implement word wrap for text as follows: ++ // wrap at width on whole words. ++ // if word is wider than width then clip word ++ // if reach height exit and don't print anymore ++ // start new line on \n character ++ painter->setPen(Qt::black); ++ QFont font = UMLWidget::font(); ++ painter->setFont(font); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ QString word; ++ QString fullLine; ++ QString testCombineLine; ++ const int margin = fm.width(QLatin1String("W")); ++ int textY = fontHeight / 2; ++ int textX = margin; ++ const int width = this -> width() - margin * 2; ++ const int height = this -> height() - fontHeight; ++ QChar returnChar = QChar::fromLatin1('\n'); ++ QChar c; ++ ++ for (int i = 0; i <= text.length(); ++i) { ++ if (i < text.length()) { ++ c = text[i]; ++ } else { ++ // all chars of text have been handled already -> ++ // perform this last run to spool current content of "word" ++ c = returnChar; ++ } ++ if (c == returnChar || c.isSpace()) { ++ // new word delimiter found -> it is time to decide on word wrap ++ testCombineLine = fullLine + QLatin1Char(' ') + word; ++ int textWidth = fm.width(testCombineLine); ++ if (textX + textWidth > width) { ++ // combination of "fullLine" and "word" doesn't fit into one line -> ++ // print "fullLine" in current line, update write position to next line ++ // and decide then on following actions ++ painter->drawText(textX, textY, ++ textWidth, fontHeight, Qt::AlignLeft, fullLine); ++ fullLine = word; ++ word = QString(); ++ // update write position ++ textX = margin; ++ textY += fontHeight; ++ if (textY > height) ++ return; ++ // in case of c==newline -> ++ // print "word" and set write position one additional line lower ++ if (c == returnChar) { ++ // print "word" - which is now "fullLine" and set to next line ++ painter->drawText(textX, textY, ++ textWidth, fontHeight, Qt::AlignLeft, fullLine); ++ fullLine = QString(); ++ textX = margin; ++ textY += fontHeight; ++ if(textY > height) return; ++ } ++ } ++ else if (c == returnChar) { ++ // newline found and combination of "fullLine" and "word" fits ++ // in one line ++ painter->drawText(textX, textY, ++ textWidth, fontHeight, Qt::AlignLeft, testCombineLine); ++ fullLine = word = QString(); ++ textX = margin; ++ textY += fontHeight; ++ if (textY > height) ++ return; ++ } else { ++ // word delimiter found, and combination of "fullLine", space and "word" fits into one line ++ fullLine = testCombineLine; ++ word = QString(); ++ } ++ } else { ++ // no word delimiter found --> add current char to "word" ++ if (c != QLatin1Char('\0')) ++ word += c; ++ } ++ }//end for ++} ++ ++/** ++ * Event handler for moude double click events. ++ * ++ * @param event The QGraphicsSceneMouseEvent event. ++ */ ++void NoteWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) ++{ ++ if (event->button() == Qt::LeftButton) { ++ if (m_diagramLink == Uml::ID::None) { ++ showPropertiesDialog(); ++ } else { ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ umldoc->changeCurrentView(m_diagramLink); ++ } ++ event->accept(); ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,83 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef NOTEWIDGET_H ++#define NOTEWIDGET_H ++ ++//app includes ++#include "umlwidget.h" ++ ++// Qt forward declarations ++class QPainter; ++ ++/** ++ * Displays a note box to allow multiple lines of text to be displayed. ++ * These widgets are diagram specific. They will still need a unique id ++ * from the @ref UMLDoc class for deletion and other purpose-kf6s. ++ * ++ * @short Displays a note box. ++ * @author Paul Hensgen ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class NoteWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ ++ /// This enum type is used to specify the type of note. ++ enum NoteType ++ { ++ Normal, ++ PreCondition, ++ PostCondition, ++ Transformation ++ }; ++ ++ explicit NoteWidget(UMLScene * scene, NoteWidget::NoteType noteType = Normal, ++ Uml::ID::Type id = Uml::ID::None); ++ virtual ~NoteWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ static NoteType stringToNoteType(const QString& noteType); ++ ++ NoteType noteType() const; ++ void setNoteType(NoteType noteType); ++ void setNoteType(const QString& noteType); ++ ++ Uml::ID::Type diagramLink() const; ++ void setDiagramLink(Uml::ID::Type viewID); ++ ++ void askForNoteType(UMLWidget* &targetWidget); ++ ++ virtual void showPropertiesDialog(); ++ ++ virtual bool loadFromXMI(QDomElement & qElement); ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++ static NoteWidget *s_pCurrentNote; ++ ++public Q_SLOTS: ++ void slotMenuSelection(QAction* action); ++ ++protected: ++ virtual QSizeF minimumSize() const; ++ virtual QSizeF calculateSize(bool withExtensions = true) const; ++ void paintText(QPainter *painter); ++ void paintTextWordWrap(QPainter *painter); ++ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); ++ ++private: ++ Uml::ID::Type m_diagramLink; ///< The diagram/scene this note links to. ++ NoteType m_noteType; ///< The type of note. @see NoteWidget::NoteType ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,377 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "objectnodewidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "dialog_utils.h" ++#include "listpopupmenu.h" ++#include "objectnodedialog.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++#include ++ ++#define OBJECTNODE_MARGIN 5 ++#define OBJECTNODE_WIDTH 30 ++#define OBJECTNODE_HEIGHT 10 ++ ++/** ++ * Creates a Object Node widget. ++ * ++ * @param scene The parent of the widget. ++ * @param objectNodeType The type of object node ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++ObjectNodeWidget::ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType, Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_ObjectNode, id) ++{ ++ setObjectNodeType(objectNodeType); ++ setState(QString()); ++} ++ ++/** ++ * Destructor. ++ */ ++ObjectNodeWidget::~ObjectNodeWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void ObjectNodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ int w = width(); ++ int h = height(); ++ ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ int textStartY = (h / 2) - (fontHeight / 2); ++ ++ setPenFromSettings(painter); ++ ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } ++ ++ painter->drawRect(0, 0, w, h); ++ painter->setFont(UMLWidget::font()); ++ ++ switch (m_objectNodeType) ++ { ++ case Normal : break; ++ case Buffer : ++ { ++ painter->setPen(textColor()); ++ painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< centralBuffer >>")); ++ painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); ++ } ++ break; ++ case Data : ++ { ++ painter->setPen(textColor()); ++ painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< datastore >>")); ++ painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); ++ } ++ break; ++ case Flow : ++ { ++ QString objectflow_value; ++ if (state() == QLatin1String("-") || state().isEmpty()) ++ { ++ objectflow_value = QLatin1Char(' '); ++ } ++ else ++ { ++ objectflow_value = QLatin1Char('[') + state() + QLatin1Char(']'); ++ } ++ ++ painter->drawLine(10, h/2, w-10, h/2); ++ painter->setPen(textColor()); ++ painter->setFont(UMLWidget::font()); ++ painter->drawText(OBJECTNODE_MARGIN, textStartY/2 - OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); ++ painter->drawText(OBJECTNODE_MARGIN, textStartY/2 + textStartY + OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, objectflow_value); ++ } ++ break; ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget. ++ */ ++QSizeF ObjectNodeWidget::minimumSize() const ++{ ++ int widthtmp = 10, height = 10, width=10; ++ if (m_objectNodeType == Buffer) { ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int textWidth = fm.width(QLatin1String("<< centralBuffer >>")); ++ const int namewidth = fm.width(name()); ++ height = fontHeight * 2; ++ widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; ++ width = namewidth > widthtmp ? namewidth : widthtmp; ++ height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; ++ width += OBJECTNODE_MARGIN * 2; ++ height += OBJECTNODE_MARGIN * 2 + 5; ++ } else if (m_objectNodeType == Data) { ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int textWidth = fm.width(QLatin1String("<< datastore >>")); ++ const int namewidth = fm.width(name()); ++ height = fontHeight * 2; ++ widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; ++ width = namewidth > widthtmp ? namewidth : widthtmp; ++ height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; ++ width += OBJECTNODE_MARGIN * 2; ++ height += OBJECTNODE_MARGIN * 2 + 5; ++ } else if (m_objectNodeType == Flow) { ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int textWidth = fm.width(QLatin1Char('[') + state() + QLatin1Char(']')); ++ const int namewidth = fm.width(name()); ++ height = fontHeight * 2; ++ widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; ++ width = namewidth > widthtmp ? namewidth : widthtmp; ++ height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; ++ width += OBJECTNODE_MARGIN * 2; ++ height += OBJECTNODE_MARGIN * 4; ++ } ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Returns the type of object node. ++ */ ++ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::objectNodeType() const ++{ ++ return m_objectNodeType; ++} ++ ++/** ++ * Returns the type of object node. ++ */ ++ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::toObjectNodeType(const QString& type) ++{ ++ if (type == QLatin1String("Central buffer")) ++ return ObjectNodeWidget::Buffer; ++ if (type == QLatin1String("Data store")) ++ return ObjectNodeWidget::Data; ++ if (type == QLatin1String("Object Flow")) ++ return ObjectNodeWidget::Flow; ++ // Shouldn't happen ++ Q_ASSERT(0); ++ return ObjectNodeWidget::Flow; ++} ++ ++/** ++ * Sets the type of object node. ++ */ ++void ObjectNodeWidget::setObjectNodeType(ObjectNodeType objectNodeType) ++{ ++ m_objectNodeType = objectNodeType; ++ UMLWidget::m_resizable = true; ++} ++ ++/** ++ * Sets the type of object node. ++ */ ++void ObjectNodeWidget::setObjectNodeType(const QString& type) ++{ ++ setObjectNodeType(ObjectNodeWidget::toObjectNodeType(type)); ++} ++ ++/** ++ * Sets the state of an object node when it's an objectflow. ++ */ ++void ObjectNodeWidget::setState(const QString& state) ++{ ++ m_state = state; ++ updateGeometry(); ++} ++ ++/** ++ * Returns the state of object node. ++ */ ++QString ObjectNodeWidget::state() const ++{ ++ return m_state; ++} ++ ++/** ++ * Captures any popup menu signals for menus it created. ++ */ ++void ObjectNodeWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Rename: ++ { ++ bool ok = false; ++ QString text = name(); ++#if QT_VERSION >= 0x050000 ++ text = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter Object Node Name"), ++ i18n("Enter the name of the object node :"), ++ QLineEdit::Normal, ++ name(), &ok); ++#else ++ text = KInputDialog::getText(i18n("Enter Object Node Name"), ++ i18n("Enter the name of the object node :"), ++ name(), &ok); ++#endif ++ if (ok && !text.isEmpty()) { ++ setName(text); ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Properties: ++ showPropertiesDialog(); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Show a properties dialog for an ObjectNodeWidget. ++ */ ++void ObjectNodeWidget::showPropertiesDialog() ++{ ++ UMLApp::app()->docWindow()->updateDocumentation(false); ++ ++ QPointer dialog = new ObjectNodeDialog(UMLApp::app()->currentView(), this); ++ if (dialog->exec() && dialog->getChangesMade()) { ++ UMLApp::app()->docWindow()->showDocumentation(this, true); ++ UMLApp::app()->document()->setModified(true); ++ } ++ delete dialog; ++} ++ ++/** ++ * Saves the widget to the "objectnodewidget" XMI element. ++ */ ++void ObjectNodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement objectNodeElement = qDoc.createElement(QLatin1String("objectnodewidget")); ++ UMLWidget::saveToXMI(qDoc, objectNodeElement); ++ objectNodeElement.setAttribute(QLatin1String("objectnodename"), m_Text); ++ objectNodeElement.setAttribute(QLatin1String("documentation"), m_Doc); ++ objectNodeElement.setAttribute(QLatin1String("objectnodetype"), m_objectNodeType); ++ objectNodeElement.setAttribute(QLatin1String("objectnodestate"), m_state); ++ qElement.appendChild(objectNodeElement); ++} ++ ++/** ++ * Loads the widget from the "objectnodewidget" XMI element. ++ */ ++bool ObjectNodeWidget::loadFromXMI(QDomElement& qElement) ++{ ++ if(!UMLWidget::loadFromXMI(qElement) ) ++ return false; ++ m_Text = qElement.attribute(QLatin1String("objectnodename")); ++ m_Doc = qElement.attribute(QLatin1String("documentation")); ++ QString type = qElement.attribute(QLatin1String("objectnodetype"), QLatin1String("1")); ++ m_state = qElement.attribute(QLatin1String("objectnodestate")); ++ setObjectNodeType((ObjectNodeType)type.toInt()); ++ return true; ++} ++ ++/** ++ * Open a dialog box to select the objectNode type (Data, Buffer or Flow). ++ */ ++void ObjectNodeWidget::askForObjectNodeType(UMLWidget* &targetWidget) ++{ ++ bool pressedOK = false; ++ int current = 0; ++ const QStringList list = QStringList() ++ << QLatin1String("Central buffer") ++ << QLatin1String("Data store") ++ << QLatin1String("Object Flow"); ++ ++#if QT_VERSION >= 0x050000 ++ QString type = QInputDialog::getItem (UMLApp::app(), ++ i18n("Select Object node type"), i18n("Select the object node type"), ++ list, current, false, &pressedOK); ++ ++#else ++ QString type = KInputDialog::getItem (i18n("Select Object node type"), i18n("Select the object node type"), list, current, false, &pressedOK, UMLApp::app()); ++#endif ++ ++ if (pressedOK) { ++ dynamic_cast(targetWidget)->setObjectNodeType(type); ++ if (type == QLatin1String("Data store")) ++ Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the data store node"), i18n("Enter the name of the data store node"), i18n("data store name")); ++ if (type == QLatin1String("Central buffer")) ++ Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the buffer node"), i18n("Enter the name of the buffer"), i18n("centralBuffer")); ++ if (type == QLatin1String("Object Flow")) { ++ Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the object flow"), i18n("Enter the name of the object flow"), i18n("object flow")); ++ askStateForWidget(); ++ } ++ } else { ++ targetWidget->cleanup(); ++ delete targetWidget; ++ targetWidget = NULL; ++ } ++} ++ ++/** ++ * Open a dialog box to input the state of the widget. ++ * This box is shown only if m_objectNodeType = Flow. ++ */ ++void ObjectNodeWidget::askStateForWidget() ++{ ++ bool pressedOK = false; ++#if QT_VERSION >= 0x050000 ++ QString state = QInputDialog::getText(UMLApp::app(), ++ i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), ++ QLineEdit::Normal, ++ i18n("-"), &pressedOK); ++#else ++ QString state = KInputDialog::getText(i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), i18n("-"), &pressedOK, UMLApp::app()); ++#endif ++ ++ if (pressedOK) { ++ setState(state); ++ } else { ++ cleanup(); ++ } ++} ++ ++void ObjectNodeWidget::slotOk() ++{ ++ // kdialog-kf6::accept(); ++} ++ ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,76 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef OBJECTNODEWIDGET_H ++#define OBJECTNODEWIDGET_H ++ ++#include "umlwidget.h" ++ ++/** ++ * This class is the graphical version of a UML Object Node. A ObjectNodeWidget is created ++ * by a @ref UMLView. An ObjectNodeWidget belongs to only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. ++ * ++ * The ObjectNodeWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @short A graphical version of a UML Activity. ++ * @author Florence Mattler ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ObjectNodeWidget : public UMLWidget ++{ ++ Q_OBJECT ++ ++public: ++ enum ObjectNodeType ++ { ++ Normal, ++ Data, ++ Buffer, ++ Flow ++ }; ++ ++ explicit ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType = Normal, Uml::ID::Type id = Uml::ID::None); ++ virtual ~ObjectNodeWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ ObjectNodeType objectNodeType() const; ++ static ObjectNodeType toObjectNodeType(const QString& type); ++ ++ void setObjectNodeType(ObjectNodeType objectNodeType); ++ void setObjectNodeType(const QString& type) ; ++ ++ void setState(const QString& state); ++ QString state() const; ++ ++ virtual void showPropertiesDialog(); ++ ++ void askStateForWidget(); ++ void askForObjectNodeType(UMLWidget* &targetWidget); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ virtual bool loadFromXMI(QDomElement& qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ void slotOk(); ++ ++private: ++ ObjectNodeType m_objectNodeType; ///< type of object node ++ QString m_state; ///< state of object node when it's an objectFlow ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,710 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header file ++#include "objectwidget.h" ++ ++// local includes ++#include "classpropertiesdialog.h" ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "listpopupmenu.h" ++#include "messagewidget.h" ++#include "seqlinewidget.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlobject.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++#include ++#include ++ ++#define O_MARGIN 5 ++#define O_WIDTH 40 ++#define A_WIDTH 20 ++#define A_HEIGHT 40 ++#define A_MARGIN 5 ++ ++DEBUG_REGISTER_DISABLED(ObjectWidget) ++ ++/** ++ * The number of pixels margin between the lowest message ++ * and the bottom of the vertical line ++ */ ++static const int sequenceLineMargin = 20; ++ ++/** ++ * Creates an ObjectWidget. ++ * ++ * @param scene The parent to this object. ++ * @param o The object it will be representing. ++ */ ++ObjectWidget::ObjectWidget(UMLScene * scene, UMLObject *o) ++ : UMLWidget(scene, WidgetBase::wt_Object, o), ++ m_multipleInstance(false), ++ m_drawAsActor(false), ++ m_showDestruction(false), ++ m_isOnDestructionBox(false) ++{ ++ if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { ++ m_pLine = new SeqLineWidget( m_scene, this ); ++ m_pLine->setStartPoint(x() + width() / 2, y() + height()); ++ } else { ++ m_pLine = 0; ++ } ++} ++ ++/** ++ * Destructor. ++ */ ++ObjectWidget::~ObjectWidget() ++{ ++ cleanup(); ++} ++ ++/** ++ * Sets whether representing a multi-instance object. ++ * ++ * @param multiple Object state. true- multi, false - single. ++ */ ++void ObjectWidget::setMultipleInstance(bool multiple) ++{ ++ //make sure only calling this in relation to an object on a collab. diagram ++ if (m_scene && (m_scene->type() == Uml::DiagramType::Collaboration)) { ++ m_multipleInstance = multiple; ++ updateGeometry(); ++ update(); ++ } ++} ++ ++/** ++ * Returns whether object is representing a multi-object. ++ * ++ * @return True if object is representing a multi-object. ++ */ ++bool ObjectWidget::multipleInstance() const ++{ ++ return m_multipleInstance; ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Moves the widget to a new position using the difference between the ++ * current position and the new position. ++ * Y position is ignored, and widget is only moved along X axis. ++ * ++ * @param diffX The difference between current X position and new X position. ++ * @param diffY The difference between current Y position and new Y position ++ * (isn't used). ++ */ ++void ObjectWidget::moveWidgetBy(qreal diffX, qreal diffY) ++{ ++ setX(x() + diffX); ++ if (m_scene && (m_scene->type() != Uml::DiagramType::Sequence)) { ++ setY(y() + diffY); ++ } ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Modifies the value of the diffX and diffY variables used to move the widgets. ++ * All the widgets are constrained to be moved only in X axis (diffY is set to 0). ++ * ++ * @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 ObjectWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) ++{ ++ Q_UNUSED(diffX); ++ if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { ++ diffY = 0; ++ } ++} ++ ++/** ++ * Override default method. ++ */ ++void ObjectWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ if (m_drawAsActor) ++ paintActor(painter); ++ else ++ paintObject(painter); ++ ++ setPenFromSettings(painter); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Handles a popup menu selection. ++ */ ++void ObjectWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Rename_Object: ++ { ++ bool ok; ++ QRegExpValidator* validator = new QRegExpValidator(QRegExp(QLatin1String(".*")), 0); ++#if QT_VERSION >= 0x050000 ++ QString name = QInputDialog::getText(m_scene->activeView(), ++ i18n("Rename Object"), ++ i18n("Enter object name:"), ++ QLineEdit::Normal, ++ m_instanceName, ++ &ok); ++#else ++ QString name = KInputDialog::getText ++ (i18n("Rename Object"), ++ i18n("Enter object name:"), ++ m_instanceName, ++ &ok, ++ m_scene->activeView(), ++ validator); ++#endif ++ if (ok) { ++ m_instanceName = name; ++ updateGeometry(); ++ moveEvent(0); ++ update(); ++ UMLApp::app()->document()->setModified(true); ++ } ++ delete validator; ++ break; ++ } ++ case ListPopupMenu::mt_Properties: ++ showPropertiesDialog(); ++ updateGeometry(); ++ moveEvent(0); ++ update(); ++ break; ++ ++ case ListPopupMenu::mt_Up: ++ tabUp(); ++ break; ++ ++ case ListPopupMenu::mt_Down: ++ tabDown(); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ break; ++ } ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF ObjectWidget::minimumSize() const ++{ ++ int width, height; ++ const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); ++ const int fontHeight = fm.lineSpacing(); ++ const QString t = m_instanceName + QLatin1String(" : ") + name(); ++ const int textWidth = fm.width(t); ++ if (m_drawAsActor) { ++ width = textWidth > A_WIDTH?textWidth:A_WIDTH; ++ height = A_HEIGHT + fontHeight + A_MARGIN; ++ width += A_MARGIN * 2; ++ } else { ++ width = textWidth > O_WIDTH?textWidth:O_WIDTH; ++ height = fontHeight + O_MARGIN * 2; ++ width += O_MARGIN * 2; ++ if (m_multipleInstance) { ++ width += 10; ++ height += 10; ++ } ++ }//end else drawasactor ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Sets whether to draw as an Actor. ++ * ++ * @param drawAsActor True if widget shall be drawn as an actor. ++ */ ++void ObjectWidget::setDrawAsActor(bool drawAsActor) ++{ ++ m_drawAsActor = drawAsActor; ++ updateGeometry(); ++} ++ ++/** ++ * Returns whether to draw as an Actor or not. ++ * ++ * @return True if widget is drawn as an actor. ++ */ ++bool ObjectWidget::drawAsActor() const ++{ ++ return m_drawAsActor; ++} ++ ++/** ++ * Activate the object after serializing it from a QDataStream ++ */ ++bool ObjectWidget::activate(IDChangeLog* ChangeLog /*= 0*/) ++{ ++ if (! UMLWidget::activate(ChangeLog)) ++ return false; ++ if (m_showDestruction && m_pLine) ++ m_pLine->setupDestructionBox(); ++ moveEvent(0); ++ return true; ++} ++ ++/** ++ * Sets the x-coordinate. ++ * Reimplements the method from UMLWidget. ++ * ++ * @param x The x-coordinate to be set. ++ */ ++void ObjectWidget::setX(qreal x) ++{ ++ UMLWidget::setX(x); ++ moveEvent(0); ++} ++ ++/** ++ * Sets the y-coordinate. ++ * Reimplements the method from UMLWidget. ++ * ++ * @param y The y-coordinate to be set. ++ */ ++void ObjectWidget::setY(qreal y) ++{ ++ UMLWidget::setY(y); ++ if (!UMLApp::app()->document()->loading()) ++ moveEvent(0); ++} ++ ++/** ++ * Return the x coordinate of the widgets center. ++ * @return The x-coordinate of the widget center. ++ */ ++qreal ObjectWidget::centerX() ++{ ++ return x() + width()/2; ++} ++ ++/** ++ * Overrides the standard operation. ++ */ ++void ObjectWidget::moveEvent(QGraphicsSceneMouseEvent *event) ++{ ++ Q_UNUSED(event) ++ emit sigWidgetMoved(m_nLocalID); ++ if (m_pLine) { ++ m_pLine->setStartPoint(x() + width() / 2, y() + height()); ++ } ++} ++ ++/** ++ * Overrides the standard operation. ++ */ ++void ObjectWidget::mousePressEvent(QGraphicsSceneMouseEvent *me) ++{ ++ UMLWidget::mousePressEvent(me); ++ m_isOnDestructionBox = false; ++ if (m_pLine && m_pLine->onDestructionBox(me->scenePos())) { ++ m_isOnDestructionBox = true; ++ qreal oldX = x() + width() / 2; ++ qreal oldY = getEndLineY() - 10; ++ m_oldPos = QPointF(oldX, oldY); ++ } ++} ++ ++/** ++ * Overrides the standard operation. ++ */ ++void ObjectWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) ++{ ++ if (m_inResizeArea) { ++ DEBUG(DBG_SRC) << "resizing..."; ++ resize(me); ++ moveEvent(0); ++ return; ++ } ++ ++ if (m_isOnDestructionBox) { ++ qreal diffY = me->scenePos().y() - m_oldPos.y(); ++ moveDestructionBy(diffY); ++ } ++ else { ++ UMLWidget::mouseMoveEvent(me); ++ } ++} ++ ++/** ++ * Moves the destruction Box to a new position using the difference between the ++ * current position and the new position. ++ * The destruction box is only moved along Y axis. ++ * ++ * @param diffY The difference between current Y position and new Y position ++ */ ++void ObjectWidget::moveDestructionBy(qreal diffY) ++{ ++ // endLine = length of the life line + diffY - 10 to center on the destruction box ++ qreal endLine = getEndLineY() + diffY - 10; ++ SeqLineWidget *pLine = sequentialLine(); ++ pLine->setEndOfLine(endLine); ++ m_oldPos.setY(endLine); ++} ++ ++/** ++ * Handles a color change signal. ++ */ ++void ObjectWidget::slotFillColorChanged(Uml::ID::Type /*viewID*/) ++{ ++ UMLWidget::setFillColor(m_scene->fillColor()); ++ UMLWidget::setLineColor(m_scene->lineColor()); ++ ++ if(m_pLine) ++ m_pLine->setPen(QPen(UMLWidget::lineColor(), UMLWidget::lineWidth(), Qt::DashLine)); ++} ++ ++/** ++ * Used to cleanup any other widget it may need to delete. ++ */ ++void ObjectWidget::cleanup() ++{ ++ UMLWidget::cleanup(); ++ if(m_pLine) { ++ m_pLine->cleanup(); ++ delete m_pLine; ++ m_pLine = 0; ++ } ++} ++ ++/** ++ * Show a properties dialog for an ObjectWidget. ++ */ ++void ObjectWidget::showPropertiesDialog() ++{ ++ UMLApp::app()->docWindow()->updateDocumentation(false); ++ QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); ++ if (dlg->exec()) { ++ UMLApp::app()->docWindow()->showDocumentation(this, true); ++ UMLApp::app()->document()->setModified(true); ++ } ++ dlg->close(); ++ delete dlg; ++} ++ ++/** ++ * Draw the object as an object (default). ++ */ ++void ObjectWidget::paintObject(QPainter *painter) ++{ ++ QFont oldFont = painter->font(); ++ QFont font = UMLWidget::font(); ++ font.setUnderline(true); ++ painter->setFont(font); ++ ++ setPenFromSettings(painter); ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ else ++ painter->setBrush(m_scene->backgroundColor()); ++ const int w = width(); ++ const int h = height(); ++ ++ const QString t = m_instanceName + QLatin1String(" : ") + name(); ++ int multiInstOfst = 0; ++ if (m_multipleInstance) { ++ painter->drawRect(10, 10, w - 10, h - 10); ++ painter->drawRect(5, 5, w - 10, h - 10); ++ multiInstOfst = 10; ++ } ++ painter->drawRect(0, 0, w - multiInstOfst, h - multiInstOfst); ++ painter->setPen(textColor()); ++ painter->drawText(O_MARGIN, O_MARGIN, ++ w - O_MARGIN * 2 - multiInstOfst, h - O_MARGIN * 2 - multiInstOfst, ++ Qt::AlignCenter, t); ++ ++ painter->setFont(oldFont); ++} ++ ++/** ++ * Draw the object as an actor. ++ */ ++void ObjectWidget::paintActor(QPainter *painter) ++{ ++ const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); ++ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ const int w = width(); ++ const int textStartY = A_HEIGHT + A_MARGIN; ++ const int fontHeight = fm.lineSpacing(); ++ ++ const int middleX = w / 2; ++ const int thirdH = A_HEIGHT / 3; ++ ++ //draw actor ++ painter->drawEllipse(middleX - A_WIDTH / 2, 0, A_WIDTH, thirdH);//head ++ painter->drawLine(middleX, thirdH, middleX, thirdH * 2);//body ++ painter->drawLine(middleX, 2 * thirdH, ++ middleX - A_WIDTH / 2, A_HEIGHT);//left leg ++ painter->drawLine(middleX, 2 * thirdH, ++ middleX + A_WIDTH / 2, A_HEIGHT);//right leg ++ painter->drawLine(middleX - A_WIDTH / 2, thirdH + thirdH / 2, ++ middleX + A_WIDTH / 2, thirdH + thirdH / 2);//arms ++ //draw text ++ painter->setPen(textColor()); ++ QString t = m_instanceName + QLatin1String(" : ") + name(); ++ painter->drawText(A_MARGIN, textStartY, ++ w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, t); ++} ++ ++/** ++ * Move the object up on a sequence diagram. ++ */ ++void ObjectWidget::tabUp() ++{ ++ int newY = y() - height(); ++ if (newY < topMargin()) ++ newY = topMargin(); ++ setY(newY); ++ adjustAssocs(x(), newY); ++} ++ ++/** ++ * Move the object down on a sequence diagram. ++ */ ++void ObjectWidget::tabDown() ++{ ++ int newY = y() + height(); ++ setY(newY); ++ adjustAssocs(x(), newY); ++} ++ ++/** ++ * Returns the top margin constant (Y axis value) ++ * ++ * @return Y coordinate of the space between the diagram top ++ * and the upper edge of the ObjectWidget. ++ */ ++int ObjectWidget::topMargin() ++{ ++ return 80 - height(); ++} ++ ++/** ++ * Returns whether or not the widget can be moved vertically up. ++ * ++ * @return True if widget can be moved upwards vertically. ++ */ ++bool ObjectWidget::canTabUp() ++{ ++ return (y() > topMargin()); ++} ++ ++/** ++ * Sets whether to show deconstruction on sequence line. ++ * ++ * @param bShow True if destruction on line shall be shown. ++ */ ++void ObjectWidget::setShowDestruction(bool bShow) ++{ ++ m_showDestruction = bShow; ++ if(m_pLine) ++ m_pLine->setupDestructionBox(); ++} ++ ++/** ++ * Returns whether to show deconstruction on sequence line. ++ * ++ * @return True if destruction on sequence line is shown. ++ */ ++bool ObjectWidget::showDestruction() const ++{ ++ return m_showDestruction; ++} ++ ++/** ++ * Sets the y position of the bottom of the vertical line. ++ * ++ * @param yPosition The y coordinate for the bottom of the line. ++ */ ++void ObjectWidget::setEndLine(int yPosition) ++{ ++ if (m_pLine) { ++ m_pLine->setEndOfLine(yPosition); ++ } ++} ++ ++/** ++ * Returns the end Y co-ord of the sequence line. ++ * ++ * @return Y coordinate of the endpoint of the sequence line. ++ */ ++int ObjectWidget::getEndLineY() ++{ ++ int y = this->y() + height(); ++ if(m_pLine) ++ y += m_pLine->getLineLength(); ++ if (m_showDestruction) ++ y += 10; ++ return y; ++} ++ ++/** ++ * Add a message widget to the list. ++ * ++ * @param message Pointer to the MessageWidget to add. ++ */ ++void ObjectWidget::messageAdded(MessageWidget* message) ++{ ++ if (m_messages.count(message)) { ++ uError() << message->name() << ": duplicate entry !"; ++ return ; ++ } ++ m_messages.append(message); ++} ++ ++/** ++ * Remove a message widget from the list. ++ * ++ * @param message Pointer to the MessageWidget to remove. ++ */ ++void ObjectWidget::messageRemoved(MessageWidget* message) ++{ ++ if (m_messages.removeAll(message) == false) { ++ uError() << message->name() << ": missing entry !"; ++ return ; ++ } ++} ++ ++/** ++ * Called when a message widget with an end on this object has ++ * moved up or down. ++ * Sets the bottom of the line to a nice position. ++ */ ++void ObjectWidget::slotMessageMoved() ++{ ++ if (m_pLine) { ++ int lowestMessage = 0; ++ foreach (MessageWidget* message, m_messages) { ++ int messageHeight = message->y() + message->height(); ++ if (lowestMessage < messageHeight) { ++ lowestMessage = messageHeight; ++ } ++ } ++ m_pLine->setEndOfLine(lowestMessage + sequenceLineMargin); ++ } ++} ++ ++/** ++ * Returns whether a message is overlapping with another message. ++ * Used by MessageWidget::paint() methods. ++ * ++ * @param y top of your message ++ * @param messageWidget pointer to your message so it doesn't check against itself ++ */ ++bool ObjectWidget::messageOverlap(qreal y, MessageWidget* messageWidget) ++{ ++ foreach (MessageWidget* message, m_messages) { ++ if (message == messageWidget) { ++ continue; ++ } ++ const qreal msgY = message->y(); ++ const qreal msgHeight = msgY + message->height(); ++ if (y >= msgY && y <= msgHeight) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++/** ++ * Return the SeqLineWidget. ++ * Returns a non NULL pointer if this ObjectWidget is part of a ++ * sequence diagram. ++ */ ++SeqLineWidget *ObjectWidget::sequentialLine() const ++{ ++ return m_pLine; ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Returns the cursor to be shown when resizing the widget. ++ * The cursor shown is KCursor::sizeHorCursor(). ++ * ++ * @return The cursor to be shown when resizing the widget. ++ */ ++QCursor ObjectWidget::resizeCursor() const ++{ ++ return Qt::SizeHorCursor; ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Resizes the width of the object widget. ++ * Object widgets can only be resized horizontally, so height isn't modified. ++ * ++ * @param newW The new width for the widget. ++ * @param newH The new height for the widget (isn't used). ++ */ ++void ObjectWidget::resizeWidget(qreal newW, qreal newH) ++{ ++ Q_UNUSED(newH); ++ setSize(newW, height()); ++} ++ ++/** ++ * Saves to the "objectwidget" XMI element. ++ */ ++void ObjectWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement objectElement = qDoc.createElement(QLatin1String("objectwidget")); ++ UMLWidget::saveToXMI(qDoc, objectElement); ++ objectElement.setAttribute(QLatin1String("drawasactor"), m_drawAsActor); ++ objectElement.setAttribute(QLatin1String("multipleinstance"), m_multipleInstance); ++ objectElement.setAttribute(QLatin1String("decon"), m_showDestruction); ++ qElement.appendChild(objectElement); ++} ++ ++/** ++ * Loads from a "objectwidget" XMI element. ++ */ ++bool ObjectWidget::loadFromXMI(QDomElement& qElement) ++{ ++ if(!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ QString draw = qElement.attribute(QLatin1String("drawasactor"), QLatin1String("0")); ++ QString multi = qElement.attribute(QLatin1String("multipleinstance"), QLatin1String("0")); ++ QString decon = qElement.attribute(QLatin1String("decon"), QLatin1String("0")); ++ ++ m_drawAsActor = (bool)draw.toInt(); ++ m_multipleInstance = (bool)multi.toInt(); ++ m_showDestruction = (bool)decon.toInt(); ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,115 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef OBJECTWIDGET_H ++#define OBJECTWIDGET_H ++ ++#include "messagewidgetlist.h" ++#include "umlwidget.h" ++ ++class MessageWidget; ++class SeqLineWidget; ++class UMLScene; ++ ++/** ++ * Displays an instance UMLObject of a concept. ++ * ++ * The local ID is needed as a it can represent a class ++ * that has many objects representing it. ++ * ++ * @short Displays an instance of a Concept. ++ * @author Paul Hensgen ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class ObjectWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ ObjectWidget(UMLScene *scene, UMLObject *o); ++ virtual ~ObjectWidget(); ++ ++ virtual void setX(qreal x); ++ virtual void setY(qreal y); ++ ++ qreal centerX(); ++ ++ void setMultipleInstance(bool multiple); ++ bool multipleInstance() const; ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ bool activate(IDChangeLog* ChangeLog = 0); ++ ++ void cleanup(); ++ ++ void showPropertiesDialog(); ++ ++ void setDrawAsActor(bool drawAsActor); ++ bool drawAsActor() const; ++ ++ void setShowDestruction(bool bShow); ++ bool showDestruction() const; ++ ++ int topMargin(); ++ ++ void setEndLine(int yPosition); ++ int getEndLineY(); ++ ++ void messageAdded(MessageWidget* message); ++ void messageRemoved(MessageWidget* message); ++ ++ bool canTabUp(); ++ ++ bool messageOverlap(qreal y, MessageWidget* messageWidget); ++ ++ SeqLineWidget *sequentialLine() const; ++ ++ virtual void resizeWidget(qreal newW, qreal newH); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ virtual bool loadFromXMI(QDomElement& qElement); ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ virtual void slotFillColorChanged(Uml::ID::Type viewID); ++ void slotMessageMoved(); ++ ++protected: ++ virtual void mousePressEvent(QGraphicsSceneMouseEvent *me); ++ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *me); ++ ++ QSizeF minimumSize() const; ++ ++ virtual void moveEvent(QGraphicsSceneMouseEvent *event); ++ virtual void moveWidgetBy(qreal diffX, qreal diffY); ++ virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); ++ ++ virtual QCursor resizeCursor() const; ++ ++ void paintActor(QPainter *p); ++ void paintObject(QPainter *p); ++ ++private: ++ void tabUp(); ++ void tabDown(); ++ ++ void moveDestructionBy(qreal diffY); ++ ++ SeqLineWidget* m_pLine; ++ bool m_multipleInstance; ///< draw an object as a multiple object ++ bool m_drawAsActor; ///< object should be drawn as an Actor or an Object ++ bool m_showDestruction; ///< show object destruction on sequence diagram line ++ bool m_isOnDestructionBox; ///< true when a click occurred on the destruction box ++ MessageWidgetList m_messages; ///< message widgets with an end on this widget ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,149 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "packagewidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "package.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlobject.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++// qt includes ++#include ++ ++/** ++ * Constructs a PackageWidget. ++ * ++ * @param scene The parent of this PackageWidget. ++ * @param o The UMLObject this will be representing. ++ */ ++PackageWidget::PackageWidget(UMLScene * scene, UMLPackage *o) ++ : UMLWidget(scene, WidgetBase::wt_Package, o), ++ m_pMenu(0) ++{ ++ setSize(100, 30); ++ setZValue(1); // above box but below UMLWidget because may embed widgets ++ //set defaults from m_scene ++ if (m_scene) { ++ //check to see if correct ++ const Settings::OptionState& ops = m_scene->optionState(); ++ m_showStereotype = ops.classState.showStereoType; ++ } ++} ++ ++/** ++ * Destructor. ++ */ ++PackageWidget::~PackageWidget() ++{ ++} ++ ++/** ++ * Overrides standard method. ++ */ ++void PackageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ else ++ painter->setBrush(m_scene->backgroundColor()); ++ ++ int w = width(); ++ int h = height(); ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ //FIXME italic is true when a package is first created until you click elsewhere, not sure why ++ font.setItalic(false); ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ ++ painter->drawRect(0, 0, 50, fontHeight); ++ if (m_umlObject != NULL ++ && m_umlObject->stereotype() == QLatin1String("subsystem")) { ++ ++ const int fHalf = fontHeight / 2; ++ const int symY = fHalf; ++ const int symX = 38; ++ painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg ++ painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg ++ painter->drawLine(symX, symY, symX + 8, symY); // waist ++ painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head ++ } ++ painter->drawRect(0, fontHeight - 1, w, h - fontHeight); ++ ++ painter->setPen(textColor()); ++ painter->setFont(font); ++ ++ int lines = 1; ++ if (m_umlObject != NULL) { ++ QString stereotype = m_umlObject->stereotype(); ++ if (!stereotype.isEmpty()) { ++ painter->drawText(0, fontHeight + PACKAGE_MARGIN, ++ w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); ++ lines = 2; ++ } ++ } ++ ++ painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, ++ w, fontHeight, Qt::AlignCenter, name()); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF PackageWidget::minimumSize() const ++{ ++ if (!m_umlObject) { ++ return UMLWidget::minimumSize(); ++ } ++ ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); ++ const int fontHeight = fm.lineSpacing(); ++ ++ int lines = 1; ++ ++ int width = fm.width(m_umlObject->name()); ++ ++ int tempWidth = 0; ++ if (!m_umlObject->stereotype().isEmpty()) { ++ tempWidth = fm.width(m_umlObject->stereotype(true)); ++ lines = 2; ++ } ++ if (tempWidth > width) ++ width = tempWidth; ++ width += PACKAGE_MARGIN * 2; ++ if (width < 70) ++ width = 70; // minumin width of 70 ++ ++ int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Saves to the "packagewidget" XMI element. ++ */ ++void PackageWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement conceptElement = qDoc.createElement(QLatin1String("packagewidget")); ++ UMLWidget::saveToXMI(qDoc, conceptElement); ++ qElement.appendChild(conceptElement); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,47 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PACKAGEWIDGET_H ++#define PACKAGEWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLPackage; ++class ListPopupMenu; ++ ++#define PACKAGE_MARGIN 5 ++ ++/** ++ * Defines a graphical version of the Package. Most of the ++ * functionality will come from the @ref UMLPackage class. ++ * ++ * @short A graphical version of a Package. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class PackageWidget : public UMLWidget ++{ ++public: ++ explicit PackageWidget(UMLScene * scene, UMLPackage * o); ++ virtual ~PackageWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++private: ++ ListPopupMenu* m_pMenu; ///< the right mouse button menu ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,378 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "pinportbase.h" ++ ++// app includes ++#include "port.h" ++#include "package.h" ++#include "debug_utils.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "floatingtextwidget.h" ++ ++// qt includes ++#include ++#include ++ ++// sys includes ++#include ++ ++PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o) ++ : UMLWidget(scene, type, o) ++{ ++ init(); ++} ++ ++PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id) ++ : UMLWidget(scene, type, id) ++{ ++ init(a); ++} ++ ++/** ++ * Standard destructor. ++ */ ++PinPortBase::~PinPortBase() ++{ ++} ++ ++/** ++ * Performs initializations which are common to PinWidget and PortWidget. ++ */ ++void PinPortBase::init(UMLWidget *owner) ++{ ++ m_ignoreSnapToGrid = true; ++ m_ignoreSnapComponentSizeToGrid = true; ++ m_resizable = false; ++ m_pOw = owner; ++ m_pName = NULL; ++ m_motionConnected = false; ++ const int edgeLength = 15; // old: (m_baseType == wt_Pin ? 10 : 15); ++ const QSizeF FixedSize(edgeLength, edgeLength); ++ setMinimumSize(FixedSize); ++ setMaximumSize(FixedSize); ++ setSize(FixedSize); ++} ++ ++UMLWidget* PinPortBase::ownerWidget() ++{ ++ return m_pOw; ++} ++ ++/** ++ * Overrides method from UMLWidget in order to set a tooltip. ++ * The tooltip is set to the name(). ++ * The reason for using a tooltip for the name is that the size of this ++ * widget is not large enough to accommodate the average name. ++ */ ++void PinPortBase::updateWidget() ++{ ++ QString strName = name(); ++ uDebug() << " port name is " << strName; ++ if (m_pName) { ++ m_pName->setText(strName); ++ } else { ++ setToolTip(strName); ++ } ++} ++ ++/** ++ * Overrides method from UMLWidget to set the name. ++ */ ++void PinPortBase::setName(const QString &strName) ++{ ++ UMLWidget::setName(strName); ++ updateGeometry(); ++ if (m_pName) { ++ m_pName->setText(strName); ++ } ++} ++ ++/** ++ * Overridden from UMLWidget. ++ * Moves the widget to a new position using the difference between the ++ * current position and the new position. ++ * Movement is constrained such that the port is always attached to its ++ * owner widget. ++ * ++ * @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 PinPortBase::moveWidgetBy(qreal diffX, qreal diffY) ++{ ++ UMLWidget* owner = ownerWidget(); ++ qreal newX = x() + diffX; ++ qreal newY = y() + diffY; ++ uDebug() << "PinPortBase::moveWidgetBy " << diffX << "," << diffY; ++ if (owner == NULL) { ++ uError() << "PinPortBase::moveWidgetBy: ownerWidget() returns NULL"; ++ setX(newX); ++ setY(newY); ++ return; ++ } ++ const qreal deltaTop = fabs(y() + height() - owner->y()); ++ const qreal deltaBottom = fabs(owner->y() + owner->height() - y()); ++ const qreal deltaLeft = fabs(x() + width() - owner->x()); ++ const qreal deltaRight = fabs(owner->x() + owner->width() - x()); ++ bool didAnyMovement = false; ++ if (deltaTop < 1.0 || deltaBottom < 1.0) { ++ if (newX < owner->x() - width()) ++ newX = owner->x() - width(); ++ else if (newX > owner->x() + owner->width()) ++ newX = owner->x() + owner->width(); ++ setX(newX); ++ didAnyMovement = true; ++ } ++ if (deltaLeft < 1.0 || deltaRight < 1.0) { ++ if (newY < owner->y() - height()) ++ newY = owner->y() - height(); ++ else if (newY > owner->y() + owner->height()) ++ newY = owner->y() + owner->height(); ++ setY(newY); ++ didAnyMovement = true; ++ } ++ if (!didAnyMovement) { ++ uDebug() << "constraint failed for (" << diffX << ", " << diffY << ")"; ++ setX(newX); ++ setY(newY); ++ } ++} ++ ++/** ++ * Align this widget's position such that it is attached at one of the ++ * sides of its owner's widget. ++ */ ++void PinPortBase::attachToOwner() { ++ UMLWidget *owner = ownerWidget(); ++ const QPointF scenePos = m_scene->pos(); ++ if (owner == NULL) { ++ uError() << "PinPortBase::attachToOwner: ownerWidget() returns NULL"; ++ setX(scenePos.x()); ++ setY(scenePos.y()); ++ return; ++ } ++ bool xIsWithinOwner = false; ++ if (scenePos.x() < owner->x() - width()) { ++ setX(owner->x() - width()); ++ } else if (scenePos.x() <= owner->x() + owner->width()) { ++ setX(scenePos.x()); ++ xIsWithinOwner = true; ++ } else { ++ setX(owner->x() + owner->width()); ++ } ++ if (scenePos.y() < owner->y() - height()) { ++ setY(owner->y() - height()); ++ } else if (scenePos.y() <= owner->y() + owner->height()) { ++ if (xIsWithinOwner) { ++ if (scenePos.y() <= owner->y() + owner->height() / 2.0) ++ setY(owner->y() - height()); ++ else ++ setY(owner->y() + owner->height()); ++ } else { ++ setY(scenePos.y()); ++ } ++ } else { ++ setY(owner->y() + owner->height()); ++ } ++ ++ if (m_motionConnected) { ++ uDebug() << "connectOwnerMotion was already done"; ++ } else { ++ connectOwnerMotion(); ++ m_motionConnected = true; ++ } ++} ++ ++/** ++ * Overrides standard method. ++ */ ++void PinPortBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } else { ++ painter->setBrush(m_scene->backgroundColor()); ++ } ++ ++ int w = width(); ++ int h = height(); ++ ++ painter->drawRect(0, 0, w, h); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++void PinPortBase::slotOwnerMoved(qreal diffX, qreal diffY) ++{ ++ setX(x() + diffX); ++ setY(y() + diffY); ++} ++ ++/** ++ * Captures any popup menu signals for menus it created. ++ */ ++void PinPortBase::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_NameAsTooltip: ++ if (m_pName) { ++ action->setChecked(true); ++ delete m_pName; ++ m_pName = NULL; ++ setToolTip(name()); ++ } else { ++ action->setChecked(false); ++ 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(); ++ UMLWidget* owner = ownerWidget(); ++ if (owner == NULL) { ++ uError() << "PinPortBase::slotMenuSelection: ownerWidget() returns NULL"; ++ setX(x()); ++ setY(y()); ++ } else { ++ const qreal w = width(); ++ const qreal h = height(); ++ if (x() < owner->x()) ++ m_pName->setX(-m_pName->width()); ++ else if (x() >= owner->x() + owner->width()) ++ m_pName->setX(w); ++ else ++ m_pName->setX(-m_pName->width() / 2.0 + w / 2.0); ++ if (y() < owner->y()) ++ m_pName->setY(-m_pName->height() - 2); ++ else if (y() >= owner->y() + owner->height()) ++ m_pName->setY(h); ++ else ++ m_pName->setY(-m_pName->height() / 2.0 + h / 2.0); ++ } ++ m_pName->update(); ++ setToolTip(QString()); ++ QToolTip::hideText(); ++ } ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++FloatingTextWidget *PinPortBase::floatingTextWidget() { ++ return m_pName; ++} ++ ++void PinPortBase::setFloatingTextWidget(FloatingTextWidget *ft) { ++ m_pName = ft; ++ if (m_pName) ++ m_pName->setParentItem(this); ++} ++ ++/** ++ * Override method from UMLWidget in order to additionally check m_pName. ++ * ++ * @param p Point to be checked. ++ * ++ * @return 'this' if UMLWidget::onWidget(p) returns non NULL; ++ * m_pName if m_pName is non NULL and m_pName->onWidget(p) returns non NULL; ++ * else NULL. ++ */ ++UMLWidget* PinPortBase::onWidget(const QPointF &p) ++{ ++ if (UMLWidget::onWidget(p) != NULL) ++ return this; ++ if (m_pName) { ++ uDebug() << "floatingtext: " << m_pName->text(); ++ return m_pName->onWidget(p); ++ } ++ return NULL; ++} ++ ++/** ++ * Reimplement function from UMLWidget ++ */ ++UMLWidget* PinPortBase::widgetWithID(Uml::ID::Type id) ++{ ++ if (UMLWidget::widgetWithID(id)) ++ return this; ++ if (m_pName && m_pName->widgetWithID(id)) ++ return m_pName; ++ return NULL; ++} ++ ++ ++/** ++ * Saves the widget to the "pinwidget" or "portwidget" XMI element. ++ */ ++void PinPortBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement element = qDoc.createElement(m_baseType == wt_Pin ? QLatin1String("pinwidget") ++ : QLatin1String("portwidget")); ++ element.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(ownerWidget()->id())); ++ UMLWidget::saveToXMI(qDoc, element); ++ if (m_pName && !m_pName->text().isEmpty()) { ++ m_pName->saveToXMI(qDoc, element); ++ } ++ qElement.appendChild(element); ++} ++ ++/** ++ * Loads from a "pinwidget" or from a "portwidget" XMI element. ++ */ ++bool PinPortBase::loadFromXMI(QDomElement & qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ ++ QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); ++ Uml::ID::Type aId = Uml::ID::fromString(widgetaid); ++ UMLWidget *owner = m_scene->findWidget(aId); ++ if (owner == NULL) { ++ DEBUG(DBG_SRC) << "owner object " << Uml::ID::toString(aId) << " not found"; ++ return false; ++ } ++ m_pOw = owner; ++ ++ // Optional child element: floatingtext ++ QDomNode node = qElement.firstChild(); ++ QDomElement element = node.toElement(); ++ if (!element.isNull()) { ++ QString tag = element.tagName(); ++ if (tag == QLatin1String("floatingtext")) { ++ m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, ++ name(), Uml::ID::Reserved); ++ if (!m_pName->loadFromXMI(element)) { ++ // Most likely cause: The FloatingTextWidget is empty. ++ delete m_pName; ++ m_pName = NULL; ++ } else { ++ m_pName->setParentItem(this); ++ m_pName->activate(); ++ m_pName->update(); ++ } ++ } else { ++ uError() << "unknown tag " << tag; ++ } ++ } ++ ++ if (m_motionConnected) { ++ uDebug() << "connectOwnerMotion was already done"; ++ } else { ++ connectOwnerMotion(); ++ m_motionConnected = true; ++ } ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.h umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +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) 2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PINPORTBASE_H ++#define PINPORTBASE_H ++ ++#include "umlwidget.h" ++ ++class FloatingTextWidget; ++ ++/** ++ * @short Abstract base class for PinWidget and PortWidget ++ * @author Oliver Kellogg ++ * @see UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class PinPortBase : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o); ++ PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id = Uml::ID::None); ++ virtual ~PinPortBase(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ virtual UMLWidget* ownerWidget(); ++ virtual void connectOwnerMotion() = 0; ++ ++ void setName(const QString &strName); ++ void updateWidget(); ++ void moveWidgetBy(qreal diffX, qreal diffY); ++ void attachToOwner(); ++ ++ UMLWidget* onWidget(const QPointF& p); ++ UMLWidget* widgetWithID(Uml::ID::Type id); ++ ++ FloatingTextWidget *floatingTextWidget(); ++ void setFloatingTextWidget(FloatingTextWidget *ft); ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ bool loadFromXMI(QDomElement& qElement); ++ ++public slots: ++ void slotOwnerMoved(qreal diffX, qreal diffY); ++ virtual void slotMenuSelection(QAction* action); ++ ++protected: ++ void init(UMLWidget *owner = 0); ++ ++ UMLWidget* m_pOw; ++ FloatingTextWidget *m_pName; ++ bool m_motionConnected; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,103 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "pinwidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "floatingtextwidget.h" ++#include "listpopupmenu.h" ++#include "umlscene.h" ++#include "activitywidget.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++ ++DEBUG_REGISTER_DISABLED(PinWidget) ++ ++/** ++ * Creates a Pin widget. ++ * ++ * @param scene The parent of the widget. ++ * @param a 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* a, Uml::ID::Type id) ++ : PinPortBase(scene, WidgetBase::wt_Pin, a, 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() ++{ ++} ++ ++/** ++ * Implement abstract function from PinPortWidget. ++ */ ++void PinWidget::connectOwnerMotion() ++{ ++ ActivityWidget *owner = static_cast(ownerWidget()); ++ connect(owner, SIGNAL(sigActMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); ++} ++ ++/** ++ * 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: ++ { ++ bool ok = false; ++ QString name = m_Text; ++#if QT_VERSION >= 0x050000 ++ name = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter Pin Name"), ++ i18n("Enter the pin name :"), ++ QLineEdit::Normal, ++ m_Text, &ok); ++#else ++ name = KInputDialog::getText(i18n("Enter Pin Name"), ++ i18n("Enter the pin name :"), ++ m_Text, &ok); ++#endif ++ if (ok) { ++ setName(name); ++ } ++ } ++ break; ++ ++ default: ++ PinPortBase::slotMenuSelection(action); ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,46 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PINWIDGET_H ++#define PINWIDGET_H ++ ++#include "pinportbase.h" ++ ++/** ++ * This class is the graphical version of a UML Pin. A pinWidget is created ++ * by a @ref UMLView. An pinWidget belongs to only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. ++ * ++ * The pinWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @short A graphical version of a UML pin. ++ * @author Hassan KOUCH ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class PinWidget : public PinPortBase ++{ ++ Q_OBJECT ++public: ++ ++ PinWidget(UMLScene* scene, UMLWidget* a, Uml::ID::Type id = Uml::ID::None); ++ virtual ~PinWidget(); ++ ++ void connectOwnerMotion(); ++ // int getMinY(); ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ ++// private: ++ // int m_nY; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,106 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "portwidget.h" ++ ++// app includes ++#include "port.h" ++#include "package.h" ++#include "debug_utils.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "componentwidget.h" ++#include "floatingtextwidget.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#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) ++ : PinPortBase(scene, WidgetBase::wt_Port, d) ++{ ++ setToolTip(d->name()); ++} ++ ++/** ++ * Standard deconstructor. ++ */ ++PortWidget::~PortWidget() ++{ ++} ++ ++/** ++ * Override function from PinPortWidget. ++ */ ++UMLWidget* PortWidget::ownerWidget() ++{ ++ if (m_pOw == NULL) { ++ const Uml::ID::Type compWidgetId = m_umlObject->umlPackage()->id(); ++ m_pOw = m_scene->widgetOnDiagram(compWidgetId); ++ } ++ return m_pOw; ++} ++ ++/** ++ * Implement abstract function from PinPortWidget. ++ */ ++void PortWidget::connectOwnerMotion() ++{ ++ ComponentWidget *owner = static_cast(ownerWidget()); ++ connect(owner, SIGNAL(sigCompMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); ++} ++ ++/** ++ * 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: ++ { ++ bool ok = false; ++ QString newName; ++#if QT_VERSION >= 0x050000 ++ newName = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter Port Name"), i18n("Enter the port name :"), ++ QLineEdit::Normal, ++ name(), &ok); ++#else ++ newName = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port name :"), ++ name(), &ok); ++#endif ++ if (ok) { ++ setName(newName); ++ } ++ } ++ break; ++ ++ default: ++ PinPortBase::slotMenuSelection(action); ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,42 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PORTWIDGET_H ++#define PORTWIDGET_H ++ ++#include "pinportbase.h" ++ ++class UMLPort; ++ ++/** ++ * Defines a graphical version of the UML2 port. Most of the functionality ++ * comes from the @ref PinPortBase class from which this class inherits. ++ * ++ * @short A graphical version of a port on a component. ++ * @author Oliver Kellogg ++ * @see PinPortBase, UMLWidget ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class PortWidget : public PinPortBase ++{ ++ Q_OBJECT ++public: ++ PortWidget(UMLScene *scene, UMLPort *d); ++ virtual ~PortWidget(); ++ ++ UMLWidget* ownerWidget(); ++ void connectOwnerMotion(); ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,335 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "preconditionwidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "listpopupmenu.h" ++#include "objectwidget.h" ++#include "uml.h" ++#include "umlscene.h" ++#include "uniqueid.h" ++#include "idchangelog.h" ++ ++// kde includes ++#if QT_VERSION < 0x050000 ++#include ++#endif ++#include ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#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->resetPastep-kf6oint(); ++ 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: ++ { ++ bool ok = false; ++ QString text = name(); ++#if QT_VERSION >= 0x050000 ++ text = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter Precondition Name"), ++ i18n("Enter the precondition :"), ++ QLineEdit::Normal, ++ text, &ok); ++#else ++ text = KInputDialog::getText(i18n("Enter Precondition Name"), ++ i18n("Enter the precondition :"), ++ text, &ok); ++#endif ++ if (ok && !text.isEmpty()) { ++ setName(text); ++ } ++ calculateWidget(); ++ } ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Saves the widget to the "preconditionwidget" XMI element. ++ */ ++void PreconditionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement preconditionElement = qDoc.createElement(QLatin1String("preconditionwidget")); ++ UMLWidget::saveToXMI(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::loadFromXMI(QDomElement& qElement) ++{ ++ if(!UMLWidget::loadFromXMI(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 loadFromXMI() 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,70 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef PRECONDITIONWIDGET_H ++#define PRECONDITIONWIDGET_H ++ ++#include "umlwidget.h" ++ ++class ObjectWidget; ++ ++/** ++ * @short A graphical version of a UML Precondition (new in UML 2.0). ++ * ++ * This class is the graphical version of a UML Precondition. A PreconditionWidget is created ++ * by a @ref UMLView. An PreconditionWidget belongs to only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. ++ * ++ * The PreconditionWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @author Florence Mattler ++ * ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class PreconditionWidget : public UMLWidget ++{ ++ Q_OBJECT ++public: ++ PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id = Uml::ID::None); ++ virtual ~PreconditionWidget(); ++ ++ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ int minY() const; ++ int maxY() const; ++ ++ bool activate(IDChangeLog* Log = 0); ++ void resolveObjectWidget(IDChangeLog* log); ++ ++ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ virtual bool loadFromXMI(QDomElement& qElement); ++ ++ void setObjectWidget(ObjectWidget* widget); ++ ++public slots: ++ void slotMenuSelection(QAction* action); ++ void slotWidgetMoved(Uml::ID::Type id); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++private: ++ void calculateWidget(); ++ void calculateDimensions(); ++ ++ ObjectWidget* m_objectWidget; ++ int m_nY; ++ ++ Uml::ID::Type m_widgetAId; ++ void loadObjectWidget(); ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.cpp 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,108 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "regionwidget.h" ++ ++// app includes ++#include "basictypes.h" ++#include "debug_utils.h" ++ ++// kde includes ++#include ++ ++#define REGION_MARGIN 5 ++#define REGION_WIDTH 90 ++#define REGION_HEIGHT 45 ++ ++/** ++ * Creates a Region widget. ++ * ++ * @param scene The parent of the widget. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++RegionWidget::RegionWidget(UMLScene* scene, Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_Region, id) ++{ ++} ++ ++/** ++ * Destructor. ++ */ ++RegionWidget::~RegionWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void RegionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ const int w = width(); ++ const int h = height(); ++ ++ setPenFromSettings(painter); ++ QPen pen = painter->pen(); ++ pen.setColor(Qt::red); ++ pen.setStyle(Qt::DashLine); ++ painter->setPen(pen); ++ painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF RegionWidget::minimumSize() const ++{ ++ int width = 10, height = 10; ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ int textWidth = fm.width(name()); ++ ++ height = fontHeight; ++ width = textWidth > REGION_WIDTH?textWidth:REGION_WIDTH; ++ height = height > REGION_HEIGHT ? height : REGION_HEIGHT; ++ width += REGION_MARGIN * 2; ++ height += REGION_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Saves region widget to XMI element. ++ */ ++void RegionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++{ ++ QDomElement regionElement = qDoc.createElement(QLatin1String("regionwidget")); ++ UMLWidget::saveToXMI(qDoc, regionElement); ++ regionElement.setAttribute(QLatin1String("regionname"), name()); ++ regionElement.setAttribute(QLatin1String("documentation"), documentation()); ++ ++ qElement.appendChild(regionElement); ++} ++ ++/** ++ * Loads region widget from XMI element. ++ */ ++bool RegionWidget::loadFromXMI(QDomElement& qElement) ++{ ++ if (!UMLWidget::loadFromXMI(qElement)) { ++ return false; ++ } ++ setName(qElement.attribute(QLatin1String("regionname"))); ++ setDocumentation(qElement.attribute(QLatin1String("documentation"))); ++ return true; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.h 2015-10-08 11:48:59.509089026 +0300 +@@ -0,0 +1,36 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++***************************************************************************/ ++ ++#ifndef REGIONWIDGET_H ++#define REGIONWIDGET_H ++ ++#include "umlwidget.h" ++ ++/** ++ * Represents a rectangular region on Activity diagram. ++ */ ++class RegionWidget: public UMLWidget ++{ ++ Q_OBJECT ++public: ++ explicit RegionWidget(UMLScene* scene, Uml::ID::Type id = Uml::ID::None); ++ virtual ~RegionWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); ++ bool loadFromXMI(QDomElement& qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,197 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "seqlinewidget.h" ++ ++//app includes ++#include "messagewidget.h" ++#include "objectwidget.h" ++#include "umlscene.h" ++#include "umlview.h" ++ ++//qt includes ++#include ++ ++// class members ++int const SeqLineWidget::m_nMouseDownEpsilonX = 20; ++ ++/** ++ * Constructor. ++ */ ++SeqLineWidget::SeqLineWidget(UMLScene *scene, ObjectWidget * pObject) ++ : QGraphicsLineItem(), ++ m_scene(scene) ++{ ++ scene->addItem(this); ++ m_pObject = pObject; ++ setPen(QPen(m_pObject->lineColor(), 0, Qt::DashLine)); ++ setZValue(0); ++ setVisible(true); ++ m_DestructionBox.line1 = 0; ++ m_nLengthY = 250; ++ setupDestructionBox(); ++} ++ ++/** ++ * Destructor. ++ */ ++SeqLineWidget::~SeqLineWidget() ++{ ++} ++ ++/** ++ * Return whether point is on sequence line. ++ * Takes into account destruction box if shown. ++ * ++ * @param p The point to investigate. ++ * @return True if point is on this sequence line. ++ */ ++bool SeqLineWidget::onWidget(const QPointF & p) ++{ ++ bool isOnWidget = false; ++ QPointF sp = line().p1(); ++ QPointF ep = line().p2(); ++ //see if on widget (for message creation) ++ if (sp.x() - m_nMouseDownEpsilonX < p.x() ++ && ep.x() + m_nMouseDownEpsilonX > p.x() ++ && sp.y() < p.y() && ep.y() + 3 > p.y()) ++ { ++ isOnWidget = true; ++ } ++ return isOnWidget; ++} ++ ++/** ++ * Return whether point is on the destruction box. ++ * ++ * @param p The point to investigate. ++ * @return True if point is on the destruction box of this sequence line. ++ */ ++bool SeqLineWidget::onDestructionBox(const QPointF & p) ++{ ++ bool isOnDestructionBox = false; ++ int x = m_pObject->x() + m_pObject->width() / 2; ++ int y = m_pObject->y() + m_pObject->height() + m_nLengthY; ++ ++ //see if on destruction box ++ if (!m_pObject->showDestruction()) { ++ return false; ++ } ++ if (x - 10 < p.x() && x + 10 > p.x() ++ && y - 10 < p.y() && y + 10 > p.y()) ++ { ++ isOnDestructionBox = true; ++ } ++ return isOnDestructionBox; ++} ++ ++/** ++ * Clean up anything before deletion. ++ */ ++void SeqLineWidget::cleanup() ++{ ++ cleanupDestructionBox(); ++} ++ ++/** ++ * Set the start point of the line. ++ * ++ * @param startX X coordinate of the start point. ++ * @param startY Y coordinate of the start point. ++ */ ++void SeqLineWidget::setStartPoint(int startX, int startY) ++{ ++ int endX = startX; ++ int endY = startY + m_nLengthY; ++ QGraphicsLineItem::setLine(startX, startY, endX, endY); ++ moveDestructionBox(); ++} ++ ++/** ++ * Clean up destruction box. ++ */ ++void SeqLineWidget::cleanupDestructionBox() ++{ ++ if (m_DestructionBox.line1) { ++ delete m_DestructionBox.line1; ++ m_DestructionBox.line1 = 0; ++ delete m_DestructionBox.line2; ++ m_DestructionBox.line2 = 0; ++ } ++} ++ ++/** ++ * Set up destruction box. ++ */ ++void SeqLineWidget::setupDestructionBox() ++{ ++ cleanupDestructionBox(); ++ if(!m_pObject->showDestruction()) { ++ return; ++ } ++ QRect rect; ++ rect.setX(m_pObject->x() + m_pObject->width() / 2 - 10); ++ rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY); ++ rect.setWidth(14); ++ rect.setHeight(14); ++ ++ m_DestructionBox.line1 = new QGraphicsLineItem; ++ m_scene->addItem(m_DestructionBox.line1); ++ m_DestructionBox.setLine1Points(rect); ++ m_DestructionBox.line1->setVisible(true); ++ m_DestructionBox.line1->setPen(QPen(m_pObject->lineColor(), 2)); ++ m_DestructionBox.line1->setZValue(3); ++ ++ m_DestructionBox.line2 = new QGraphicsLineItem; ++ m_scene->addItem(m_DestructionBox.line2); ++ m_DestructionBox.setLine2Points(rect); ++ m_DestructionBox.line2->setVisible(true); ++ m_DestructionBox.line2->setPen(QPen(m_pObject->lineColor(), 2)); ++ m_DestructionBox.line2->setZValue(3); ++} ++ ++/** ++ * Move destruction box. ++ */ ++void SeqLineWidget::moveDestructionBox() ++{ ++ if(!m_DestructionBox.line1) { ++ return; ++ } ++ QRect rect; ++ rect.setX(m_pObject->x() + m_pObject->width() / 2 - 7); ++ rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY - 7); ++ rect.setWidth(14); ++ rect.setHeight(14); ++ m_DestructionBox.setLine1Points(rect); ++ m_DestructionBox.setLine2Points(rect); ++} ++ ++/** ++ * Sets the y position of the bottom of the vertical line. ++ * ++ * @param yPosition The y coordinate for the bottom of the line. ++ */ ++void SeqLineWidget::setEndOfLine(int yPosition) ++{ ++ QPointF sp = line().p1(); ++ int newY = yPosition; ++ m_nLengthY = yPosition - m_pObject->y() - m_pObject->height(); ++ // normally the managing Objectwidget is responsible for the call of this function ++ // but to be sure - make a double check _against current position_ ++ if (m_nLengthY < 0) { ++ m_nLengthY = 0; ++ newY = m_pObject->y() + m_pObject->height(); ++ } ++ setLine(sp.x(), sp.y(), sp.x(), newY); ++ moveDestructionBox(); ++ m_scene->resizeSceneToItems(); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,86 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef SEQLINEWIDGET_H ++#define SEQLINEWIDGET_H ++ ++#include ++ ++class ObjectWidget; ++class UMLScene; ++ ++/** ++ * @short Widget class for graphical representation of sequence lines ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class SeqLineWidget : public QGraphicsLineItem ++{ ++public: ++ SeqLineWidget(UMLScene *scene, ObjectWidget * pObject); ++ virtual ~SeqLineWidget(); ++ ++ bool onWidget(const QPointF& p); ++ ++ bool onDestructionBox(const QPointF& p); ++ ++ void cleanup(); ++ ++ void setupDestructionBox(); ++ ++ void setStartPoint(int startX, int startY); ++ ++ /** ++ * Gets the length of the line. ++ * ++ * @return Length of the line. ++ */ ++ int getLineLength() { ++ return m_nLengthY; ++ } ++ ++ /** ++ * Returns the @ref ObjectWidget associated with this sequence line. ++ * ++ * @return Pointer to the associated ObjectWidget. ++ */ ++ ObjectWidget * getObjectWidget() { ++ return m_pObject; ++ } ++ ++ void setEndOfLine(int yPosition); ++ ++protected: ++ void cleanupDestructionBox(); ++ ++ void moveDestructionBox(); ++ ++ ObjectWidget* m_pObject; ///< ObjectWidget associated with this sequence line ++ UMLScene* m_scene; ///< scene displayed on ++ ++ struct DestructionBox { ++ QGraphicsLineItem * line1; ++ QGraphicsLineItem * line2; ++ void setLine1Points(QRect rect) { ++ line1->setLine(rect.x(), rect.y(), ++ rect.x() + rect.width(), rect.y() + rect.height()); ++ } ++ void setLine2Points(QRect rect) { ++ line2->setLine(rect.x(), rect.y() + rect.height(), ++ rect.x() + rect.width(), rect.y()); ++ } ++ } m_DestructionBox; ///< the destruction box ++ ++ int m_nLengthY; ///< the length of the line ++ ++ static int const m_nMouseDownEpsilonX; ///< margin used for mouse clicks ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,386 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "signalwidget.h" ++ ++// app includes ++#include "basictypes.h" ++#include "debug_utils.h" ++#include "floatingtextwidget.h" ++#include "linkwidget.h" ++#include "listpopupmenu.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "uniqueid.h" ++#include "umlview.h" ++#include "umlwidget.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#include ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++ ++/** ++ * Creates a Signal widget. ++ * ++ * @param scene The parent of the widget. ++ * @param signalType The type of Signal. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++SignalWidget::SignalWidget(UMLScene *scene, SignalType signalType, Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_Signal, id), ++ m_oldX(0), ++ m_oldY(0) ++{ ++ m_signalType = signalType; ++ m_pName = NULL; ++ if (signalType == SignalWidget::Time) { ++ m_pName = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString()); ++ scene->setupNewWidget(m_pName); ++ m_pName->setX(0); ++ m_pName->setY(0); ++ connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); ++ } ++} ++ ++/** ++ * Destructor. ++ */ ++SignalWidget::~SignalWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void SignalWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ setPenFromSettings(painter); ++ const int w = width(); ++ const int h = height(); ++ QPolygon a; ++ switch (m_signalType) ++ { ++ case Send : ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ { ++ a.setPoints(5, 0, 0, ++ (w*2)/3, 0, ++ w, h/2, ++ (w*2)/3, h, ++ 0, h); ++ painter->drawPolygon(a); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ int textStartY = (h / 2) - (fontHeight / 2); ++ ++ painter->setPen(textColor()); ++ QFont font = UMLWidget::font(); ++ font.setBold(false); ++ painter->setFont(font); ++ painter->drawText(SIGNAL_MARGIN, textStartY, ++ w - SIGNAL_MARGIN * 2, fontHeight, ++ Qt::AlignCenter, name()); ++ setPenFromSettings(painter); ++ } ++ break; ++ case Accept : ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ { ++ a.setPoints(5, 0, 0, ++ w/3, h/2, ++ 0, h, ++ w, h, ++ w, 0); ++ ++ painter->drawPolygon(a); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ int textStartY = (h / 2) - (fontHeight / 2); ++ ++ painter->setPen(textColor()); ++ QFont font = UMLWidget::font(); ++ font.setBold(false); ++ painter->setFont(font); ++ painter->drawText(SIGNAL_MARGIN, textStartY, ++ w - SIGNAL_MARGIN * 2 + (w/3), fontHeight, ++ Qt::AlignCenter, name()); ++ setPenFromSettings(painter); ++ } ++ break; ++ case Time : ++ if(UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ { ++ a.setPoints(4, 0, 0, ++ w, h, ++ 0, h, ++ w, 0); ++ ++ painter->drawPolygon(a); ++ //const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ //const int fontHeight = fm.lineSpacing(); ++ //int textStartY = (h / 2) - (fontHeight / 2); ++ painter->setPen(textColor()); ++ QFont font = UMLWidget::font(); ++ font.setBold(false); ++ painter->setFont(font); ++ ++ setPenFromSettings(painter); ++ } ++ 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(); ++ } ++ ++ break; ++ default: ++ uWarning() << "Unknown signal type:" << m_signalType; ++ break; ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides the UMLWidget method. ++ */ ++void SignalWidget::setX(qreal newX) ++{ ++ m_oldX = x(); ++ UMLWidget::setX(newX); ++} ++ ++/** ++ * Overrides the UMLWidget method. ++ */ ++void SignalWidget::setY(qreal newY) ++{ ++ m_oldY = y(); ++ UMLWidget::setY(newY); ++} ++ ++/** ++ * Sets the name of the signal. ++ */ ++void SignalWidget::setName(const QString &strName) ++{ ++ UMLWidget::setName(strName); ++ updateGeometry(); ++ if (signalType() == SignalWidget::Time) { ++ 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); ++ connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); ++ } ++ else ++ m_pName->setText(m_Text); ++ } ++} ++ ++/** ++ * Returns the type of Signal. ++ */ ++SignalWidget::SignalType SignalWidget::signalType() const ++{ ++ return m_signalType; ++} ++ ++/** ++ * Returns the type string of Signal. ++ */ ++QString SignalWidget::signalTypeStr() const ++{ ++ return QLatin1String(ENUM_NAME(SignalWidget, SignalType, m_signalType)); ++} ++ ++/** ++ * Sets the type of Signal. ++ */ ++void SignalWidget::setSignalType(SignalType signalType) ++{ ++ m_signalType = signalType; ++} ++ ++/** ++ * Show a properties dialog for a UMLWidget. ++ */ ++void SignalWidget::showPropertiesDialog() ++{ ++} ++ ++/** ++ * Overrides mouseMoveEvent. ++ */ ++void SignalWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) ++{ ++ UMLWidget::mouseMoveEvent(me); ++ int diffX = m_oldX - x(); ++ int diffY = m_oldY - y(); ++ if (m_pName!=NULL) { ++ m_pName->setX(m_pName->x() - diffX); ++ m_pName->setY(m_pName->y() - diffY); ++ } ++} ++ ++/** ++ * Loads a "signalwidget" XMI element. ++ */ ++bool SignalWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if(!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ m_Text = qElement.attribute(QLatin1String("signalname")); ++ m_Doc = qElement.attribute(QLatin1String("documentation")); ++ QString type = qElement.attribute(QLatin1String("signaltype")); ++ QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); ++ Uml::ID::Type textId = Uml::ID::fromString(textid); ++ ++ setSignalType((SignalType)type.toInt()); ++ if (signalType() == Time) { ++ ++ if (textId != Uml::ID::None) { ++ UMLWidget *flotext = m_scene -> findWidget(textId); ++ if (flotext != NULL) { ++ // This only happens when loading files produced by ++ // umbrello-kf6-1.3-beta2. ++ m_pName = static_cast(flotext); ++ return true; ++ } ++ } else { ++ // no textid stored -> get unique new one ++ textId = UniqueID::gen(); ++ } ++ } ++ //now load child elements ++ QDomNode node = qElement.firstChild(); ++ QDomElement element = node.toElement(); ++ if (!element.isNull()) { ++ QString tag = element.tagName(); ++ if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { ++ m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, m_Text, textId); ++ if(! m_pName->loadFromXMI(element)) { ++ // Most likely cause: The FloatingTextWidget is empty. ++ delete m_pName; ++ m_pName = NULL; ++ } ++ else ++ connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); ++ } else { ++ uError() << "unknown tag " << tag; ++ } ++ } ++ return true; ++} ++ ++/** ++ * Creates the "signalwidget" XMI element. ++ */ ++void SignalWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement signalElement = qDoc.createElement(QLatin1String("signalwidget")); ++ UMLWidget::saveToXMI(qDoc, signalElement); ++ signalElement.setAttribute(QLatin1String("signalname"), m_Text); ++ signalElement.setAttribute(QLatin1String("documentation"), m_Doc); ++ signalElement.setAttribute(QLatin1String("signaltype"), m_signalType); ++ if (m_pName && !m_pName->text().isEmpty()) { ++ signalElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pName->id())); ++ m_pName -> saveToXMI(qDoc, signalElement); ++ } ++ qElement.appendChild(signalElement); ++} ++ ++/** ++ * Show a properties dialog for a SignalWidget. ++ * ++ */ ++void SignalWidget::slotMenuSelection(QAction* action) ++{ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Rename: ++ { ++ bool ok = false; ++ QString name = m_Text; ++#if QT_VERSION >= 0x050000 ++ name = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter signal name"), ++ i18n("Enter the signal name :"), ++ QLineEdit::Normal, ++ m_Text, &ok); ++#else ++ name = KInputDialog::getText(i18n("Enter signal name"), ++ i18n("Enter the signal name :"), ++ m_Text, &ok); ++#endif ++ if (ok && name.length() > 0) { ++ setName(name); ++ } ++ } ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ } ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF SignalWidget::minimumSize() const ++{ ++ int width = SIGNAL_WIDTH, height = SIGNAL_HEIGHT; ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ int textWidth = fm.width(name()); ++ ++ if (m_signalType == Accept) ++ textWidth = int((float)textWidth * 1.3f); ++ height = fontHeight; ++ if (m_signalType != Time) ++ { ++ width = textWidth > SIGNAL_WIDTH?textWidth:SIGNAL_WIDTH; ++ height = height > SIGNAL_HEIGHT?height:SIGNAL_HEIGHT; ++ } ++ width += SIGNAL_MARGIN * 2; ++ height += SIGNAL_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Called if user deletes text widget ++ */ ++void SignalWidget::slotTextDestroyed() ++{ ++ m_pName = 0; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,86 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++***************************************************************************/ ++ ++#ifndef SIGNALWIDGET_H ++#define SIGNALWIDGET_H ++ ++#include "floatingtextwidget.h" ++#include "linkwidget.h" ++#include "umlwidget.h" ++#include "worktoolbar.h" ++ ++#define SIGNAL_MARGIN 5 ++#define SIGNAL_WIDTH 45 ++#define SIGNAL_HEIGHT 15 ++ ++/** ++ * Represents a Send signal, Accept signal or Time event on an ++ * Activity diagram. ++ */ ++class SignalWidget : public UMLWidget ++{ ++ Q_OBJECT ++ Q_ENUMS(SignalType) ++public: ++ /// Enumeration that codes the different types of signal. ++ enum SignalType ++ { ++ Send = 0, ++ Accept, ++ Time ++ }; ++ ++ explicit SignalWidget(UMLScene * scene, SignalType signalType = Send, Uml::ID::Type id = Uml::ID::None); ++ virtual ~SignalWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ void setX(qreal newX); ++ void setY(qreal newY); ++ ++ virtual void setName(const QString &strName); ++ ++ SignalType signalType() const; ++ QString signalTypeStr() const; ++ void setSignalType(SignalType signalType); ++ ++ virtual void showPropertiesDialog(); ++ ++ void mouseMoveEvent(QGraphicsSceneMouseEvent *me); ++ ++ virtual bool loadFromXMI(QDomElement & qElement); ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++protected: ++ QSizeF minimumSize() const; ++ ++ /** ++ * Save the value of the widget to know how to move the floatingtext ++ */ ++ int m_oldX; ++ int m_oldY; ++ ++ // Only for the time event ++ /** ++ * This is a pointer to the Floating Text widget which displays the ++ * name of the signal widget. ++ */ ++ FloatingTextWidget* m_pName; ++ ++ SignalType m_signalType; ///< Type of signal ++ ++protected Q_SLOTS: ++ void slotTextDestroyed(); ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,534 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "statewidget.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "listpopupmenu.h" ++#include "statedialog.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "umlwidget.h" ++ ++// kde includes ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++#include ++ ++/** ++ * Creates a State widget. ++ * ++ * @param scene The parent of the widget. ++ * @param stateType The type of state. ++ * @param id The ID to assign (-1 will prompt a new ID.) ++ */ ++StateWidget::StateWidget(UMLScene * scene, StateType stateType, Uml::ID::Type id) ++ : UMLWidget(scene, WidgetBase::wt_State, id) ++{ ++ m_stateType = stateType; ++ m_drawVertical = true; ++ setAspectRatioMode(); ++ m_Text = QLatin1String("State"); ++ QSizeF size = minimumSize(); ++ setSize(size.width(), size.height()); ++} ++ ++/** ++ * Destructor. ++ */ ++StateWidget::~StateWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void StateWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ const qreal w = width(); ++ const qreal h = height(); ++ if (w == 0 || h == 0) ++ return; ++ ++ setPenFromSettings(painter); ++ switch (m_stateType) { ++ case StateWidget::Normal: ++ { ++ if (UMLWidget::useFillColor()) { ++ painter->setBrush(UMLWidget::fillColor()); ++ } ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ int textStartY = (h / 2) - (fontHeight / 2); ++ const int count = m_Activities.count(); ++ if (count == 0) { ++ painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); ++ painter->setPen(textColor()); ++ QFont font = UMLWidget::font(); ++ font.setBold(false); ++ painter->setFont(font); ++ painter->drawText(STATE_MARGIN, textStartY, ++ w - STATE_MARGIN * 2, fontHeight, ++ Qt::AlignCenter, name()); ++ setPenFromSettings(painter); ++ } else { ++ painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); ++ textStartY = STATE_MARGIN; ++ painter->setPen(textColor()); ++ QFont font = UMLWidget::font(); ++ font.setBold(true); ++ painter->setFont(font); ++ painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, ++ fontHeight, Qt::AlignCenter, name()); ++ font.setBold(false); ++ painter->setFont(font); ++ setPenFromSettings(painter); ++ int linePosY = textStartY + fontHeight; ++ ++ QStringList::Iterator end(m_Activities.end()); ++ for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { ++ textStartY += fontHeight; ++ painter->drawLine(0, linePosY, w, linePosY); ++ painter->setPen(textColor()); ++ painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, ++ fontHeight, Qt::AlignCenter, *it); ++ setPenFromSettings(painter); ++ linePosY += fontHeight; ++ }//end for ++ }//end else ++ } ++ break; ++ case StateWidget::Initial : ++ painter->setBrush(WidgetBase::lineColor()); ++ painter->drawEllipse(0, 0, w, h); ++ break; ++ case StateWidget::End : ++ 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 StateWidget::Fork: ++ case StateWidget::Join: ++ { ++ painter->setPen(Qt::black); ++ painter->setBrush(Qt::black); ++ painter->drawRect(rect()); ++ } ++ break; ++ case StateWidget::Junction: ++ { ++ painter->setPen(Qt::black); ++ painter->setBrush(Qt::black); ++ painter->drawEllipse(rect()); ++ } ++ break; ++ case StateWidget::DeepHistory: ++ { ++ painter->setBrush(Qt::white); ++ painter->drawEllipse(rect()); ++ painter->setPen(Qt::black); ++ painter->setFont(UMLWidget::font()); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing() / 2; ++ const int xStar = fm.boundingRect(QLatin1String("H")).width(); ++ const int yStar = fontHeight / 4; ++ painter->drawText((w / 6), ++ (h / 4) + fontHeight, QLatin1String("H")); ++ painter->drawText((w / 6) + xStar, ++ (h / 4) + fontHeight - yStar, QLatin1String("*")); ++ } ++ break; ++ case StateWidget::ShallowHistory: ++ { ++ painter->setBrush(Qt::white); ++ painter->drawEllipse(rect()); ++ painter->setPen(Qt::black); ++ painter->setFont(UMLWidget::font()); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing() / 2; ++ painter->drawText((w / 6), ++ (h / 4) + fontHeight, QLatin1String("H")); ++ } ++ break; ++ case StateWidget::Choice: ++ { ++ const qreal x = w / 2; ++ const qreal y = h / 2; ++ QPolygonF polygon; ++ polygon << QPointF(x, 0) << QPointF(w, y) ++ << QPointF(x, h) << QPointF(0, y); ++ painter->setBrush(UMLWidget::fillColor()); ++ painter->drawPolygon(polygon); ++ } ++ break; ++ default: ++ uWarning() << "Unknown state type: " << stateTypeStr(); ++ break; ++ } ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF StateWidget::minimumSize() const ++{ ++ int width = 10, height = 10; ++ switch (m_stateType) { ++ case StateWidget::Normal: ++ { ++ const QFontMetrics &fm = getFontMetrics(FT_BOLD); ++ const int fontHeight = fm.lineSpacing(); ++ int textWidth = fm.width(name()); ++ const int count = m_Activities.count(); ++ height = fontHeight; ++ if(count > 0) { ++ height = fontHeight * (count + 1); ++ ++ QStringList::ConstIterator end(m_Activities.end()); ++ for(QStringList::ConstIterator it(m_Activities.begin()); it != end; ++it) { ++ int w = fm.width(*it); ++ if(w > textWidth) ++ textWidth = w; ++ }//end for ++ }//end if ++ width = textWidth > STATE_WIDTH?textWidth:STATE_WIDTH; ++ height = height > STATE_HEIGHT?height:STATE_HEIGHT; ++ width += STATE_MARGIN * 2; ++ height += STATE_MARGIN * 2; ++ break; ++ } ++ case StateWidget::Fork: ++ case StateWidget::Join: ++ if (m_drawVertical) { ++ width = 8; ++ height = 60; ++ } else { ++ width = 60; ++ height = 8; ++ } ++ break; ++ case StateWidget::Junction: ++ width = 18; ++ height = 18; ++ break; ++ case StateWidget::DeepHistory: ++ case StateWidget::ShallowHistory: ++ { ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ width = height = fm.lineSpacing(); ++ } ++ break; ++ case StateWidget::Choice: ++ width = 25; ++ height = 25; ++ break; ++ default: ++ break; ++ } ++ ++ return QSizeF(width, height); ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF StateWidget::maximumSize() ++{ ++ switch (m_stateType) { ++ case StateWidget::Initial: ++ case StateWidget::End: ++ case StateWidget::Junction: ++ case StateWidget::Choice: ++ return QSizeF(35, 35); ++ break; ++ case StateWidget::DeepHistory: ++ case StateWidget::ShallowHistory: ++ { ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ return QSizeF(fontHeight + 10, fontHeight + 10); ++ } ++ break; ++ default: ++ break; ++ } ++ return UMLWidget::maximumSize(); ++} ++ ++/** ++ * Set the aspect ratio mode. ++ * Some state types have a fixed aspect ratio ++ */ ++void StateWidget::setAspectRatioMode() ++{ ++ switch (m_stateType) { ++ case StateWidget::Initial: ++ case StateWidget::End: ++ case StateWidget::Choice: ++ case StateWidget::DeepHistory: ++ case StateWidget::ShallowHistory: ++ case StateWidget::Fork: ++ case StateWidget::Join: ++ case StateWidget::Junction: ++ setFixedAspectRatio(true); ++ break; ++ default: ++ setFixedAspectRatio(false); ++ break; ++ } ++} ++ ++/** ++ * Returns the type of state. ++ * @return StateType ++ */ ++StateWidget::StateType StateWidget::stateType() const ++{ ++ return m_stateType; ++} ++ ++/** ++ * Returns the type string of state. ++ */ ++QString StateWidget::stateTypeStr() const ++{ ++ return QLatin1String(ENUM_NAME(StateWidget, StateType, m_stateType)); ++} ++ ++/** ++ * Sets the type of state. ++ */ ++void StateWidget::setStateType(StateType stateType) ++{ ++ m_stateType = stateType; ++ setAspectRatioMode(); ++} ++ ++/** ++ * Adds an activity to this widget. ++ * @return true on success ++ */ ++bool StateWidget::addActivity(const QString &activity) ++{ ++ m_Activities.append(activity); ++ updateGeometry(); ++ return true; ++} ++ ++/** ++ * Removes the given activity from the state. ++ */ ++bool StateWidget::removeActivity(const QString &activity) ++{ ++ if(m_Activities.removeAll(activity) == 0) ++ return false; ++ updateGeometry(); ++ return true; ++} ++ ++/** ++ * Renames the given activity. ++ */ ++bool StateWidget::renameActivity(const QString &activity, const QString &newName) ++{ ++ int index = - 1; ++ if((index = m_Activities.indexOf(activity)) == -1) ++ return false; ++ m_Activities[ index ] = newName; ++ return true; ++} ++ ++/** ++ * Sets the states activities to the ones given. ++ */ ++void StateWidget::setActivities(const QStringList &list) ++{ ++ m_Activities = list; ++ updateGeometry(); ++} ++ ++/** ++ * Returns the list of activities. ++ */ ++QStringList StateWidget::activities() const ++{ ++ return m_Activities; ++} ++ ++/** ++ * Get whether to draw a fork or join vertically. ++ */ ++bool StateWidget::drawVertical() const ++{ ++ return m_drawVertical; ++} ++ ++/** ++ * Set whether to draw a fork or join vertically. ++ */ ++void StateWidget::setDrawVertical(bool to) ++{ ++ m_drawVertical = to; ++ setSize(height(), width()); ++ updateGeometry(); ++ UMLWidget::adjustAssocs(x(), y()); ++} ++ ++/** ++ * Show a properties dialog for a StateWidget. ++ */ ++void StateWidget::showPropertiesDialog() ++{ ++ UMLApp::app()->docWindow()->updateDocumentation(false); ++ ++ QPointer dialog = new StateDialog(m_scene->activeView(), this); ++ if (dialog->exec() && dialog->getChangesMade()) { ++ UMLApp::app()->docWindow()->showDocumentation(this, true); ++ UMLApp::app()->document()->setModified(true); ++ } ++ delete dialog; ++} ++ ++/** ++ * Creates the "statewidget" XMI element. ++ */ ++void StateWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement stateElement = qDoc.createElement(QLatin1String("statewidget")); ++ UMLWidget::saveToXMI(qDoc, stateElement); ++ stateElement.setAttribute(QLatin1String("statename"), m_Text); ++ stateElement.setAttribute(QLatin1String("documentation"), m_Doc); ++ stateElement.setAttribute(QLatin1String("statetype"), m_stateType); ++ if (m_stateType == Fork || m_stateType == Join) ++ stateElement.setAttribute(QLatin1String("drawvertical"), m_drawVertical); ++ //save states activities ++ QDomElement activitiesElement = qDoc.createElement(QLatin1String("Activities")); ++ ++ QStringList::Iterator end(m_Activities.end()); ++ for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { ++ QDomElement tempElement = qDoc.createElement(QLatin1String("Activity")); ++ tempElement.setAttribute(QLatin1String("name"), *it); ++ activitiesElement.appendChild(tempElement); ++ }//end for ++ stateElement.appendChild(activitiesElement); ++ qElement.appendChild(stateElement); ++} ++ ++/** ++ * Loads a "statewidget" XMI element. ++ */ ++bool StateWidget::loadFromXMI(QDomElement & qElement) ++{ ++ if(!UMLWidget::loadFromXMI(qElement)) ++ return false; ++ m_Text = qElement.attribute(QLatin1String("statename")); ++ m_Doc = qElement.attribute(QLatin1String("documentation")); ++ QString type = qElement.attribute(QLatin1String("statetype"), QLatin1String("1")); ++ m_stateType = (StateType)type.toInt(); ++ setAspectRatioMode(); ++ QString drawVertical = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("1")); ++ m_drawVertical = (bool)drawVertical.toInt(); ++ //load states activities ++ QDomNode node = qElement.firstChild(); ++ QDomElement tempElement = node.toElement(); ++ if(!tempElement.isNull() && tempElement.tagName() == QLatin1String("Activities")) { ++ QDomNode node = tempElement.firstChild(); ++ QDomElement activityElement = node.toElement(); ++ while(!activityElement.isNull()) { ++ if(activityElement.tagName() == QLatin1String("Activity")) { ++ QString name = activityElement.attribute(QLatin1String("name")); ++ if(!name.isEmpty()) ++ m_Activities.append(name); ++ }//end if ++ node = node.nextSibling(); ++ activityElement = node.toElement(); ++ }//end while ++ }//end if ++ return true; ++} ++ ++/** ++ * Captures any popup menu signals for menus it created. ++ */ ++void StateWidget::slotMenuSelection(QAction* action) ++{ ++ bool ok = false; ++ QString nameNew = name(); ++ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); ++ switch(sel) { ++ case ListPopupMenu::mt_Rename: ++#if QT_VERSION >= 0x050000 ++ nameNew = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter State Name"), ++ i18n("Enter the name of the new state:"), ++ QLineEdit::Normal, ++ name(), &ok); ++#else ++ nameNew = KInputDialog::getText(i18n("Enter State Name"), ++ i18n("Enter the name of the new state:"), ++ name(), &ok); ++#endif ++ if (ok && nameNew.length() > 0) { ++ setName(nameNew); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Properties: ++ showPropertiesDialog(); ++ break; ++ ++ case ListPopupMenu::mt_New_Activity: ++#if QT_VERSION >= 0x050000 ++ nameNew = QInputDialog::getText(Q_NULLPTR, ++ i18n("Enter Activity"), ++ i18n("Enter the name of the new activity:"), ++ QLineEdit::Normal, ++ i18n("new activity"), &ok); ++#else ++ nameNew = KInputDialog::getText(i18n("Enter Activity"), ++ i18n("Enter the name of the new activity:"), ++ i18n("new activity"), &ok); ++#endif ++ if (ok && nameNew.length() > 0) { ++ addActivity(nameNew); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Flip: ++ setDrawVertical(!m_drawVertical); ++ break; ++ ++ default: ++ UMLWidget::slotMenuSelection(action); ++ break; ++ } ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,99 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++***************************************************************************/ ++ ++#ifndef STATEWIDGET_H ++#define STATEWIDGET_H ++ ++#include "umlwidget.h" ++ ++#include ++#include ++ ++#define STATE_MARGIN 5 ++#define STATE_WIDTH 30 ++#define STATE_HEIGHT 10 ++ ++/** ++ * This class is the graphical version of a UML State. ++ * ++ * A StateWidget is created by a @ref UMLView. A StateWidget belongs to ++ * only one @ref UMLView instance. ++ * When the @ref UMLView instance that this class belongs to is destroyed, ++ * it will be automatically deleted. ++ * ++ * The StateWidget class inherits from the @ref UMLWidget class ++ * which adds most of the functionality to this class. ++ * ++ * @short A graphical version of a UML State. ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class StateWidget : public UMLWidget ++{ ++ Q_OBJECT ++ Q_ENUMS(StateType) ++public: ++ /// Enumeration that codes the different types of state. ++ enum StateType ++ { ++ Initial = 0, // Pseudostate ++ Normal, ++ End, ++ Fork, // Pseudostate ++ Join, // Pseudostate ++ Junction, // Pseudostate ++ DeepHistory, // Pseudostate ++ ShallowHistory, // Pseudostate ++ Choice // Pseudostate ++ //Terminate // Pseudostate ++ //EntryPoint // Pseudostate ++ //ExitPoint // Pseudostate ++ }; ++ ++ explicit StateWidget(UMLScene * scene, StateType stateType = Normal, Uml::ID::Type id = Uml::ID::None); ++ virtual ~StateWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ StateType stateType() const; ++ QString stateTypeStr() const; ++ void setStateType(StateType stateType); ++ ++ bool addActivity(const QString &activity); ++ bool removeActivity(const QString &activity); ++ bool renameActivity(const QString &activity, const QString &newName); ++ ++ QStringList activities() const; ++ void setActivities(const QStringList &list); ++ ++ bool drawVertical() const; ++ void setDrawVertical(bool to = true); ++ ++ virtual void showPropertiesDialog(); ++ ++ virtual bool loadFromXMI(QDomElement & qElement); ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++ QSizeF maximumSize(); ++ void setAspectRatioMode(); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction* action); ++ ++private: ++ StateType m_stateType; ///< Type of state. ++ bool m_drawVertical; ///< whether to draw the fork/join horizontally or vertically ++ QStringList m_Activities; ///< List of activities for the state. ++ ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,122 @@ ++// vim: set tabstop=4 shiftwidth=4 noexpandtab: ++/* ++Widget taken from gwenview-kf6 ++Copyright 2007 Aurélien Gâteau ++ ++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. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ ++*/ ++// Self ++#include "statusbartoolbutton.h" ++ ++// Qt ++#include ++#include ++#include ++#include ++ ++// KDE ++#include ++ ++StatusBarToolButton::StatusBarToolButton(QWidget* parent) ++ : QToolButton(parent), ++ mGroupPosition(NotGrouped) ++{ ++ setToolButtonStyle(Qt::ToolButtonTextOnly); ++ setFocusPolicy(Qt::NoFocus); ++ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ++} ++ ++ ++QSize StatusBarToolButton::minimumSizeHint() const ++{ ++ return sizeHint(); ++} ++ ++ ++QSize StatusBarToolButton::sizeHint() const ++{ ++ QSize sh = QToolButton::sizeHint(); ++ sh.setHeight(fontMetrics().height()); ++ return sh; ++} ++ ++ ++void StatusBarToolButton::setGroupPosition(StatusBarToolButton::GroupPosition groupPosition) ++{ ++ mGroupPosition = groupPosition; ++} ++ ++ ++void StatusBarToolButton::paintEvent(QPaintEvent* event) ++{ ++ if (mGroupPosition == NotGrouped) { ++ QToolButton::paintEvent(event); ++ return; ++ } ++ QStylePainter painter(this); ++ QStyleOptionToolButton opt; ++ initStyleOption(&opt); ++ QStyleOptionToolButton panelOpt = opt; ++ ++ // Panel ++ QRect& panelRect = panelOpt.rect; ++ switch (mGroupPosition) { ++ case GroupLeft: ++ panelRect.setWidth(panelRect.width() * 2); ++ break; ++ case GroupCenter: ++ panelRect.setLeft(panelRect.left() - panelRect.width()); ++ panelRect.setWidth(panelRect.width() * 3); ++ break; ++ case GroupRight: ++ panelRect.setLeft(panelRect.left() - panelRect.width()); ++ break; ++ case NotGrouped: ++ Q_ASSERT(0); ++ } ++ painter.drawPrimitive(QStyle::PE_PanelButtonTool, panelOpt); ++ ++ // Separator ++ const int y1 = opt.rect.top() + 6; ++ const int y2 = opt.rect.bottom() - 6; ++ if (mGroupPosition & GroupRight) { ++ const int x = opt.rect.left(); ++ painter.setPen(opt.palette.color(QPalette::Light)); ++ painter.drawLine(x, y1, x, y2); ++ } ++ if (mGroupPosition & GroupLeft) { ++ const int x = opt.rect.right(); ++ painter.setPen(opt.palette.color(QPalette::Mid)); ++ painter.drawLine(x, y1, x, y2); ++ } ++ ++ // Text ++ painter.drawControl(QStyle::CE_ToolButtonLabel, opt); ++ ++ // Filtering message on tooltip text for CJK to remove accelerators. ++ // Quoting ktoolbar.cpp: ++ // """ ++ // CJK languages use more verbose accelerator marker: they add a Latin ++ // letter in parenthesis, and put accelerator on that. Hence, the default ++ // removal of ampersand only may not be enough there, instead the whole ++ // parenthesis construct should be removed. Provide these filtering i18n ++ // messages so that translators can use Transcript for custom removal. ++ // """ ++ if (!actions().isEmpty()) { ++ QAction* action = actions().first(); ++ setToolTip(i18nc("@info:tooltip of custom toolbar button", "%1", action->toolTip())); ++ } ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.h umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,58 @@ ++// vim: set tabstop=4 shiftwidth=4 noexpandtab: ++/* ++gwenview-kf6: an image viewer ++Copyright 2007 Aurélien Gâteau ++ ++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. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ ++*/ ++#ifndef STATUSBARTOOLBUTTON_H ++#define STATUSBARTOOLBUTTON_H ++ ++// Qt ++#include ++ ++/** ++ * A thin tool button which can be grouped with another and look like one solid-kf6 ++ * bar: ++ * ++ * (button1 | button2) ++ */ ++class StatusBarToolButton : public QToolButton ++{ ++ Q_OBJECT ++public: ++ enum GroupPosition { ++ NotGrouped = 0, ++ GroupLeft = 1, ++ GroupRight = 2, ++ GroupCenter = 3 ++ }; ++ ++ explicit StatusBarToolButton(QWidget* parent = 0); ++ ++ virtual QSize minimumSizeHint() const; ++ virtual QSize sizeHint() const; ++ ++ void setGroupPosition(StatusBarToolButton::GroupPosition groupPosition); ++ ++protected: ++ virtual void paintEvent(QPaintEvent* event); ++ ++private: ++ GroupPosition mGroupPosition; ++}; ++ ++#endif /* STATUSBARTOOLBUTTON_H */ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,249 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "toolbarstateonewidget.h" ++ ++// app includes ++#include "activitywidget.h" ++#include "dialog_utils.h" ++#include "floatingtextwidget.h" ++#include "messagewidget.h" ++#include "objectwidget.h" ++#include "pinwidget.h" ++#include "portwidget.h" ++#include "preconditionwidget.h" ++#include "regionwidget.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlwidget.h" ++#include "object_factory.h" ++#include "package.h" ++#include "widget_factory.h" ++ ++// kde includes ++#include ++#include ++#if QT_VERSION < 0x050000 ++#include ++#endif ++ ++// qt includes ++#if QT_VERSION >= 0x050000 ++#include ++#endif ++ ++// 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) { ++ m_firstObject = 0; ++ } ++ ++ if (m_pMouseEvent->button() != Qt::LeftButton || ++ (currentWidget()->baseType() != WidgetBase::wt_Object && ++ currentWidget()->baseType() != WidgetBase::wt_Activity && ++ currentWidget()->baseType() != WidgetBase::wt_Component && ++ currentWidget()->baseType() != WidgetBase::wt_Region)) { ++ return; ++ } ++ ++ if (!m_firstObject && type == WidgetBase::wt_Pin) { ++ 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) { ++ if (m_firstObject->baseType() == WidgetBase::wt_Activity) { ++ umlwidget = new PinWidget(m_pUMLScene, m_firstObject); ++ // Create the widget. Some setup functions can remove the widget. ++ } else if (m_firstObject->baseType() == WidgetBase::wt_Component) { ++ bool pressedOK = false; ++#if QT_VERSION >= 0x050000 ++ QString name = QInputDialog::getText(UMLApp::app(), ++ i18n("Enter Port Name"), i18n("Enter the port"), ++ QLineEdit::Normal, ++ i18n("new port"), ++ &pressedOK); ++#else ++ QString name = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port"), i18n("new port"), ++ &pressedOK, UMLApp::app()); ++#endif ++ if (pressedOK) { ++ UMLPackage* component = static_cast(m_firstObject->umlObject()); ++ UMLObject *port = Object_Factory::createUMLObject(UMLObject::ot_Port, name, component); ++ umlwidget = Widget_Factory::createWidget(m_pUMLScene, port); ++ } ++ } ++ } ++ ++ if (umlwidget) { ++ m_pUMLScene->setupNewWidget(umlwidget); ++ } ++ ++} ++ ++/** ++ * 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; ++ } ++ // Shouldn't happen ++ Q_ASSERT(0); ++ return WidgetBase::wt_Pin; ++} ++ ++/** ++ * Goes back to the initial state. ++ */ ++void ToolBarStateOneWidget::init() ++{ ++ ToolBarStatePool::init(); ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,59 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef TOOLBARSTATEONEWIDGET_H ++#define TOOLBARSTATEONEWIDGET_H ++ ++#include "toolbarstatepool.h" ++#include "widgetbase.h" ++ ++/** ++ * Sequence tool to create components linked with one object in sequence diagram ++ * like precondition. ++ * With sequence tool, one objects is selected clicking with left button on ++ * it ++ */ ++class ToolBarStateOneWidget : public ToolBarStatePool ++{ ++ Q_OBJECT ++public: ++ explicit ToolBarStateOneWidget(UMLScene *umlScene); ++ virtual ~ToolBarStateOneWidget(); ++ ++ virtual void cleanBeforeChange(); ++ ++ // FIXME: obsolete ++ virtual void mouseMove(QGraphicsSceneMouseEvent* ome); ++ ++public Q_SLOTS: ++ virtual void slotWidgetRemoved(UMLWidget* widget); ++ ++protected: ++ virtual void setCurrentElement(); ++ ++ virtual void mouseReleaseWidget(); ++ virtual void mouseReleaseEmpty(); ++ ++ void setWidget(UMLWidget* firstObject); ++ WidgetBase::WidgetType widgetType(); ++ ++ UMLWidget* m_firstObject; ///< The first object in the message. ++ ++ /** ++ * If there is a current widget, it is true if the press event happened on ++ * the line of an object, or false if it happened on a normal UMLWidget. ++ */ ++ bool m_isObjectWidgetLine; ++ ++private: ++ virtual void init(); ++}; ++ ++#endif //TOOLBARSTATEONEWIDGET_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,1859 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "umlwidget.h" ++ ++// local includes ++#include "associationwidget.h" ++#include "classifier.h" ++#include "classpropertiesdialog.h" ++#include "cmds.h" ++#include "debug_utils.h" ++#include "docwindow.h" ++#include "floatingtextwidget.h" ++#include "idchangelog.h" ++#include "listpopupmenu.h" ++#include "settingsdialog.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umllistview.h" ++#include "umlobject.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "uniqueid.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 qreal UMLWidget::defaultMargin = 5; ++ ++/** ++ * 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 (m_baseType != other.m_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 != NULL && id == m_umlObject->id()) || ++ id == m_nId) ++ return this; ++ return NULL; ++} ++ ++/** ++ * 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(); ++ adjustUnselectedAssocs(delta.x(), delta.y()); ++ ++ DEBUG(DBG_SRC) << "diffX=" << diffX << " / diffY=" << diffY; ++ foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { ++ widget->moveWidgetBy(diffX, diffY); ++ 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_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; ++ } ++} ++ ++/** ++ * 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(); ++ switch(baseType()) { ++ case WidgetBase::wt_Message: // will be handled in its class ++ QGraphicsItem::mouseDoubleClickEvent(event); ++ break; ++ default: ++ showPropertiesDialog(); ++ event->accept(); ++ break; ++ } ++ } ++} ++ ++/** ++ * 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); ++} ++ ++/** ++ * When a widget changes this slot captures that signal. ++ */ ++void UMLWidget::updateWidget() ++{ ++ updateGeometry(); ++ switch (m_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; ++ ++ 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; ++ ++ 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(m_baseType) && m_umlObject == NULL) { ++ m_umlObject = m_doc->findObjectById(m_nId); ++ if (m_umlObject == NULL) { ++ 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->getPastep-kf6oint(); ++ int x = point.x() + this->x(); ++ int y = point.y() + this->y(); ++ if (m_scene->type() == Uml::DiagramType::Sequence) { ++ 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 pastep-kf6oint ++ 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 && !m_Assocs.contains(pAssoc)) { ++ m_Assocs.append(pAssoc); ++ } ++} ++ ++/** ++ * Removes an already created association from the list of ++ * associations that include this UMLWidget ++ */ ++void UMLWidget::removeAssoc(AssociationWidget* pAssoc) ++{ ++ if (pAssoc) { ++ m_Assocs.removeAll(pAssoc); ++ } ++} ++ ++/** ++ * 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) ++{ ++ // 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, m_Assocs) { ++ assocwidget->saveIdealTextPositions(); ++ } ++ ++ foreach(AssociationWidget* assocwidget, m_Assocs) { ++ 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, m_Assocs) { ++ if (!assocwidget->isSelected()) ++ assocwidget->saveIdealTextPositions(); ++ } ++ ++ foreach(AssociationWidget* assocwidget, m_Assocs) { ++ if (!assocwidget->isSelected()) { ++ assocwidget->widgetMoved(this, dx, dy); ++ } ++ } ++} ++ ++/** ++ * Show a properties dialog for a UMLWidget. ++ */ ++void UMLWidget::showPropertiesDialog() ++{ ++ // 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); ++ } ++ dlg->close(); //wipe from memory ++ delete dlg; ++} ++ ++/** ++ * 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) ++ 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) ++{ ++ // TODO the status message lies for at least MessageWidget which could only be resized vertical ++ 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 resize.")); ++ ++ 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 = m_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); ++ } ++ ++ // TODO: isn't this handled by toForeground() ? ++ const QPoint pos(x(), y()); ++ UMLWidget *bkgnd = m_scene->widgetAt(pos); ++ if (bkgnd && bkgnd != this && _select) { ++ DEBUG(DBG_SRC) << "setting Z to " << bkgnd->zValue() + 1.0 << ", SelectState: " << _select; ++ setZValue(bkgnd->zValue() + 1.0); ++ } ++ ++ 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(); ++ } ++ ++ setRect(rect().x(), rect().y(), width, height); ++} ++ ++/** ++ * Sets the size with another size. ++ */ ++void UMLWidget::setSize(const QSizeF& size) ++{ ++ setSize(size.width(), size.height()); ++} ++ ++/** ++ * Update the size of this widget. ++ */ ++void UMLWidget::updateGeometry() ++{ ++ if (m_doc->loading()) { ++ 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(); ++ adjustAssocs(size.width()-oldW, size.height()-oldH); ++} ++ ++/** ++ * 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 = 4; ++ 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::red); ++ 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::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ /* ++ Call after required actions in child class. ++ Type must be set in the child class. ++ */ ++ WidgetBase::saveToXMI(qDoc, qElement); ++ qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(id())); ++ qElement.setAttribute(QLatin1String("x"), x()); ++ qElement.setAttribute(QLatin1String("y"), y()); ++ qElement.setAttribute(QLatin1String("width"), width()); ++ qElement.setAttribute(QLatin1String("height"), height()); ++ 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::loadFromXMI(QDomElement & qElement) ++{ ++ QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); ++ m_nId = Uml::ID::fromString(id); ++ ++ WidgetBase::loadFromXMI(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")); ++ ++ setSize(w.toFloat(), h.toFloat()); ++ setX(x.toFloat()); ++ setY(y.toFloat()); ++ 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; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,347 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLWIDGET_H ++#define UMLWIDGET_H ++ ++#include "associationwidgetlist.h" ++#include "basictypes.h" ++#include "optionstate.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-kf6-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 qreal defaultMargin; ++ ++ 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); ++ 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); ++ ++ bool getIgnoreSnapToGrid() const; ++ void setIgnoreSnapToGrid(bool to); ++ ++ void moveByLocal(qreal dx, qreal dy); ++ ++ void removeAssoc(AssociationWidget* pAssoc); ++ void addAssoc(AssociationWidget* pAssoc); ++ ++ /** ++ * Returns the list of associations connected to this widget. ++ */ ++ AssociationWidgetList & associationWidgetList() { ++ return m_Assocs; ++ } ++ ++ /** ++ * 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 void showPropertiesDialog(); ++ ++ virtual void adjustAssocs(qreal dx, qreal dy); ++ 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(); ++ ++ void clipSize(); ++ ++ void forceUpdateFontMetrics(QPainter *painter); ++ void forceUpdateFontMetrics(QFont &font, QPainter *painter); ++ ++ virtual bool loadFromXMI(QDomElement &qElement); ++ virtual void saveToXMI(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(); ++ ++ ///////////////// Data Loaded/Saved ///////////////////////////////// ++ ++ /// A list of AssociationWidgets between the UMLWidget and other UMLWidgets in the diagram ++ AssociationWidgetList m_Assocs; ++ ++ 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(); ++ void toForeground(); ++ ++}; ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,96 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header file ++#include "usecasewidget.h" ++ ++// app includes ++#include "usecase.h" ++#include "umlview.h" ++ ++/** ++ * Creates a UseCase widget. ++ * @param scene The parent of the widget. ++ * @param o The UMLUseCase to represent. ++ */ ++UseCaseWidget::UseCaseWidget(UMLScene * scene, UMLUseCase *o) ++ : UMLWidget(scene, WidgetBase::wt_UseCase, o) ++{ ++} ++ ++/** ++ * Destructor. ++ */ ++UseCaseWidget::~UseCaseWidget() ++{ ++} ++ ++/** ++ * Overrides the standard paint event. ++ */ ++void UseCaseWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(option); ++ Q_UNUSED(widget); ++ ++ setPenFromSettings(painter); ++ if (UMLWidget::useFillColor()) ++ painter->setBrush(UMLWidget::fillColor()); ++ QFont font = UMLWidget::font(); ++ font.setUnderline(false); ++ font.setBold(false); ++ font.setItalic(m_umlObject->isAbstract()); ++ painter->setFont(font); ++ const QFontMetrics &fm = getFontMetrics(FT_NORMAL); ++ const int fontHeight = fm.lineSpacing(); ++ const int w = width(); ++ const int h = height(); ++ //int middleX = w / 2; ++ bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); ++ const int textStartY = (h / 2) - (drawStereotype ? fontHeight / 4 : fontHeight / 2); ++ ++ painter->drawEllipse(0, 0, w, h); ++ painter->setPen(textColor()); ++ if (drawStereotype) ++ painter->drawText(UC_MARGIN, textStartY-fontHeight, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); ++ ++ painter->drawText(UC_MARGIN, textStartY, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); ++ setPenFromSettings(painter); ++ ++ UMLWidget::paint(painter, option, widget); ++} ++ ++/** ++ * Saves this UseCase to file. ++ */ ++void UseCaseWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) ++{ ++ QDomElement usecaseElement = qDoc.createElement(QLatin1String("usecasewidget")); ++ UMLWidget::saveToXMI(qDoc, usecaseElement); ++ qElement.appendChild(usecaseElement); ++} ++ ++/** ++ * Overrides method from UMLWidget ++ */ ++QSizeF UseCaseWidget::minimumSize() const ++{ ++ const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); ++ const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); ++ const int fontHeight = fm.lineSpacing(); ++ const int textWidth = fm.width(name()); ++ bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); ++ int width = textWidth > UC_WIDTH?textWidth:UC_WIDTH; ++ int height = UC_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + UC_MARGIN; ++ ++ width += UC_MARGIN * 2; ++ ++ return QSizeF(width, height); ++} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,58 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef USECASEWIDGET_H ++#define USECASEWIDGET_H ++ ++#include "umlwidget.h" ++ ++class UMLUseCase; ++ ++#define UC_MARGIN 5 ++#define UC_WIDTH 60 ++#define UC_HEIGHT 30 ++ ++ ++/** ++ * This class is the graphical version of a UMLUseCase. The ++ * UseCaseWidget class inherits from the @ref UMLWidget class ++ * which adds most of the functionality to this class. ++ ++ * A UseCaseWidget is created by a @ref UMLView. An UseCaseWidget belongs to only one ++ * @ref UMLView instance. When the @ref UMLView instance that this class belongs to, ++ * it will be automatically deleted. ++ * ++ * If the @ref UMLUseCase class that this UseCaseWidget is displaying is deleted, the @ref UMLView will ++ * make sure that this instance is also deleted. ++ * ++ * The UseCaseWidget class inherits from the @ref UMLWidget class which adds most of the functionality ++ * to this class. ++ * ++ * @short A graphical version of a UMLUseCase. ++ * @author Paul Hensgen ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class UseCaseWidget : public UMLWidget ++{ ++public: ++ UseCaseWidget(UMLScene * scene, UMLUseCase *o); ++ virtual ~UseCaseWidget(); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++ // For loading we can use the loadFromXMI() inherited from ++ // UMLWidget. ++ virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); ++ ++protected: ++ QSizeF minimumSize() const; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,1119 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#include "widgetbase.h" ++ ++#include "classifier.h" ++#include "debug_utils.h" ++#include "floatingtextwidget.h" ++#include "optionstate.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlobject.h" ++#include "umlscene.h" ++ ++#if QT_VERSION < 0x050000 ++#include ++#include ++#endif ++#include ++ ++#include ++#if QT_VERSION >= 0x050000 ++#include ++#include ++#endif ++#include ++ ++/** ++ * Creates a WidgetBase 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. ++ */ ++WidgetBase::WidgetBase(UMLScene *scene, WidgetType type) ++ : QGraphicsObject(), ++ m_baseType(type), ++ m_scene(scene), ++ m_umlObject(0), ++ m_textColor(QColor("black")), ++ m_lineColor(QColor("black")), ++ m_fillColor(QColor("yellow")), ++ m_brush(m_fillColor), ++ m_lineWidth(0), // initialize with 0 to have valid start condition ++ m_useFillColor(true), ++ m_usesDiagramTextColor(true), ++ m_usesDiagramLineColor(true), ++ m_usesDiagramLineWidth(true) ++{ ++ setSelected(false); ++ scene->addItem(this); ++ ++ // TODO 310283 ++ setFlags(ItemIsSelectable); ++ //setFlags(ItemIsSelectable | ItemIsMovable |ItemSendsGeometryChanges); ++ if (m_scene) { ++ m_usesDiagramLineColor = true; ++ m_usesDiagramLineWidth = true; ++ m_usesDiagramTextColor = true; ++ const Settings::OptionState& optionState = m_scene->optionState(); ++ m_textColor = optionState.uiState.textColor; ++ m_lineColor = optionState.uiState.lineColor; ++ m_lineWidth = optionState.uiState.lineWidth; ++ m_font = optionState.uiState.font; ++ } else { ++ uError() << "WidgetBase constructor: SERIOUS PROBLEM - m_scene is NULL"; ++ } ++} ++ ++/** ++ * Destructor. ++ */ ++WidgetBase::~WidgetBase() ++{ ++} ++ ++/** ++ * Read property of m_baseType. ++ */ ++WidgetBase::WidgetType WidgetBase::baseType() const ++{ ++ return m_baseType; ++} ++ ++/** ++ * @return The type used for rtti as string. ++ */ ++QLatin1String WidgetBase::baseTypeStr() const ++{ ++ return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, m_baseType)); ++} ++ ++/* ++ * Sets the state of whether the widget is selected. ++ * ++ * @param select The state of whether the widget is selected. ++ */ ++void WidgetBase::setSelected(bool select) ++{ ++ QGraphicsObject::setSelected(select); ++} ++ ++/** ++ * Deliver a pointer to the connected UMLView ++ * (needed esp. by event handling of AssociationLine). ++ */ ++UMLScene* WidgetBase::umlScene() const ++{ ++ return m_scene; ++} ++ ++/** ++ * This is shortcut method for UMLApp::app()->document(). ++ * ++ * @return Pointer to the UMLDoc object. ++ */ ++UMLDoc* WidgetBase::umlDoc() const ++{ ++ return UMLApp::app()->document(); ++} ++ ++/** ++ * Returns the @ref UMLObject set to represent. ++ * ++ * @return the UMLObject to represent. ++ */ ++UMLObject* WidgetBase::umlObject() const ++{ ++ return m_umlObject; ++} ++ ++/** ++ * Sets the @ref UMLObject to represent. ++ * ++ * @param obj The object to represent. ++ */ ++void WidgetBase::setUMLObject(UMLObject *obj) ++{ ++ m_umlObject = obj; ++} ++ ++/** ++ * Write property of m_nId. ++ */ ++void WidgetBase::setID(Uml::ID::Type id) ++{ ++ if (m_umlObject) { ++ if (m_umlObject->id() != Uml::ID::None) ++ uWarning() << "changing old UMLObject " << Uml::ID::toString(m_umlObject->id()) ++ << " to " << Uml::ID::toString(id); ++ m_umlObject->setID(id); ++ } ++ m_nId = id; ++} ++ ++/** ++ * Read property of m_nId. ++ */ ++Uml::ID::Type WidgetBase::id() const ++{ ++ if (m_umlObject) ++ return m_umlObject->id(); ++ return m_nId; ++} ++ ++/** ++ * Used by some child classes to get documentation. ++ * ++ * @return The documentation from the UMLObject (if m_umlObject is set.) ++ */ ++QString WidgetBase::documentation() const ++{ ++ if (m_umlObject) ++ return m_umlObject->doc(); ++ return m_Doc; ++} ++ ++/** ++ * Returns state of documentation for the widget. ++ * ++ * @return false if documentation is empty ++ */ ++bool WidgetBase::hasDocumentation() ++{ ++ if (m_umlObject) ++ return m_umlObject->hasDoc(); ++ return !m_Doc.isEmpty(); ++} ++ ++/** ++ * Used by some child classes to set documentation. ++ * ++ * @param doc The documentation to be set in the UMLObject ++ * (if m_umlObject is set.) ++ */ ++void WidgetBase::setDocumentation(const QString& doc) ++{ ++ if (m_umlObject) ++ m_umlObject->setDoc(doc); ++ else ++ m_Doc = doc; ++} ++ ++/** ++ * Gets the name from the corresponding UMLObject if this widget has an ++ * underlying UMLObject; if it does not, then it returns the local ++ * m_Text (notably the case for FloatingTextWidget.) ++ * ++ * @return the currently set name ++ */ ++QString WidgetBase::name() const ++{ ++ if (m_umlObject) ++ return m_umlObject->name(); ++ return m_Text; ++} ++ ++/** ++ * Sets the name in the corresponding UMLObject. ++ * Sets the local m_Text if m_umlObject is NULL. ++ * ++ * @param strName The name to be set. ++ */ ++void WidgetBase::setName(const QString &strName) ++{ ++ if (m_umlObject) ++ m_umlObject->setName(strName); ++ else ++ m_Text = strName; ++} ++ ++/** ++ * Returns text color ++ * ++ * @return currently used text color ++ */ ++QColor WidgetBase::textColor() const ++{ ++ return m_textColor; ++} ++ ++/** ++ * Sets the text color ++ * ++ * @param color the new text color ++ */ ++void WidgetBase::setTextColor(const QColor &color) ++{ ++ m_textColor = color; ++ m_usesDiagramTextColor = false; ++} ++ ++/** ++ * Returns line color ++ * ++ * @return currently used line color ++ */ ++QColor WidgetBase::lineColor() const ++{ ++ return m_lineColor; ++} ++ ++/** ++ * Sets the line color ++ * ++ * @param color The new line color ++ */ ++void WidgetBase::setLineColor(const QColor &color) ++{ ++ m_lineColor = color; ++ m_usesDiagramLineColor = false; ++} ++ ++/** ++ * Returns fill color ++ * ++ * @return currently used fill color ++ */ ++QColor WidgetBase::fillColor() const ++{ ++ return m_fillColor; ++} ++ ++/** ++ * Sets the fill color ++ * ++ * @param color The new fill color ++ */ ++void WidgetBase::setFillColor(const QColor &color) ++{ ++ m_fillColor = color; ++ m_usesDiagramFillColor = false; ++} ++ ++/** ++ * Returns line width ++ * ++ * @return currently used line with ++ */ ++uint WidgetBase::lineWidth() const ++{ ++ return m_lineWidth; ++} ++ ++/** ++ * Sets the line width ++ * ++ * @param width The new line width ++ */ ++void WidgetBase::setLineWidth(uint width) ++{ ++ m_lineWidth = width; ++ m_usesDiagramLineWidth = false; ++} ++ ++/** ++ * Return state of fill color usage ++ * ++ * @return True if fill color is used ++ */ ++bool WidgetBase::useFillColor() ++{ ++ return m_useFillColor; ++} ++ ++/** ++ * Set state if fill color is used ++ * ++ * @param state The state to set ++ */ ++void WidgetBase::setUseFillColor(bool state) ++{ ++ m_useFillColor = state; ++ m_usesDiagramUseFillColor = false; ++} ++ ++/** ++ * Returns state if diagram text color is used ++ * ++ * @return True means diagram text color is used ++ */ ++bool WidgetBase::usesDiagramTextColor() const ++{ ++ return m_usesDiagramTextColor; ++} ++ ++/** ++ * Set state if diagram text color is used ++ * ++ * @param state The state to set ++ */ ++void WidgetBase::setUsesDiagramTextColor(bool state) ++{ ++ if (m_usesDiagramTextColor == state) { ++ return; ++ } ++ m_usesDiagramTextColor = state; ++ setTextColor(m_textColor); ++} ++ ++/** ++ * Returns state of diagram line color is used ++ * ++ * @return True means diagrams line color is used ++*/ ++bool WidgetBase::usesDiagramLineColor() const ++{ ++ return m_usesDiagramLineColor; ++} ++ ++/** ++ * Set state of diagram line color is used ++ * ++ * @param state The state to set ++ */ ++void WidgetBase::setUsesDiagramLineColor(bool state) ++{ ++ m_usesDiagramLineColor = state; ++} ++ ++/** ++ * Returns state of diagram fill color is used ++ * ++ * @return True means diagrams fill color is used ++*/ ++bool WidgetBase::usesDiagramFillColor() const ++{ ++ return m_usesDiagramFillColor; ++} ++ ++/** ++ * Set state if diagram fill color is used ++ * ++ * @param state The state to set ++ */ ++void WidgetBase::setUsesDiagramFillColor(bool state) ++{ ++ m_usesDiagramFillColor = state; ++} ++ ++/** ++ * Returns state of diagram use fill color is used ++ * ++ * @return True means diagrams fill color is used ++*/ ++bool WidgetBase::usesDiagramUseFillColor() const ++{ ++ return m_usesDiagramUseFillColor; ++} ++ ++/** ++ * Set state of diagram use fill color is used ++ * ++ * @param state The state to set ++ */ ++void WidgetBase::setUsesDiagramUseFillColor(bool state) ++{ ++ m_usesDiagramUseFillColor = state; ++} ++ ++/** ++ * Returns state of diagram line width is used ++ * ++ * @return True means diagrams line width is used ++ */ ++bool WidgetBase::usesDiagramLineWidth() const ++{ ++ return m_usesDiagramLineWidth; ++} ++ ++/** ++ * Set state of diagram line width is used ++ * ++ * @param state The state to set ++ */ ++void WidgetBase::setUsesDiagramLineWidth(bool state) ++{ ++ m_usesDiagramLineWidth = state; ++} ++ ++/** ++ * Returns the font used for diaplaying any text. ++ * @return the font ++ */ ++QFont WidgetBase::font() const ++{ ++ return m_font; ++} ++ ++/** ++ * Set the font used to display text inside this widget. ++ */ ++void WidgetBase::setFont(const QFont& font) ++{ ++ m_font = font; ++} ++ ++/** ++ * A virtual method for the widget to display a property dialog box. ++ * Subclasses should reimplment this appropriately. ++ */ ++void WidgetBase::showPropertiesDialog() ++{ ++} ++ ++/** ++ * A virtual method to save the properties of this widget into a ++ * QDomElement i.e xml. ++ * ++ * Subclasses should first create a new dedicated element as the child ++ * of \a qElement parameter passed. Then this base method should be ++ * called to save basic widget properties. ++ * ++ * @param qDoc A QDomDocument object representing the xml document. ++ * @param qElement A QDomElement representing xml element data. ++ */ ++void WidgetBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) ++ { ++ Q_UNUSED(qDoc) ++ ++ qElement.setAttribute(QLatin1String("textcolor"), m_usesDiagramTextColor ? QLatin1String("none") ++ : m_textColor.name()); ++ if (m_usesDiagramLineColor) { ++ qElement.setAttribute(QLatin1String("linecolor"), QLatin1String("none")); ++ } else { ++ qElement.setAttribute(QLatin1String("linecolor"), m_lineColor.name()); ++ } ++ if (m_usesDiagramLineWidth) { ++ qElement.setAttribute(QLatin1String("linewidth"), QLatin1String("none")); ++ } else { ++ qElement.setAttribute(QLatin1String("linewidth"), m_lineWidth); ++ } ++ qElement.setAttribute(QLatin1String("usefillcolor"), m_useFillColor); ++ // for consistency the following attributes now use american spelling for "color" ++ qElement.setAttribute(QLatin1String("usesdiagramfillcolor"), m_usesDiagramFillColor); ++ qElement.setAttribute(QLatin1String("usesdiagramusefillcolor"), m_usesDiagramUseFillColor); ++ if (m_usesDiagramFillColor) { ++ qElement.setAttribute(QLatin1String("fillcolor"), QLatin1String("none")); ++ } else { ++ qElement.setAttribute(QLatin1String("fillcolor"), m_fillColor.name()); ++ } ++ qElement.setAttribute(QLatin1String("font"), m_font.toString()); ++} ++ ++/** ++ * A virtual method to load the properties of this widget from a ++ * QDomElement into this widget. ++ * ++ * Subclasses should reimplement this to load addtional properties ++ * required, calling this base method to load the basic properties of ++ * the widget. ++ * ++ * @param qElement A QDomElement which contains xml info for this widget. ++ * ++ * @todo Add support to load older version. ++ */ ++bool WidgetBase::loadFromXMI(QDomElement& qElement) ++{ ++ // first load from "linecolour" and then overwrite with the "linecolor" ++ // attribute if that one is present. The "linecolour" name was a "typo" in ++ // earlier versions of umbrello-kf6 ++ QString lineColor = qElement.attribute(QLatin1String("linecolour"), QLatin1String("none")); ++ lineColor = qElement.attribute(QLatin1String("linecolor"), lineColor); ++ if (lineColor != QLatin1String("none")) { ++ m_lineColor = QColor(lineColor); ++ m_usesDiagramLineColor = false; ++ } else if (m_baseType != WidgetBase::wt_Box && m_scene != NULL) { ++ m_lineColor = m_scene->lineColor(); ++ m_usesDiagramLineColor = true; ++ } ++ QString lineWidth = qElement.attribute(QLatin1String("linewidth"), QLatin1String("none")); ++ if (lineWidth != QLatin1String("none")) { ++ m_lineWidth = lineWidth.toInt(); ++ m_usesDiagramLineWidth = false; ++ } else if (m_scene) { ++ m_lineWidth = m_scene->lineWidth(); ++ m_usesDiagramLineWidth = true; ++ } ++ QString textColor = qElement.attribute(QLatin1String("textcolor"), QLatin1String("none")); ++ if (textColor != QLatin1String("none")) { ++ m_textColor = QColor(textColor); ++ m_usesDiagramTextColor = false; ++ } else if (m_scene) { ++ m_textColor = m_scene->textColor(); ++ m_usesDiagramTextColor = true; ++ } ++ QString usefillcolor = qElement.attribute(QLatin1String("usefillcolor"), QLatin1String("1")); ++ m_useFillColor = (bool)usefillcolor.toInt(); ++ /* ++ For the next three *color attributes, there was a mixup of american and english spelling for "color". ++ So first we need to keep backward compatibility and try to retrieve the *colour attribute. ++ Next we overwrite this value if we find a *color, otherwise the former *colour is kept. ++ */ ++ QString fillColor = qElement.attribute(QLatin1String("fillcolour"), QLatin1String("none")); ++ fillColor = qElement.attribute(QLatin1String("fillcolor"), fillColor); ++ if (fillColor != QLatin1String("none")) { ++ m_fillColor = QColor(fillColor); ++ } ++ ++ QString usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolour"), QLatin1String("1")); ++ usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolor"), usesDiagramFillColor); ++ m_usesDiagramFillColor = (bool)usesDiagramFillColor.toInt(); ++ ++ QString usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolour"), QLatin1String("1")); ++ usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolor"), usesDiagramUseFillColor); ++ m_usesDiagramUseFillColor = (bool)usesDiagramUseFillColor.toInt(); ++ ++ QString font = qElement.attribute(QLatin1String("font")); ++ if (!font.isEmpty()) { ++ QFont newFont; ++ newFont.fromString(font); ++ m_font = newFont; ++ } else { ++ uWarning() << "Using default font " << m_font.toString() ++ << " for widget with xmi.id " << Uml::ID::toString(m_nId); ++ } ++ ++ return true; ++} ++ ++/** ++ * Assignment operator ++ */ ++WidgetBase& WidgetBase::operator=(const WidgetBase& other) ++{ ++ m_baseType = other.m_baseType; ++ m_scene = other.m_scene; ++ m_umlObject = other.m_umlObject; ++ m_Doc = other.m_Doc; ++ m_Text = other.m_Text; ++ m_nId = other.m_nId; ++ m_textColor = other.m_textColor; ++ m_lineColor = other.m_lineColor; ++ m_fillColor = other.m_fillColor; ++ m_brush = other.m_brush; ++ m_font = other.m_font; ++ m_lineWidth = other.m_lineWidth; ++ m_useFillColor = other.m_useFillColor; ++ m_usesDiagramTextColor = other.m_usesDiagramTextColor; ++ m_usesDiagramLineColor = other.m_usesDiagramLineColor; ++ m_usesDiagramFillColor = other.m_usesDiagramFillColor; ++ m_usesDiagramLineWidth = other.m_usesDiagramLineWidth; ++ setSelected(other.isSelected()); ++ ++ return *this; ++} ++ ++/** ++ * return drawing rectangle of widget in local coordinates ++ */ ++QRectF WidgetBase::rect() const ++{ ++ return m_rect; ++} ++ ++/** ++ * set widget rectangle in item coordinates ++ */ ++void WidgetBase::setRect(const QRectF& rect) ++{ ++ if (m_rect == rect) ++ return; ++ prepareGeometryChange(); ++ m_rect = rect; ++ update(); ++} ++ ++/** ++ * set widget rectangle in item coordinates ++ */ ++void WidgetBase::setRect(qreal x, qreal y, qreal width, qreal height) ++{ ++ setRect(QRectF(x, y, width, height)); ++} ++ ++/** ++ * @return The bounding rectangle for this widget. ++ * @see setRect ++ */ ++QRectF WidgetBase::boundingRect() const ++{ ++ int halfWidth = lineWidth()/2; ++ return m_rect.adjusted(-halfWidth, -halfWidth, halfWidth, halfWidth); ++} ++ ++/** ++ * Test if point is inside the bounding rectangle of the widget. ++ * Inheriting classes may reimplement this to test possible child widgets. ++ * ++ * @param p Point to be checked. ++ * ++ * @return 'this' if the given point is in the boundaries of the widget; ++ * else NULL. ++ */ ++UMLWidget* WidgetBase::onWidget(const QPointF &p) ++{ ++ UMLWidget *uw = dynamic_cast(this); ++ if (uw == NULL) ++ return NULL; ++ const qreal w = m_rect.width(); ++ const qreal h = m_rect.height(); ++ const qreal left = x(); // don't use m_rect.x() for this, it is always 0 ++ const qreal right = left + w; ++ const qreal top = y(); // don't use m_rect.y() for this, it is always 0 ++ const qreal bottom = top + h; ++ // uDebug() << "p=(" << p.x() << "," << p.y() ++ // << "), x=" << left << ", y=" << top << ", w=" << w << ", h=" << h ++ // << "; right=" << right << ", bottom=" << bottom; ++ if (p.x() < left || p.x() > right || ++ p.y() < top || p.y() > bottom) { // Qt coord.sys. origin in top left corner ++ // uDebug() << "returning NULL"; ++ return NULL; ++ } ++ // uDebug() << "returning this"; ++ return uw; ++} ++ ++/** ++ * Draws the UMLWidget on the given paint device ++ * ++ * @param painter The painter for the drawing device ++ * @param option Painting related options ++ * @param widget Background widget on which to paint (optional) ++ * ++ */ ++void WidgetBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ++{ ++ Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); ++} ++ ++/** ++ * Reimplemented to show appropriate context menu. ++ */ ++void WidgetBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) ++{ ++ event->accept(); ++ uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); ++ ++ UMLScene *scene = umlScene(); ++ ++ // If right-click was done on a widget that was not selected, clear the ++ // current selection and select the new widget. The context menu is shown ++ // with actions for that single widget. ++ // If a keyboard modifier was used, add the widget to the current selection ++ // and show the menu with actions for the whole selection. ++ if (!isSelected()) { ++ Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); ++ if ((event->modifiers() & forSelection) == 0) { ++ scene->clearSelected(); ++ } ++ ++ if (umlObject() != 0) { ++ scene->selectWidget(dynamic_cast(this)); ++ } else { ++ setSelected(true); ++ } ++ } ++ ++ int count = scene->selectedCount(true); ++ ++ // Determine multi state ++ bool multi = (isSelected() && count > 1); ++ ++ ListPopupMenu popup(0, this, multi, scene->getUniqueSelectionType()); ++ ++ // Disable the "view code" menu for simple code generators ++ if (UMLApp::app()->isSimpleCodeGeneratorActive()) { ++ popup.setActionEnabled(ListPopupMenu::mt_ViewCode, false); ++ } ++ ++ QAction *triggered = popup.exec(event->screenPos()); ++ ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); ++ ++ if (!parentMenu) { ++ uDebug() << "Action's data field does not contain ListPopupMenu pointer"; ++ return; ++ } ++ ++ WidgetBase *ownerWidget = parentMenu->ownerWidget(); ++ // assert because logic is based on only WidgetBase being the owner of ++ // ListPopupMenu actions executed in this context menu. ++ Q_ASSERT_X(ownerWidget != 0, "WidgetBase::contextMenuEvent", ++ "ownerWidget is null which means action belonging to UMLView, UMLScene" ++ " or UMLObject is the one triggered in ListPopupMenu"); ++ ++ ownerWidget->slotMenuSelection(triggered); ++} ++ ++/** ++ * 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 WidgetBase::slotMenuSelection(QAction *trigger) ++{ ++ if (!trigger) { ++ return; ++ } ++ QColor newColor; ++ ++ const WidgetType wt = m_baseType; // short hand name ++ ++ ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); ++ switch (sel) { ++ case ListPopupMenu::mt_Rename: ++ umlDoc()->renameUMLObject(umlObject()); ++ break; ++ ++ case ListPopupMenu::mt_Properties: ++ if (wt == WidgetBase::wt_Actor || wt == WidgetBase::wt_UseCase || ++ wt == WidgetBase::wt_Package || wt == WidgetBase::wt_Interface || ++ wt == WidgetBase::wt_Datatype || wt == WidgetBase::wt_Node || ++ wt == WidgetBase::wt_Component || wt == WidgetBase::wt_Artifact || ++ wt == WidgetBase::wt_Enum || wt == WidgetBase::wt_Entity || ++ wt == WidgetBase::wt_Port || ++ (wt == WidgetBase::wt_Class && umlScene()->type() == Uml::DiagramType::Class)) { ++ ++ showPropertiesDialog(); ++ ++ } else if (wt == WidgetBase::wt_Object) { ++ m_umlObject->showPropertiesDialog(); ++ } else { ++ uWarning() << "making properties dialog for unknown widget type"; ++ } ++ break; ++ ++ case ListPopupMenu::mt_Line_Color: ++ case ListPopupMenu::mt_Line_Color_Selection: ++#if QT_VERSION >= 0x050000 ++ newColor = QColorDialog::getColor(lineColor()); ++ if (newColor != lineColor()) { ++#else ++ newColor = lineColor(); ++ if (KColorDialog::getColor(newColor)) { ++#endif ++ if (sel == ListPopupMenu::mt_Line_Color_Selection) { ++ umlScene()->selectionSetLineColor(newColor); ++ } else { ++ setLineColor(newColor); ++ } ++ setUsesDiagramLineColor(false); ++ umlDoc()->setModified(true); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Fill_Color: ++ case ListPopupMenu::mt_Fill_Color_Selection: ++#if QT_VERSION >= 0x050000 ++ newColor = QColorDialog::getColor(fillColor()); ++ if (newColor != fillColor()) { ++#else ++ newColor = fillColor(); ++ if (KColorDialog::getColor(newColor)) { ++#endif ++ if (sel == ListPopupMenu::mt_Fill_Color_Selection) { ++ umlScene()->selectionSetFillColor(newColor); ++ } else { ++ setFillColor(newColor); ++ } ++ umlDoc()->setModified(true); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Use_Fill_Color: ++ setUseFillColor(!m_useFillColor); ++ break; ++ ++ case ListPopupMenu::mt_Set_Use_Fill_Color_Selection: ++ umlScene()->selectionUseFillColor(true); ++ break; ++ ++ case ListPopupMenu::mt_Unset_Use_Fill_Color_Selection: ++ umlScene()->selectionUseFillColor(false); ++ break; ++ ++ case ListPopupMenu::mt_Show_Attributes_Selection: ++ case ListPopupMenu::mt_Hide_Attributes_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowAttributes, sel != ListPopupMenu::mt_Hide_Attributes_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Show_Operations_Selection: ++ case ListPopupMenu::mt_Hide_Operations_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowOperations, sel != ListPopupMenu::mt_Hide_Operations_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Show_Visibility_Selection: ++ case ListPopupMenu::mt_Hide_Visibility_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowVisibility, sel != ListPopupMenu::mt_Hide_Visibility_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Show_Operation_Signature_Selection: ++ case ListPopupMenu::mt_Hide_Operation_Signature_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowOperationSignature, sel != ListPopupMenu::mt_Hide_Operation_Signature_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Show_Attribute_Signature_Selection: ++ case ListPopupMenu::mt_Hide_Attribute_Signature_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowAttributeSignature, sel != ListPopupMenu::mt_Hide_Attribute_Signature_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Show_Packages_Selection: ++ case ListPopupMenu::mt_Hide_Packages_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowPackage, sel != ListPopupMenu::mt_Hide_Packages_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Show_Stereotypes_Selection: ++ case ListPopupMenu::mt_Hide_Stereotypes_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowStereotype, sel != ListPopupMenu::mt_Hide_Stereotypes_Selection ++ ); ++ break; ++ ++ case ListPopupMenu::mt_Hide_NonPublic_Selection: ++ case ListPopupMenu::mt_Show_NonPublic_Selection: ++ umlScene()->selectionSetVisualProperty( ++ ClassifierWidget::ShowPublicOnly, sel != ListPopupMenu::mt_Show_NonPublic_Selection ++ ); ++ break; ++ ++ ++ case ListPopupMenu::mt_ViewCode: { ++ UMLClassifier *c = dynamic_cast(umlObject()); ++ if (c) { ++ UMLApp::app()->viewCodeDocument(c); ++ } ++ break; ++ } ++ ++ case ListPopupMenu::mt_Delete: ++ umlScene()->deleteSelection(); ++ break; ++ ++ case ListPopupMenu::mt_Change_Font: ++ case ListPopupMenu::mt_Change_Font_Selection: { ++#if QT_VERSION >= 0x050000 ++ bool ok = false; ++ QFont newFont = QFontDialog::getFont(&ok, font()); ++ if (ok) { ++#else ++ QFont newFont = font(); ++ if (KFontDialog::getFont(newFont, KFontChooser::NoDisplayFlags, 0) == KFontDialog::Accepted) { ++#endif ++ if (sel == ListPopupMenu::mt_Change_Font_Selection) { ++ m_scene->selectionSetFont(newFont); ++ } else { ++ setFont(newFont); ++ } ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Cut: ++ umlScene()->setStartedCut(); ++ UMLApp::app()->slotEditCut(); ++ break; ++ ++ case ListPopupMenu::mt_Copy: ++ UMLApp::app()->slotEditCopy(); ++ break; ++ ++ case ListPopupMenu::mt_Paste: ++ UMLApp::app()->slotEditPaste(); ++ break; ++ ++ case ListPopupMenu::mt_Refactoring: ++ //check if we are operating on a classifier, or some other kind of UMLObject ++ if (dynamic_cast(umlObject())) { ++ UMLApp::app()->refactor(static_cast(umlObject())); ++ } ++ break; ++ ++ case ListPopupMenu::mt_Clone: ++ { ++ foreach (UMLWidget* widget, umlScene()->selectedWidgets()) { ++ if (Model_Utils::isCloneable(widget->baseType())) { ++ UMLObject *clone = widget->umlObject()->clone(); ++ umlScene()->addObject(clone); ++ } ++ } ++ } ++ break; ++ ++ case ListPopupMenu::mt_Rename_MultiA: ++ case ListPopupMenu::mt_Rename_MultiB: ++ case ListPopupMenu::mt_Rename_Name: ++ case ListPopupMenu::mt_Rename_RoleAName: ++ case ListPopupMenu::mt_Rename_RoleBName: { ++ FloatingTextWidget *ft = static_cast(this); ++ ft->handleRename(); ++ break; ++ } ++ case ListPopupMenu::mt_Align_Right: ++ umlScene()->alignRight(); ++ break; ++ case ListPopupMenu::mt_Align_Left: ++ umlScene()->alignLeft(); ++ break; ++ case ListPopupMenu::mt_Align_Top: ++ umlScene()->alignTop(); ++ break; ++ case ListPopupMenu::mt_Align_Bottom: ++ umlScene()->alignBottom(); ++ break; ++ case ListPopupMenu::mt_Align_VerticalMiddle: ++ umlScene()->alignVerticalMiddle(); ++ break; ++ case ListPopupMenu::mt_Align_HorizontalMiddle: ++ umlScene()->alignHorizontalMiddle(); ++ break; ++ case ListPopupMenu::mt_Align_VerticalDistribute: ++ umlScene()->alignVerticalDistribute(); ++ break; ++ case ListPopupMenu::mt_Align_HorizontalDistribute: ++ umlScene()->alignHorizontalDistribute(); ++ break; ++ default: ++ uDebug() << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; ++ break; ++ } ++} ++ ++/** ++ * Helper function for debug output. ++ * Returns the given enum value as string. ++ * @param wt WidgetType of which a string representation is wanted ++ * @return the WidgetType as string ++ */ ++QString WidgetBase::toString(WidgetType wt) ++{ ++ return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, wt)); ++} ++ ++/** ++ * Returns the given enum value as localized string. ++ * @param wt WidgetType of which a string representation is wanted ++ * @return the WidgetType as localized string ++ */ ++QString WidgetBase::toI18nString(WidgetType wt) ++{ ++ QString name; ++ ++ switch (wt) { ++ case wt_Activity: ++ name = i18n("Activity"); ++ break; ++ case wt_Actor: ++ name = i18n("Actor"); ++ break; ++ case wt_Artifact: ++ name = i18n("Artifact"); ++ break; ++ case wt_Association: ++ name = i18n("Association"); ++ break; ++ case wt_Box: ++ name = i18n("Box"); ++ break; ++ case wt_Category: ++ name = i18n("Category"); ++ break; ++ case wt_CombinedFragment: ++ name = i18n("CombinedFragment"); ++ break; ++ case wt_Component: ++ name = i18n("Component"); ++ break; ++ case wt_Class: ++ name = i18n("Class"); ++ break; ++ case wt_Datatype: ++ name = i18n("Datatype"); ++ break; ++ case wt_Entity: ++ name = i18n("Entity"); ++ break; ++ case wt_Enum: ++ name = i18n("Enum"); ++ break; ++ case wt_FloatingDashLine: ++ name = i18n("FloatingDashLine"); ++ break; ++ case wt_ForkJoin: ++ name = i18n("ForkJoin"); ++ break; ++ case wt_Interface: ++ name = i18n("Interface"); ++ break; ++ case wt_Message: ++ name = i18n("Message"); ++ break; ++ case wt_Node: ++ name = i18n("Node"); ++ break; ++ case wt_Note: ++ name = i18n("Note"); ++ break; ++ case wt_Object: ++ name = i18n("Object"); ++ break; ++ case wt_ObjectNode: ++ name = i18n("ObjectNode"); ++ break; ++ case wt_Package: ++ name = i18n("Package"); ++ break; ++ case wt_Pin: ++ name = i18n("Pin"); ++ break; ++ case wt_Port: ++ name = i18n("Port"); ++ break; ++ case wt_Precondition: ++ name = i18n("Precondition"); ++ break; ++ case wt_Region: ++ name = i18n("Region"); ++ break; ++ case wt_Signal: ++ name = i18n("Signal"); ++ break; ++ case wt_State: ++ name = i18n("State"); ++ break; ++ case wt_Text: ++ name = i18n("Text"); ++ break; ++ case wt_UseCase: ++ name = i18n("UseCase"); ++ break; ++ default: ++ name = QLatin1String(" &name:"); ++ uWarning() << "unknown widget type"; ++ break; ++ } ++ return name; ++} ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,192 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef WIDGETBASE_H ++#define WIDGETBASE_H ++ ++#include "basictypes.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// forward declarations ++class QAction; ++class UMLDoc; ++class UMLObject; ++class UMLScene; ++class UMLWidget; // required by function onWidget() ++ ++/** ++ * @short Common base class for UMLWidget and AssociationWidget ++ * @author Oliver Kellogg ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++class WidgetBase : public QGraphicsObject ++{ ++ Q_OBJECT ++ Q_ENUMS(WidgetType) ++ ++public: ++ enum WidgetType ++ { ++ wt_UMLWidget = 300, // does not have UMLObject representation ++ wt_Actor, // has UMLObject representation ++ wt_UseCase, // has UMLObject representation ++ wt_Class, // has UMLObject representation ++ wt_Interface, // has UMLObject representation ++ wt_Datatype, // has UMLObject representation ++ wt_Enum, // has UMLObject representation ++ wt_Entity, // has UMLObject representation ++ wt_Package, // has UMLObject representation ++ wt_Object, // has UMLObject representation ++ wt_Note, // does not have UMLObject representation ++ wt_Box, // does not have UMLObject representation ++ wt_Message, // does not have UMLObject representation ++ wt_Text, // does not have UMLObject representation ++ wt_State, // does not have UMLObject representation ++ wt_Activity, // does not have UMLObject representation ++ wt_Component, // has UMLObject representation ++ wt_Artifact, // has UMLObject representation ++ wt_Node, // has UMLObject representation ++ wt_Association, // has UMLObject representation ++ wt_ForkJoin, // does not have UMLObject representation ++ wt_Precondition, // does not have UMLObject representation ++ wt_CombinedFragment, // does not have UMLObject representation ++ wt_FloatingDashLine, // does not have UMLObject representation ++ wt_Signal, // does not have UMLObject representation ++ wt_Pin, ++ wt_ObjectNode, ++ wt_Region, ++ wt_Category, // has UMLObject representation ++ wt_Port // has UMLObject representation ++ }; ++ ++ static QString toString(WidgetType wt); ++ static QString toI18nString(WidgetType wt); ++ ++ explicit WidgetBase(UMLScene * scene, WidgetType type= wt_UMLWidget); ++ virtual ~WidgetBase(); ++ ++ UMLObject* umlObject() const; ++ virtual void setUMLObject(UMLObject *obj); ++ ++ Uml::ID::Type id() const; ++ void setID(Uml::ID::Type id); ++ ++ WidgetType baseType() const; ++ QLatin1String baseTypeStr() const; ++ ++ virtual void setSelected(bool select); ++ ++ UMLScene* umlScene() const; ++ UMLDoc* umlDoc() const; ++ ++ QString documentation() const; ++ bool hasDocumentation(); ++ virtual void setDocumentation(const QString& doc); ++ ++ QString name() const; ++ virtual void setName(const QString &strName); ++ ++ QColor lineColor() const; ++ virtual void setLineColor(const QColor& color); ++ ++ uint lineWidth() const; ++ virtual void setLineWidth(uint width); ++ ++ QColor textColor() const; ++ virtual void setTextColor(const QColor& color); ++ ++ QColor fillColor() const; ++ virtual void setFillColor(const QColor& color); ++ ++ bool usesDiagramLineColor() const; ++ void setUsesDiagramLineColor(bool state); ++ ++ bool usesDiagramLineWidth() const; ++ void setUsesDiagramLineWidth(bool state); ++ ++ bool useFillColor(); ++ virtual void setUseFillColor(bool state); ++ ++ bool usesDiagramTextColor() const; ++ void setUsesDiagramTextColor(bool state); ++ ++ bool usesDiagramFillColor() const; ++ void setUsesDiagramFillColor(bool state); ++ ++ bool usesDiagramUseFillColor() const; ++ void setUsesDiagramUseFillColor(bool state); ++ ++ virtual QFont font() const; ++ virtual void setFont(const QFont& font); ++ ++ virtual void showPropertiesDialog(); ++ ++ virtual bool loadFromXMI(QDomElement &qElement); ++ virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); ++ ++ WidgetBase& operator=(const WidgetBase& other); ++ ++ QRectF rect() const; ++ void setRect(const QRectF& rect); ++ void setRect(qreal x, qreal y, qreal width, qreal height); ++ ++ virtual QRectF boundingRect() const; ++ ++ virtual UMLWidget* onWidget(const QPointF &p); ++ ++ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); ++ ++public Q_SLOTS: ++ virtual void slotMenuSelection(QAction *trigger); ++ ++protected: ++ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); ++ ++ WidgetType m_baseType; ///< Type of widget. ++ UMLScene *m_scene; ++ UMLObject *m_umlObject; ++ QString m_Doc; ///< Only used if m_umlObject is not set. ++ QString m_Text; ++ QRectF m_rect; ///< widget size ++ ++ /** ++ * This ID is only used when the widget does not have a ++ * corresponding UMLObject (i.e. the m_umlObject pointer is NULL.) ++ * For UMLObjects, the ID from the UMLObject is used. ++ */ ++ Uml::ID::Type m_nId; ++ ++ QColor m_textColor; ///< Color of the text of the widget. Is saved to XMI. ++ QColor m_lineColor; ///< Color of the lines of the widget. Is saved to XMI. ++ QColor m_fillColor; ///< color of the background of the widget ++ QBrush m_brush; ++ QFont m_font; ++ uint m_lineWidth; ///< Width of the lines of the widget. Is saved to XMI. ++ bool m_useFillColor; ///< flag indicates if the UMLWidget uses the Diagram FillColour ++ ++ /** ++ * true by default, false if the colors have ++ * been explicitly set for this widget. ++ * These are saved to XMI. ++ */ ++ bool m_usesDiagramTextColor; ++ bool m_usesDiagramLineColor; ++ bool m_usesDiagramFillColor; ++ bool m_usesDiagramUseFillColor; ++ bool m_usesDiagramLineWidth; ++}; ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,298 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "widget_factory.h" ++ ++// app includes ++#include "activitywidget.h" ++#include "actor.h" ++#include "actorwidget.h" ++#include "artifact.h" ++#include "artifactwidget.h" ++#include "associationwidget.h" ++#include "boxwidget.h" ++#include "category.h" ++#include "categorywidget.h" ++#include "classifier.h" ++#include "classifierwidget.h" ++#include "cmds.h" ++#include "combinedfragmentwidget.h" ++#include "component.h" ++#include "componentwidget.h" ++#include "datatypewidget.h" ++#include "debug_utils.h" ++#include "entity.h" ++#include "entitywidget.h" ++#include "enum.h" ++#include "enumwidget.h" ++#include "floatingdashlinewidget.h" ++#include "floatingtextwidget.h" ++#include "folder.h" ++#include "forkjoinwidget.h" ++#include "messagewidget.h" ++#include "node.h" ++#include "nodewidget.h" ++#include "notewidget.h" ++#include "object_factory.h" ++#include "objectnodewidget.h" ++#include "objectwidget.h" ++#include "package.h" ++#include "packagewidget.h" ++#include "pinwidget.h" ++#include "port.h" ++#include "portwidget.h" ++#include "preconditionwidget.h" ++#include "regionwidget.h" ++#include "signalwidget.h" ++#include "statewidget.h" ++#include "uml.h" ++#include "umldoc.h" ++#include "umlscene.h" ++#include "umlview.h" ++#include "usecase.h" ++#include "usecasewidget.h" ++ ++namespace Widget_Factory { ++ ++/** ++ * Create a UMLWidget in the given view and representing the given document object. ++ */ ++UMLWidget *createWidget(UMLScene *scene, UMLObject *o) ++{ ++ QPointF pos = scene->pos(); ++ int y = pos.y(); ++ Uml::DiagramType::Enum diagramType = scene->type(); ++ UMLObject::ObjectType type = o->baseType(); ++ UMLWidget *newWidget = NULL; ++ switch (type) { ++ case UMLObject::ot_Actor: ++ if (diagramType == Uml::DiagramType::Sequence) { ++ ObjectWidget *ow = new ObjectWidget(scene, o); ++ ow->setDrawAsActor(true); ++ y = ow->topMargin(); ++ newWidget = ow; ++ } else ++ newWidget = new ActorWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_UseCase: ++ newWidget = new UseCaseWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Folder: ++ newWidget = new PackageWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Package: ++ newWidget = new ClassifierWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Component: ++ newWidget = new ComponentWidget(scene, static_cast(o)); ++ if (diagramType == Uml::DiagramType::Deployment) { ++ newWidget->setIsInstance(true); ++ } ++ break; ++ case UMLObject::ot_Port: ++ { ++ PinPortBase *pw = new PortWidget(scene, static_cast(o)); ++ pw->attachToOwner(); ++ newWidget = pw; ++ } ++ break; ++ case UMLObject::ot_Node: ++ newWidget = new NodeWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Artifact: ++ newWidget = new ArtifactWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Datatype: ++ newWidget = new DatatypeWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Enum: ++ newWidget = new EnumWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Entity: ++ newWidget = new EntityWidget(scene, static_cast(o)); ++ break; ++ case UMLObject::ot_Interface: ++ if (diagramType == Uml::DiagramType::Sequence || diagramType == Uml::DiagramType::Collaboration) { ++ ObjectWidget *ow = new ObjectWidget(scene, o); ++ if (diagramType == Uml::DiagramType::Sequence) { ++ y = ow->topMargin(); ++ } ++ newWidget = ow; ++ } else { ++ UMLClassifier *c = static_cast(o); ++ ClassifierWidget* interfaceWidget = new ClassifierWidget(scene, c); ++ if (diagramType == Uml::DiagramType::Component || diagramType == Uml::DiagramType::Deployment) { ++ interfaceWidget->setDrawAsCircle(true); ++ } ++ newWidget = interfaceWidget; ++ } ++ break; ++ case UMLObject::ot_Class: ++ //see if we really want an object widget or class widget ++ if (diagramType == Uml::DiagramType::Class || diagramType == Uml::DiagramType::Component) { ++ UMLClassifier *c = static_cast(o); ++ ClassifierWidget *cw = new ClassifierWidget(scene, c); ++ if (diagramType == Uml::DiagramType::Component) ++ cw->setDrawAsCircle(true); ++ newWidget = cw; ++ } else { ++ ObjectWidget *ow = new ObjectWidget(scene, o); ++ if (diagramType == Uml::DiagramType::Sequence) { ++ y = ow->topMargin(); ++ } ++ newWidget = ow; ++ } ++ break; ++ case UMLObject::ot_Category: ++ newWidget = new CategoryWidget(scene, static_cast(o)); ++ break; ++ default: ++ uWarning() << "trying to create an invalid widget (" << UMLObject::toString(type) << ")"; ++ } ++ ++ if (newWidget) { ++ newWidget->setX(pos.x()); ++ newWidget->setY(y); ++ } ++ ++ return newWidget; ++} ++ ++bool validateObjType(UMLObject::ObjectType expected, UMLObject* &o, Uml::ID::Type id) ++{ ++ if (o == NULL) { ++ uDebug() << "Widget_Factory::validateObjType: creating new object of type " ++ << expected; ++ QString artificialName = QLatin1String("LOST_") + Uml::ID::toString(id); ++ o = Object_Factory::createUMLObject(expected, artificialName, NULL, false); ++ if (o == NULL) ++ return false; ++ o->setID(id); ++ UMLPackage *parentPkg = o->umlPackage(); ++ parentPkg->addObject(o); ++ return true; ++ } ++ UMLObject::ObjectType actual = o->baseType(); ++ if (actual == expected) ++ return true; ++ uError() << "validateObjType(" << o->name() ++ << "): expected type " << UMLObject::toString(expected) << ", actual type " ++ << UMLObject::toString(actual); ++ return false; ++} ++ ++/** ++ * Create a UMLWidget according to the given XMI tag. ++ */ ++UMLWidget* makeWidgetFromXMI(const QString& tag, ++ const QString& idStr, UMLScene *scene) ++{ ++ UMLWidget *widget = NULL; ++ ++ // Loading of widgets which do NOT represent any UMLObject, ++ // just graphic stuff with no real model information ++ //FIXME while boxes and texts are just diagram objects, activities and ++ // states should be UMLObjects ++ if (tag == QLatin1String("statewidget") || tag == QLatin1String("UML:StateWidget")) { ++ widget = new StateWidget(scene, StateWidget::Normal, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("notewidget") || tag == QLatin1String("UML:NoteWidget")) { ++ widget = new NoteWidget(scene, NoteWidget::Normal, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("boxwidget")) { ++ widget = new BoxWidget(scene, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML:FloatingTextWidget")) { ++ widget = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString(), Uml::ID::Reserved); ++ } else if (tag == QLatin1String("activitywidget") || tag == QLatin1String("UML:ActivityWidget")) { ++ widget = new ActivityWidget(scene, ActivityWidget::Initial, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("messagewidget")) { ++ widget = new MessageWidget(scene, Uml::SequenceMessage::Asynchronous, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("forkjoin")) { ++ widget = new ForkJoinWidget(scene, Qt::Vertical, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("preconditionwidget")) { ++ widget = new PreconditionWidget(scene, NULL, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("combinedFragmentwidget")) { ++ widget = new CombinedFragmentWidget(scene, CombinedFragmentWidget::Ref, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("signalwidget")) { ++ widget = new SignalWidget(scene, SignalWidget::Send, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("floatingdashlinewidget")) { ++ widget = new FloatingDashLineWidget(scene, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("objectnodewidget")) { ++ widget = new ObjectNodeWidget(scene, ObjectNodeWidget::Normal, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("regionwidget")) { ++ widget = new RegionWidget(scene, Uml::ID::Reserved); ++ } else if (tag == QLatin1String("pinwidget")) { ++ PinPortBase *pw = new PinWidget(scene, NULL, Uml::ID::Reserved); ++ pw->attachToOwner(); ++ widget = pw; ++ } ++ else ++ { ++ // Loading of widgets which represent an UMLObject ++ ++ // Find the UMLObject and create the Widget to represent it ++ Uml::ID::Type id = Uml::ID::fromString(idStr); ++ UMLDoc *umldoc = UMLApp::app()->document(); ++ UMLObject *o = umldoc->findObjectById(id); ++ if (o == NULL) { ++ uDebug() << "makeWidgetFromXMI: cannot find object with id " ++ << Uml::ID::toString(id); ++ } ++ ++ if (tag == QLatin1String("actorwidget") || tag == QLatin1String("UML:ActorWidget")) { ++ if (validateObjType(UMLObject::ot_Actor, o, id)) ++ widget = new ActorWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("usecasewidget") || tag == QLatin1String("UML:UseCaseWidget")) { ++ if (validateObjType(UMLObject::ot_UseCase, o, id)) ++ widget = new UseCaseWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("classwidget") || ++ tag == QLatin1String("UML:ClassWidget") || tag == QLatin1String("UML:ConceptWidget")) { ++ if (validateObjType(UMLObject::ot_Class, o, id) || validateObjType(UMLObject::ot_Package, o, id)) ++ widget = new ClassifierWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("packagewidget")) { ++ if (validateObjType(UMLObject::ot_Package, o, id)) ++ widget = new ClassifierWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("componentwidget")) { ++ if (validateObjType(UMLObject::ot_Component, o, id)) ++ widget = new ComponentWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("portwidget")) { ++ if (validateObjType(UMLObject::ot_Port, o, id)) ++ widget = new PortWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("nodewidget")) { ++ if (validateObjType(UMLObject::ot_Node, o, id)) ++ widget = new NodeWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("artifactwidget")) { ++ if (validateObjType(UMLObject::ot_Artifact, o, id)) ++ widget = new ArtifactWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("interfacewidget")) { ++ if (validateObjType(UMLObject::ot_Interface, o, id)) ++ widget = new ClassifierWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("datatypewidget")) { ++ if (validateObjType(UMLObject::ot_Datatype, o, id)) ++ widget = new DatatypeWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("enumwidget")) { ++ if (validateObjType(UMLObject::ot_Enum, o, id)) ++ widget = new EnumWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("entitywidget")) { ++ if (validateObjType(UMLObject::ot_Entity, o, id)) ++ widget = new EntityWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("categorywidget")) { ++ if (validateObjType(UMLObject::ot_Category, o, id)) ++ widget = new CategoryWidget(scene, static_cast(o)); ++ } else if (tag == QLatin1String("objectwidget") || tag == QLatin1String("UML:ObjectWidget")) { ++ widget = new ObjectWidget(scene, o); ++ } else { ++ uWarning() << "Trying to create an unknown widget:" << tag; ++ } ++ } ++ return widget; ++} ++ ++} // end namespace Widget_Factory ++ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,34 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef WIDGET_FACTORY_H ++#define WIDGET_FACTORY_H ++ ++#include ++ ++// forward declarations ++class UMLObject; ++class UMLScene; ++class UMLWidget; ++ ++/** ++ * Widget factory methods. ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++namespace Widget_Factory { ++ ++ UMLWidget *createWidget(UMLScene *scene, UMLObject *docObj); ++ ++ UMLWidget* makeWidgetFromXMI(const QString& tag, ++ const QString& idStr, UMLScene *scene); ++ ++} // end namespace Widget_Factory ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,157 @@ ++/*************************************************************************** ++ * 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) 2009-2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "widgetlist_utils.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "umlwidget.h" ++ ++// qt/kde includes ++#include ++ ++namespace WidgetList_Utils ++{ ++ ++/** ++ * Looks for the smallest x-value of the given UMLWidgets. ++ * @param widgetList A list with UMLWidgets. ++ * @return The smallest X position. ++ */ ++qreal getSmallestX(const UMLWidgetList &widgetList) ++{ ++ qreal smallestX = 0; ++ ++ int i = 1; ++ foreach(UMLWidget *widget, widgetList) { ++ if (i == 1) { ++ smallestX = widget->x(); ++ } else { ++ if (smallestX > widget->x()) ++ smallestX = widget->x(); ++ } ++ i++; ++ } ++ ++ return smallestX; ++} ++ ++/** ++ * Looks for the smallest y-value of the given UMLWidgets. ++ * @param widgetList A list with UMLWidgets. ++ * @return The smallest Y position. ++ */ ++qreal getSmallestY(const UMLWidgetList &widgetList) ++{ ++ if (widgetList.isEmpty()) ++ return -1; ++ ++ qreal smallestY = 0; ++ ++ int i = 1; ++ foreach(UMLWidget *widget, widgetList) { ++ if (i == 1) { ++ smallestY = widget->y(); ++ } else { ++ if (smallestY > widget->y()) ++ smallestY = widget->y(); ++ } ++ i++; ++ } ++ ++ return smallestY; ++} ++ ++/** ++ * Looks for the biggest x-value of the given UMLWidgets. ++ * @param widgetList A list with UMLWidgets. ++ * @return The biggest X position. ++ */ ++qreal getBiggestX(const UMLWidgetList &widgetList) ++{ ++ if (widgetList.isEmpty()) ++ return -1; ++ ++ qreal biggestX = 0; ++ ++ int i = 1; ++ foreach(UMLWidget *widget, widgetList) { ++ if (i == 1) { ++ biggestX = widget->x(); ++ biggestX += widget->width(); ++ } else { ++ if (biggestX < widget->x() + widget->width()) ++ biggestX = widget->x() + widget->width(); ++ } ++ i++; ++ } ++ ++ return biggestX; ++} ++ ++/** ++ * Looks for the biggest y-value of the given UMLWidgets. ++ * @param widgetList A list with UMLWidgets. ++ * @return The biggest Y position. ++ */ ++qreal getBiggestY(const UMLWidgetList &widgetList) ++{ ++ if (widgetList.isEmpty()) ++ return -1; ++ ++ qreal biggestY = 0; ++ ++ int i = 1; ++ foreach(UMLWidget *widget, widgetList) { ++ if (i == 1) { ++ biggestY = widget->y(); ++ biggestY += widget->height(); ++ } else { ++ if (biggestY < widget->y() + widget->height()) ++ biggestY = widget->y() + widget->height(); ++ } ++ i++; ++ } ++ ++ return biggestY; ++} ++ ++/** ++ * Returns the sum of the heights of the given UMLWidgets ++ * @param widgetList A list with UMLWidgets. ++ */ ++qreal getHeightsSum(const UMLWidgetList &widgetList) ++{ ++ qreal heightsSum = 0; ++ ++ foreach(UMLWidget *widget, widgetList) { ++ heightsSum += widget->height(); ++ } ++ ++ return heightsSum; ++} ++ ++/** ++ * Returns the sum of the widths of the given UMLWidgets. ++ * @param widgetList A list with UMLWidgets. ++ */ ++qreal getWidthsSum(const UMLWidgetList &widgetList) ++{ ++ qreal widthsSum = 0; ++ ++ foreach(UMLWidget *widget, widgetList) { ++ widthsSum += widget->width(); ++ } ++ ++ return widthsSum; ++} ++ ++} // namespace WidgetList_Utils +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,30 @@ ++/*************************************************************************** ++ * 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) 2009-2014 * ++ * umbrello-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef WIDGETLIST_UTILS_H ++#define WIDGETLIST_UTILS_H ++ ++#include "umlwidgetlist.h" ++ ++/** ++ * General purpose-kf6 widget list utilities. ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++namespace WidgetList_Utils ++{ ++ qreal getSmallestX(const UMLWidgetList &widgetList); ++ qreal getSmallestY(const UMLWidgetList &widgetList); ++ qreal getBiggestX(const UMLWidgetList &widgetList); ++ qreal getBiggestY(const UMLWidgetList &widgetList); ++ qreal getHeightsSum(const UMLWidgetList &widgetList); ++ qreal getWidthsSum(const UMLWidgetList &widgetList); ++} // namespace WidgetList_Utils ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,827 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++// own header ++#include "widget_utils.h" ++ ++// app includes ++#include "debug_utils.h" ++#include "objectwidget.h" ++#include "messagewidget.h" ++#include "umlwidget.h" ++ ++// qt includes ++#include ++#include ++#include ++#include ++#include ++ ++// c++ include ++#include ++ ++namespace Widget_Utils ++{ ++ ++ /** ++ * Find the widget identified by the given ID in the given widget ++ * or message list. ++ * ++ * @param id The unique ID to find. ++ * @param widgets The UMLWidgetList to search in. ++ * @param messages Optional pointer to a MessageWidgetList to search in. ++ */ ++ UMLWidget* findWidget(Uml::ID::Type id, ++ const UMLWidgetList& widgets, ++ const MessageWidgetList* messages /* = 0 */) ++ { ++ foreach (UMLWidget* obj, widgets) { ++ if (obj->baseType() == WidgetBase::wt_Object) { ++ if (static_cast(obj)->localID() == id) ++ return obj; ++ } else if (obj->id() == id) { ++ return obj; ++ } ++ } ++ ++ if (messages) { ++ foreach (UMLWidget* obj, *messages) { ++ if (obj->id() == id) ++ return obj; ++ } ++ } ++ return NULL; ++ } ++ ++ /** ++ * Creates the decoration point. ++ * @param p base point to decorate ++ * @param parent parent item ++ * @return decoration point ++ */ ++ QGraphicsRectItem* decoratePoint(const QPointF &p, QGraphicsItem* parent) ++ { ++ const qreal SIZE = 4.0; ++ const qreal SIZE_HALF = SIZE / 2.0; ++ QGraphicsRectItem *rect = new QGraphicsRectItem(p.x() - SIZE_HALF, ++ p.y() - SIZE_HALF, ++ SIZE, SIZE, ++ parent); ++ rect->setBrush(QBrush(Qt::blue)); ++ rect->setPen(QPen(Qt::blue)); ++ return rect; ++ } ++ ++ /** ++ * Calculates and draws a cross inside an ellipse ++ * @param p Pointer to a QPainter object. ++ * @param r The rectangle describing the ellipse. ++ */ ++ void drawCrossInEllipse(QPainter *p, const QRectF& r) ++ { ++ QRectF ellipse = r; ++ ellipse.moveCenter(QPointF(0, 0)); ++ qreal a = ellipse.width() * 0.5; ++ qreal b = ellipse.height() * .5; ++ qreal xc = ellipse.center().x(); ++ qreal yc = ellipse.center().y(); ++ ++ // The first point's x value is chosen to be center.x() + 70% of x radius. ++ qreal x1 = ellipse.center().x() + .7 * .5 * ellipse.width(); ++ // Calculate y1 corresponding to x1 using formula. ++ qreal y1_sqr = b*b*(1 - (x1 * x1) / (a*a)); ++ qreal y1 = std::sqrt(y1_sqr); ++ ++ // Mirror x1, y1 along both the axes to get 4 points for the cross. ++ QPointF p1(xc + x1, yc + y1); ++ QPointF p2(xc - x1, yc + y1); ++ QPointF p3(xc + x1, yc - y1); ++ QPointF p4(xc - x1, yc - y1); ++ ++ // Translate as we calculate for ellipse with (0, 0) as center. ++ p->translate(r.center().x(), r.center().y()); ++ ++ // Draw the cross now ++ p->drawLine(QLineF(p1, p4)); ++ p->drawLine(QLineF(p2, p3)); ++ ++ // Restore the translate on painter. ++ p->translate(-r.center().x(), -r.center().y()); ++ } ++ ++ /** ++ * Draws a polygon which is almost rectangular except for the top ++ * right corner. A triangle is drawn in top right corner of the ++ * rectangle. ++ * ++ * @param painter The painter with which this shape is to be drawn. ++ * @param rect The rectangle dimensions. ++ * @param triSize The size of the triangle in the top-right corner. ++ */ ++ void drawTriangledRect(QPainter *painter, ++ const QRectF &rect, const QSizeF &triSize) ++ { ++ // Draw outer boundary defined by polygon "poly". ++ QPolygonF poly(5); ++ poly[0] = rect.topLeft(); ++ poly[1] = rect.topRight() - QPointF(triSize.width(), 0); ++ poly[2] = rect.topRight() + QPointF(0, triSize.height()); ++ poly[3] = rect.bottomRight(); ++ poly[4] = rect.bottomLeft(); ++ painter->drawPolygon(poly); ++ ++ // Now draw the triangle base and height edges. ++ QLineF heightEdge(poly[1], poly[1] + QPointF(0, triSize.height())); ++ painter->drawLine(heightEdge); ++ QLineF baseEdge(heightEdge.p2(), poly[2]); ++ painter->drawLine(baseEdge); ++ } ++ ++// /** ++// * Draws an arrow head with the given painter, with the arrow ++// * sharp point at \a headPos. ++// * ++// * param painter The painter with which this arrow should be drawn. ++// * param headPos The position where the head of the arrow should lie. ++// * param arrowSize This indicates the size of the arrow head. ++// * param arrowType This indicates direction of arrow as in LeftArrow, RightArrow.. ++// * param solid-kf6 If true, a solid-kf6 head is drawn. Otherwise 2 lines are drawn. ++// */ ++// void drawArrowHead(QPainter *painter, const QPointF &arrowPos, ++// const QSizeF& arrowSize, Qt::ArrowType arrowType, ++// bool solid-kf6) ++// { ++// QPolygonF poly; ++// if (arrowType == Qt::LeftArrow) { ++// poly << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) ++// << arrowPos ++// << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); ++// } ++// else if (arrowType == Qt::RightArrow) { ++// poly << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) ++// << arrowPos ++// << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); ++// } ++ ++// if (solid-kf6) { ++// painter->drawPolygon(poly); ++// } ++// else { ++// painter->drawPolyline(poly); ++// } ++// } ++ ++// /** ++// * Draws a rounded rect rounded at specified corners. ++// * ++// * param painter The painter with which this round rect should be drawn. ++// * param rect The rectangle to be drawn. ++// * param xRadius The x radius of rounded corner. ++// * param yRadius The y radius of rounded corner. ++// * param corners The corners to be rounded. ++// */ ++// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, ++// qreal yRadius, Uml::Corners corners) ++// { ++// if (xRadius < 0 || yRadius < 0) { ++// painter->drawRect(rect); ++// return; ++// } ++// QRectF arcRect(0, 0, 2 * xRadius, 2 * yRadius); ++ ++// QPainterPath path; ++// path.moveTo(rect.left(), rect.top() + yRadius); ++// if (corners.testFlag(Uml::Corner::TopLeft)) { ++// arcRect.moveTopLeft(rect.topLeft()); ++// path.arcTo(arcRect, 180, -90); ++// } else { ++// path.lineTo(rect.topLeft()); ++// } ++ ++// path.lineTo(rect.right() - xRadius, rect.top()); ++ ++// if (corners.testFlag(Uml::Corner::TopRight)) { ++// arcRect.moveTopRight(rect.topRight()); ++// path.arcTo(arcRect, 90, -90); ++// } else { ++// path.lineTo(rect.topRight()); ++// } ++ ++// path.lineTo(rect.right(), rect.bottom() - yRadius); ++ ++// if (corners.testFlag(Uml::Corner::BottomRight)) { ++// arcRect.moveBottomRight(rect.bottomRight()); ++// path.arcTo(arcRect, 0, -90); ++// } else { ++// path.lineTo(rect.bottomRight()); ++// } ++ ++// path.lineTo(rect.left() + xRadius, rect.bottom()); ++ ++// if (corners.testFlag(Uml::Corner::BottomLeft)) { ++// arcRect.moveBottomLeft(rect.bottomLeft()); ++// path.arcTo(arcRect, 270, 90); ++// } else { ++// path.lineTo(rect.bottomLeft()); ++// } ++ ++// path.closeSubpath(); ++// painter->drawPath(path); ++// } ++ ++ /** ++ * Converts a point to a comma separated string i.e "x,y" ++ * @param point The QPointF to convert. ++ */ ++ QString pointToString(const QPointF& point) ++ { ++ return QString::fromLatin1("%1,%2").arg(point.x()).arg(point.y()); ++ } ++ ++ /** ++ * Converts a comma separated string to point. ++ */ ++ QPointF stringToPoint(const QString& str) ++ { ++ QPointF retVal; ++ QStringList list = str.split(QLatin1Char(',')); ++ ++ if(list.size() == 2) { ++ retVal.setX(list.first().toDouble()); ++ retVal.setY(list.last().toDouble()); ++ } ++ return retVal; ++ } ++ ++ /** ++ * Loads pixmap from xmi. ++ * ++ * @param pixEle The dom element from which pixmap should be loaded. ++ * ++ * @param pixmap The pixmap into which the image should be loaded. ++ * ++ * @return True or false based on success or failure of this method. ++ */ ++ bool loadPixmapFromXMI(QDomElement &pixEle, QPixmap &pixmap) ++ { ++ if (pixEle.isNull()) { ++ return false; ++ } ++ QDomElement xpmElement = pixEle.firstChildElement(QLatin1String("xpm")); ++ ++ QByteArray xpmData = xpmElement.text().toLatin1(); ++ QBuffer buffer(&xpmData); ++ buffer.open(QIODevice::ReadOnly); ++ ++ QImageReader reader(&buffer, "xpm"); ++ QImage image; ++ if (!reader.read(&image)) { ++ return false; ++ } ++ ++ pixmap = QPixmap::fromImage(image); ++ return true; ++ } ++ ++ /** ++ * Saves pixmap information into DOM element \a qElement. ++ * ++ * @param qDoc The DOM document object. ++ * ++ * @param qElement The DOM element into which the pixmap should be ++ * saved. ++ * ++ * @param pixmap The pixmap to be saved. ++ */ ++ void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap) ++ { ++ QDomElement pixmapElement = qDoc.createElement(QLatin1String("pixmap")); ++ ++ QDomElement xpmElement = qDoc.createElement(QLatin1String("xpm")); ++ pixmapElement.appendChild(xpmElement); ++ ++ QBuffer buffer; ++ buffer.open(QIODevice::WriteOnly); ++ pixmap.save(&buffer, "xpm"); ++ buffer.close(); ++ ++ xpmElement.appendChild(qDoc.createTextNode(QString::fromLatin1(buffer.data()))); ++ ++ qElement.appendChild(pixmapElement); ++ } ++ ++ /** ++ * Loads gradient from xmi. The gradient pointer should be null ++ * and the new gradient object will be created inside this method. ++ * The gradient should later be deleted externally. ++ * ++ * @param gradientElement The DOM element from which gradient should be ++ * loaded. ++ * ++ * @param gradient The pointer to gradient into which the gradient ++ * should be loaded. (Allocated inside this ++ * method) ++ * ++ * @return True or false based on success or failure of this method. ++ */ ++ bool loadGradientFromXMI(QDomElement &gradientElement, QGradient *&gradient) ++ { ++ if(gradientElement.isNull()) { ++ return false; ++ } ++ ++ int type_as_int; ++ QGradient::Type type; ++ QGradientStops stops; ++ QGradient::CoordinateMode cmode = QGradient::LogicalMode; ++ QGradient::Spread spread = QGradient::PadSpread; ++ ++ type_as_int = gradientElement.attribute(QLatin1String("type")).toInt(); ++ type = QGradient::Type(type_as_int); ++ type_as_int = gradientElement.attribute(QLatin1String("spread")).toInt(); ++ spread = QGradient::Spread(type_as_int); ++ type_as_int = gradientElement.attribute(QLatin1String("coordinatemode")).toInt(); ++ cmode = QGradient::CoordinateMode(type_as_int); ++ ++ QDomElement stopElement = gradientElement.firstChildElement(QLatin1String("stops")); ++ if(stopElement.isNull()) { ++ return false; ++ } ++ for(QDomNode node = stopElement.firstChild(); !node.isNull(); node = node.nextSibling()) { ++ QDomElement ele = node.toElement(); ++ if(ele.tagName() != QLatin1String("stop")) { ++ continue; ++ } ++ ++ qreal posn = ele.attribute(QLatin1String("position")).toDouble(); ++ QColor color = QColor(ele.attribute(QLatin1String("color"))); ++ stops << QGradientStop(posn, color); ++ } ++ ++ if (type == QGradient::LinearGradient) { ++ QPointF p1 = stringToPoint(gradientElement.attribute(QLatin1String("start"))); ++ QPointF p2 = stringToPoint(gradientElement.attribute(QLatin1String("finalstop"))); ++ gradient = new QLinearGradient(p1, p2); ++ } ++ else if (type == QGradient::RadialGradient) { ++ QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); ++ QPointF focal = stringToPoint(gradientElement.attribute(QLatin1String("focalpoint"))); ++ double radius = gradientElement.attribute(QLatin1String("radius")).toDouble(); ++ gradient = new QRadialGradient(center, radius, focal); ++ } ++ else { // type == QGradient::ConicalGradient ++ QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); ++ double angle = gradientElement.attribute(QLatin1String("angle")).toDouble(); ++ gradient = new QConicalGradient(center, angle); ++ } ++ ++ if(gradient) { ++ gradient->setStops(stops); ++ gradient->setSpread(spread); ++ gradient->setCoordinateMode(cmode); ++ return true; ++ } ++ ++ return false; ++ } ++ ++ /** ++ * Saves gradient information into DOM element \a qElement. ++ * ++ * @param qDoc The DOM document object. ++ * ++ * @param qElement The DOM element into which the gradient should be ++ * saved. ++ * ++ * @param gradient The gradient to be saved. ++ */ ++ void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient) ++ { ++ QDomElement gradientElement = qDoc.createElement(QLatin1String("gradient")); ++ ++ gradientElement.setAttribute(QLatin1String("type"), int(gradient->type())); ++ gradientElement.setAttribute(QLatin1String("spread"), int(gradient->spread())); ++ gradientElement.setAttribute(QLatin1String("coordinatemode"), int(gradient->coordinateMode())); ++ ++ QDomElement stopsElement = qDoc.createElement(QLatin1String("stops")); ++ gradientElement.appendChild(stopsElement); ++ ++ foreach(const QGradientStop& stop, gradient->stops()) { ++ QDomElement ele = qDoc.createElement(QLatin1String("stop")); ++ ele.setAttribute(QLatin1String("position"), stop.first); ++ ele.setAttribute(QLatin1String("color"), stop.second.name()); ++ stopsElement.appendChild(ele); ++ } ++ ++ QGradient::Type type = gradient->type(); ++ ++ if(type == QGradient::LinearGradient) { ++ const QLinearGradient *lg = static_cast(gradient); ++ gradientElement.setAttribute(QLatin1String("start"), pointToString(lg->start())); ++ gradientElement.setAttribute(QLatin1String("finalstop"), pointToString(lg->finalStop())); ++ } ++ else if(type == QGradient::RadialGradient) { ++ const QRadialGradient *rg = static_cast(gradient); ++ gradientElement.setAttribute(QLatin1String("center"), pointToString(rg->center())); ++ gradientElement.setAttribute(QLatin1String("focalpoint"), pointToString(rg->focalPoint())); ++ gradientElement.setAttribute(QLatin1String("radius"), rg->radius()); ++ } ++ else { //type == QGradient::ConicalGradient ++ const QConicalGradient *cg = static_cast(gradient); ++ gradientElement.setAttribute(QLatin1String("center"), pointToString(cg->center())); ++ gradientElement.setAttribute(QLatin1String("angle"), cg->angle()); ++ } ++ ++ qElement.appendChild(gradientElement); ++ } ++ ++ /** ++ * Extracts the QBrush properties into brush from the XMI xml ++ * element qElement. ++ * ++ * @param qElement The DOM element from which the xmi info should ++ * be extracted. ++ * ++ * @param brush The QBrush object into which brush details should ++ * be read into. ++ */ ++ bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush) ++ { ++ if(qElement.isNull()) { ++ return false; ++ } ++ ++ quint8 style = qElement.attribute(QLatin1String("style")).toShort(); ++ const QString colorString = qElement.attribute(QLatin1String("color")); ++ QColor color; ++ color.setNamedColor(colorString); ++ ++ if(style == Qt::TexturePattern) { ++ QPixmap pixmap; ++ QDomElement pixElement = qElement.firstChildElement(QLatin1String("pixmap")); ++ if(!loadPixmapFromXMI(pixElement, pixmap)) { ++ return false; ++ } ++ brush = QBrush(color, pixmap); ++ } ++ ++ else if(style == Qt::LinearGradientPattern ++ || style == Qt::RadialGradientPattern ++ || style == Qt::ConicalGradientPattern) { ++ QGradient *gradient = 0; ++ QDomElement gradElement = qElement.firstChildElement(QLatin1String("gradient")); ++ ++ if(!loadGradientFromXMI(gradElement, gradient) || !gradient) { ++ delete gradient; ++ return false; ++ } ++ ++ brush = QBrush(*gradient); ++ delete gradient; ++ } ++ ++ else { ++ brush = QBrush(color, (Qt::BrushStyle)style); ++ } ++ ++ //TODO: Checks if transform needs to be loaded. ++ ++ return true; ++ } ++ ++ /** ++ * Saves the brush info as xmi into the DOM element \a qElement. ++ * ++ * @param qDoc The QDomDocument object pointing to the xmi document. ++ * ++ * @param qElement The element into which the pen, brush and font ++ * info should be saved. ++ * ++ * @param brush The QBrush whose details should be saved. ++ */ ++ void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, ++ const QBrush& brush) ++ { ++ QDomElement brushElement = qDoc.createElement(QLatin1String("brush")); ++ ++ brushElement.setAttribute(QLatin1String("style"), (quint8)brush.style()); ++ brushElement.setAttribute(QLatin1String("color"), brush.color().name()); ++ ++ if(brush.style() == Qt::TexturePattern) { ++ savePixmapToXMI(qDoc, brushElement, brush.texture()); ++ } ++ else if(brush.style() == Qt::LinearGradientPattern ++ || brush.style() == Qt::RadialGradientPattern ++ || brush.style() == Qt::ConicalGradientPattern) { ++ saveGradientToXMI(qDoc, brushElement, brush.gradient()); ++ } ++ ++ //TODO: Check if transform of this brush needs to be saved. ++ qElement.appendChild(brushElement); ++ } ++ ++ /** ++ * Returns true if the first widget's X is smaller than second's. ++ * Used for sorting the UMLWidgetList. ++ * @param widget1 The widget to compare. ++ * @param widget2 The widget to compare with. ++ */ ++ bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2) ++ { ++ return widget1->x() < widget2->x(); ++ } ++ ++ /** ++ * Returns true if the first widget's Y is smaller than second's. ++ * Used for sorting the UMLWidgetList. ++ * @param widget1 The widget to compare. ++ * @param widget2 The widget to compare with. ++ */ ++ bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2) ++ { ++ return widget1->y() < widget2->y(); ++ } ++ ++ /** ++ * Find the region in which the rectangle \a other lies with respect to ++ * the rectangle \a self. ++ * Beware that the Qt coordinate system has its origin point (0,0) in ++ * the upper left corner with Y values growing downwards, thus the Y ++ * related comparisons might look inverted if your are used to the ++ * natural coordinate system with (0,0) in the lower left corner. ++ */ ++ Uml::Region::Enum findRegion(const QRectF& self, const QRectF &other) ++ { ++ const qreal ownX = self.x(); ++ const qreal ownY = self.y(); ++ const qreal ownWidth = self.width(); ++ const qreal ownHeight = self.height(); ++ const qreal otherX = other.x(); ++ const qreal otherY = other.y(); ++ const qreal otherWidth = other.width(); ++ const qreal otherHeight = other.height(); ++ Uml::Region::Enum region = Uml::Region::Center; ++ if (otherX + otherWidth < ownX) { ++ if (otherY + otherHeight < ownY) ++ region = Uml::Region::NorthWest; ++ else if (otherY > ownY + ownHeight) ++ region = Uml::Region::SouthWest; ++ else ++ region = Uml::Region::West; ++ } else if (otherX > ownX + ownWidth) { ++ if (otherY + otherHeight < ownY) ++ region = Uml::Region::NorthEast; ++ else if (otherY > ownY + ownHeight) ++ region = Uml::Region::SouthEast; ++ else ++ region = Uml::Region::East; ++ } else { ++ if (otherY + otherHeight < ownY) ++ region = Uml::Region::North; ++ else if (otherY > ownY + ownHeight) ++ region = Uml::Region::South; ++ else ++ region = Uml::Region::Center; ++ } ++ return region; ++ } ++ ++ /** ++ * Return the point in \a poly which precedes the point at index \a index. ++ * If \a index is 0 then return the last (or, if \a poly.isClosed() is ++ * true, the second to last) point. ++ */ ++ QPointF prevPoint(int index, const QPolygonF& poly) { ++ if (poly.size() < 3 || index >= poly.size()) ++ return QPoint(); ++ if (index == 0) ++ return poly.at(poly.size() - 1 - (int)poly.isClosed()); ++ return poly.at(index - 1); ++ } ++ ++ /** ++ * Return the point in \a poly which follows the point at index \a index. ++ * If \a index is the last index then return the first (or, if ++ * \a poly.isClosed() is true, the second) point. ++ */ ++ QPointF nextPoint(int index, const QPolygonF& poly) { ++ if (poly.size() < 3 || index >= poly.size()) ++ return QPoint(); ++ if (index == poly.size() - 1) ++ return poly.at((int)poly.isClosed()); ++ return poly.at(index + 1); ++ } ++ ++ /** ++ * Return the middle value between \a a and \a b. ++ */ ++ qreal middle(qreal a, qreal b) ++ { ++ return (a + b) / 2.0; ++ } ++ ++ /** ++ * Auxiliary type for function findLine() ++ */ ++ enum Axis_Type { X , Y }; ++ ++ /** ++ * Auxiliary type for function findLine() ++ */ ++ enum Comparison_Type { Smallest, Largest }; ++ ++ /** ++ * Find the line of \a poly with the smallest or largest value (controlled by \a seek) ++ * along the axis controlled by \a axis. ++ * In case \a axis is X, do not consider lines whose Y values lie outside the Y values ++ * defined by \a boundingRect. ++ * In case \a axis is Y, do not consider lines whose X values lie outside the X values ++ * defined by \a boundingRect. ++ */ ++ QLineF findLine(const QPolygonF& poly, Axis_Type axis, Comparison_Type seek, const QRectF& boundingRect) ++ { ++ const int lastIndex = poly.size() - 1 - (int)poly.isClosed(); ++ QPointF prev = poly.at(lastIndex), curr; ++ QPointF p1(seek == Smallest ? QPointF(1.0e6, 1.0e6) : QPointF(-1.0e6, -1.0e6)); ++ QPointF p2; ++ for (int i = 0; i <= lastIndex; i++) { ++ curr = poly.at(i); ++ // uDebug() << " poly[" << i << "] = " << curr; ++ if (axis == X) { ++ if (fmin(prev.y(), curr.y()) > boundingRect.y() + boundingRect.height() || ++ fmax(prev.y(), curr.y()) < boundingRect.y()) { ++ // line is outside Y-axis range defined by boundingRect ++ } else if ((seek == Smallest && curr.x() <= p1.x()) || ++ (seek == Largest && curr.x() >= p1.x())) { ++ p1 = curr; ++ p2 = prev; ++ } ++ } else { ++ if (fmin(prev.x(), curr.x()) > boundingRect.x() + boundingRect.width() || ++ fmax(prev.x(), curr.x()) < boundingRect.x()) { ++ // line is outside X-axis range defined by boundingRect ++ } else if ((seek == Smallest && curr.y() <= p1.y()) || ++ (seek == Largest && curr.y() >= p1.y())) { ++ p1 = curr; ++ p2 = prev; ++ } ++ } ++ prev = curr; ++ } ++ return QLineF(p1, p2); ++ } ++ ++ /** ++ * Determine the approximate closest points of two polygons. ++ * @param self First QPolygonF. ++ * @param other Second QPolygonF. ++ * @return QLineF::p1() returns point of \a self; ++ * QLineF::p2() returns point of \a other. ++ */ ++ QLineF closestPoints(const QPolygonF& self, const QPolygonF& other) ++ { ++ const QRectF& selfRect = self.boundingRect(); ++ const QRectF& otherRect = other.boundingRect(); ++ Uml::Region::Enum region = findRegion(selfRect, otherRect); ++ if (region == Uml::Region::Center) ++ return QLineF(); ++ if (self.size() < 3 || other.size() < 3) ++ return QLineF(); ++ QLineF result; ++ const int selfLastIndex = self.size() - 1 - (int)self.isClosed(); ++ const int otherLastIndex = other.size() - 1 - (int)other.isClosed(); ++ QPointF selfPoint(self.at(selfLastIndex)); ++ QPointF otherPoint(other.at(otherLastIndex)); ++ QLineF selfLine, otherLine; ++ int i; ++ ++ switch (region) { ++ ++ case Uml::Region::North: ++ // Find other's line with largest Y values ++ otherLine = findLine(other, Y, Largest, selfRect); ++ // Find own line with smallest Y values ++ selfLine = findLine(self, Y, Smallest, otherRect); ++ // Use the middle value of the X values ++ result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), ++ middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); ++ break; ++ ++ case Uml::Region::South: ++ // Find other's line with smallest Y values ++ otherLine = findLine(other, Y, Smallest, selfRect); ++ // Find own line with largest Y values ++ selfLine = findLine(self, Y, Largest, otherRect); ++ // Use the middle value of the X values ++ result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), ++ middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); ++ break; ++ ++ case Uml::Region::West: ++ // Find other's line with largest X values ++ otherLine = findLine(other, X, Largest, selfRect); ++ // Find own line with smallest X values ++ selfLine = findLine(self, X, Smallest, otherRect); ++ // Use the middle value of the Y values ++ result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), ++ otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); ++ break; ++ ++ case Uml::Region::East: ++ // Find other's line with smallest X values ++ otherLine = findLine(other, X, Smallest, selfRect); ++ // Find own line with largest X values ++ selfLine = findLine(self, X, Largest, otherRect); ++ // Use the middle value of the Y values ++ result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), ++ otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); ++ break; ++ ++ case Uml::Region::NorthWest: ++ // Find other's point with largest X and largest Y value ++ for (i = 0; i < otherLastIndex; ++i) { ++ QPointF current(other.at(i)); ++ if (current.x() + current.y() >= otherPoint.x() + otherPoint.y()) { ++ otherPoint = current; ++ } ++ } ++ // Find own point with smallest X and smallest Y value ++ for (i = 0; i < selfLastIndex; ++i) { ++ QPointF current(self.at(i)); ++ if (current.x() + current.y() <= selfPoint.x() + selfPoint.y()) { ++ selfPoint = current; ++ } ++ } ++ result.setPoints(selfPoint, otherPoint); ++ break; ++ ++ case Uml::Region::SouthWest: ++ // Find other's point with largest X and smallest Y value ++ for (i = 0; i < otherLastIndex; ++i) { ++ QPointF current(other.at(i)); ++ if (current.x() >= otherPoint.x() && current.y() <= otherPoint.y()) { ++ otherPoint = current; ++ } ++ } ++ // Find own point with smallest X and largest Y value ++ for (i = 0; i < selfLastIndex; ++i) { ++ QPointF current(self.at(i)); ++ if (current.x() <= selfPoint.x() && current.y() >= selfPoint.y()) { ++ selfPoint = current; ++ } ++ } ++ result.setPoints(selfPoint, otherPoint); ++ break; ++ ++ case Uml::Region::NorthEast: ++ // Find other's point with smallest X and largest Y value ++ for (i = 0; i < otherLastIndex; ++i) { ++ QPointF current(other.at(i)); ++ if (current.x() <= otherPoint.x() && current.y() >= otherPoint.y()) { ++ otherPoint = current; ++ } ++ } ++ // Find own point with largest X and smallest Y value ++ for (i = 0; i < selfLastIndex; ++i) { ++ QPointF current(self.at(i)); ++ if (current.x() >= selfPoint.x() && current.y() <= selfPoint.y()) { ++ selfPoint = current; ++ } ++ } ++ result.setPoints(selfPoint, otherPoint); ++ break; ++ ++ case Uml::Region::SouthEast: ++ // Find other's point with smallest X and smallest Y value ++ for (i = 0; i < otherLastIndex; ++i) { ++ QPointF current(other.at(i)); ++ if (current.x() + current.y() <= otherPoint.x() + otherPoint.y()) { ++ otherPoint = current; ++ } ++ } ++ // Find own point with largest X and largest Y value ++ for (i = 0; i < selfLastIndex; ++i) { ++ QPointF current(self.at(i)); ++ if (current.x() + current.y() >= selfPoint.x() + selfPoint.y()) { ++ selfPoint = current; ++ } ++ } ++ result.setPoints(selfPoint, otherPoint); ++ break; ++ ++ default: ++ // Error ++ break; ++ } ++ ++ return result; ++ } ++ ++} // namespace Widget_Utils +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.h +--- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.h 2015-10-08 11:48:59.553089025 +0300 +@@ -0,0 +1,66 @@ ++/*************************************************************************** ++ * 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-kf6 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef WIDGET_UTILS_H ++#define WIDGET_UTILS_H ++ ++#include "basictypes.h" ++#include "messagewidgetlist.h" ++#include "umlwidgetlist.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++class QGraphicsItem; ++class QGraphicsRectItem; ++ ++/** ++ * General purpose-kf6 widget utilities. ++ * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org ++ */ ++namespace Widget_Utils ++{ ++ UMLWidget* findWidget(Uml::ID::Type id, ++ const UMLWidgetList& widgets, ++ const MessageWidgetList* messages = 0); ++ ++ QGraphicsRectItem* decoratePoint(const QPointF& p, QGraphicsItem* parent = 0); ++ ++ void drawCrossInEllipse(QPainter *p, const QRectF& ellipse); ++ void drawTriangledRect(QPainter *painter, const QRectF& rect, const QSizeF& triSize); ++// void drawArrowHead(QPainter *painter, const QPointF& arrowPos, ++// const QSizeF& arrowSize, Qt::ArrowType arrowType, ++// bool solid-kf6 = false); ++// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, ++// qreal yRadius, Uml::Corners corners); ++ ++ QString pointToString(const QPointF& point); ++ QPointF stringToPoint(const QString& str); ++ ++ bool loadPixmapFromXMI(QDomElement &qElement, QPixmap &pixmap); ++ void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap); ++ ++ bool loadGradientFromXMI(QDomElement &qElement, QGradient *&gradient); ++ void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient); ++ ++ bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush); ++ void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, ++ const QBrush& brush); ++ ++ bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2); ++ bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2); ++ ++ QLineF closestPoints(const QPolygonF& self, const QPolygonF& other); ++} ++ ++#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.cpp umbrello-kf6-15.08.1/umbrello/uniqueconstraint.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/uniqueconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,325 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-//own header +-#include "uniqueconstraint.h" +- +-// app includes +-#include "debug_utils.h" +-#include "entity.h" +-#include "entityattribute.h" +-#include "umldoc.h" +-#include "uml.h" +-#include "umlattributedialog.h" +-#include "umluniqueconstraintdialog.h" +-#include "object_factory.h" +- +-/** +- * Sets up a constraint. +- * +- * @param parent The parent of this UMLUniqueConstraint. +- * @param name The name of this UMLUniqueConstraint. +- * @param id The unique id given to this UMLUniqueConstraint. +- */ +-UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent, const QString& name, Uml::ID::Type id) +- : UMLEntityConstraint(parent, name, id) +-{ +- init(); +-} +- +-/** +- * Sets up a constraint. +- * +- * @param parent The parent of this UMLUniqueConstraint. +- */ +-UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent) +- : UMLEntityConstraint(parent) +-{ +- init(); +-} +- +-/** +- * Overloaded '==' operator +- */ +-bool UMLUniqueConstraint::operator==(const UMLUniqueConstraint &rhs) const +-{ +- if(this == &rhs) +- return true; +- +- if(!UMLObject::operator==(rhs)) +- return false; +- +- return true; +-} +- +-/** +- * Destructor. +- */ +-UMLUniqueConstraint::~UMLUniqueConstraint() +-{ +-} +- +-/** +- * Copy the internal presentation of this object into the UMLUniqueConstraint +- * object. +- */ +-void UMLUniqueConstraint::copyInto(UMLObject *lhs) const +-{ +- UMLUniqueConstraint *target = static_cast(lhs); +- +- // call the parent first. +- UMLEntityConstraint::copyInto(target); +- +- // Copy all datamembers +- target->m_EntityAttributeList.clear(); +- bool valid = true; +- foreach(UMLEntityAttribute* attr, m_EntityAttributeList) { +- if (!valid) +- break; +- valid = target->addEntityAttribute(attr); +- } +- +- if (!valid) { +- target->m_EntityAttributeList.clear(); +- uDebug() <<"Copying Attributes Failed : Target list cleared instead"; +- } +-} +- +-/** +- * Make a clone of the UMLUniqueConstraint. +- */ +-UMLObject* UMLUniqueConstraint::clone() const +-{ +- //FIXME: The new attribute should be slaved to the NEW parent not the old. +- UMLUniqueConstraint *clone = new UMLUniqueConstraint(static_cast(parent())); +- copyInto(clone); +- return clone; +-} +- +-/** +- * Returns a string representation of the UMLUniqueConstraint. +- * +- * @param sig If true will show the attribute type and initial value. +- * @return Returns a string representation of the UMLAttribute. +- */ +-QString UMLUniqueConstraint::toString(Uml::SignatureType::Enum sig) +-{ +- QString s; +- +- if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { +- s = name() + QLatin1Char(':'); +- +- if (static_cast(parent())->isPrimaryKey(this)) { +- s += QLatin1String("Primary Key ("); +- } else { +- s += QLatin1String("Unique ("); +- } +- +- bool first = true; +- foreach(UMLEntityAttribute* att, m_EntityAttributeList) { +- if (first) { +- first = false; +- } else +- s += QLatin1Char(','); +- s += att->name(); +- } +- s += QLatin1Char(')') ; +- } +- +- return s; +-} +- +-QString UMLUniqueConstraint::getFullyQualifiedName(const QString& separator, +- bool includeRoot) const +-{ +- Q_UNUSED(separator); Q_UNUSED(includeRoot); +- return this->name(); +-} +- +-/** +- * Creates the XMI element. +- */ +-void UMLUniqueConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement uniqueConstraintElement = UMLObject::save(QLatin1String("UML:UniqueConstraint"), qDoc); +- +- UMLEntity* parentEnt = static_cast(parent()); +- if (parentEnt->isPrimaryKey(this)) { +- uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("1")); +- } else { +- uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("0")); +- } +- +- foreach(UMLEntityAttribute* att, m_EntityAttributeList) { +- att->saveToXMI(qDoc, uniqueConstraintElement); +- } +- +- qElement.appendChild(uniqueConstraintElement); +-} +- +-/** +- * Display the properties configuration dialog for the attribute. +- */ +-bool UMLUniqueConstraint::showPropertiesDialog(QWidget* parent) +-{ +- UMLUniqueConstraintDialog dialog(parent, this); +- return dialog.exec(); +-} +- +-/** +- * Loads the XMI element. +- */ +-bool UMLUniqueConstraint::load(QDomElement & element) +-{ +- int isPrimary = element.attribute(QLatin1String("isPrimary"), QLatin1String("0")).toInt(); +- UMLEntity* parentEnt = static_cast(parent()); +- +- if (isPrimary == 1) { +- parentEnt->setAsPrimaryKey(this); +- } +- +- QDomNode node = element.firstChild(); +- while (!node.isNull()) { +- if (node.isComment()) { +- node = node.nextSibling(); +- continue; +- } +- QDomElement tempElement = node.toElement(); +- QString tag = tempElement.tagName(); +- if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { +- +- QString attName = tempElement.attribute(QLatin1String("name")); +- UMLObject* obj = parentEnt->findChildObject(attName); +- +- UMLEntityAttribute* entAtt = static_cast(obj); +- if (entAtt == NULL) +- continue; +- +- m_EntityAttributeList.append(entAtt); +- +- } else { +- uWarning() << "unknown child type in UMLUniqueConstraint::load"; +- } +- +- node = node.nextSibling(); +- } +- +- return true; +-} +- +- +-/** +- * Check if a entity attribute is present in m_entityAttributeList +- * +- * @param attr The Entity Attribute to check for existence in list +- * @return true if it exists in the list, else false +- */ +-bool UMLUniqueConstraint::hasEntityAttribute(UMLEntityAttribute* attr) +-{ +- if (m_EntityAttributeList.indexOf(attr) == -1) { +- //not present +- return false; +- } +- +- // else present +- return true; +-} +- +-/** +- * Adds a UMLEntityAttribute to the list. +- * The UMLEntityAttribute should already exist and should +- * belong to the parent UMLEntity. +- * +- * @param attr The UMLEntityAttribute to add +- * @return false if it failed to add, else true +- */ +-bool UMLUniqueConstraint::addEntityAttribute(UMLEntityAttribute* attr) +-{ +- UMLEntity *owningParent = dynamic_cast(parent()); +- +- if (hasEntityAttribute(attr)) { +- uDebug() << "Unique Constraint already contains" << attr->name(); +- return false; +- +- } +- if (owningParent == NULL) { +- uError() << name() << ": parent is not a UMLEntity"; +- return false; +- } +- +- if (owningParent->findChildObjectById(attr->id()) == NULL) { +- uError() +- << " parent " << owningParent->name() +- << " does not contain attribute " << attr->name(); +- return false; +- } +- +- //else add the attribute to the Entity Attribute List +- m_EntityAttributeList.append(attr); +- +- return true; +-} +- +-/** +- * Removes a UMLEntityAttribute from the list +- * +- * @param attr The UMLEntityAttribute to remove from list +- * @return false if it failed to remove the attribute from the list +- */ +-bool UMLUniqueConstraint::removeEntityAttribute(UMLEntityAttribute* attr) +-{ +- UMLEntity *owningParent = dynamic_cast(parent()); +- +- if (owningParent == NULL) { +- uError() << name() << ": parent is not a UMLEntity"; +- return false; +- } +- +- /* +- * The attribute may already be removed from the Entity when this function +- * is called. So checking this is not right +- * +- * if (owningParent->findChildObjectById(attr->ID()) == NULL) { +- * uError() +- * << " parent " << owningParent->getName() +- * << " does not contain attribute " << attr->getName(); +- * return false; +- * } +- */ +- +- //else remove the attribute from the Entity Attribute List +- if (m_EntityAttributeList.removeAll(attr)) { +- return true; +- } +- +- return false; +-} +- +-/** +- * Get the Entity Attributes List. +- */ +-UMLEntityAttributeList UMLUniqueConstraint::getEntityAttributeList() const +-{ +- return m_EntityAttributeList; +-} +- +-void UMLUniqueConstraint::init() +-{ +- m_BaseType = UMLObject::ot_UniqueConstraint; +-} +- +-/** +- * Clear the list of attributes contained in this UniqueConstraint +- */ +-void UMLUniqueConstraint::clearAttributeList() +-{ +- m_EntityAttributeList.clear(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.h umbrello-kf6-15.08.1/umbrello/uniqueconstraint.h +--- umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/uniqueconstraint.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,77 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UNIQUECONSTRAINT_H +-#define UNIQUECONSTRAINT_H +- +-#include "basictypes.h" +-#include "classifierlistitem.h" +-#include "entityconstraint.h" +-#include "umlclassifierlist.h" +-#include "umlentityattributelist.h" +- +-/** +- * This class is used to set up information for a unique entity constraint. +- * +- * @short Sets up Unique entity constraint information. +- * @author Sharan Rao +- * @see UMLObject UMLClassifierListItem UMLEntityConstraint +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLUniqueConstraint : public UMLEntityConstraint +-{ +-public: +- +- UMLUniqueConstraint(UMLObject *parent, const QString& name, +- Uml::ID::Type id = Uml::ID::None); +- explicit UMLUniqueConstraint(UMLObject *parent); +- virtual ~UMLUniqueConstraint(); +- +- bool operator==(const UMLUniqueConstraint &rhs) const; +- +- virtual void copyInto(UMLObject *lhs) const; +- +- virtual UMLObject* clone() const; +- +- QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); +- +- QString getFullyQualifiedName(const QString& separator = QString(), +- bool includeRoot = false) const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- virtual bool showPropertiesDialog(QWidget* parent = 0); +- +- bool hasEntityAttribute(UMLEntityAttribute* attr); +- +- bool addEntityAttribute(UMLEntityAttribute* attr); +- +- bool removeEntityAttribute(UMLEntityAttribute* attr); +- +- UMLEntityAttributeList getEntityAttributeList() const; +- +- void clearAttributeList(); +- +-protected: +- +- bool load(QDomElement & element); +- +-private: +- +- void init(); +- +- /** +- * The list of entity attributes that together make up the unique constraint. +- */ +- UMLEntityAttributeList m_EntityAttributeList; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/usecase.cpp umbrello-kf6-15.08.1/umbrello/usecase.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/usecase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/usecase.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,67 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "usecase.h" +- +-/** +- * Creates a UseCase object +- * +- * @param name The name of the object. +- * @param id The id of the object. +- */ +-UMLUseCase::UMLUseCase(const QString & name, Uml::ID::Type id) +- : UMLCanvasObject(name, id) +-{ +- init(); +-} +- +-/** +- * Standard decstructor. +- */ +-UMLUseCase::~UMLUseCase() +-{ +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void UMLUseCase::init() +-{ +- m_BaseType = UMLObject::ot_UseCase; +-} +- +-/** +- * Make a clone of this object. +- */ +-UMLObject* UMLUseCase::clone() const +-{ +- UMLUseCase *clone = new UMLUseCase(); +- UMLObject::copyInto(clone); +- return clone; +-} +- +-/** +- * Creates the element. +- */ +-void UMLUseCase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement usecaseElement = UMLObject::save(QLatin1String("UML:UseCase"), qDoc); +- qElement.appendChild(usecaseElement); +-} +- +-/** +- * Loads the element (TODO). +- */ +-bool UMLUseCase::load(QDomElement&) +-{ +- return true; +-} +- +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/usecase.h umbrello-kf6-15.08.1/umbrello/usecase.h +--- umbrello-kf6-15.08.1.orig/umbrello/usecase.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/usecase.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,40 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef USECASE_H +-#define USECASE_H +- +-#include "umlcanvasobject.h" +- +-/** +- * This class contains the non-graphical information required for a UML UseCase. +- * This class inherits from @ref UMLCanvasObject which contains most of the information. +- * +- * @short Information for a non-graphical UML UseCase. +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UMLUseCase : public UMLCanvasObject +-{ +-public: +- explicit UMLUseCase(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); +- ~UMLUseCase(); +- +- virtual void init(); +- +- virtual UMLObject* clone() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- bool load(QDomElement & element); +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,457 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "activitywidget.h" +- +-// app includes +-#include "activitydialog.h" +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "listpopupmenu.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#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. +- */ +-void ActivityWidget::showPropertiesDialog() +-{ +- 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); +- } +- delete dialog; +-} +- +-/** +- * 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::loadFromXMI(QDomElement& qElement) +-{ +- if(!UMLWidget::loadFromXMI(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::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement activityElement = qDoc.createElement(QLatin1String("activitywidget")); +- UMLWidget::saveToXMI(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: +- { +- bool ok = false; +- QString n = name(); +-#if QT_VERSION >= 0x050000 +- n = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter Activity Name"), +- i18n("Enter the name of the new activity:"), +- QLineEdit::Normal, +- n, &ok); +-#else +- n = KInputDialog::getText(i18n("Enter Activity Name"), +- i18n("Enter the name of the new activity:"), +- n, &ok); +-#endif +- 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.h umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,98 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ACTIVITYWIDGET_H +-#define ACTIVITYWIDGET_H +- +-#include "umlwidget.h" +-#include "worktoolbar.h" +- +-#define ACTIVITY_MARGIN 5 +-#define ACTIVITY_WIDTH 30 +-#define ACTIVITY_HEIGHT 10 +- +-/** +- * This class is the graphical version of a UML Activity. A ActivityWidget is created +- * by a @ref UMLView. An ActivityWidget belongs to only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. +- * +- * The ActivityWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @short A graphical version of a UML Activity. +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ActivityWidget : public UMLWidget +-{ +- Q_OBJECT +- Q_ENUMS(ActivityType) +-public: +- enum ActivityType +- { +- Initial = 0, +- Normal, +- End, +- Final, +- Branch, +- Invok, +- Param +- }; +- +- explicit ActivityWidget(UMLScene * scene, ActivityType activityType = Normal, Uml::ID::Type id = Uml::ID::None); +- virtual ~ActivityWidget(); +- +- ActivityType activityType() const; +- QString activityTypeStr() const; +- void setActivityType(ActivityType activityType); +- +- static bool isActivity(WorkToolBar::ToolBar_Buttons tbb, +- ActivityType& resultType); +- +- QString preconditionText() const; +- void setPreconditionText(const QString&); +- +- QString postconditionText() const; +- void setPostconditionText(const QString&); +- +- virtual void showPropertiesDialog(); +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- virtual void moveWidgetBy(qreal diffX, qreal diffY); +- +- virtual bool loadFromXMI(QDomElement & qElement); +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- void constrain(qreal& width, qreal& height); +- +-signals: +- /** +- * Emitted when the activity widget is moved. +- * Provides the delta X and delta Y amount by which the widget was moved +- * relative to the previous position. +- * Slots into PinWidget::slotActMoved() +- * @param diffX The difference between previous and new X value. +- * @param diffY The difference between previous and new Y value. +- */ +- void sigActMoved(qreal diffX, qreal diffY); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-protected: +- virtual QSizeF minimumSize() const; +- virtual QSizeF maximumSize(); +- +- ActivityType m_activityType; ///< Type of activity. +- +- QString m_preconditionText; +- QString m_postconditionText; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,104 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header file +-#include "actorwidget.h" +- +-// local includes +-#include "actor.h" +-#include "umlview.h" +- +-/** +- * Constructs an ActorWidget. +- * +- * @param scene The parent of this ActorWidget. +- * @param a The Actor class this ActorWidget will display. +- */ +-ActorWidget::ActorWidget(UMLScene * scene, UMLActor *a) +- : UMLWidget(scene, WidgetBase::wt_Actor, a) +-{ +- setFixedAspectRatio(true); +-} +- +-/** +- * Destructor. +- */ +-ActorWidget::~ActorWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void ActorWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- UMLWidget::setPenFromSettings(painter); +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- const int w = width(); +- const int h = height(); +- painter->setFont(UMLWidget::font()); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); +- const int a_height = h - (drawStereotype ? 2 * fontHeight : fontHeight) - A_MARGIN; +- const int h2 = a_height / 2; +- const int a_width = (h2); +- const int middleX = w / 2; +- const int thirdY = a_height / 3; +- +- //draw actor +- painter->drawEllipse(middleX - a_width / 2, 0, a_width, thirdY); //head +- painter->drawLine(middleX, thirdY, +- middleX, thirdY * 2); //body +- painter->drawLine(middleX, 2 * thirdY, +- middleX - a_width / 2, a_height); //left leg +- painter->drawLine(middleX, 2 * thirdY, +- middleX + a_width / 2, a_height); //right leg +- painter->drawLine(middleX - a_width / 2, thirdY + thirdY / 2, +- middleX + a_width / 2, thirdY + thirdY / 2); //arms +- //draw text +- painter->setPen(textColor()); +- if (drawStereotype) +- painter->drawText(A_MARGIN, h - 2 * fontHeight, w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); +- painter->drawText(A_MARGIN, h - fontHeight, +- w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Saves the widget to the "actorwidget" XMI element. +- * Note: For loading from XMI, the inherited parent method is used. +- */ +-void ActorWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement actorElement = qDoc.createElement(QLatin1String("actorwidget")); +- UMLWidget::saveToXMI(qDoc, actorElement); +- qElement.appendChild(actorElement); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF ActorWidget::minimumSize() const +-{ +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int textWidth = fm.width(name()); +- bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); +- int width = textWidth > A_WIDTH ? textWidth : A_WIDTH; +- int height = A_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + A_MARGIN; +- width += A_MARGIN * 2; +- return QSizeF(width, height); +-} +- +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.h umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,55 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ACTORWIDGET_H +-#define ACTORWIDGET_H +- +-#include "umlwidget.h" +- +-#define A_WIDTH 20 +-#define A_HEIGHT 40 +-#define A_MARGIN 5 +- +-class UMLActor; +- +-/** +- * This class is the graphical version of a UML Actor. +- * An ActorWidget is created by a @ref UMLView. An ActorWidget belongs to only +- * one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to is destroyed, the +- * ActorWidget will be automatically deleted. +- * +- * If the UMLActor class that this ActorWidget is displaying is deleted, the +- * @ref UMLView will make sure that this instance is also deleted. +- * +- * The ActorWidget class inherits from the @ref UMLWidget class +- * which adds most of the functionality to this class. +- * +- * @short A graphical version of a UML Actor. +- * @author Paul Hensgen +- * @see UMLWidget +- * @see UMLView +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ActorWidget : public UMLWidget +-{ +-public: +- ActorWidget(UMLScene * scene, UMLActor *o); +- virtual ~ActorWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- QSizeF minimumSize() const; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,293 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "artifactwidget.h" +- +-// app includes +-#include "artifact.h" +-#include "debug_utils.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-/** +- * Constructs a ArtifactWidget. +- * +- * @param scene The parent of this ArtifactWidget. +- * @param a The Artifact this widget will be representing. +- */ +-ArtifactWidget::ArtifactWidget(UMLScene *scene, UMLArtifact *a) +- : UMLWidget(scene, WidgetBase::wt_Artifact, a) +-{ +- setSize(100, 30); +-} +- +-/** +- * Destructor. +- */ +-ArtifactWidget::~ArtifactWidget() +-{ +-} +- +-/** +- * Reimplemented to paint the articraft widget. Some part of specific +- * drawing is delegeted to private method like drawAsFile.. +- */ +-void ArtifactWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- UMLWidget::setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } else { +- painter->setBrush(m_scene->backgroundColor()); +- } +- +- if (umlObject()) { +- UMLArtifact *umlart = static_cast(m_umlObject); +- UMLArtifact::Draw_Type drawType = umlart->getDrawAsType(); +- switch (drawType) { +- case UMLArtifact::defaultDraw: +- paintAsNormal(painter, option); +- break; +- case UMLArtifact::file: +- paintAsFile(painter, option); +- break; +- case UMLArtifact::library: +- paintAsLibrary(painter, option); +- break; +- case UMLArtifact::table: +- paintAsTable(painter, option); +- break; +- default: +- uWarning() << "Artifact drawn as unknown type"; +- break; +- } +- } +- else { +- uWarning() << "Cannot draw as there is no UMLArtifact for this widget."; +- } +-} +- +-/** +- * Reimplemented from WidgetBase::saveToXMI to save the widget to +- * the "artifactwidget" XMI element. +- */ +-void ArtifactWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("artifactwidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- qElement.appendChild(conceptElement); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF ArtifactWidget::minimumSize() const +-{ +- if (!m_umlObject) { +- return UMLWidget::minimumSize(); +- } +- UMLArtifact *umlart = static_cast(m_umlObject); +- if (umlart->getDrawAsType() == UMLArtifact::defaultDraw) { +- return calculateNormalSize(); +- } else { +- return calculateIconSize(); +- } +-} +- +-/** +- * calculates the size when drawing as an icon (it's the same size for all icons) +- */ +-QSize ArtifactWidget::calculateIconSize() const +-{ +- const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); +- const int fontHeight = fm.lineSpacing(); +- +- int width = fm.width(m_umlObject->name()); +- +- width = width<50 ? 50 : width; +- +- int height = 50 + fontHeight; +- +- return QSize(width, height); +-} +- +-/** +- * calculates the size for drawing as a box +- */ +-QSize ArtifactWidget::calculateNormalSize() const +-{ +- const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); +- const int fontHeight = fm.lineSpacing(); +- +- int width = fm.width(m_umlObject->name()); +- +- int tempWidth = 0; +- if(!m_umlObject->stereotype().isEmpty()) { +- tempWidth = fm.width(m_umlObject->stereotype(true)); +- } +- width = tempWidth>width ? tempWidth : width; +- width += ARTIFACT_MARGIN * 2; +- +- int height = (2*fontHeight) + (ARTIFACT_MARGIN * 2); +- +- return QSize(width, height); +-} +- +-/** +- * draw as a file icon +- */ +-void ArtifactWidget::paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- const int w = width(); +- const int h = height(); +- QFont font = UMLWidget::font(); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- +- int startX = (w/2) - 25; +- int iconHeight = h - fontHeight; +- QPolygon pointArray(5); +- pointArray.setPoint(0, startX, 0); +- pointArray.setPoint(1, startX + 40, 0); +- pointArray.setPoint(2, startX + 50, 10); +- pointArray.setPoint(3, startX + 50, iconHeight); +- pointArray.setPoint(4, startX, iconHeight); +- painter->drawPolygon(pointArray); +- +- painter->drawLine(startX + 40, 0, startX + 40, 10); +- painter->drawLine(startX + 40, 10, startX + 50, 10); +- painter->drawLine(startX + 40, 0, startX + 50, 10); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- painter->drawText(0, h - fontHeight, +- w, fontHeight, Qt::AlignCenter, name()); +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * draw as a library file icon +- */ +-void ArtifactWidget::paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- //FIXME this should have gears on it +- const int w = width(); +- const int h = height(); +- const QFont font = UMLWidget::font(); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- +- const int startX = (w/2) - 25; +- const int iconHeight = h - fontHeight; +- QPolygon pointArray(5); +- pointArray.setPoint(0, startX, 0); +- pointArray.setPoint(1, startX + 40, 0); +- pointArray.setPoint(2, startX + 50, 10); +- pointArray.setPoint(3, startX + 50, iconHeight); +- pointArray.setPoint(4, startX, iconHeight); +- painter->drawPolygon(pointArray); +- +- painter->drawLine(startX + 40, 0, startX + 40, 10); +- painter->drawLine(startX + 40, 10, startX + 50, 10); +- painter->drawLine(startX + 40, 0, startX + 50, 10); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- painter->drawText(0, h - fontHeight, +- w, fontHeight, Qt::AlignCenter, name()); +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * draw as a database table icon +- */ +-void ArtifactWidget::paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- const int w = width(); +- const int h = height(); +- const QFont font = UMLWidget::font(); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- +- const int startX = (w/2) - 25; +- const int iconHeight = h - fontHeight; +- +- painter->drawRect(startX, 0, 50, h - fontHeight + 1); +- painter->drawLine(startX + 20, 0, startX + 20, iconHeight); +- painter->drawLine(startX + 30, 0, startX + 30, iconHeight); +- painter->drawLine(startX + 40, 0, startX + 40, iconHeight); +- painter->drawLine(startX, (iconHeight/2), startX + 49, (iconHeight/2)); +- painter->drawLine(startX, (iconHeight/2) + (iconHeight/4), +- startX + 49, (iconHeight/2) + (iconHeight/4)); +- +- QPen thickerPen = painter->pen(); +- thickerPen.setWidth(2); +- painter->setPen(thickerPen); +- painter->drawLine(startX + 10, 0, startX + 10, iconHeight); +- painter->drawLine(startX, (iconHeight/4), startX + 50, (iconHeight/4)); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- painter->drawText(0, h - fontHeight, +- w, fontHeight, Qt::AlignCenter, name()); +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * draw as a box +- */ +-void ArtifactWidget::paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- int w = width(); +- int h = height(); +- QFont font = UMLWidget::font(); +- font.setBold(true); +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- QString stereotype = m_umlObject->stereotype(); +- +- painter->drawRect(0, 0, w, h); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- if (!stereotype.isEmpty()) { +- painter->drawText(ARTIFACT_MARGIN, (h/2) - fontHeight, +- w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); +- } +- +- int lines; +- if (!stereotype.isEmpty()) { +- lines = 2; +- } else { +- lines = 1; +- } +- +- if (lines == 1) { +- painter->drawText(0, (h/2) - (fontHeight/2), +- w, fontHeight, Qt::AlignCenter, name()); +- } else { +- painter->drawText(0, (h/2), +- w, fontHeight, Qt::AlignCenter, name()); +- } +- +- UMLWidget::paint(painter, option); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.h umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,55 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ARTIFACTWIDGET_H +-#define ARTIFACTWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLScene; +-class UMLArtifact; +- +-#define ARTIFACT_MARGIN 5 +- +-/** +- * Defines a graphical version of the @ref UMLArtifact. +- * Most of the functionality will come from the @ref UMLWidget class. +- * +- * @short A graphical version of a Artifact. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ArtifactWidget : public UMLWidget +-{ +-public: +- ArtifactWidget(UMLScene *scene, UMLArtifact *a); +- virtual ~ArtifactWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- // Note: For loading from XMI, the inherited parent method is used. +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-protected: +- QSizeF minimumSize() const; +- +-private: +- void paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option); +- +- QSize calculateIconSize() const; +- QSize calculateNormalSize() const; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.cpp umbrello-kf6-15.08.1/umbrello/widgets/associationline.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/associationline.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1404 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "associationline.h" +- +-// application includes +-#include "associationwidget.h" +-#include "debug_utils.h" +-#include "umlwidget.h" +- +-// qt includes +-#include +-#include +- +-// system includes +-#include +-#include +- +-DEBUG_REGISTER_DISABLED(AssociationLine) +- +-// Initialize static variables. +-const qreal AssociationLine::Delta = 5; +-const qreal AssociationLine::SelectedPointDiameter = 4; +-const qreal AssociationLine::SelfAssociationMinimumHeight = 30; +- +-/** +- * Constructor. +- * Constructs an AssociationLine item with its parent being \a parent. +- */ +-AssociationLine::AssociationLine(AssociationWidget *association) +- : QGraphicsObject(association), +- m_associationWidget(association), +- m_activePointIndex(-1), +- m_activeSegmentIndex(-1), +- m_startSymbol(0), +- m_endSymbol(0), +- m_subsetSymbol(0), +- m_collaborationLineItem(0), +- m_collaborationLineHead(0), +- m_layout(Polyline) +-{ +- Q_ASSERT(association); +- setFlag(QGraphicsLineItem::ItemIsSelectable); +- setAcceptHoverEvents(true); +- setZValue(3); +-} +- +-/** +- * Destructor. +- */ +-AssociationLine::~AssociationLine() +-{ +-} +- +-/** +- * Returns the point at the point index. +- * @return point at given index +- */ +-QPointF AssociationLine::point(int index) const +-{ +- if ((index < 0) | (index >= m_points.size())) { +- uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; +- return QPointF(-1.0, -1.0); +- } +- return m_points.at(index); +-} +- +-/** +- * Sets the point value at given index to \a point. +- */ +-bool AssociationLine::setPoint(int index, const QPointF &point) +-{ +- if ((index < 0) | (index >= m_points.size())) { +- uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; +- return false; +- } +- if (m_points.at(index) == point) { +- return false; // nothing to change +- } +- prepareGeometryChange(); +- m_points[index] = point; +- alignSymbols(); +- return true; +-} +- +-/** +- * Shortcut for point(0). +- */ +-QPointF AssociationLine::startPoint() const +-{ +- return m_points.at(0); +-} +- +-/** +- * Shortcut for end point. +- */ +-QPointF AssociationLine::endPoint() const +-{ +- return m_points.at(m_points.size()-1); +-} +- +-/** +- * Inserts the passed in \a point at the \a index passed in and +- * recalculates the bounding rect. +- */ +-void AssociationLine::insertPoint(int index, const QPointF &point) +-{ +- prepareGeometryChange(); +- m_points.insert(index, point); +- alignSymbols(); +-} +- +-/** +- * Removes the point at \a index passed in. +- * @see removeNonEndPoint +- */ +-void AssociationLine::removePoint(int index) +-{ +- prepareGeometryChange(); +- m_points.remove(index); +- alignSymbols(); +-} +- +-/** +- * Returns the amount of POINTS on the line. +- * Includes start and end points. +- * @return number of points in the AssociationLine +- */ +-int AssociationLine::count() const +-{ +- return m_points.size(); +-} +- +-/** +- * Removes all the points and signals a geometry update. +- */ +-void AssociationLine::cleanup() +-{ +- if (!m_points.isEmpty()) { +- prepareGeometryChange(); +- m_points.clear(); +- alignSymbols(); +- } +-} +- +-/** +- * This method optimizes the number of points in the +- * AssociationLine. This can be used to reduce the clutter caused +- * due to too many points. +- * TODO: Use delta comparison 'closestPointIndex' instead of exact comparison. +- * TODO: Not used anywhere. +- */ +-void AssociationLine::optimizeLinePoints() +-{ +- int i = 1; +- prepareGeometryChange(); +- while (i < m_points.size()) { +- if (m_points.at(i) == m_points.at(i-1)) { +- m_points.remove(i); +- } +- else { +- ++i; +- } +- } +- alignSymbols(); +-} +- +-/** +- * Return index of point closer a given delta. +- * +- * @param point The point which is to be tested for closeness. +- * @param delta The distance the point should be closer to. +- * +- * @retval "Index" of the first line point closer to the \a point passed. +- * @retval -1 If no line point is closer to passed in \a point. +- */ +-int AssociationLine::closestPointIndex(const QPointF &point, qreal delta) const +-{ +- for(int i = 0; i < m_points.size(); ++i) { +- const QPointF& linePoint = m_points.at(i); +- // Apply distance formula to see point closeness. +- qreal deltaXSquare = (point.x() - linePoint.x()) * (point.x() - linePoint.x()); +- qreal deltaYSquare = (point.y() - linePoint.y()) * (point.y() - linePoint.y()); +- +- qreal lhs = deltaXSquare + deltaYSquare; +- qreal rhs = delta * delta; +- +- if (lhs <= rhs) { +- return i; +- } +- } +- return -1; +-} +- +-/** +- * Return index of closest segment. +- * +- * @param point The point which is to be tested for closeness. +- * +- * @return Index of the line segment closest to the \a point passed; +- * -1 if no line segment is closer to passed in \a point. +- */ +-int AssociationLine::closestSegmentIndex(const QPointF &point, qreal delta) const +-{ +- QPainterPathStroker stroker; +- stroker.setWidth(delta); +- +- for(int i = 1; i < m_points.size(); ++i) { +- QLineF segment(m_points[i-1], m_points[i]); +- +- QPainterPath path; +- path.moveTo(segment.p1()); +- path.lineTo(segment.p2()); +- +- path = stroker.createStroke(path); +- +- if (path.contains(point)) { +- return i-1; +- } +- } +- return -1; +-} +- +-/** +- * Retval True If point at \a index is start or end. +- */ +-bool AssociationLine::isEndPointIndex(int index) const +-{ +- const int size = m_points.size(); +- Q_ASSERT(index >= 0 && index < size); +- +- return (index == 0 || index == (size - 1)); +-} +- +-/** +- * Retval True If segment at \a index is start or end. +- */ +-bool AssociationLine::isEndSegmentIndex(int index) const +-{ +- // num of seg = num of points - 1 +- const int size = m_points.size() - 1; +- Q_ASSERT(index >= 0 && index < size); +- +- return (index == 0 || index == (size - 1)); +-} +- +-/** +- * Sets the start and end points. +- */ +-bool AssociationLine::setEndPoints(const QPointF &start, const QPointF &end) +-{ +- const int size = m_points.size(); +- +- prepareGeometryChange(); +- +- if (size == 0) { +- m_points.insert(0, start); +- m_points.insert(1, end); +- } +- else if (size == 1) { +- m_points[0] = start; +- m_points.insert(1, end); +- } +- else { +- m_points[0] = start; +- m_points[size-1] = end; +- } +- +- alignSymbols(); +- return true; +-} +- +-/** +- * Debug helper method to write out the points. +- */ +-void AssociationLine::dumpPoints() +-{ +- for (int i = 1; i < m_points.size(); ++i) { +- QPointF p = m_points.at(i); +- DEBUG(DBG_SRC) << i << ". point x:" << p.x() << " / y:" << p.y(); +- } +-} +- +-/** +- * Loads AssociationLine information saved in \a qElement XMI element. +- */ +-bool AssociationLine::loadFromXMI(QDomElement &qElement) +-{ +- QString layout = qElement.attribute(QLatin1String("layout"), QLatin1String("polyline")); +- m_layout = fromString(layout); +- +- QDomNode node = qElement.firstChild(); +- +- m_points.clear(); +- +- QDomElement startElement = node.toElement(); +- if(startElement.isNull() || startElement.tagName() != QLatin1String("startpoint")) { +- return false; +- } +- QString x = startElement.attribute(QLatin1String("startx"), QLatin1String("0")); +- qreal nX = x.toFloat(); +- QString y = startElement.attribute(QLatin1String("starty"), QLatin1String("0")); +- qreal nY = y.toFloat(); +- QPointF startPoint(nX, nY); +- +- node = startElement.nextSibling(); +- QDomElement endElement = node.toElement(); +- if(endElement.isNull() || endElement.tagName() != QLatin1String("endpoint")) { +- return false; +- } +- x = endElement.attribute(QLatin1String("endx"), QLatin1String("0")); +- nX = x.toFloat(); +- y = endElement.attribute(QLatin1String("endy"), QLatin1String("0")); +- nY = y.toFloat(); +- QPointF endPoint(nX, nY); +- setEndPoints(startPoint, endPoint); +- QPointF point; +- node = endElement.nextSibling(); +- QDomElement element = node.toElement(); +- int i = 1; +- while(!element.isNull()) { +- if(element.tagName() == QLatin1String("point")) { +- x = element.attribute(QLatin1String("x"), QLatin1String("0")); +- y = element.attribute(QLatin1String("y"), QLatin1String("0")); +- point.setX(x.toFloat()); +- point.setY(y.toFloat()); +- insertPoint(i++, point); +- } +- node = element.nextSibling(); +- element = node.toElement(); +- } +- +- return true; +-} +- +-/** +- * Saves association line information into XMI element named "linepath". +- * @note Stored as linepath for backwared compatibility +- */ +-void AssociationLine::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +-{ +- QPointF point = m_associationWidget->mapToScene(startPoint()); +- QDomElement lineElement = qDoc.createElement(QLatin1String("linepath")); +- lineElement.setAttribute(QLatin1String("layout"), toString(m_layout)); +- QDomElement startElement = qDoc.createElement(QLatin1String("startpoint")); +- startElement.setAttribute(QLatin1String("startx"), point.x()); +- startElement.setAttribute(QLatin1String("starty"), point.y()); +- lineElement.appendChild(startElement); +- QDomElement endElement = qDoc.createElement(QLatin1String("endpoint")); +- point = m_associationWidget->mapToScene(endPoint()); +- endElement.setAttribute(QLatin1String("endx"), point.x()); +- endElement.setAttribute(QLatin1String("endy"), point.y()); +- lineElement.appendChild(endElement); +- for(int i = 1; i < count()-1; ++i) { +- QDomElement pointElement = qDoc.createElement(QLatin1String("point")); +- point = m_associationWidget->mapToScene(this->point(i)); +- pointElement.setAttribute(QLatin1String("x"), point.x()); +- pointElement.setAttribute(QLatin1String("y"), point.y()); +- lineElement.appendChild(pointElement); +- } +- qElement.appendChild(lineElement); +-} +- +-/** +- * Returns the type of brush to use depending on the type of Association. +- */ +-QBrush AssociationLine::brush() const +-{ +- QBrush brush(Qt::solid-kf6Pattern); +- Uml::AssociationType::Enum type = m_associationWidget->associationType(); +- if (type == Uml::AssociationType::Aggregation || +- type == Uml::AssociationType::Generalization || +- type == Uml::AssociationType::Realization) { +- brush.setColor(Qt::white); +- } +- if (type == Uml::AssociationType::Composition) { +- brush.setColor(m_associationWidget->lineColor()); +- } +- return brush; +-} +- +-/** +- * Returns the type of pen to use depending on the type of Association. +- */ +-QPen AssociationLine::pen() const +-{ +- QPen pen(m_associationWidget->lineColor(), +- m_associationWidget->lineWidth(), +- Qt::solid-kf6Line, +- Qt::RoundCap, +- Qt::RoundJoin); +- Uml::AssociationType::Enum type = m_associationWidget->associationType(); +- if (type == Uml::AssociationType::Dependency || +- type == Uml::AssociationType::Realization || +- type == Uml::AssociationType::Anchor) { +- pen.setStyle(Qt::DashLine); +- } +- return pen; +-} +- +-/** +- * This method simply ensures presence of two points and +- * adds the needed points for self associations. +- */ +-void AssociationLine::calculateInitialEndPoints() +-{ +- if (m_associationWidget->isSelf() && count() < 4) { +- for (int i = count(); i < 4; ++i) { +- insertPoint(i, QPointF()); +- } +- UMLWidget *wid = m_associationWidget->widgetForRole(Uml::RoleType::B); +- if (!wid) { +- uError() << "AssociationWidget is partially constructed." +- "UMLWidget for role B is null."; +- return; +- } +- const QRectF rect = m_associationWidget->mapFromScene( +- mapToScene(wid->rect()).boundingRect()).boundingRect(); +- +- qreal l = rect.left() + .25 * rect.width(); +- qreal r = rect.left() + .75 * rect.width(); +- bool drawAbove = rect.top() >= SelfAssociationMinimumHeight; +- qreal y = drawAbove ? rect.top() : rect.bottom(); +- qreal yOffset = SelfAssociationMinimumHeight; +- if (drawAbove) { +- yOffset *= -1.0; +- } +- +- setPoint(0, QPointF(l, y)); +- setPoint(1, QPointF(l, y + yOffset)); +- setPoint(2, QPointF(r, y + yOffset)); +- setPoint(3, QPointF(r, y)); +- } else if (!m_associationWidget->isSelf() && count() < 2) { +- setEndPoints(QPointF(), QPointF()); +- } +-} +- +-/** +- * This method creates, deletes symbols and collaboration lines based on +- * m_associationWidget->associationType(). +- * +- * Call this method when associationType of m_associationWidget changes. +- */ +-void AssociationLine::reconstructSymbols() +-{ +- switch( m_associationWidget->associationType() ) { +- case Uml::AssociationType::State: +- case Uml::AssociationType::Activity: +- case Uml::AssociationType::Exception: +- case Uml::AssociationType::UniAssociation: +- case Uml::AssociationType::Dependency: +- setStartSymbol(Symbol::None); +- setEndSymbol(Symbol::OpenArrow); +- removeSubsetSymbol(); +- removeCollaborationLine(); +- break; +- +- case Uml::AssociationType::Relationship: +- setStartSymbol(Symbol::None); +- setEndSymbol(Symbol::CrowFeet); +- removeSubsetSymbol(); +- removeCollaborationLine(); +- break; +- +- case Uml::AssociationType::Generalization: +- case Uml::AssociationType::Realization: +- setStartSymbol(Symbol::None); +- setEndSymbol(Symbol::ClosedArrow); +- removeSubsetSymbol(); +- removeCollaborationLine(); +- break; +- +- case Uml::AssociationType::Composition: +- case Uml::AssociationType::Aggregation: +- setStartSymbol(Symbol::Diamond); +- setEndSymbol(Symbol::None); +- removeSubsetSymbol(); +- removeCollaborationLine(); +- break; +- +- case Uml::AssociationType::Containment: +- setStartSymbol(Symbol::Circle); +- setEndSymbol(Symbol::None); +- removeSubsetSymbol(); +- removeCollaborationLine(); +- break; +- +- case Uml::AssociationType::Child2Category: +- setStartSymbol(Symbol::None); +- setEndSymbol(Symbol::None); +- createSubsetSymbol(); +- removeCollaborationLine(); +- break; +- +- case Uml::AssociationType::Coll_Message_Synchronous: +- case Uml::AssociationType::Coll_Message_Asynchronous: +- case Uml::AssociationType::Coll_Message_Self: +- setStartSymbol(Symbol::None); +- setEndSymbol(Symbol::None); +- removeSubsetSymbol(); +- createCollaborationLine(); +- break; +- +- default: +- break; +- } +- alignSymbols(); +-} +- +-/** +- * Sets the Symbol to appear at the first line segment to \a symbol. +- * +- * If symbol == Symbol::None , then it deletes the symbol item. +- */ +-void AssociationLine::setStartSymbol(Symbol::SymbolType symbolType) +-{ +- Q_ASSERT(symbolType != Symbol::Count); +- if (symbolType == Symbol::None) { +- delete m_startSymbol; +- m_startSymbol = 0; +- return; +- } +- +- if (m_startSymbol) { +- m_startSymbol->setSymbolType(symbolType); +- } +- else { +- m_startSymbol = new Symbol(symbolType, m_associationWidget); +- } +- m_startSymbol->setPen(pen()); +- m_startSymbol->setBrush(brush()); +-} +- +-/** +- * Sets the Symbol to appear at the last line segment to \a symbol. +- * +- * If symbol == Symbol::None , then it deletes the symbol item. +- */ +-void AssociationLine::setEndSymbol(Symbol::SymbolType symbolType) +-{ +- Q_ASSERT(symbolType != Symbol::Count); +- if (symbolType == Symbol::None) { +- delete m_endSymbol; +- m_endSymbol = 0; +- return; +- } +- +- if (m_endSymbol) { +- m_endSymbol->setSymbolType(symbolType); +- } +- else { +- m_endSymbol = new Symbol(symbolType, m_associationWidget); +- } +- m_endSymbol->setPen(pen()); +- m_endSymbol->setBrush(brush()); +-} +- +-/** +- * Constructs a new subset symbol. +- */ +-void AssociationLine::createSubsetSymbol() +-{ +- delete m_subsetSymbol; // recreate +- m_subsetSymbol = new Symbol(Symbol::Subset, m_associationWidget); +- m_subsetSymbol->setPen(pen()); +- m_subsetSymbol->setBrush(brush()); +-} +- +-/** +- * Removes the subset symbol if it existed by deleting appropriate items. +- */ +-void AssociationLine::removeSubsetSymbol() +-{ +- delete m_subsetSymbol; +- m_subsetSymbol = 0; +-} +- +-/** +- * Constructs the open arrow symbol and arrow line, that would represent Collaboration line. +- */ +-void AssociationLine::createCollaborationLine() +-{ +- const QPen p = pen(); +- +- // recreate +- delete m_collaborationLineItem; +- delete m_collaborationLineHead; +- +- m_collaborationLineItem = new QGraphicsLineItem(m_associationWidget); +- m_collaborationLineItem->setPen(p); +- +- if (m_associationWidget->associationType() == Uml::AssociationType::Coll_Message_Synchronous) { +- m_collaborationLineHead = new Symbol(Symbol::ClosedArrow, m_associationWidget); +- m_collaborationLineHead->setBrush(p.color()); +- } +- else +- m_collaborationLineHead = new Symbol(Symbol::OpenArrow, m_associationWidget); +- m_collaborationLineHead->setPen(p); +-} +- +-/** +- * Removes collaboration line by deleting the head and line item. +- */ +-void AssociationLine::removeCollaborationLine() +-{ +- delete m_collaborationLineItem; +- m_collaborationLineItem = 0; +- +- delete m_collaborationLineHead; +- m_collaborationLineHead = 0; +-} +- +-/** +- * This method aligns both the \b "start" and \b "end" symbols to +- * the current angles of the \b "first" and the \b "last" line +- * segment respectively. +- */ +-void AssociationLine::alignSymbols() +-{ +- const int sz = m_points.size(); +- if (sz < 2) { +- // cannot align if there is no line (one line = 2 points) +- return; +- } +- +- QList polygons = path().toSubpathPolygons(); +- +- if (m_startSymbol) { +- QPolygonF firstLine = polygons.first(); +- QLineF segment(firstLine.at(1), firstLine.at(0)); +- m_startSymbol->alignTo(segment); +- } +- +- if (m_endSymbol) { +- QPolygonF lastLine = polygons.last(); +- int maxIndex = lastLine.size(); +- QLineF segment(lastLine.at(maxIndex-2), lastLine.at(maxIndex-1)); +- m_endSymbol->alignTo(segment); +- } +- +- if (m_subsetSymbol) { +- QPointF p1 = path().pointAtPercent(0.4); +- QPointF p2 = path().pointAtPercent(0.5); +- QLineF segment(p1, p2); +- m_subsetSymbol->alignTo(segment); +- } +- +- if (m_collaborationLineItem) { +- const qreal distance = 10; +- const int midSegmentIndex = (sz - 1) / 2; +- +- const QPointF a = m_points.at(midSegmentIndex); +- const QPointF b = m_points.at(midSegmentIndex + 1); +- +- if (a == b) +- return; +- +- const QPointF p1 = (a + b) / 2.0; +- const QPointF p2 = (p1 + b) / 2.0; +- +- // Reversed line as we want normal in opposite direction. +- QLineF segment(p2, p1); +- QLineF normal = segment.normalVector().unitVector(); +- normal.setLength(distance); +- +- QLineF actualLine; +- actualLine.setP2(normal.p2()); +- +- normal.translate(p1 - p2); +- actualLine.setP1(normal.p2()); +- +- m_collaborationLineItem->setLine(actualLine); +- m_collaborationLineHead->alignTo(actualLine); +- } +-} +- +-/** +- * @return The path of the AssociationLine. +- */ +-QPainterPath AssociationLine::path() const +-{ +- if (m_points.count() > 0) { +- QPainterPath path; +- switch (m_layout) { +- case Direct: +- path.moveTo(m_points.first()); +- path.lineTo(m_points.last()); +- break; +- +- case Spline: +- path = createBezierCurve(m_points); +- break; +- +- case Orthogonal: +- path = createOrthogonalPath(m_points); +- break; +- +- case Polyline: +- default: +- QPolygonF polygon(m_points); +- path.addPolygon(polygon); +- break; +- } +- return path; +- } +- else { +- return QPainterPath(); +- } +-} +- +-/** +- * The points are used for the bounding rect. The reason is, +- * that for splines the control points are further away from the path. +- * @return The bounding rectangle for the AssociationLine. +- */ +-QRectF AssociationLine::boundingRect() const +-{ +- QPolygonF polygon(m_points); +- QRectF rect = polygon.boundingRect(); +- const qreal margin(5.0); +- rect.adjust(-margin, -margin, margin, margin); +- return rect; +-} +- +-/** +- * @return The shape of the AssociationLine. +- */ +-QPainterPath AssociationLine::shape() const +-{ +- QPainterPathStroker stroker; +- stroker.setWidth(qMax(2*SelectedPointDiameter, pen().widthF()) + 2.0); // allow delta region +- stroker.setCapStyle(Qt::FlatCap); +- return stroker.createStroke(path()); +-} +- +-/** +- * Convert enum LayoutType to string. +- */ +-QString AssociationLine::toString(LayoutType layout) +-{ +- return QLatin1String(ENUM_NAME(AssociationLine, LayoutType, layout)); +-} +- +-/** +- * Convert string to enum LayoutType. +- */ +-AssociationLine::LayoutType AssociationLine::fromString(const QString &layout) +-{ +- if (layout == QLatin1String("Direct")) +- return Direct; +- if (layout == QLatin1String("Spline")) +- return Spline; +- if (layout == QLatin1String("Orthogonal")) +- return Orthogonal; +- return Polyline; +-} +- +-/** +- * Return the layout type of the association line. +- * @return the currently used layout +- */ +-AssociationLine::LayoutType AssociationLine::layout() const +-{ +- return m_layout; +-} +- +-/** +- * Set the layout type of the association line. +- * @param layout the desired layout to set +- */ +-void AssociationLine::setLayout(LayoutType layout) +-{ +- prepareGeometryChange(); +- m_layout = layout; +- DEBUG(DBG_SRC) << "new layout = " << toString(m_layout); +- if (m_layout == Spline) { +- createSplinePoints(); +- } +- alignSymbols(); +-} +- +-/** +- * For a cubic Bezier curve at least four points are needed. +- * If there are less, the missing points will be created. +- * Note: Implementation is only for two points. +- */ +-void AssociationLine::createSplinePoints() +-{ +- if (m_points.size() == 2) { // create two points +- QPointF p1 = m_points.first(); // start point +- QPointF p2 = m_points.last(); // end point +- qreal dx = p2.x() - p1.x(); +- qreal dy = p2.y() - p1.y(); +- qreal oneThirdX = 0.33 * dx; +- qreal oneThirdY = 0.33 * dy; +- QPointF c1(p1.x() + oneThirdX, // control point 1 +- p1.y() - oneThirdY); +- QPointF c2(p2.x() - oneThirdX, // control point 2 +- p2.y() + oneThirdY); +- insertPoint(1, c1); +- insertPoint(2, c2); +- } +- if (m_points.size() == 3) { // create one point +- // insertPoint(1 or 2, ); +- // Note: For now we use a quadratic Bezier curve in createBezierCurve(...). +- } +-} +- +-/** +- * Returns a Bézier path from given points. +- * @param points points which define the Bézier curve +- * @return cubic Bézier spline +- */ +-QPainterPath AssociationLine::createBezierCurve(QVector points) +-{ +- QPainterPath path; +- if (points.size() > 3) { // cubic Bezier curve(s) +- path.moveTo(points.at(0)); +- int i = 1; +- while (i + 2 < points.size()) { +- path.cubicTo(points.at(i), points.at(i+1), points.at(i+2)); +- i += 3; +- } +- while (i < points.size()) { // draw a line if points are not modulo 3 +- path.lineTo(points.at(i)); +- ++i; +- } +- } +- else { +- if (points.size() == 3) { // quadratic Bezier curve +- path.moveTo(points.at(0)); +- path.quadTo(points.at(1), points.at(2)); +- } +- else { // should not be reached +- QPolygonF polygon(points); +- path.addPolygon(polygon); +- } +- } +- return path; +-} +- +-/** +- * Returns an orthogonal path constructed of vertical and horizontal segments +- * through the given points. +- * @param points base points for the path +- * @return orthogonal path +- */ +-QPainterPath AssociationLine::createOrthogonalPath(QVector points) +-{ +- QPainterPath path; +- if (points.size() > 1) { +- QPointF start = points.first(); +- QPointF end = points.last(); +- qreal deltaX = fabs(start.x() - end.x()); +- qreal deltaY = fabs(start.y() - end.y()); +- // DEBUG("AssociationLine") << "start=" << start << " / end=" << end +- // << " / deltaX=" << deltaX << " / deltaY=" << deltaY; +- QVector vector; +- for (int i = 0; i < points.size() - 1; ++i) { +- QPointF curr = points.at(i); +- QPointF next = points.at(i+1); +- QPointF center = (next + curr)/2.0; +- +- vector.append(curr); +- if (deltaX < deltaY) { +- // go vertical first +- vector.append(QPointF(curr.x(), center.y())); +- vector.append(QPointF(next.x(), center.y())); +- } +- else { +- // go horizontal first +- vector.append(QPointF(center.x(), curr.y())); +- vector.append(QPointF(center.x(), next.y())); +- } +- vector.append(next); +- } +- +- QPolygonF rectLine(vector); +- path.addPolygon(rectLine); +- } +- else { +- QPolygonF polygon(points); +- path.addPolygon(polygon); +- } +- return path; +-} +- +-/** +- * Reimplemented from QGraphicsItem::paint. +- * Draws the AssociationLine and also takes care of highlighting active point or line. +- */ +-void AssociationLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +-{ +- Q_UNUSED(widget) +- QPen _pen = pen(); +- const QColor orig = _pen.color().lighter(); +- QColor invertedColor(orig.green(), orig.blue(), orig.red()); +- if (invertedColor == _pen.color()) { +- // Ensure different color. +- invertedColor.setRed((invertedColor.red() + 50) % 256); +- } +- invertedColor.setAlpha(150); +- +- int sz = m_points.size(); +- if (sz < 1) { +- // not enough points - do nothing +- return; +- } +- +- QPointF savedStart = m_points.first(); +- QPointF savedEnd = m_points.last(); +- +- // modify the m_points array not to include the Symbol, the value depends on Symbol +- if (m_startSymbol) { +- QPointF newStart = m_startSymbol->mapToParent(m_startSymbol->symbolEndPoints().first); +- m_points[0] = newStart; +- } +- +- if (m_endSymbol) { +- QPointF newEnd = m_endSymbol->mapToParent(m_endSymbol->symbolEndPoints().first); +- m_points[sz - 1] = newEnd; +- } +- +- painter->setPen(_pen); +- painter->setBrush(Qt::NoBrush); +- painter->drawPath(path()); +- +- if (option->state & QStyle::State_Selected) { +- // make the association broader in the selected state +- QPainterPathStroker stroker; +- stroker.setWidth(3.0); +- QPainterPath outline = stroker.createStroke(path()); +- QColor shadowColor(Qt::lightGray); +- shadowColor.setAlpha(80); +- QBrush shadowBrush(shadowColor); +- painter->setBrush(shadowBrush); +- painter->setPen(Qt::NoPen); +- painter->drawPath(outline); +- +- // set color for selected painting +- _pen.setColor(Qt::blue); +- QRectF circle(0, 0, SelectedPointDiameter, SelectedPointDiameter); +- painter->setBrush(_pen.color()); +- painter->setPen(Qt::NoPen); +- +- // draw points +- circle.moveCenter(savedStart); +- painter->drawRect(circle); +- for (int i = 1; i < sz-1; ++i) { +- if (i != m_activePointIndex) { +- circle.moveCenter(m_points.at(i)); +- painter->drawRect(circle); +- } +- } +- circle.moveCenter(savedEnd); +- painter->drawRect(circle); +- +- if (m_activePointIndex != -1) { +- painter->setBrush(invertedColor); +- painter->setPen(Qt::NoPen); +- circle.setWidth(1.5*SelectedPointDiameter); +- circle.setHeight(1.5*SelectedPointDiameter); +- circle.moveCenter(m_points.at(m_activePointIndex)); +- painter->drawEllipse(circle); +- } +- else if (m_activeSegmentIndex != -1) { +- if (m_layout == Polyline) { +- painter->setPen(QPen(invertedColor, _pen.widthF() + 1)); +- painter->setBrush(Qt::NoBrush); +- +- QLineF segmentLine(m_points[m_activeSegmentIndex], m_points[m_activeSegmentIndex + 1]); +- painter->drawLine(segmentLine); +- } +- } +- // debug info +- if (Tracer::instance()->isEnabled(QString::fromLatin1(metaObject()->className()))) { +- painter->setPen(Qt::green); +- painter->setBrush(Qt::NoBrush); +- painter->drawPath(shape()); +- painter->setPen(Qt::red); +- painter->drawRect(boundingRect()); +- // origin +- painter->drawLine(-10, 0, 10, 0); +- painter->drawLine(0, -10, 0, 10); +- } +- +- } +- +- // now restore the points array +- m_points[0] = savedStart; +- m_points[sz - 1] = savedEnd; +-} +- +-/** +- * Determines the active point or segment, the latter being given more priority. +- */ +-void AssociationLine::mousePressEvent(QGraphicsSceneMouseEvent *event) +-{ +- DEBUG(DBG_SRC) << "at " << event->scenePos(); +- if (event->buttons() & Qt::LeftButton) { +- m_activePointIndex = closestPointIndex(event->scenePos()); +- if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { +- // end points are not drawn and hence not active +- m_activePointIndex = -1; +- } +- // calculate only if active point index is -1 +- m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); +- } +- else if (event->buttons() & Qt::RightButton) { +- DEBUG(DBG_SRC) << "call context menu of association widget at " << event->scenePos(); +- } +- else { +- m_activePointIndex = -1; +- m_activeSegmentIndex = -1; +- } +-} +- +-/** +- * Moves the point or line if active. +- */ +-void AssociationLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +-{ +- UMLScene* scene = m_associationWidget->umlScene(); +- +- QPointF oldPos = event->scenePos(); +- QPointF newPos( +- scene->snappedX(oldPos.x()), +- scene->snappedY(oldPos.y()) +- ); +- +- // Prevent the moving vertex from disappearing underneath a widget +- // (else there's no way to get it back.) +- UMLWidget *onW = scene->widgetAt(newPos); +- if (onW && onW->baseType() != WidgetBase::wt_Box) { // boxes are transparent +- const qreal pX = newPos.x(); +- const qreal pY = newPos.y(); +- const qreal wX = onW->x(); +- const qreal wY = onW->y(); +- const qreal wWidth = onW->width(); +- const qreal wHeight = onW->height(); +- if (pX > wX && pX < wX + wWidth) { +- const qreal midX = wX + wWidth / 2.0; +- if (pX <= midX) +- newPos.setX(wX); +- else +- newPos.setX(wX + wWidth); +- } +- if (pY > wY && pY < wY + wHeight) { +- const qreal midY = wY + wHeight / 2.0; +- if (pY <= midY) +- newPos.setY(wY); +- else +- newPos.setY(wY + wHeight); +- } +- } +- +- if (m_activePointIndex != -1) { +- // Move a single point (snap behaviour) +- setPoint(m_activePointIndex, newPos); +- } +- else if (m_activeSegmentIndex != -1 && !isEndSegmentIndex(m_activeSegmentIndex)) { +- // Move a segment (between two points, snap behaviour not implemented) +- QPointF delta = event->scenePos() - event->lastScenePos(); +- setPoint(m_activeSegmentIndex, m_points[m_activeSegmentIndex] + delta); +- setPoint(m_activeSegmentIndex + 1, m_points[m_activeSegmentIndex + 1] + delta); +- } +-} +- +-/** +- * Reset active indices and also push undo command. +- */ +-void AssociationLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +-{ +- if (event->buttons() & Qt::LeftButton) { +- m_activeSegmentIndex = -1; +- m_activePointIndex = -1; +- } +-} +- +-/** +- * Calculates the "to be highlighted" point and segment indicies +- * and updates if necessary. +- */ +-void AssociationLine::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +-{ +- DEBUG(DBG_SRC) << "at " << event->scenePos(); +- int oldPointIndex = m_activePointIndex; +- int oldSegmentIndex = m_activeSegmentIndex; +- +- m_activePointIndex = closestPointIndex(event->scenePos()); +- // End points are not drawn and hence not active. +- if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { +- m_activePointIndex = -1; +- } +- // Activate segment index only if point index is -1 +- m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); +- +- bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); +- if (isChanged) { +- m_associationWidget->update(); +- } +-} +- +-/** +- * Calculates the "to be highlighted" point and segment indicies +- * and updates if necessary. +- */ +-void AssociationLine::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +-{ +- int oldPointIndex = m_activePointIndex; +- int oldSegmentIndex = m_activeSegmentIndex; +- +- m_activePointIndex = closestPointIndex(event->scenePos()); +- // End points are not drawn and hence not active. +- if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { +- m_activePointIndex = -1; +- } +- // Activate segment index only if point index is -1 +- m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); +- +- bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); +- if (isChanged) { +- m_associationWidget->update(); +- } +-} +- +-/** +- * Reset active indicies and updates. +- */ +-void AssociationLine::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +-{ +- DEBUG(DBG_SRC) << "at " << event->scenePos(); +- //Q_UNUSED(event) +- m_activePointIndex = -1; +- m_activeSegmentIndex = -1; +- m_associationWidget->update(); +-} +- +-//----------------------------------------------------------------------------- +- +-/** +- * SymbolEndPoints: +- * The first point is where the AssociationLine's visible line is +- * supposed to end. +- * The second points is where the actual symbol part is to appear. +- */ +-Symbol::SymbolProperty Symbol::symbolTable[Count] = +-{ +- { +- QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), +- SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) +- }, +- { +- QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), +- SymbolEndPoints(QPointF(0, 0), QPointF(0, 10)) +- }, +- { +- QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), +- SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) +- }, +- { +- QRectF(-5, -10, 10, 20), QPainterPath(), QLineF(0, -10, 0, 10), +- SymbolEndPoints(QPointF(0, -10), QPointF(0, 10)) +- }, +- { +- QRectF(-15, -10, 30, 20), QPainterPath(), QLineF(-10, 0, 0, 0), +- SymbolEndPoints(QPointF(0, 0), QPointF(0, 0)) +- }, +- { +- QRectF(-8, -8, 16, 16), QPainterPath(), QLineF(0, -8, 0, 8), +- SymbolEndPoints(QPointF(0, -8), QPointF(0, 8)) +- } +- +-}; +- +-/** +- * @internal A convenience method to setup shapes of all symbols. +- */ +-void Symbol::setupSymbolTable() +-{ +- SymbolProperty &openArrow = symbolTable[OpenArrow]; +- if (openArrow.shape.isEmpty()) { +- QRectF rect = openArrow.boundRect; +- // Defines a 'V' shape arrow fitting in the bound rect. +- openArrow.shape.moveTo(rect.topLeft()); +- openArrow.shape.lineTo(rect.center().x(), rect.bottom()); +- openArrow.shape.lineTo(rect.topRight()); +- } +- +- SymbolProperty &closedArrow = symbolTable[ClosedArrow]; +- if (closedArrow.shape.isEmpty()) { +- QRectF rect = closedArrow.boundRect; +- // Defines a 'V' shape arrow fitting in the bound rect. +- closedArrow.shape.moveTo(rect.topLeft()); +- closedArrow.shape.lineTo(rect.center().x(), rect.bottom()); +- closedArrow.shape.lineTo(rect.topRight()); +- closedArrow.shape.lineTo(rect.topLeft()); +- } +- +- SymbolProperty &crowFeet = symbolTable[CrowFeet]; +- if (crowFeet.shape.isEmpty()) { +- QRectF rect = crowFeet.boundRect; +- // Defines a crowFeet fitting in the bound rect. +- QPointF topMid(rect.center().x(), rect.top()); +- +- // left leg +- crowFeet.shape.moveTo(rect.bottomLeft()); +- crowFeet.shape.lineTo(topMid); +- +- // middle leg +- crowFeet.shape.moveTo(rect.center().x(), rect.bottom()); +- crowFeet.shape.lineTo(topMid); +- +- // right leg +- crowFeet.shape.moveTo(rect.bottomRight()); +- crowFeet.shape.lineTo(topMid); +- } +- +- SymbolProperty &diamond = symbolTable[Diamond]; +- if (diamond.shape.isEmpty()) { +- QRectF rect = diamond.boundRect; +- // Defines a 'diamond' shape fitting in the bound rect. +- diamond.shape.moveTo(rect.center().x(), rect.top()); +- diamond.shape.lineTo(rect.left(), rect.center().y()); +- diamond.shape.lineTo(rect.center().x(), rect.bottom()); +- diamond.shape.lineTo(rect.right(), rect.center().y()); +- diamond.shape.lineTo(rect.center().x(), rect.top()); +- } +- +- SymbolProperty &subset = symbolTable[Subset]; +- if (subset.shape.isEmpty()) { +- QRectF rect = subset.boundRect; +- // Defines an arc fitting in bound rect. +- qreal start = 90, span = 180; +- subset.shape.arcMoveTo(rect, start); +- subset.shape.arcTo(rect, start, span); +- } +- +- SymbolProperty &circle = symbolTable[Circle]; +- if (circle.shape.isEmpty()) { +- QRectF rect = circle.boundRect; +- // Defines a circle with a horizontal-vertical cross lines. +- circle.shape.addEllipse(rect); +- +- circle.shape.moveTo(rect.center().x(), rect.top()); +- circle.shape.lineTo(rect.center().x(), rect.bottom()); +- +- circle.shape.moveTo(rect.left(), rect.center().y()); +- circle.shape.lineTo(rect.right(), rect.center().y()); +- } +- +-} +- +-/** +- * Constructs a Symbol with current symbol being \a symbol and +- * parented to \a parent. +- */ +-Symbol::Symbol(SymbolType symbolType, QGraphicsItem *parent) +- : QGraphicsItem(parent), +- m_symbolType(symbolType) +-{ +- // ensure SymbolTable is validly initialized +- setupSymbolTable(); +-} +- +-/** +- * Destructor. +- */ +-Symbol::~Symbol() +-{ +-} +- +-/** +- * @return The current symbol being represented. +- */ +-Symbol::SymbolType Symbol::symbolType() const +-{ +- return m_symbolType; +-} +- +-/** +- * Sets the current symbol type to \a symbol and updates the geometry. +- */ +-void Symbol::setSymbolType(SymbolType symbolType) +-{ +- prepareGeometryChange(); // calls update implicitly +- m_symbolType = symbolType; +-} +- +-/** +- * Draws the current symbol using the QPainterPath stored for the current +- * symbol. +- */ +-void Symbol::paint(QPainter *painter, const QStyleOptionGraphicsItem * option, QWidget * widget) +-{ +- Q_UNUSED(option) Q_UNUSED(widget) +- painter->setPen(m_pen); +- switch (m_symbolType) { +- case ClosedArrow: +- case CrowFeet: +- case Diamond: +- painter->setBrush(m_brush); +- break; +- default: +- break; +- } +- painter->drawPath(Symbol::symbolTable[m_symbolType].shape); +-} +- +-/** +- * @return The bound rectangle for this based on current symbol. +- */ +-QRectF Symbol::boundingRect() const +-{ +- const qreal adj = .5 * m_pen.widthF(); +- return Symbol::symbolTable[m_symbolType].boundRect. +- adjusted(-adj, -adj, adj, adj); +-} +- +-/** +- * @return The path for this based on current symbol. +- */ +-QPainterPath Symbol::shape() const +-{ +- QPainterPath path; +- path.addRect(boundingRect()); +- return path; +-} +- +-/** +- * This method aligns *this* Symbol to the line being +- * passed. That is, it ensures that the axis of this symbol aligns +- * exactly with the \a "to" line passed. +- * +- * Also this item is moved such that the second end point of the +- * SymbolEndPoints for the current symbol *collides* with the second end +- * point of \a "to" line. +- */ +-void Symbol::alignTo(const QLineF& to) +-{ +- QLineF toMapped(mapFromParent(to.p1()), mapFromParent(to.p2())); +- +- QLineF origAxis = Symbol::symbolTable[m_symbolType].axisLine; +- QLineF translatedAxis = origAxis.translated(toMapped.p2() - origAxis.p2()); +- +- qreal angle = translatedAxis.angleTo(toMapped); +- setRotation(rotation() - angle); +- +- QPointF delta = to.p2() - mapToParent(symbolEndPoints().second); +- moveBy(delta.x(), delta.y()); +-} +- +-/** +- * @return The end points for the symbol. +- */ +-Symbol::SymbolEndPoints Symbol::symbolEndPoints() const +-{ +- return Symbol::symbolTable[m_symbolType].endPoints; +-} +- +-/** +- * @return The pen used to draw symbol. +- */ +-QPen Symbol::pen() const +-{ +- return m_pen; +-} +- +-/** +- * Sets the pen used to draw the symbol. +- */ +-void Symbol::setPen(const QPen& pen) +-{ +- prepareGeometryChange(); +- m_pen = pen; +- if (m_symbolType == ClosedArrow) +- m_pen.setStyle(Qt::solid-kf6Line); +-} +- +-/** +- * @return The brush used to fill symbol. +- */ +-QBrush Symbol::brush() const +-{ +- return m_brush; +-} +- +-/** +- * Sets the brush used to fill symbol. +- */ +-void Symbol::setBrush(const QBrush &brush) +-{ +- m_brush = brush; +- update(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.h umbrello-kf6-15.08.1/umbrello/widgets/associationline.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/associationline.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,207 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ASSOCIATIONLINE_H +-#define ASSOCIATIONLINE_H +- +-#include "basictypes.h" +- +-#include +-#include +-#include +-#include +- +-// forward declarations +-class AssociationWidget; +-class QDomDocument; +-class QDomElement; +-class QPainter; +- +-/** +- * This class provides with various symbols that can be embedded in +- * AssociationLine. It also provides with convenience methods to align +- * the symbol to AssociationLine. +- */ +-class Symbol : public QGraphicsItem +-{ +- public: +- typedef QPair SymbolEndPoints; +- +- /** +- * This enumeration lists all the symbols that can be used as +- * embedded on AssociationLine. +- */ +- enum SymbolType { +- None = -1, +- OpenArrow, +- ClosedArrow, +- CrowFeet, +- Diamond, +- Subset, +- Circle, +- Count +- }; +- +- explicit Symbol(SymbolType symbolType, QGraphicsItem *parent = 0); +- virtual ~Symbol(); +- +- SymbolType symbolType() const; +- void setSymbolType(SymbolType symbolType); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); +- +- virtual QRectF boundingRect() const; +- virtual QPainterPath shape() const; +- +- void alignTo(const QLineF& line); +- SymbolEndPoints symbolEndPoints() const; +- +- QPen pen() const; +- void setPen(const QPen &pen); +- +- QBrush brush() const; +- void setBrush(const QBrush& brush); +- +- private: +- QPen m_pen; ///< pen used to draw Symbol +- QBrush m_brush; ///< brush used to fill Symbol +- SymbolType m_symbolType; ///< current symbol being represented by this item +- +- /// A structure to hold a table of values for all symbols. +- struct SymbolProperty { +- QRectF boundRect; +- QPainterPath shape; +- QLineF axisLine; +- SymbolEndPoints endPoints; +- }; +- +- static SymbolProperty symbolTable[Symbol::Count]; ///< a table which stores all symbol properties +- static void setupSymbolTable(); +-}; +- +-/** +- * A convenience class that encapsulates geometry management, handles +- * mouse and hover events, embeds and aligns symbols and finally draws the +- * lines and points. +- * Context menu events are handled in AssociationWidget. +- * +- * This class is infact a draw and event handling proxy for +- * AssociationWidget. +- * +- * @note m_activePointIndex and m_activeSegmentIndex can't be +- * active at same time! +- * +- * @author Gopala Krishna +- * @author Andi Fischer +- * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org +- */ +-class AssociationLine : public QGraphicsObject +-{ +- Q_OBJECT +- Q_ENUMS(LayoutType) +-public: +- enum LayoutType { +- Direct = 1, +- Orthogonal, +- Polyline, +- Spline +- }; +- +- static QString toString(LayoutType layout); +- static LayoutType fromString(const QString& layout); +- +- explicit AssociationLine(AssociationWidget *association); +- virtual ~AssociationLine(); +- +- QPointF point(int index) const; +- bool setPoint(int index, const QPointF& point); +- QPointF startPoint() const; +- QPointF endPoint() const; +- +- void insertPoint(int index, const QPointF& point); +- void removePoint(int index); +- +- int count() const; +- void cleanup(); +- +- void optimizeLinePoints(); +- +- int closestPointIndex(const QPointF& point, qreal delta = Delta) const; +- int closestSegmentIndex(const QPointF& point, qreal delta = Delta) const; +- +- bool isEndPointIndex(int index) const; +- bool isEndSegmentIndex(int index) const; +- +- bool setEndPoints(const QPointF &start, const QPointF &end); +- +- void dumpPoints(); +- +- bool loadFromXMI(QDomElement &qElement); +- void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); +- +- QBrush brush() const; +- QPen pen() const; +- +- virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); +- +- QPainterPath path() const; +- +- QRectF boundingRect() const; +- QPainterPath shape() const; +- +- LayoutType layout() const; +- void setLayout(LayoutType layout); +- +- void mousePressEvent(QGraphicsSceneMouseEvent *event); +- void mouseMoveEvent(QGraphicsSceneMouseEvent *event); +- void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); +- +- void hoverEnterEvent(QGraphicsSceneHoverEvent *event); +- void hoverMoveEvent(QGraphicsSceneHoverEvent *event); +- void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); +- +- void calculateInitialEndPoints(); +- +- void reconstructSymbols(); +- +-private: +- void setStartSymbol(Symbol::SymbolType symbolType); +- void setEndSymbol(Symbol::SymbolType symbolType); +- +- void createSubsetSymbol(); +- void removeSubsetSymbol(); +- +- void createCollaborationLine(); +- void removeCollaborationLine(); +- +- void alignSymbols(); +- +- void createSplinePoints(); +- +- AssociationWidget *m_associationWidget; ///< association widget for which this line represents +- QVector m_points; ///< points representing the association line +- int m_activePointIndex; ///< index of active point which can be dragged to modify association line +- int m_activeSegmentIndex; ///< index of active segment +- Symbol *m_startSymbol; ///< symbol drawn at the end of "first" line segment +- Symbol *m_endSymbol; ///< symbol drawn at the end of "last" line segment +- Symbol *m_subsetSymbol; ///< subset symbol +- QGraphicsLineItem *m_collaborationLineItem; ///< parallel arrow line drawn in case of collaboration message +- Symbol *m_collaborationLineHead; ///< arrow head drawn at end of m_collaborationLineItem +- LayoutType m_layout; +- +- static QPainterPath createBezierCurve(QVector points); +- static QPainterPath createOrthogonalPath(QVector points); +- +- static const qreal Delta; ///< default delta for fuzzy recognition of points closer to point +- static const qreal SelectedPointDiameter; ///< radius of circles drawn to show "selection" +- static const qreal SelfAssociationMinimumHeight; ///< minimum height for self association's loop +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,4407 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "associationwidget.h" +- +-// app includes +-#include "association.h" +-#include "associationline.h" +-#include "associationpropertiesdialog.h" +-#include "assocrules.h" +-#include "attribute.h" +-#include "classifier.h" +-#include "classifierwidget.h" +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "entity.h" +-#include "floatingtextwidget.h" +-#include "listpopupmenu.h" +-#include "messagewidget.h" +-#include "objectwidget.h" +-#include "operation.h" +-#include "optionstate.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "umlwidget.h" +-#include "widget_utils.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#include +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#include +-#include +-#endif +-#include +-#include +-#include +-#include +- +-// system includes +-#include +- +-#define DBG_AW() DEBUG(QLatin1String("AssociationWidget")) +-DEBUG_REGISTER_DISABLED(AssociationWidget) +- +-using namespace Uml; +- +-/** +- * Constructor is private because the static create() methods shall +- * be used for constructing AssociationWidgets. +- * +- * @param scene The parent view of this widget. +- */ +-AssociationWidget::AssociationWidget(UMLScene *scene) +- : WidgetBase(scene, WidgetBase::wt_Association), +- m_positions_len(0), +- m_activated(false), +- m_unNameLineSegment(-1), +- m_nLinePathSegmentIndex(-1), +- m_pAssocClassLine(0), +- m_pAssocClassLineSel0(0), +- m_pAssocClassLineSel1(0), +- m_associationLine(new AssociationLine(this)), +- m_associationClass(0), +- m_associationType(Uml::AssociationType::Association), +- m_nameWidget(0) +-{ +- // floating text widgets objects owned by this association +- m_role[RoleType::A].changeabilityWidget = 0; +- m_role[RoleType::B].changeabilityWidget = 0; +- m_role[RoleType::A].multiplicityWidget = 0; +- m_role[RoleType::B].multiplicityWidget = 0; +- m_role[RoleType::A].roleWidget = 0; +- m_role[RoleType::B].roleWidget = 0; +- m_role[RoleType::A].umlWidget = 0; +- m_role[RoleType::B].umlWidget = 0; +- +- // associationwidget attributes +- m_role[RoleType::A].m_WidgetRegion = Uml::Region::Error; +- m_role[RoleType::B].m_WidgetRegion = Uml::Region::Error; +- m_role[RoleType::A].m_nIndex = 0; +- m_role[RoleType::B].m_nIndex = 0; +- m_role[RoleType::A].m_nTotalCount = 0; +- m_role[RoleType::B].m_nTotalCount = 0; +- m_role[RoleType::A].visibility = Uml::Visibility::Public; +- m_role[RoleType::B].visibility = Uml::Visibility::Public; +- m_role[RoleType::A].changeability = Uml::Changeability::Changeable; +- m_role[RoleType::B].changeability = Uml::Changeability::Changeable; +- +- setFlag(QGraphicsLineItem::ItemIsSelectable); +- setAcceptHoverEvents(true); +-} +- +-/** +- * This constructor is really only for loading from XMI, otherwise it +- * should not be allowed as it creates an incomplete associationwidget. +- * +- * @param scene The parent view of this widget. +- */ +-AssociationWidget* AssociationWidget::create(UMLScene *scene) +-{ +- AssociationWidget* instance = new AssociationWidget(scene); +- return instance; +-} +- +-/** +- * Preferred constructor (static factory method.) +- * +- * @param scene The parent view of this widget. +- * @param pWidgetA Pointer to the role A widget for the association. +- * @param assocType The AssociationType::Enum for this association. +- * @param pWidgetB Pointer to the role B widget for the association. +- * @param umlobject Pointer to the underlying UMLObject (if applicable.) +- */ +-AssociationWidget* AssociationWidget::create +- (UMLScene *scene, UMLWidget* pWidgetA, +- Uml::AssociationType::Enum assocType, UMLWidget* pWidgetB, +- UMLObject *umlobject /* = NULL */) +-{ +- AssociationWidget* instance = new AssociationWidget(scene); +- if (umlobject) { +- instance->setUMLObject(umlobject); +- } else { +- // set up UMLAssociation obj if assoc is represented and both roles are UML objects +- if (Uml::AssociationType::hasUMLRepresentation(assocType)) { +- UMLObject* umlRoleA = pWidgetA->umlObject(); +- UMLObject* umlRoleB = pWidgetB->umlObject(); +- if (umlRoleA != NULL && umlRoleB != NULL) { +- bool swap; +- +- // This is not correct. We could very easily have more than one +- // of the same type of association between the same two objects. +- // Just create the association. This search should have been +- // done BEFORE creation of the widget, if it mattered to the code. +- // But lets leave check in here for the time being so that debugging +- // output is shown, in case there is a collision with code elsewhere. +- UMLDoc *doc = UMLApp::app()->document(); +- UMLAssociation *myAssoc = doc->findAssociation(assocType, umlRoleA, umlRoleB, &swap); +- if (myAssoc != NULL) { +- switch (assocType) { +- case Uml::AssociationType::Generalization: +- case Uml::AssociationType::Dependency: +- case Uml::AssociationType::Association_Self: +- case Uml::AssociationType::Coll_Message_Self: +- case Uml::AssociationType::Seq_Message_Self: +- case Uml::AssociationType::Containment: +- case Uml::AssociationType::Realization: +- DBG_AW() << "Ignoring second construction of same assoctype " +- << assocType << " between " << umlRoleA->name() +- << " and " << umlRoleB->name(); +- break; +- default: +- DBG_AW() << "constructing a similar or exact same assoctype " +- << assocType << " between " << umlRoleA->name() << " and " +- << umlRoleB->name() << "as an already existing assoc (swap=" +- << swap << ")"; +- // now, just create a new association anyways +- myAssoc = NULL; +- break; +- } +- } +- if (myAssoc == NULL) { +- myAssoc = new UMLAssociation(assocType, umlRoleA, umlRoleB); +- // CHECK: myAssoc is not yet inserted at any parent UMLPackage - +- // need to check carefully that all callers do this, lest it be +- // orphaned. +- // ToolBarStateAssociation::addAssociationInViewAndDoc() is +- // okay in this regard. +- } +- instance->setUMLAssociation(myAssoc); +- } +- } +- } +- +- instance->setWidgetForRole(pWidgetA, RoleType::A); +- instance->setWidgetForRole(pWidgetB, RoleType::B); +- +- instance->setAssociationType(assocType); +- +- instance->calculateEndingPoints(); +- +- instance->associationLine()->calculateInitialEndPoints(); +- instance->associationLine()->reconstructSymbols(); +- +- //The AssociationWidget is set to Activated because it already has its side widgets +- instance->setActivated(true); +- +- // sync UML meta-data to settings here +- instance->mergeAssociationDataIntoUMLRepresentation(); +- +- // Collaboration messages need a name label because it's that +- // which lets operator== distinguish them, which in turn +- // permits us to have more than one message between two objects. +- if (instance->isCollaboration()) { +- // Create a temporary name to bring on setName() +- int collabID = instance->m_scene->generateCollaborationId(); +- instance->setName(QLatin1Char('m') + QString::number(collabID)); +- } +- +- return instance; +-} +- +-/** +- * Destructor. +- */ +-AssociationWidget::~AssociationWidget() +-{ +- delete m_associationLine; +-} +- +-/** +- * Overriding the method from WidgetBase because we need to do +- * something extra in case this AssociationWidget represents +- * an attribute of a classifier. +- */ +-void AssociationWidget::setUMLObject(UMLObject *obj) +-{ +- WidgetBase::setUMLObject(obj); +- if (obj == NULL) +- return; +- UMLClassifier *klass = NULL; +- UMLAttribute *attr = NULL; +- UMLEntity *ent = NULL; +- const UMLObject::ObjectType ot = obj->baseType(); +- switch (ot) { +- case UMLObject::ot_Association: +- setUMLAssociation(dynamic_cast(obj)); +- break; +- case UMLObject::ot_Operation: +- setOperation(dynamic_cast(obj)); +- break; +- case UMLObject::ot_Attribute: +- klass = static_cast(obj->parent()); +- connect(klass, SIGNAL(attributeRemoved(UMLClassifierListItem*)), +- this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); +- attr = static_cast(obj); +- connect(attr, SIGNAL(attributeChanged()), this, SLOT(slotAttributeChanged())); +- break; +- case UMLObject::ot_EntityAttribute: +- ent = static_cast(obj->parent()); +- connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), +- this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); +- break; +- case UMLObject::ot_ForeignKeyConstraint: +- ent = static_cast(obj->parent()); +- connect(ent, SIGNAL(entityConstraintRemoved(UMLClassifierListItem*)), +- this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); +- break; +- default: +- uError() << "cannot associate UMLObject of type " << UMLObject::toString(ot); +- break; +- } +-} +- +-/** +- * Set all 'owned' child widgets to this font. +- */ +-void AssociationWidget::lwSetFont (QFont font) +-{ +- if (m_nameWidget) { +- m_nameWidget->setFont(font); +- } +- if (m_role[RoleType::A].roleWidget) { +- m_role[RoleType::A].roleWidget->setFont(font); +- } +- if (m_role[RoleType::B].roleWidget) { +- m_role[RoleType::B].roleWidget->setFont(font); +- } +- if (m_role[RoleType::A].multiplicityWidget) { +- m_role[RoleType::A].multiplicityWidget->setFont(font); +- } +- if (m_role[RoleType::B].multiplicityWidget) { +- m_role[RoleType::B].multiplicityWidget->setFont(font); +- } +- if (m_role[RoleType::A].changeabilityWidget) +- m_role[RoleType::A].changeabilityWidget->setFont(font); +- if (m_role[RoleType::B].changeabilityWidget) +- m_role[RoleType::B].changeabilityWidget->setFont(font); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * @todo Move to LinkWidget. +- */ +-UMLClassifier *AssociationWidget::operationOwner() +-{ +- Uml::RoleType::Enum role = (isCollaboration() ? Uml::RoleType::B : Uml::RoleType::A); +- UMLObject *o = widgetForRole(role)->umlObject(); +- if (!o) { +- return 0; +- } +- UMLClassifier *c = dynamic_cast(o); +- if (!c) { +- uError() << "widgetForRole(" << role << ") is not a classifier"; +- } +- return c; +-} +- +-/** +- * Implements operation from LinkWidget. +- * Motivated by FloatingTextWidget. +- */ +-UMLOperation *AssociationWidget::operation() +-{ +- return dynamic_cast(m_umlObject); +-} +- +-/** +- * Implements operation from LinkWidget. +- * Motivated by FloatingTextWidget. +- */ +-void AssociationWidget::setOperation(UMLOperation *op) +-{ +- if (m_umlObject) +- disconnect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); +- m_umlObject = op; +- if (m_umlObject) +- connect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); +- if (m_nameWidget) +- m_nameWidget->setMessageText(); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-QString AssociationWidget::customOpText() +-{ +- return name(); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-void AssociationWidget::setCustomOpText(const QString &opText) +-{ +- setName(opText); +-} +- +-/** +- * Calls setTextPosition on all the labels. +- * Overrides operation from LinkWidget. +- */ +-void AssociationWidget::resetTextPositions() +-{ +- if (m_role[RoleType::A].multiplicityWidget) { +- setTextPosition(TextRole::MultiA); +- } +- if (m_role[RoleType::B].multiplicityWidget) { +- setTextPosition(Uml::TextRole::MultiB); +- } +- if (m_role[RoleType::A].changeabilityWidget) { +- setTextPosition(Uml::TextRole::ChangeA); +- } +- if (m_role[RoleType::B].changeabilityWidget) { +- setTextPosition(Uml::TextRole::ChangeB); +- } +- if (m_nameWidget) { +- setTextPosition(Uml::TextRole::Name); +- } +- if (m_role[RoleType::A].roleWidget) { +- setTextPosition(Uml::TextRole::RoleAName); +- } +- if (m_role[RoleType::B].roleWidget) { +- setTextPosition(Uml::TextRole::RoleBName); +- } +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @param ft The text widget which to update. +- */ +-void AssociationWidget::setMessageText(FloatingTextWidget *ft) +-{ +- if (isCollaboration()) { +- ft->setSequenceNumber(m_SequenceNumber); +- if (m_umlObject != NULL) { +- ft->setText(operationText(m_scene)); +- } else { +- ft->setText(name()); +- } +- } else { +- ft->setText(name()); +- } +-} +- +-/** +- * Sets the text of the given FloatingTextWidget. +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-void AssociationWidget::setText(FloatingTextWidget *ft, const QString &text) +-{ +- Uml::TextRole::Enum role = ft->textRole(); +- switch (role) { +- case Uml::TextRole::Name: +- setName(text); +- break; +- case Uml::TextRole::RoleAName: +- setRoleName(text, RoleType::A); +- break; +- case Uml::TextRole::RoleBName: +- setRoleName(text, RoleType::B); +- break; +- case Uml::TextRole::MultiA: +- setMultiplicity(text, RoleType::A); +- break; +- case Uml::TextRole::MultiB: +- setMultiplicity(text, RoleType::B); +- break; +- default: +- uWarning() << "Unhandled TextRole: " << Uml::TextRole::toString(role); +- break; +- } +-} +- +-/** +- * Shows the association properties dialog and updates the +- * corresponding texts if its execution is successful. +- */ +-void AssociationWidget::showPropertiesDialog() +-{ +- UMLApp::app()->docWindow()->updateDocumentation(); +- QPointer dlg = new AssociationPropertiesDialog(static_cast(m_scene->activeView()), this); +- if (dlg->exec()) { +- //rules built into these functions to stop updating incorrect values +- setName(name()); +- +- setRoleName(roleName(RoleType::A), RoleType::A); +- setRoleName(roleName(RoleType::B), RoleType::B); +- +- setDocumentation(documentation()); +- +- setRoleDocumentation(roleDocumentation(RoleType::A), RoleType::A); +- setRoleDocumentation(roleDocumentation(RoleType::B), RoleType::B); +- +- setMultiplicity(multiplicity(RoleType::A), RoleType::A); +- setMultiplicity(multiplicity(RoleType::B), RoleType::B); +- +- setVisibility(visibility(RoleType::A), RoleType::A); +- setVisibility(visibility(RoleType::B), RoleType::B); +- +- setChangeability(changeability(RoleType::A), RoleType::A); +- setChangeability(changeability(RoleType::B), RoleType::B); +- +- UMLApp::app()->docWindow()->showDocumentation(this, true); +- } +- delete dlg; +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @param op Return this AssociationWidget's operation string. +- */ +-QString AssociationWidget::lwOperationText() +-{ +- return name(); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @return classifier +- */ +-UMLClassifier* AssociationWidget::lwClassifier() +-{ +- UMLObject *o = widgetForRole(RoleType::B)->umlObject(); +- UMLClassifier *c = dynamic_cast(o); +- return c; +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @param op The new operation string to set. +- */ +-void AssociationWidget::setOperationText(const QString &op) +-{ +- if (!op.isEmpty()) { +- setName(op); +- } +-} +- +-/** +- * Calculates the m_unNameLineSegment value according to the new +- * NameText topleft corner PT. +- * It iterates through all AssociationLine's segments and for each one +- * calculates the sum of PT's distance to the start point + PT's +- * distance to the end point. The segment with the smallest sum will +- * be the RoleTextSegment (if this segment moves then the RoleText +- * will move with it). It sets m_unNameLineSegment to the start point +- * of the chosen segment. +- * +- * Overrides operation from LinkWidget (i.e. this method is also +- * required by FloatingTextWidget.) +- */ +-void AssociationWidget::calculateNameTextSegment() +-{ +- if (!m_nameWidget) { +- return; +- } +- //changed to use the middle of the text +- //i think this will give a better result. +- //never know what sort of lines people come up with +- //and text could be long to give a false reading +- qreal xt = m_nameWidget->x(); +- qreal yt = m_nameWidget->y(); +- xt += m_nameWidget->width() / 2; +- yt += m_nameWidget->height() / 2; +- int size = m_associationLine->count(); +- //sum of length(PTP1) and length(PTP2) +- qreal total_length = 0; +- qreal smallest_length = 0; +- for (int i = 0; i < size - 1; ++i) { +- QPointF pi = m_associationLine->point( i ); +- QPointF pj = m_associationLine->point( i+1 ); +- qreal xtiDiff = xt - pi.x(); +- qreal xtjDiff = xt - pj.x(); +- qreal ytiDiff = yt - pi.y(); +- qreal ytjDiff = yt - pj.y(); +- total_length = sqrt( double(xtiDiff * xtiDiff + ytiDiff * ytiDiff) ) +- + sqrt( double(xtjDiff * xtjDiff + ytjDiff * ytjDiff) ); +- //this gives the closest point +- if (total_length < smallest_length || i == 0) { +- smallest_length = total_length; +- m_unNameLineSegment = i; +- } +- } +-} +- +-/** +- * Returns the UMLAssociation representation of this object. +- * +- * @return Pointer to the UMLAssociation that is represented by +- * this AsociationWidget. +- */ +-UMLAssociation* AssociationWidget::association() const +-{ +- if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) +- return NULL; +- return static_cast(m_umlObject); +-} +- +-/** +- * Returns the UMLAttribute representation of this object. +- * +- * @return Pointer to the UMLAttribute that is represented by +- * this AsociationWidget. +- */ +-UMLAttribute* AssociationWidget::attribute() const +-{ +- if (m_umlObject == NULL) +- return NULL; +- UMLObject::ObjectType ot = m_umlObject->baseType(); +- if (ot != UMLObject::ot_Attribute && ot != UMLObject::ot_EntityAttribute) +- return NULL; +- return static_cast(m_umlObject); +-} +- +-#if 0 //:TODO: +-/** +- * Overrides the assignment operator. +- */ +-AssociationWidget& AssociationWidget::operator=(const AssociationWidget& other) +-{ +- *m_associationLine = *other.m_associationLine; +- +- if (other.m_nameWidget) { +- m_nameWidget = new FloatingTextWidget(m_scene); +- *m_nameWidget = *(other.m_nameWidget); +- } else { +- m_nameWidget = NULL; +- } +- +- for (unsigned r = (unsigned)A; r <= (unsigned)B; ++r) { +- WidgetRole& lhs = m_role[r]; +- const WidgetRole& rhs = other.m_role[r]; +- lhs.m_nIndex = rhs.m_nIndex; +- lhs.m_nTotalCount = rhs.m_nTotalCount; +- +- if (rhs.multiplicityWidget) { +- lhs.multiplicityWidget = new FloatingTextWidget(m_scene); +- *(lhs.multiplicityWidget) = *(rhs.multiplicityWidget); +- } else { +- lhs.multiplicityWidget = NULL; +- } +- +- if (rhs.roleWidget) { +- lhs.roleWidget = new FloatingTextWidget(m_scene); +- *(lhs.roleWidget) = *(rhs.roleWidget); +- } else { +- lhs.roleWidget = NULL; +- } +- +- if (rhs.changeabilityWidget) { +- lhs.changeabilityWidget = new FloatingTextWidget(m_scene); +- *(lhs.changeabilityWidget) = *(rhs.changeabilityWidget); +- } else { +- lhs.changeabilityWidget = NULL; +- } +- +- lhs.umlWidget = rhs.umlWidget; +- lhs.m_WidgetRegion = rhs.m_WidgetRegion; +- } +- +- m_activated = other.m_activated; +- m_unNameLineSegment = other.m_unNameLineSegment; +- m_pMenu = other.m_pMenu; +- setUMLAssociation(other.association()); +- setSelected(other.isSelected()); +- +- return *this; +-} +-#endif //:TODO: +- +-/** +- * Overrides the equality test operator. +- */ +-bool AssociationWidget::operator==(const AssociationWidget& other) const +-{ +- if (this == &other) +- return true; +- +- // if no model representation exists, then the widgets are not equal +- if (association() == NULL && other.association() == NULL) +- return false; +- +- if (!m_umlObject || !other.m_umlObject ) { +- if (!other.m_umlObject && m_umlObject) +- return false; +- if (other.m_umlObject && !m_umlObject) +- return false; +- +- } else if (m_umlObject != other.m_umlObject) +- return false; +- +- if (associationType() != other.associationType()) +- return false; +- +- if (widgetIDForRole(RoleType::A) != other.widgetIDForRole(RoleType::A)) +- return false; +- +- if (widgetIDForRole(RoleType::B) != other.widgetIDForRole(RoleType::B)) +- return false; +- +- if (widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object && +- other.widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object) { +- ObjectWidget *ownA = static_cast(widgetForRole(RoleType::A)); +- ObjectWidget *otherA = static_cast(other.widgetForRole(RoleType::A)); +- if (ownA->localID() != otherA->localID()) +- return false; +- } +- +- if (widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object && +- other.widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object) { +- ObjectWidget *ownB = static_cast(widgetForRole(RoleType::B)); +- ObjectWidget *otherB = static_cast(other.widgetForRole(RoleType::B)); +- if (ownB->localID() != otherB->localID()) +- return false; +- } +- +- // Two objects in a collaboration can have multiple messages between each other. +- // Here we depend on the messages having names, and the names must be different. +- // That is the reason why collaboration messages have strange initial names like +- // "m29997" or similar. +- return (name() == other.name()); +-} +- +-/** +- * Overrides the != operator. +- */ +-bool AssociationWidget::operator!=(AssociationWidget& other) const +-{ +- return !(*this == other); +-} +- +-/** +- * Returns a pointer to the association widget's line path. +- */ +-AssociationLine* AssociationWidget::associationLine() const +-{ +- return m_associationLine; +-} +- +-/** +- * Activates the AssociationWidget after a load. +- * +- * @return true for success +- */ +-bool AssociationWidget::activate() +-{ +- if (m_umlObject == NULL && +- AssociationType::hasUMLRepresentation(m_associationType)) { +- UMLObject *myObj = umlDoc()->findObjectById(m_nId); +- if (myObj == NULL) { +- uError() << "cannot find UMLObject " << Uml::ID::toString(m_nId); +- return false; +- } else { +- const UMLObject::ObjectType ot = myObj->baseType(); +- if (ot == UMLObject::ot_Association) { +- UMLAssociation * myAssoc = static_cast(myObj); +- setUMLAssociation(myAssoc); +- } else { +- setUMLObject(myObj); +- setAssociationType(m_associationType); +- } +- } +- } +- +- if (m_activated) +- return true; +- +- Uml::AssociationType::Enum type = associationType(); +- +- if (m_role[RoleType::A].umlWidget == NULL) +- setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::A)), RoleType::A); +- if (m_role[RoleType::B].umlWidget == NULL) +- setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::B)), RoleType::B); +- +- if (!m_role[RoleType::A].umlWidget || !m_role[RoleType::B].umlWidget) { +- DEBUG(DBG_SRC) << "Cannot make association!"; +- return false; +- } +- +- calculateEndingPoints(); +- +- if (AssocRules::allowRole(type)) { +- for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { +- WidgetRole& robj = m_role[r]; +- if (robj.roleWidget == NULL) +- continue; +- robj.roleWidget->setLink(this); +- TextRole::Enum tr = (r == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); +- robj.roleWidget->setTextRole(tr); +- Uml::Visibility::Enum vis = visibility(Uml::RoleType::fromInt(r)); +- robj.roleWidget->setPreText(Uml::Visibility::toString(vis, true)); +- +- if (FloatingTextWidget::isTextValid(robj.roleWidget->text())) +- robj.roleWidget->show(); +- else +- robj.roleWidget->hide(); +- if (m_scene->type() == DiagramType::Collaboration) +- robj.roleWidget->setUMLObject(robj.umlWidget->umlObject()); +- robj.roleWidget->activate(); +- } +- } +- +- if (m_nameWidget != NULL) { +- m_nameWidget->setLink(this); +- m_nameWidget->setTextRole(calculateNameType(TextRole::Name)); +- +- if (FloatingTextWidget::isTextValid(m_nameWidget->text())) { +- m_nameWidget->show(); +- } else { +- m_nameWidget->hide(); +- } +- m_nameWidget->activate(); +- calculateNameTextSegment(); +- } +- +- for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { +- WidgetRole& robj = m_role[r]; +- +- FloatingTextWidget* pMulti = robj.multiplicityWidget; +- if (pMulti != NULL && +- AssocRules::allowMultiplicity(type, robj.umlWidget->baseType())) { +- pMulti->setLink(this); +- TextRole::Enum tr = (r == RoleType::A ? TextRole::MultiA : TextRole::MultiB); +- pMulti->setTextRole(tr); +- if (FloatingTextWidget::isTextValid(pMulti->text())) +- pMulti->show(); +- else +- pMulti->hide(); +- pMulti->activate(); +- } +- +- FloatingTextWidget* pChangeWidget = robj.changeabilityWidget; +- if (pChangeWidget != NULL) { +- pChangeWidget->setLink(this); +- TextRole::Enum tr = (r == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); +- pChangeWidget->setTextRole(tr); +- if (FloatingTextWidget::isTextValid(pChangeWidget->text())) +- pChangeWidget->show(); +- else +- pChangeWidget->hide (); +- pChangeWidget->activate(); +- } +- } +- +- // Prepare the association class line if needed. +- if (m_associationClass && !m_pAssocClassLine) { +- createAssocClassLine(); +- } +- +- m_activated = true; +- return true; +-} +- +-/** +- * Set the widget of the given role. +- * Add this AssociationWidget at the widget. +- * If this AssociationWidget has an underlying UMLAssociation then set +- * the widget's underlying UMLObject at the UMLAssociation's role object. +- * +- * @param widget Pointer to the UMLWidget. +- * @param role Role for which to set the widget. +- */ +-void AssociationWidget::setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role) +-{ +- m_role[role].umlWidget = widget; +- if (widget) { +- m_role[role].umlWidget->addAssoc(this); +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) +- association()->setObject(widget->umlObject(), role); +- } +-} +- +-/** +- * Return the multiplicity FloatingTextWidget widget of the given role. +- * +- * @return Pointer to the multiplicity FloatingTextWidget object. +- */ +-FloatingTextWidget* AssociationWidget::multiplicityWidget(Uml::RoleType::Enum role) const +-{ +- return m_role[role].multiplicityWidget; +-} +- +-/** +- * Read property of FloatingTextWidget* m_nameWidget. +- * +- * @return Pointer to the FloatingTextWidget name widget. +- */ +-FloatingTextWidget* AssociationWidget::nameWidget() const +-{ +- return m_nameWidget; +-} +- +-/** +- * Return the given role's FloatingTextWidget object. +- * +- * @return Pointer to the role's FloatingTextWidget widget. +- */ +-FloatingTextWidget* AssociationWidget::roleWidget(Uml::RoleType::Enum role) const +-{ +- return m_role[role].roleWidget; +-} +- +-/** +- * Return the given role's changeability FloatingTextWidget widget. +- */ +-FloatingTextWidget* AssociationWidget::changeabilityWidget(Uml::RoleType::Enum role) const +-{ +- return m_role[role].changeabilityWidget; +-} +- +-/** +- * Return the FloatingTextWidget object indicated by the given TextRole::Enum. +- * +- * @return Pointer to the text role's FloatingTextWidget widget. +- */ +-FloatingTextWidget* AssociationWidget::textWidgetByRole(Uml::TextRole::Enum tr) const +-{ +- switch (tr) { +- case Uml::TextRole::MultiA: +- return m_role[RoleType::A].multiplicityWidget; +- case Uml::TextRole::MultiB: +- return m_role[RoleType::B].multiplicityWidget; +- case Uml::TextRole::Name: +- case Uml::TextRole::Coll_Message: +- return m_nameWidget; +- case Uml::TextRole::RoleAName: +- return m_role[RoleType::A].roleWidget; +- case Uml::TextRole::RoleBName: +- return m_role[RoleType::B].roleWidget; +- case Uml::TextRole::ChangeA: +- return m_role[RoleType::A].changeabilityWidget; +- case Uml::TextRole::ChangeB: +- return m_role[RoleType::B].changeabilityWidget; +- default: +- break; +- } +- return NULL; +-} +- +-/** +- * Returns the m_nameWidget's text. +- * +- * @return Text of the FloatingTextWidget name widget. +- */ +-QString AssociationWidget::name() const +-{ +- if (m_nameWidget == NULL) +- return QString(); +- return m_nameWidget->text(); +-} +- +-/** +- * Sets the text in the FloatingTextWidget widget representing the Name +- * of this association. +- */ +-void AssociationWidget::setName(const QString &strName) +-{ +- // set attribute of UMLAssociation associated with this associationwidget +- UMLAssociation *umla = association(); +- if (umla) +- umla->setName(strName); +- +- bool newLabel = false; +- if (!m_nameWidget) { +- // Don't construct the FloatingTextWidget if the string is empty. +- if (! FloatingTextWidget::isTextValid(strName)) +- return; +- +- newLabel = true; +- m_nameWidget = new FloatingTextWidget(m_scene, calculateNameType(Uml::TextRole::Name), strName); +- m_nameWidget->setParentItem(this); +- m_nameWidget->setLink(this); +- } else { +- m_nameWidget->setText(strName); +- if (! FloatingTextWidget::isTextValid(strName)) { +- //m_nameWidget->hide(); +- m_scene->removeWidget(m_nameWidget); +- m_nameWidget = NULL; +- return; +- } +- } +- +- setTextPosition(Uml::TextRole::Name); +- if (newLabel) { +- m_nameWidget->setActivated(); +- m_scene->addFloatingTextWidget(m_nameWidget); +- } +- +- m_nameWidget->show(); +-} +- +-void AssociationWidget::setStereotype(const QString &stereo) { +- UMLAssociation *umlassoc = association(); +- if (umlassoc) { +- umlassoc->setStereotype(stereo); +- if (m_nameWidget) { +- m_nameWidget->setText(umlassoc->stereotype(true)); +- } else { +- uDebug() << "not setting " << stereo << " because m_nameWidget is NULL"; +- } +- } else { +- uDebug() << "not setting " << stereo << " because association is NULL"; +- } +-} +- +-/** +- * Return the given role's FloatingTextWidget widget text. +- * +- * @return The name set at the FloatingTextWidget. +- */ +-QString AssociationWidget::roleName(Uml::RoleType::Enum role) const +-{ +- if (m_role[role].roleWidget == NULL) +- return QString(); +- return m_role[role].roleWidget->text(); +-} +- +-/** +- * Sets the text to the FloatingTextWidget that display the Role text of this +- * association. +- * For this function to work properly, the associated widget +- * should already be set. +- */ +-void AssociationWidget::setRoleName(const QString &strRole, Uml::RoleType::Enum role) +-{ +- Uml::AssociationType::Enum type = associationType(); +- //if the association is not supposed to have a Role FloatingTextWidget +- if (!AssocRules::allowRole(type)) { +- return; +- } +- +- TextRole::Enum tr = (role == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); +- setFloatingText(tr, strRole, m_role[role].roleWidget); +- if (m_role[role].roleWidget) { +- Uml::Visibility::Enum vis = visibility(role); +- if (FloatingTextWidget::isTextValid(m_role[role].roleWidget->text())) { +- m_role[role].roleWidget->setPreText(Uml::Visibility::toString(vis, true)); +- //m_role[role].roleWidget->show(); +- } else { +- m_role[role].roleWidget->setPreText(QString()); +- //m_role[role].roleWidget->hide(); +- } +- } +- +- // set attribute of UMLAssociation associated with this associationwidget +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) +- association()->setRoleName(strRole, role); +-} +- +-/** +- * Set the documentation on the given role. +- */ +-void AssociationWidget::setRoleDocumentation(const QString &doc, Uml::RoleType::Enum role) +-{ +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) +- association()->setRoleDoc(doc, role); +- else +- m_role[role].roleDocumentation = doc; +-} +- +-/** +- * Returns the given role's documentation. +- */ +-QString AssociationWidget::roleDocumentation(Uml::RoleType::Enum role) const +-{ +- if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) +- return QString(); +- UMLAssociation *umla = static_cast(m_umlObject); +- return umla->getRoleDoc(role); +-} +- +-/** +- * Change, create, or delete the FloatingTextWidget indicated by the given TextRole::Enum. +- * +- * @param tr TextRole::Enum of the FloatingTextWidget to change or create. +- * @param text Text string that controls the action: +- * If empty and ft is NULL then setFloatingText() is a no-op. +- * If empty and ft is non-NULL then the existing ft is deleted. +- * If non-empty and ft is NULL then a new FloatingTextWidget is created +- * and returned in ft with the text set. +- * If non-empty and ft is non-NULL then the existing ft text is modified. +- * @param ft Reference to the pointer to FloatingTextWidget to change or create. +- * On creation/deletion, the pointer value will be changed. +- */ +-void AssociationWidget::setFloatingText(Uml::TextRole::Enum role, +- const QString &text, +- FloatingTextWidget* &ft) +-{ +- if (! FloatingTextWidget::isTextValid(text)) { +- if (ft) { +- // Remove preexisting FloatingTextWidget +- m_scene->removeWidget(ft); // physically deletes ft +- ft = NULL; +- } +- return; +- } +- +- if (ft == NULL) { +- ft = new FloatingTextWidget(m_scene, role, text); +- ft->setParentItem(this); +- ft->setLink(this); +- ft->activate(); +- setTextPosition(role); +- m_scene->addFloatingTextWidget(ft); +- } else { +- bool newLabel = ft->text().isEmpty(); +- ft->setText(text); +- if (newLabel) +- setTextPosition(role); +- } +- +- ft->show(); +-} +- +-/** +- * Return the given role's multiplicity text. +- * +- * @return Text of the given role's multiplicity widget. +- */ +-QString AssociationWidget::multiplicity(Uml::RoleType::Enum role) const +-{ +- if (m_role[role].multiplicityWidget == NULL) +- return QString(); +- return m_role[role].multiplicityWidget->text(); +-} +- +-/** +- * Sets the text in the FloatingTextWidget representing the multiplicity +- * at the given side of the association. +- */ +-void AssociationWidget::setMultiplicity(const QString& text, Uml::RoleType::Enum role) +-{ +- TextRole::Enum tr = (role == RoleType::A ? TextRole::MultiA : TextRole::MultiB); +- +- setFloatingText(tr, text, m_role[role].multiplicityWidget); +- +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) +- association()->setMultiplicity(text, role); +-} +- +-/** +- * Gets the visibility on the given role of the association. +- */ +-Visibility::Enum AssociationWidget::visibility(Uml::RoleType::Enum role) const +-{ +- const UMLAssociation *assoc = association(); +- if (assoc) +- return assoc->visibility(role); +- const UMLAttribute *attr = attribute(); +- if (attr) +- return attr->visibility(); +- return m_role[role].visibility; +-} +- +-/** +- * Sets the visibility on the given role of the association. +- */ +-void AssociationWidget::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) +-{ +- if (value == visibility(role)) { +- return; +- } +- if (m_umlObject) { +- // update our model object +- const UMLObject::ObjectType ot = m_umlObject->baseType(); +- if (ot == UMLObject::ot_Association) +- association()->setVisibility(value, role); +- else if (ot == UMLObject::ot_Attribute) +- attribute()->setVisibility(value); +- } +- m_role[role].visibility = value; +- // update role pre-text attribute as appropriate +- if (m_role[role].roleWidget) { +- QString scopeString = Visibility::toString(value, true); +- m_role[role].roleWidget->setPreText(scopeString); +- } +-} +- +-/** +- * Gets the changeability on the given end of the Association. +- */ +-Uml::Changeability::Enum AssociationWidget::changeability(Uml::RoleType::Enum role) const +-{ +- if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) +- return m_role[role].changeability; +- UMLAssociation *umla = static_cast(m_umlObject); +- return umla->changeability(role); +-} +- +-/** +- * Sets the changeability on the given end of the Association. +- */ +-void AssociationWidget::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) +-{ +- if (value == changeability(role)) +- return; +- QString changeString = Uml::Changeability::toString(value); +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) // update our model object +- association()->setChangeability(value, role); +- m_role[role].changeability = value; +- // update our string representation +- setChangeWidget(changeString, role); +-} +- +-/** +- * For internal purpose-kf6s only. +- * Other classes/users should use setChangeability() instead. +- */ +-void AssociationWidget::setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role) +-{ +- bool newLabel = false; +- TextRole::Enum tr = (role == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); +- +- if (!m_role[role].changeabilityWidget) { +- // Don't construct the FloatingTextWidget if the string is empty. +- if (strChangeWidget.isEmpty()) +- return; +- +- newLabel = true; +- m_role[role].changeabilityWidget = new FloatingTextWidget(m_scene, tr, strChangeWidget); +- m_role[role].changeabilityWidget->setParentItem(this); +- m_role[role].changeabilityWidget->setLink(this); +- m_scene->addFloatingTextWidget(m_role[role].changeabilityWidget); +- m_role[role].changeabilityWidget->setPreText(QLatin1String("{")); // all types have this +- m_role[role].changeabilityWidget->setPostText(QLatin1String("}")); // all types have this +- } else { +- if (m_role[role].changeabilityWidget->text().isEmpty()) { +- newLabel = true; +- } +- m_role[role].changeabilityWidget->setText(strChangeWidget); +- } +- m_role[role].changeabilityWidget->setActivated(); +- +- if (newLabel) { +- setTextPosition(tr); +- } +- +- if (FloatingTextWidget::isTextValid(m_role[role].changeabilityWidget->text())) +- m_role[role].changeabilityWidget->show(); +- else +- m_role[role].changeabilityWidget->hide(); +-} +- +-/** +- * Returns true if the line path starts at the given widget. +- */ +-bool AssociationWidget::linePathStartsAt(const UMLWidget* widget) +-{ +-//:TODO: +-// QPointF lpStart = m_associationLine->point(0); +-// int startX = lpStart.x(); +-// int startY = lpStart.y(); +-// int wX = widget->x(); +-// int wY = widget->y(); +-// int wWidth = widget->width(); +-// int wHeight = widget->height(); +-// bool result = (startX >= wX && startX <= wX + wWidth && +-// startY >= wY && startY <= wY + wHeight); +-// return result; +- bool result = widget->contains(m_associationLine->point(0)); +- DEBUG(DBG_SRC) << "widget=" << widget->name() << " / result=" << result; +- return result; +-} +- +-/** +- * This function calculates which role should be set for the m_nameWidget FloatingTextWidget. +- */ +-Uml::TextRole::Enum AssociationWidget::calculateNameType(Uml::TextRole::Enum defaultRole) +-{ +- TextRole::Enum result = defaultRole; +- if (m_scene->type() == DiagramType::Collaboration) { +- if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { +- result = TextRole::Coll_Message;//for now same as other Coll_Message +- } else { +- result = TextRole::Coll_Message; +- } +- } else if (m_scene->type() == DiagramType::Sequence) { +- if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { +- result = TextRole::Seq_Message_Self; +- } else { +- result = TextRole::Seq_Message; +- } +- } +- +- return result; +-} +- +-/** +- * Gets the given role widget. +- * +- * @return Pointer to the role's UMLWidget. +- */ +-UMLWidget* AssociationWidget::widgetForRole(Uml::RoleType::Enum role) const +-{ +- return m_role[role].umlWidget; +-} +- +-/** +- * Sets the associated widgets. +- * +- * @param widgetA Pointer the role A widget for the association. +- * @param assocType The AssociationType::Enum for this association. +- * @param widgetB Pointer the role B widget for the association. +- */ +-bool AssociationWidget::setWidgets(UMLWidget* widgetA, +- Uml::AssociationType::Enum assocType, +- UMLWidget* widgetB) +-{ +- //if the association already has a WidgetB or WidgetA associated, then +- //it cannot be changed to other widget, that would require a deletion +- //of the association and the creation of a new one +- if ((m_role[RoleType::A].umlWidget && (m_role[RoleType::A].umlWidget != widgetA)) || +- (m_role[RoleType::B].umlWidget && (m_role[RoleType::B].umlWidget != widgetB))) { +- return false; +- } +- setWidgetForRole(widgetA, RoleType::A); +- setAssociationType(assocType); +- setWidgetForRole(widgetB, RoleType::B); +- +- calculateEndingPoints(); +- return true; +-} +- +-/** +- * CleansUp all the association's data in the related widgets. +- */ +-void AssociationWidget::cleanup() +-{ +- //let any other associations know we are going so they can tidy their positions up +- if (m_role[RoleType::A].m_nTotalCount > 2) +- updateAssociations(m_role[RoleType::A].m_nTotalCount - 1, m_role[RoleType::A].m_WidgetRegion, RoleType::A); +- if (m_role[RoleType::B].m_nTotalCount > 2) +- updateAssociations(m_role[RoleType::B].m_nTotalCount - 1, m_role[RoleType::B].m_WidgetRegion, RoleType::B); +- +- for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { +- WidgetRole& robj = m_role[r]; +- +- if (robj.umlWidget) { +- robj.umlWidget->removeAssoc(this); +- robj.umlWidget = 0; +- } +- if (robj.roleWidget) { +- m_scene->removeWidget(robj.roleWidget); +- robj.roleWidget = 0; +- } +- if (robj.multiplicityWidget) { +- m_scene->removeWidget(robj.multiplicityWidget); +- robj.multiplicityWidget = 0; +- } +- if (robj.changeabilityWidget) { +- m_scene->removeWidget(robj.changeabilityWidget); +- robj.changeabilityWidget = 0; +- } +- } +- +- if (m_nameWidget) { +- m_scene->removeWidget(m_nameWidget); +- m_nameWidget = 0; +- } +- +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { +- /* +- We do not remove the UMLAssociation from the document. +- Why? - Well, for example we might be in the middle of +- a cut/paste. If the UMLAssociation is removed by the cut +- then upon pasteing we have a problem. +- This is not quite clean yet - there should be a way to +- explicitly delete a UMLAssociation. The Right Thing would +- be to have a ListView representation for UMLAssociation. +- ` +- IF we are cut n pasting, why are we handling this association as a pointer? +- We should be using the XMI representation for a cut and paste. This +- allows us to be clean here, AND a choice of recreating the object +- w/ same id IF its a "cut", or a new object if its a "copy" operation +- (in which case we wouldnt be here, in cleanup()). +- */ +- setUMLAssociation(0); +- } +- +- m_associationLine->cleanup(); +- removeAssocClassLine(); +-} +- +-/** +- * @brief Return state if the assocation line point in the near of the last context +- * menu event position is addable or not. +- * A point is addable if the association is not an Exception and there is no point in the near. +- * +- * @return true if point is addable +- */ +-bool AssociationWidget::isPointAddable() +-{ +- if (!isSelected() || associationType() == Uml::AssociationType::Exception) +- return false; +- int i = m_associationLine->closestPointIndex(m_eventScenePos); +- return i == -1; +-} +- +-/** +- * @brief Return state if the assocation line point in the near of the last context +- * menu event position is removable or not. +- * A point is removable if the association is not an Exception and is not the start or end point. +- * +- * @return true if point is removable +- */ +-bool AssociationWidget::isPointRemovable() +-{ +- if (!isSelected() || associationType() == Uml::AssociationType::Exception || m_associationLine->count() <= 2) +- return false; +- int i = m_associationLine->closestPointIndex(m_eventScenePos); +- return i > 0 && i < m_associationLine->count() - 1; +-} +- +-/** +- * Set our internal umlAssociation. +- */ +-void AssociationWidget::setUMLAssociation (UMLAssociation * assoc) +-{ +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { +- UMLAssociation *umla = association(); +- +- // safety check. Did some num-nuts try to set the existing +- // association again? If so, just bail here +- if (umla == assoc) +- return; +- +- //umla->disconnect(this); //Qt does disconnect automatically upon destruction. +- umla->nrof_parent_widgets--; +- +- // ANSWER: This is the wrong treatment of cut and paste. Associations that +- // are being cut/n pasted should be serialized to XMI, then reconstituted +- // (IF a paste operation) rather than passing around object pointers. Its +- // just too hard otherwise to prevent problems in the code. Bottom line: we need to +- // delete orphaned associations or we well get code crashes and memory leaks. +- if (umla->nrof_parent_widgets <= 0) { +- //umla->deleteLater(); +- } +- +- m_umlObject = NULL; +- } +- +- if (assoc) { +- m_umlObject = assoc; +- +- // move counter to "0" from "-1" (which means, no assocwidgets) +- if (assoc->nrof_parent_widgets < 0) +- assoc->nrof_parent_widgets = 0; +- +- assoc->nrof_parent_widgets++; +- connect(assoc, SIGNAL(modified()), this, SLOT(syncToModel())); +- } +- +-} +- +-/** +- * Returns true if the Widget is either at the starting or ending side of the association. +- */ +-bool AssociationWidget::containsAsEndpoint(UMLWidget* widget) +-{ +- return (widget == m_role[RoleType::A].umlWidget || widget == m_role[RoleType::B].umlWidget); +-} +- +-/** +- * Returns true if this AssociationWidget represents a collaboration message. +- */ +-bool AssociationWidget::isCollaboration() const +-{ +- Uml::AssociationType::Enum at = associationType(); +- return (at == AssociationType::Coll_Message_Synchronous +- || at == AssociationType::Coll_Message_Asynchronous +- || at == AssociationType::Coll_Message_Self); +-} +- +-/** +- * Returns true if this AssociationWidget represents a self message. +- */ +-bool AssociationWidget::isSelf() const +-{ +- return widgetForRole(Uml::RoleType::A) == widgetForRole(Uml::RoleType::B); +-} +- +-/** +- * Gets the association's type. +- * +- * @return This AssociationWidget's AssociationType::Enum. +- */ +-Uml::AssociationType::Enum AssociationWidget::associationType() const +-{ +- if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) +- return m_associationType; +- UMLAssociation *umla = static_cast(m_umlObject); +- return umla->getAssocType(); +-} +- +-/** +- * Sets the association's type. +- * +- * @param type The AssociationType::Enum to set. +- */ +-void AssociationWidget::setAssociationType(Uml::AssociationType::Enum type) +-{ +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { +- association()->setAssociationType(type); +- } +- m_associationType = type; +- // If the association new type is not supposed to have Multiplicity +- // FloatingTexts and a Role FloatingTextWidget then set the texts +- // to empty. +- // NB We do not physically delete the floatingtext widgets here because +- // those widgets are also stored in the UMLView::m_WidgetList. +- if (!AssocRules::allowMultiplicity(type, widgetForRole(RoleType::A)->baseType())) { +- if (m_role[RoleType::A].multiplicityWidget) { +- m_role[RoleType::A].multiplicityWidget->setName(QString()); +- } +- if (m_role[RoleType::B].multiplicityWidget) { +- m_role[RoleType::B].multiplicityWidget->setName(QString()); +- } +- } +- if (!AssocRules::allowRole(type)) { +- if (m_role[RoleType::A].roleWidget) { +- m_role[RoleType::A].roleWidget->setName(QString()); +- } +- if (m_role[RoleType::B].roleWidget) { +- m_role[RoleType::B].roleWidget->setName(QString()); +- } +- setRoleDocumentation(QString(), RoleType::A); +- setRoleDocumentation(QString(), RoleType::B); +- } +- m_associationLine->reconstructSymbols(); +-} +- +-/** +- * Gets the ID of the given role widget. +- */ +-Uml::ID::Type AssociationWidget::widgetIDForRole(Uml::RoleType::Enum role) const +-{ +- if (m_role[role].umlWidget == NULL) { +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { +- UMLAssociation *umla = static_cast(m_umlObject); +- return umla->getObjectId(role); +- } +- uError() << "umlWidget is NULL"; +- return Uml::ID::None; +- } +- if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) +- return static_cast(m_role[role].umlWidget)->localID(); +- Uml::ID::Type id = m_role[role].umlWidget->id(); +- return id; +-} +- +-/** +- * Gets the local ID of the given role widget. +- */ +-Uml::ID::Type AssociationWidget::widgetLocalIDForRole(Uml::RoleType::Enum role) const +-{ +- if (m_role[role].umlWidget == NULL) { +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { +- UMLAssociation *umla = static_cast(m_umlObject); +- return umla->getObjectId(role); +- } +- uError() << "umlWidget is NULL"; +- return Uml::ID::None; +- } +- if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) +- return static_cast(m_role[role].umlWidget)->localID(); +- Uml::ID::Type id = m_role[role].umlWidget->localID(); +- return id; +-} +- +-/** +- * Returns a QString Object representing this AssociationWidget. +- */ +-QString AssociationWidget::toString() const +-{ +- QString string; +- static const QChar colon(QLatin1Char(':')); +- +- if (widgetForRole(RoleType::A)) { +- string = widgetForRole(RoleType::A)->name(); +- } +- string.append(colon); +- +- if (m_role[RoleType::A].roleWidget) { +- string += m_role[RoleType::A].roleWidget->text(); +- } +- string.append(colon); +- string.append(Uml::AssociationType::toStringI18n(associationType())); +- string.append(colon); +- +- if (widgetForRole(RoleType::B)) { +- string += widgetForRole(RoleType::B)->name(); +- } +- +- string.append(colon); +- if (m_role[RoleType::B].roleWidget) { +- string += m_role[RoleType::B].roleWidget->text(); +- } +- +- return string; +-} +- +-/** +- * Adds a break point (if left mouse button). +- */ +-void AssociationWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +-{ +- if (event->button() == Qt::LeftButton) { +- uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); +- showPropertiesDialog(); +- event->accept(); +- } +-} +- +-/** +- * Overrides moveEvent. +- */ +-void AssociationWidget::moveEvent(QGraphicsSceneMouseEvent *me) +-{ +- // 2004-04-30: Achim Spangler +- // Simple Approach to block moveEvent during load of XMI +- /// @todo avoid trigger of this event during load +- +- if (umlDoc()->loading()) { +- // hmmh - change of position during load of XMI +- // -> there is something wrong +- // -> avoid movement during opening +- // -> print warn and stay at old position +- uWarning() << "called during load of XMI for ViewType: " +- << m_scene->type() << ", and BaseType: " << baseType(); +- return; +- } +- /*to be here a line segment has moved. +- we need to see if the three text widgets needs to be moved. +- there are a few things to check first though: +- +- 1) Do they exist +- 2) does it need to move: +- 2a) for the multi widgets only move if they changed region, otherwise they are close enough +- 2b) for role name move if the segment it is on moves. +- */ +- //first see if either the first or last segments moved, else no need to recalculate their point positions +- +- QPointF oldNamePoint = calculateTextPosition(TextRole::Name); +- QPointF oldMultiAPoint = calculateTextPosition(TextRole::MultiA); +- QPointF oldMultiBPoint = calculateTextPosition(TextRole::MultiB); +- QPointF oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); +- QPointF oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); +- QPointF oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); +- QPointF oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); +- +- int movingPoint = m_associationLine->closestPointIndex(me->scenePos()); +- if (movingPoint != -1) +- m_associationLine->setPoint(movingPoint, me->scenePos()); +- int pos = m_associationLine->count() - 1;//set to last point for widget b +- +- if ( movingPoint == 1 || (movingPoint == pos-1) ) { +- calculateEndingPoints(); +- } +- if (m_role[RoleType::A].changeabilityWidget && (movingPoint == 1)) { +- setTextPositionRelatively(TextRole::ChangeA, oldChangeAPoint); +- } +- if (m_role[RoleType::B].changeabilityWidget && (movingPoint == 1)) { +- setTextPositionRelatively(TextRole::ChangeB, oldChangeBPoint); +- } +- if (m_role[RoleType::A].multiplicityWidget && (movingPoint == 1)) { +- setTextPositionRelatively(TextRole::MultiA, oldMultiAPoint); +- } +- if (m_role[RoleType::B].multiplicityWidget && (movingPoint == pos-1)) { +- setTextPositionRelatively(TextRole::MultiB, oldMultiBPoint); +- } +- +- if (m_nameWidget) { +- if (movingPoint == m_unNameLineSegment || +- movingPoint - 1 == m_unNameLineSegment) { +- setTextPositionRelatively(TextRole::Name, oldNamePoint); +- } +- } +- +- if (m_role[RoleType::A].roleWidget) { +- setTextPositionRelatively(TextRole::RoleAName, oldRoleAPoint); +- } +- if (m_role[RoleType::B].roleWidget) { +- setTextPositionRelatively(TextRole::RoleBName, oldRoleBPoint); +- } +- +- if (m_pAssocClassLine) { +- computeAssocClassLine(); +- } +-} +- +-/** +- * Calculates and sets the first and last point in the Association's AssociationLine. +- * Each point is a middle point of its respecting UMLWidget's Bounding rectangle +- * or a corner of it. +- * This method picks which sides to use for the association. +- */ +-void AssociationWidget::calculateEndingPoints() +-{ +- /* +- * For each UMLWidget the diagram is divided in four regions by its diagonals +- * as indicated below +- * Region 2 +- * \ / +- * \ / +- * +--------+ +- * | \ / | +- * Region 1 | >< | Region 3 +- * | / \ | +- * +--------+ +- * / \ +- * / \ +- * Region 4 +- * +- * Each diagonal is defined by two corners of the bounding rectangle +- * +- * To calculate the first point in the AssociationLine we have to find out in which +- * Region (defined by WidgetA's diagonals) is WidgetB's center +- * (let's call it Region M.) After that the first point will be the middle +- * point of the rectangle's side contained in Region M. +- * +- * To calculate the last point in the AssociationLine we repeat the above but +- * in the opposite direction (from widgetB to WidgetA) +- */ +- +- UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; +- UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; +- if (!pWidgetA || !pWidgetB) { +- uWarning() << "Returning - one of the role widgets is not set."; +- return; +- } +- +- int size = m_associationLine->count(); +- if (size < 2) { +- QPointF pA = pWidgetA->pos(); +- QPointF pB = pWidgetB->pos(); +- QPolygonF polyA = pWidgetA->shape().toFillPolygon().translated(pA); +- QPolygonF polyB = pWidgetB->shape().toFillPolygon().translated(pB); +- QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); +- if (nearestPoints.isNull()) { +- uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; +- } else { +- pA = nearestPoints.p1(); +- pB = nearestPoints.p2(); +- } +- m_associationLine->setEndPoints(pA, pB); +- } +- +- // See if an association to self. +- // See if it needs to be set up before we continue: +- // If self association/message and doesn't have the minimum 4 points +- // then create it. Make sure no points are out of bounds of viewing area. +- // This only happens on first time through that we are worried about. +- if (isSelf() && size < 4) { +- createPointsSelfAssociation(); +- return; +- } +- +- if (associationType() == AssociationType::Exception && size < 4) { +- createPointsException(); +- updatePointsException(); +- return; +- } +- +- // If the line has more than one segment change the values to calculate +- // from widget to point 1. +- qreal xB = pWidgetB->x() + pWidgetB->width() / 2; +- qreal yB = pWidgetB->y() + pWidgetB->height() / 2; +- if (size > 2) { +- QPointF p = m_associationLine->point(1); +- xB = p.x(); +- yB = p.y(); +- } +- doUpdates(QPointF(xB, yB), RoleType::A); +- +- // Now do the same for widgetB. +- // If the line has more than one segment change the values to calculate +- // from widgetB to the last point away from it. +- qreal xA = pWidgetA->x() + pWidgetA->width() / 2; +- qreal yA = pWidgetA->y() + pWidgetA->height() / 2; +- if (size > 2 ) { +- QPointF p = m_associationLine->point(size - 2); +- xA = p.x(); +- yA = p.y(); +- } +- doUpdates(QPointF(xA, yA), RoleType::B); +- +- computeAssocClassLine(); +-} +- +-/** +- * Used by @ref calculateEndingPoints. +- */ +-void AssociationWidget::doUpdates(const QPointF &otherP, RoleType::Enum role) +-{ +- // Find widget region. +- Uml::Region::Enum oldRegion = m_role[role].m_WidgetRegion; +- UMLWidget *pWidget = m_role[role].umlWidget; +- QRectF rc(pWidget->x(), pWidget->y(), +- pWidget->width(), pWidget->height()); +- Uml::Region::Enum region = m_role[role].m_WidgetRegion; // alias for brevity +- region = findPointRegion(rc, otherP); +- // Move some regions to the standard ones. +- switch( region ) { +- case Uml::Region::NorthWest: +- region = Uml::Region::North; +- break; +- case Uml::Region::NorthEast: +- region = Uml::Region::East; +- break; +- case Uml::Region::SouthEast: +- region = Uml::Region::South; +- break; +- case Uml::Region::SouthWest: +- case Uml::Region::Center: +- region = Uml::Region::West; +- break; +- default: +- break; +- } +- int regionCount = getRegionCount(region, role) + 2; //+2 = (1 for this one and one to halve it) +- int totalCount = m_role[role].m_nTotalCount; +- if (oldRegion != region) { +- updateRegionLineCount(regionCount - 1, regionCount, region, role); +- updateAssociations(totalCount - 1, oldRegion, role); +- } else if (totalCount != regionCount) { +- updateRegionLineCount(regionCount - 1, regionCount, region, role); +- } else { +- updateRegionLineCount(m_role[role].m_nIndex, totalCount, region, role); +- } +- updateAssociations(regionCount, region, role); +-} +- +-/** +- * Read property of bool m_activated. +- */ +-bool AssociationWidget::isActivated() const +-{ +- return m_activated; +-} +- +-/** +- * Set the m_activated flag of a widget but does not perform the Activate method. +- */ +-void AssociationWidget::setActivated(bool active) +-{ +- m_activated = active; +-} +- +-/** +- * Synchronize this widget from the UMLAssociation. +- */ +-void AssociationWidget::syncToModel() +-{ +- UMLAssociation *uml = association(); +- +- if (uml == NULL) { +- UMLAttribute *attr = attribute(); +- if (attr == NULL) +- return; +- setVisibility(attr->visibility(), RoleType::B); +- setRoleName(attr->name(), RoleType::B); +- return; +- } +- // block signals until finished +- uml->blockSignals(true); +- +- setName(uml->name()); +- setRoleName(uml->getRoleName(RoleType::A), RoleType::A); +- setRoleName(uml->getRoleName(RoleType::B), RoleType::B); +- setVisibility(uml->visibility(RoleType::A), RoleType::A); +- setVisibility(uml->visibility(RoleType::B), RoleType::B); +- setChangeability(uml->changeability(RoleType::A), RoleType::A); +- setChangeability(uml->changeability(RoleType::B), RoleType::B); +- setMultiplicity(uml->getMultiplicity(RoleType::A), RoleType::A); +- setMultiplicity(uml->getMultiplicity(RoleType::B), RoleType::B); +- +- uml->blockSignals(false); +-} +- +-/** +- * Merges/syncs the association widget data into UML object +- * representation. +- * This will synchronize UMLAssociation w/ this new Widget +- * CHECK: Can we get rid of this. +- */ +-void AssociationWidget::mergeAssociationDataIntoUMLRepresentation() +-{ +- UMLAssociation *umlassoc = association(); +- UMLAttribute *umlattr = attribute(); +- if (umlassoc == NULL && umlattr == NULL) +- return; +- +- // block emit modified signal, or we get a horrible loop +- m_umlObject->blockSignals(true); +- +- // would be desirable to do the following +- // so that we can be sure its back to initial state +- // in case we missed something here. +- //uml->init(); +- +- // floating text widgets +- FloatingTextWidget *text = nameWidget(); +- if (text) +- m_umlObject->setName(text->text()); +- +- text = roleWidget(RoleType::A); +- if (text && umlassoc) +- umlassoc->setRoleName(text->text(), RoleType::A); +- +- text = roleWidget(RoleType::B); +- if (text) { +- if (umlassoc) +- umlassoc->setRoleName(text->text(), RoleType::B); +- else if (umlattr) +- umlattr->setName(text->text()); +- } +- +- text = multiplicityWidget(RoleType::A); +- if (text && umlassoc) +- umlassoc->setMultiplicity(text->text(), RoleType::A); +- +- text = multiplicityWidget(RoleType::B); +- if (text && umlassoc) +- umlassoc->setMultiplicity(text->text(), RoleType::B); +- +- // unblock +- m_umlObject->blockSignals(false); +-} +- +-/** +- * Auxiliary method for widgetMoved(): +- * Saves all ideally computed floatingtext positions before doing any +- * kind of change. This is necessary because a single invocation of +- * calculateEndingPoints() modifies the AssociationLine ending points on ALL +- * AssociationWidgets. This means that if we don't save the old ideal +- * positions then they are irretrievably lost as soon as +- * calculateEndingPoints() is invoked. +- */ +-void AssociationWidget::saveIdealTextPositions() +-{ +- m_oldNamePoint = calculateTextPosition(TextRole::Name); +- m_oldMultiAPoint = calculateTextPosition(TextRole::MultiA); +- m_oldMultiBPoint = calculateTextPosition(TextRole::MultiB); +- m_oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); +- m_oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); +- m_oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); +- m_oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); +-} +- +-/** +- * Adjusts the ending point of the association that connects to Widget. +- */ +-void AssociationWidget::widgetMoved(UMLWidget* widget, qreal dx, qreal dy) +-{ +- Q_UNUSED(dx); Q_UNUSED(dy); +- +- // Simple Approach to block moveEvent during load of XMI +- /// @todo avoid trigger of this event during load +- if (umlDoc()->loading()) { +- // change of position during load of XMI +- // -> there is something wrong +- // -> avoid movement during opening +- // -> print warn and stay at old position +- DEBUG(DBG_SRC) << "called during load of XMI for ViewType: " << m_scene->type() +- << ", and BaseType: " << baseTypeStr(); +- return; +- } +- +- DEBUG(DBG_SRC) << "association type=" << Uml::AssociationType::toString(associationType()); +- if (associationType() == AssociationType::Exception) { +- updatePointsException(); +- setTextPosition(TextRole::Name); +- } +- else { +- calculateEndingPoints(); +- computeAssocClassLine(); +- } +- +- // Assoc to self - move all points: +- if (isSelf()) { +- updatePointsSelfAssociation(); +- +- if (m_nameWidget && !m_nameWidget->isSelected()) { +- setTextPositionRelatively(TextRole::Name, m_oldNamePoint); +- } +- +- }//end if widgetA = widgetB +- else if (m_role[RoleType::A].umlWidget == widget) { +- if (m_nameWidget && m_unNameLineSegment == 0 && !m_nameWidget->isSelected() ) { +- //only calculate position and move text if the segment it is on is moving +- setTextPositionRelatively(TextRole::Name, m_oldNamePoint); +- } +- }//end if widgetA moved +- else if (m_role[RoleType::B].umlWidget == widget) { +- const int size = m_associationLine->count(); +- if (m_nameWidget && (m_unNameLineSegment == size-2) && !m_nameWidget->isSelected() ) { +- //only calculate position and move text if the segment it is on is moving +- setTextPositionRelatively(TextRole::Name, m_oldNamePoint); +- } +- }//end if widgetB moved +- +- if (m_role[RoleType::A].roleWidget && !m_role[RoleType::A].roleWidget->isSelected()) { +- setTextPositionRelatively(TextRole::RoleAName, m_oldRoleAPoint); +- } +- if (m_role[RoleType::B].roleWidget && !m_role[RoleType::B].roleWidget->isSelected()) { +- setTextPositionRelatively(TextRole::RoleBName, m_oldRoleBPoint); +- } +- if (m_role[RoleType::A].multiplicityWidget && !m_role[RoleType::A].multiplicityWidget->isSelected()) { +- setTextPositionRelatively(TextRole::MultiA, m_oldMultiAPoint); +- } +- if (m_role[RoleType::B].multiplicityWidget && !m_role[RoleType::B].multiplicityWidget->isSelected()) { +- setTextPositionRelatively(TextRole::MultiB, m_oldMultiBPoint); +- } +- if (m_role[RoleType::A].changeabilityWidget && !m_role[RoleType::A].changeabilityWidget->isSelected()) { +- setTextPositionRelatively(TextRole::ChangeA, m_oldChangeAPoint); +- } +- if (m_role[RoleType::B].changeabilityWidget && !m_role[RoleType::B].changeabilityWidget->isSelected()) { +- setTextPositionRelatively(TextRole::ChangeB, m_oldChangeBPoint); +- } +-} +- +-/** +- * Creates the points of the self association. +- * Method called when a widget end points are calculated by calculateEndingPoints(). +- */ +-void AssociationWidget::createPointsSelfAssociation() +-{ +- UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; +- +- const int DISTANCE = 50; +- qreal x = pWidgetA->x(); +- qreal y = pWidgetA->y(); +- qreal h = pWidgetA->height(); +- qreal w = pWidgetA->width(); +- // see if above widget ok to start +- if (y - DISTANCE > 0) { +- m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); +- m_associationLine->insertPoint(1, QPointF(x + w / 4, y - DISTANCE)); +- m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); +- m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; +- } else { +- m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); +- m_associationLine->insertPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); +- m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); +- m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; +- } +-} +- +-/** +- * Adjusts the points of the self association. +- * Method called when a widget was moved by widgetMoved(widget, x, y). +- */ +-void AssociationWidget::updatePointsSelfAssociation() +-{ +- UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; +- +- const int DISTANCE = 50; +- qreal x = pWidgetA->x(); +- qreal y = pWidgetA->y(); +- qreal h = pWidgetA->height(); +- qreal w = pWidgetA->width(); +- // see if above widget ok to start +- if (y - DISTANCE > 0) { +- m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); +- m_associationLine->setPoint(1, QPointF(x + w / 4, y - DISTANCE)); +- m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); +- m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; +- } else { +- m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); +- m_associationLine->setPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); +- m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); +- m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; +- } +-} +- +-/** +- * Creates the points of the association exception. +- * Method called when a widget end points are calculated by calculateEndingPoints(). +- */ +-void AssociationWidget::createPointsException() +-{ +- UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; +- UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; +- +- qreal xa = pWidgetA->x(); +- qreal ya = pWidgetA->y(); +- qreal ha = pWidgetA->height(); +- qreal wa = pWidgetA->width(); +- +- qreal xb = pWidgetB->x(); +- qreal yb = pWidgetB->y(); +- qreal hb = pWidgetB->height(); +- //qreal wb = pWidgetB->width(); +- +- m_associationLine->setEndPoints(QPointF(xa + wa , ya + ha/2) , QPointF(xb , yb + hb/2)); +- m_associationLine->insertPoint(1, QPointF(xa + wa , ya + ha/2)); +- m_associationLine->insertPoint(2, QPointF(xb , yb + hb/2)); +-} +- +-/** +- * Adjusts the points of the association exception. +- * Method called when a widget was moved by widgetMoved(widget, x, y). +- */ +-void AssociationWidget::updatePointsException() +-{ +- UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; +- UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; +- +- qreal xa = pWidgetA->x(); +- qreal ya = pWidgetA->y(); +- qreal ha = pWidgetA->height(); +- qreal wa = pWidgetA->width(); +- +- qreal xb = pWidgetB->x(); +- qreal yb = pWidgetB->y(); +- qreal hb = pWidgetB->height(); +- qreal wb = pWidgetB->width(); +- qreal xmil, ymil; +- qreal xdeb, ydeb; +- qreal xfin, yfin; +- qreal ESPACEX, ESPACEY; +- QPointF p1; +- QPointF p2; +- //calcul des coordonnées au milieu de la flèche eclair +- if (xb - xa - wa >= 45) { +- ESPACEX = 0; +- xdeb = xa + wa; +- xfin = xb; +- } else if (xa - xb - wb > 45) { +- ESPACEX = 0; +- xdeb = xa; +- xfin = xb + wb; +- } else { +- ESPACEX = 15; +- xdeb = xa + wa/2; +- xfin = xb + wb/2; +- } +- +- xmil = xdeb + (xfin - xdeb)/2; +- +- if (yb - ya - ha >= 45) { +- ESPACEY = 0; +- ydeb = ya + ha; +- yfin = yb; +- } else if (ya - yb - hb > 45) { +- ESPACEY = 0; +- ydeb = ya; +- yfin = yb + hb; +- } else { +- ESPACEY = 15; +- ydeb = ya + ha/2; +- yfin = yb + hb/2; +- } +- +- ymil = ydeb + (yfin - ydeb)/2; +- +- p1.setX(xmil + (xfin - xmil)*1/2); p1.setY(ymil + (yfin - ymil)*1/3); +- p2.setX(xmil - (xmil - xdeb)*1/2); p2.setY(ymil - (ymil - ydeb)*1/3); +- +- if (abs(p1.x() - p2.x()) <= 10) +- ESPACEX = 15; +- if (abs(p1.y() - p2.y()) <= 10) +- ESPACEY = 15; +- +- m_associationLine->setEndPoints(QPointF(xdeb, ydeb), QPointF(xfin, yfin)); +- m_associationLine->setPoint(1, QPointF(p1.x() + ESPACEX, p1.y() + ESPACEY)); +- m_associationLine->setPoint(2, QPointF(p2.x() - ESPACEX, p2.y() - ESPACEY)); +- +- m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; +-} +- +-/** +- * Finds out which region of rectangle 'rect' contains the point 'pos' and returns the region +- * number: +- * 1 = Region 1 +- * 2 = Region 2 +- * 3 = Region 3 +- * 4 = Region 4 +- * 5 = On diagonal 2 between Region 1 and 2 +- * 6 = On diagonal 1 between Region 2 and 3 +- * 7 = On diagonal 2 between Region 3 and 4 +- * 8 = On diagonal 1 between Region 4 and 1 +- * 9 = On diagonal 1 and On diagonal 2 (the center) +- */ +-Uml::Region::Enum AssociationWidget::findPointRegion(const QRectF& rect, const QPointF &pos) +-{ +- qreal w = rect.width(); +- qreal h = rect.height(); +- qreal x = rect.x(); +- qreal y = rect.y(); +- qreal slope2 = w / h; +- qreal slope1 = slope2 *(-1.0); +- qreal b1 = x + w - (slope1 * y); +- qreal b2 = x - (slope2 * y); +- +- qreal eval1 = slope1 * pos.y() + b1; +- qreal eval2 = slope2 * pos.y() + b2; +- +- Uml::Region::Enum result = Uml::Region::Error; +- //if inside region 1 +- if (eval1 > pos.x() && eval2 > pos.x()) { +- result = Uml::Region::West; +- } +- //if inside region 2 +- else if (eval1 > pos.x() && eval2 < pos.x()) { +- result = Uml::Region::North; +- } +- //if inside region 3 +- else if (eval1 < pos.x() && eval2 < pos.x()) { +- result = Uml::Region::East; +- } +- //if inside region 4 +- else if (eval1 < pos.x() && eval2 > pos.x()) { +- result = Uml::Region::South; +- } +- //if inside region 5 +- else if (eval1 == pos.x() && eval2 < pos.x()) { +- result = Uml::Region::NorthWest; +- } +- //if inside region 6 +- else if (eval1 < pos.x() && eval2 == pos.x()) { +- result = Uml::Region::NorthEast; +- } +- //if inside region 7 +- else if (eval1 == pos.x() && eval2 > pos.x()) { +- result = Uml::Region::SouthEast; +- } +- //if inside region 8 +- else if (eval1 > pos.x() && eval2 == pos.x()) { +- result = Uml::Region::SouthWest; +- } +- //if inside region 9 +- else if (eval1 == pos.x() && eval2 == pos.x()) { +- result = Uml::Region::Center; +- } +- return result; +-} +- +-/** +- * Returns a point with interchanged X and Y coordinates. +- */ +-QPointF AssociationWidget::swapXY(const QPointF &p) +-{ +- QPointF swapped( p.y(), p.x() ); +- return swapped; +-} +- +-#if 0 // not used at the moment +-/** +- * Calculates which point of segment P1P2 has a distance equal to +- * Distance from P1. +- * Let's say such point is PX, the distance from P1 to PX must be equal +- * to Distance and if PX is not a point of the segment P1P2 then the +- * function returns (-1, -1). +- */ +-QPointF AssociationWidget::calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance) +-{ +- /* +- the distance D between points (x1, y1) and (x3, y3) has the following formula: +- --- ------------------------------ +- D = \ / 2 2 +- \ / (x3 - x1) + (y3 - y1) +- +- D, x1 and y1 are known and the point (x3, y3) is inside line (x1, y1)(x2, y2), so if the +- that line has the formula y = mx + b +- then y3 = m*x3 + b +- +- 2 2 2 +- D = (x3 - x1) + (y3 - y1) +- +- 2 2 2 2 2 +- D = x3 - 2*x3*x1 + x1 + y3 - 2*y3*y1 + y1 +- +- 2 2 2 2 2 +- D - x1 - y1 = x3 - 2*x3*x1 + y3 - 2*y3*y1 +- +- 2 2 2 2 2 +- D - x1 - y1 = x3 - 2*x3*x1 + (m*x3 + b) - 2*(m*x3 + b)*y1 +- +- 2 2 2 2 2 2 +- D - x1 - y1 + 2*b*y1 - b = (m + 1)*x3 + (-2*x1 + 2*m*b -2*m*y1)*x3 +- +- 2 2 2 2 +- C = - D + x1 + y1 - 2*b*y1 + b +- +- +- 2 +- A = (m + 1) +- +- B = (-2*x1 + 2*m*b -2*m*y1) +- +- and we have +- 2 +- A * x3 + B * x3 - C = 0 +- +- --------------- +- -B + --- / 2 +- \/ B - 4*A*C +- sol_1 = -------------------------------- +- 2*A +- +- +- --------------- +- -B - --- / 2 +- \/ B - 4*A*C +- sol_2 = -------------------------------- +- 2*A +- +- +- then in the distance formula we have only one variable x3 and that is easy +- to calculate +- */ +- int x1 = P1.y(); +- int y1 = P1.x(); +- int x2 = P2.y(); +- int y2 = P2.x(); +- +- if (x2 == x1) { +- return QPointF(x1, y1 + (int)Distance); +- } +- float slope = ((float)y2 - (float)y1) / ((float)x2 - (float)x1); +- float b = (y1 - slope*x1); +- float A = (slope * slope) + 1; +- float B = (2*slope*b) - (2*x1) - (2*slope*y1); +- float C = (b*b) - (Distance*Distance) + (x1*x1) + (y1*y1) - (2*b*y1); +- float t = B*B - 4*A*C; +- +- if (t < 0) { +- return QPointF(-1, -1); +- } +- float sol_1 = ((-1* B) + sqrt(t)) / (2*A); +- float sol_2 = ((-1*B) - sqrt(t)) / (2*A); +- +- if (sol_1 < 0.0 && sol_2 < 0.0) { +- return QPointF(-1, -1); +- } +- QPointF sol1Point((int)(slope*sol_1 + b), (int)(sol_1)); +- QPointF sol2Point((int)(slope*sol_2 + b), (int)(sol_2)); +- if (sol_1 < 0 && sol_2 >=0) { +- if (x2 > x1) { +- if (x1 <= sol_2 && sol_2 <= x2) +- return sol2Point; +- } else { +- if (x2 <= sol_2 && sol_2 <= x1) +- return sol2Point; +- } +- } else if (sol_1 >= 0 && sol_2 < 0) { +- if (x2 > x1) { +- if (x1 <= sol_1 && sol_1 <= x2) +- return sol1Point; +- } else { +- if (x2 <= sol_1 && sol_1 <= x1) +- return sol1Point; +- } +- } else { +- if (x2 > x1) { +- if (x1 <= sol_1 && sol_1 <= x2) +- return sol1Point; +- if (x1 <= sol_2 && sol_2 <= x2) +- return sol2Point; +- } else { +- if (x2 <= sol_1 && sol_1 <= x1) +- return sol1Point; +- if (x2 <= sol_2 && sol_2 <= x1) +- return sol2Point; +- } +- } +- return QPointF(-1, -1); +-} +- +-/** +- * Calculates which point of a perpendicular line to segment P1P2 that contains P2 +- * has a distance equal to Distance from P2, +- * Lets say such point is P3, the distance from P2 to P3 must be equal to Distance +- */ +-QPointF AssociationWidget::calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance) +-{ +- /* +- the distance D between points (x2, y2) and (x3, y3) has the following formula: +- +- --- ------------------------------ +- D = \ / 2 2 +- \ / (x3 - x2) + (y3 - y2) +- +- D, x2 and y2 are known and line P2P3 is perpendicular to line (x1, y1)(x2, y2), so if the +- line P1P2 has the formula y = m*x + b, +- then (x1 - x2) +- m = -----------, because it is perpendicular to line P1P2 +- (y2 - y1) +- +- also y2 = m*x2 + b +- => b = y2 - m*x2 +- +- then P3 = (x3, m*x3 + b) +- +- 2 2 2 +- D = (x3 - x2) + (y3 - y2) +- +- 2 2 2 2 2 +- D = x3 - 2*x3*x2 + x2 + y3 - 2*y3*y2 + y2 +- +- 2 2 2 2 2 +- D - x2 - y2 = x3 - 2*x3*x2 + y3 - 2*y3*y2 +- +- +- +- 2 2 2 2 2 +- D - x2 - y2 = x3 - 2*x3*x2 + (m*x3 + b) - 2*(m*x3 + b)*y2 +- +- 2 2 2 2 2 2 +- D - x2 - y2 + 2*b*y2 - b = (m + 1)*x3 + (-2*x2 + 2*m*b -2*m*y2)*x3 +- +- 2 2 2 2 +- C = - D + x2 + y2 - 2*b*y2 + b +- +- 2 +- A = (m + 1) +- +- B = (-2*x2 + 2*m*b -2*m*y2) +- +- and we have +- 2 +- A * x3 + B * x3 - C = 0 +- +- +- --------------- +- --- / 2 +- -B + \/ B - 4*A*C +- sol_1 = -------------------------------- +- 2*A +- +- +- --------------- +- --- / 2 +- -B - \/ B - 4*A*C +- sol_2 = -------------------------------- +- 2*A +- +- then in the distance formula we have only one variable x3 and that is easy +- to calculate +- */ +- if (P1.x() == P2.x()) { +- return QPointF((int)(P2.x() + Distance), P2.y()); +- } +- const int x1 = P1.y(); +- const int y1 = P1.x(); +- const int x2 = P2.y(); +- const int y2 = P2.x(); +- +- float slope = ((float)x1 - (float)x2) / ((float)y2 - (float)y1); +- float b = (y2 - slope*x2); +- float A = (slope * slope) + 1; +- float B = (2*slope*b) - (2*x2) - (2*slope*y2); +- float C = (b*b) - (Distance*Distance) + (x2*x2) + (y2*y2) - (2*b*y2); +- float t = B*B - 4*A*C; +- if (t < 0) { +- return QPointF(-1, -1); +- } +- float sol_1 = ((-1* B) + sqrt(t)) / (2*A); +- +- float sol_2 = ((-1*B) - sqrt(t)) / (2*A); +- +- if (sol_1 < 0 && sol_2 < 0) { +- return QPointF(-1, -1); +- } +- QPointF sol1Point((int)(slope*sol_1 + b), (int)sol_1); +- QPointF sol2Point((int)(slope*sol_2 + b), (int)sol_2); +- if (sol_1 < 0 && sol_2 >=0) { +- return sol2Point; +- } else if (sol_1 >= 0 && sol_2 < 0) { +- return sol1Point; +- } else { // Choose one solution, either will work fine +- if (slope >= 0) { +- if (sol_1 <= sol_2) +- return sol2Point; +- else +- return sol1Point; +- } else { +- if (sol_1 <= sol_2) +- return sol1Point; +- else +- return sol2Point; +- } +- +- } +- return QPointF(-1, -1); // never reached, just keep compilers happy +-} +- +-/** +- * Calculates the intersection (PS) between line P1P2 and a perpendicular line containing +- * P3, the result is returned in ResultingPoint. and result value represents the distance +- * between ResultingPoint and P3; if this value is negative an error ocurred. +- */ +-float AssociationWidget::perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, +- QPointF& ResultingPoint) +-{ +- //line P1P2 is Line 1 = y=slope1*x + b1 +- +- //line P3PS is Line 1 = y=slope2*x + b2 +- +- float slope2 = 0; +- float slope1 = 0; +- float sx = 0, sy = 0; +- int y2 = P2.x(); +- int y1 = P1.x(); +- int x2 = P2.y(); +- int x1 = P1.y(); +- int y3 = P3.x(); +- int x3 = P3.y(); +- float distance = 0; +- float b1 = 0; +- +- float b2 = 0; +- +- if (x2 == x1) { +- sx = x2; +- sy = y3; +- } else if (y2 == y1) { +- sy = y2; +- sx = x3; +- } else { +- slope1 = (y2 - y1)/ (x2 - x1); +- slope2 = (x1 - x2)/ (y2 - y1); +- b1 = y2 - (slope1 * x2); +- b2 = y3 - (slope2 * x3); +- sx = (b2 - b1) / (slope1 - slope2); +- sy = slope1*sx + b1; +- } +- distance = (int)(sqrt(((x3 - sx)*(x3 - sx)) + ((y3 - sy)*(y3 - sy)))); +- +- ResultingPoint.setX((int)sy); +- ResultingPoint.setY((int)sx); +- +- return distance; +-} +-#endif +- +-/** +- * Calculates the position of the text widget depending on the role +- * that widget is playing. +- * Returns the point at which to put the widget. +- */ +-QPointF AssociationWidget::calculateTextPosition(Uml::TextRole::Enum role) +-{ +- const int SPACE = 2; +- QPointF p(-1, -1), q(-1, -1); +- +- // used to find out if association end point (p) +- // is at top or bottom edge of widget. +- +- if (role == TextRole::MultiA || role == TextRole::ChangeA || role == TextRole::RoleAName) { +- p = m_associationLine->point(0); +- q = m_associationLine->point(1); +- } else if (role == TextRole::MultiB || role == TextRole::ChangeB || role == TextRole::RoleBName) { +- const int lastSegment = m_associationLine->count() - 1; +- p = m_associationLine->point(lastSegment); +- q = m_associationLine->point(lastSegment - 1); +- } else if (role != TextRole::Name) { +- uError() << "called with unsupported TextRole::Enum " << role; +- return QPointF(-1, -1); +- } +- +- FloatingTextWidget *text = textWidgetByRole(role); +- int textW = 0, textH = 0; +- if (text) { +- textW = text->width(); +- textH = text->height(); +- } +- +- qreal x = 0.0, y = 0.0; +- +- if (role == TextRole::MultiA || role == TextRole::MultiB) { +- const bool isHorizontal = (p.y() == q.y()); +- const int atBottom = p.y() + SPACE; +- const int atTop = p.y() - SPACE - textH; +- const int atLeft = p.x() - SPACE - textW; +- const int atRight = p.x() + SPACE; +- y = (p.y() > q.y()) == isHorizontal ? atBottom : atTop; +- x = (p.x() < q.x()) == isHorizontal ? atRight : atLeft; +- +- } else if (role == TextRole::ChangeA || role == TextRole::ChangeB) { +- +- if (p.y() > q.y()) +- y = p.y() - SPACE - (textH * 2); +- else +- y = p.y() + SPACE + textH; +- +- if (p.x() < q.x()) +- x = p.x() + SPACE; +- else +- x = p.x() - SPACE - textW; +- +- } else if (role == TextRole::RoleAName || role == TextRole::RoleBName) { +- +- if (p.y() > q.y()) +- y = p.y() - SPACE - textH; +- else +- y = p.y() + SPACE; +- +- if (p.x() < q.x()) +- x = p.x() + SPACE; +- else +- x = p.x() - SPACE - textW; +- +- } else if (role == TextRole::Name) { +- +- calculateNameTextSegment(); +- if (m_unNameLineSegment == -1) { +- uWarning() << "TODO:negative line segment index"; +- m_unNameLineSegment = 0; +- } +- x = ( m_associationLine->point(m_unNameLineSegment).x() + +- m_associationLine->point(m_unNameLineSegment + 1).x() ) / 2; +- y = ( m_associationLine->point(m_unNameLineSegment).y() + +- m_associationLine->point(m_unNameLineSegment + 1).y() ) / 2; +- } +- +- if (text) { +- constrainTextPos(x, y, textW, textH, role); +- } +- p = QPointF( x, y ); +- return p; +-} +- +-/** +- * Return the mid point between p0 and p1 +- */ +-QPointF AssociationWidget::midPoint(const QPointF& p0, const QPointF& p1) +-{ +- QPointF midP; +- if (p0.x() < p1.x()) +- midP.setX(p0.x() + (p1.x() - p0.x()) / 2); +- else +- midP.setX(p1.x() + (p0.x() - p1.x()) / 2); +- if (p0.y() < p1.y()) +- midP.setY(p0.y() + (p1.y() - p0.y()) / 2); +- else +- midP.setY(p1.y() + (p0.y() - p1.y()) / 2); +- return midP; +-} +- +-/** +- * Constrains the FloatingTextWidget X and Y values supplied. +- * Implements the abstract operation from LinkWidget. +- * +- * @param textX Candidate X value (may be modified by the constraint.) +- * @param textY Candidate Y value (may be modified by the constraint.) +- * @param textWidth Width of the text. +- * @param textHeight Height of the text. +- * @param tr Uml::Text_Role of the text. +- */ +-void AssociationWidget::constrainTextPos(qreal &textX, qreal &textY, +- qreal textWidth, qreal textHeight, +- Uml::TextRole::Enum tr) +-{ +- const int textCenterX = textX + textWidth / 2; +- const int textCenterY = textY + textHeight / 2; +- const int lastSegment = m_associationLine->count() - 1; +- QPointF p0, p1; +- switch (tr) { +- case TextRole::RoleAName: +- case TextRole::MultiA: +- case TextRole::ChangeA: +- p0 = m_associationLine->point(0); +- p1 = m_associationLine->point(1); +- // If we are dealing with a single line then tie the +- // role label to the proper half of the line, i.e. +- // the role label must be closer to the "other" +- // role object. +- if (lastSegment == 1) +- p1 = midPoint(p0, p1); +- break; +- case TextRole::RoleBName: +- case TextRole::MultiB: +- case TextRole::ChangeB: +- p0 = m_associationLine->point(lastSegment - 1); +- p1 = m_associationLine->point(lastSegment); +- if (lastSegment == 1) +- p0 = midPoint(p0, p1); +- break; +- case TextRole::Name: +- case TextRole::Coll_Message: // CHECK: collab.msg texts seem to be TextRole::Name +- case TextRole::State: // CHECK: is this used? +- // Find the linepath segment to which the (textX, textY) is closest +- // and constrain to the corridor of that segment (see farther below) +- { +- int minDistSquare = 100000; // utopian initial value +- int lpIndex = 0; +- for (int i = 0; i < lastSegment; ++i) { +- p0 = m_associationLine->point(i); +- p1 = m_associationLine->point(i + 1); +- QPointF midP = midPoint(p0, p1); +- const int deltaX = textCenterX - midP.x(); +- const int deltaY = textCenterY - midP.y(); +- const int cSquare = deltaX * deltaX + deltaY * deltaY; +- if (cSquare < minDistSquare) { +- minDistSquare = cSquare; +- lpIndex = i; +- } +- } +- p0 = m_associationLine->point(lpIndex); +- p1 = m_associationLine->point(lpIndex + 1); +- } +- break; +- default: +- uError() << "unexpected TextRole::Enum " << tr; +- return; +- break; +- } +- /* Constraint: +- The midpoint between p0 and p1 is taken to be the center of a circle +- with radius D/2 where D is the distance between p0 and p1. +- The text center needs to be within this circle else it is constrained +- to the nearest point on the circle. +- */ +- p0 = swapXY(p0); // go to the natural coordinate system +- p1 = swapXY(p1); // with (0,0) in the lower left corner +- QPointF midP = midPoint(p0, p1); +- // If (textX,textY) is not inside the circle around midP then +- // constrain (textX,textY) to the nearest point on that circle. +- const int x0 = p0.x(); +- const int y0 = p0.y(); +- const int x1 = p1.x(); +- const int y1 = p1.y(); +- double r = sqrt((double)((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0))) / 2; +- if (textWidth > r) +- r = textWidth; +- // swap textCenter{X,Y} to convert from Qt coord.system. +- const QPointF origTextCenter(textCenterY, textCenterX); +- const int relX = abs(origTextCenter.x() - midP.x()); +- const int relY = abs(origTextCenter.y() - midP.y()); +- const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r; +- if (negativeWhenInsideCircle <= 0.0) { +- return; +- } +- /* +- The original constraint was to snap the text position to the +- midpoint but that creates unpleasant visual jitter: +- textX = midP.y() - textWidth / 2; // go back to Qt coord.sys. +- textY = midP.x() - textHeight / 2; // go back to Qt coord.sys. +- +- Rather, we project the text position onto the closest point +- on the circle: +- +- Circle equation: +- relX^2 + relY^2 - r^2 = 0, or in other words +- relY^2 = r^2 - relX^2, or +- relY = sqrt(r^2 - relX^2) +- Line equation: +- relY = a * relX + b +- We can omit "b" because relX and relY are already relative to +- the circle origin, therefore we can also write: +- a = relY / relX +- To obtain the point of intersection between the circle of radius r +- and the line connecting the circle origin with the point (relX, relY), +- we equate the relY: +- a * x = sqrt(r^2 - x^2), or in other words +- a^2 * x^2 = r^2 - x^2, or +- x^2 * (a^2 + 1) = r^2, or +- x^2 = r^2 / (a^2 + 1), or +- x = sqrt(r^2 / (a^2 + 1)) +- and then +- y = a * x +- The resulting x and y are relative to the circle origin so we just add +- the circle origin (X, Y) to obtain the constrained (textX, textY). +- */ +- // Handle the special case, relX = 0. +- if (relX == 0) { +- if (origTextCenter.y() > midP.y()) +- textX = midP.y() + (int)r; // go back to Qt coord.sys. +- else +- textX = midP.y() - (int)r; // go back to Qt coord.sys. +- textX -= textWidth / 2; +- return; +- } +- const double a = (double)relY / (double)relX; +- const double x = sqrt(r*r / (a*a + 1)); +- const double y = a * x; +- if (origTextCenter.x() > midP.x()) +- textY = midP.x() + (int)x; // go back to Qt coord.sys. +- else +- textY = midP.x() - (int)x; // go back to Qt coord.sys. +- textY -= textHeight / 2; +- if (origTextCenter.y() > midP.y()) +- textX = midP.y() + (int)y; // go back to Qt coord.sys. +- else +- textX = midP.y() - (int)y; // go back to Qt coord.sys. +- textX -= textWidth / 2; +-} +- +-/** +- * Puts the text widget with the given role at the given position. +- * This method calls @ref calculateTextPostion to get the needed position. +- * I.e. the line segment it is on has moved and it should move the same +- * amount as the line. +- */ +-void AssociationWidget::setTextPosition(Uml::TextRole::Enum role) +-{ +- bool startMove = false; +- if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) +- startMove = true; +- else if (m_nameWidget && m_nameWidget->getStartMove()) +- startMove = true; +- if (startMove) { +- return; +- } +- FloatingTextWidget *ft = textWidgetByRole(role); +- if (ft == NULL) +- return; +- QPointF pos = calculateTextPosition(role); +- ft->setX(pos.x()); +- ft->setY(pos.y()); +-} +- +-/** +- * Moves the text widget with the given role by the difference between +- * the two points. +- */ +-void AssociationWidget::setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition) +-{ +- bool startMove = false; +- if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) +- startMove = true; +- else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) +- startMove = true; +- else if (m_nameWidget && m_nameWidget->getStartMove()) +- startMove = true; +- +- if (startMove) { +- return; +- } +- FloatingTextWidget *ft = textWidgetByRole(role); +- if (ft == NULL) +- return; +- qreal ftX = ft->x(); +- qreal ftY = ft->y(); +- +- QPointF pos = calculateTextPosition(role); +- int relX = pos.x() - oldPosition.x(); +- int relY = pos.y() - oldPosition.y(); +- qreal ftNewX = ftX + relX; +- qreal ftNewY = ftY + relY; +- +- bool oldIgnoreSnapToGrid = ft->getIgnoreSnapToGrid(); +- ft->setIgnoreSnapToGrid(true); +- ft->setX(ftNewX); +- ft->setY(ftNewY); +- ft->setIgnoreSnapToGrid(oldIgnoreSnapToGrid); +-} +- +-/** +- * Remove dashed connecting line for association class. +- */ +-void AssociationWidget::removeAssocClassLine() +-{ +- delete m_pAssocClassLineSel0; +- m_pAssocClassLineSel0 = 0; +- delete m_pAssocClassLineSel1; +- m_pAssocClassLineSel1 = 0; +- delete m_pAssocClassLine; +- m_pAssocClassLine = 0; +- if (m_associationClass) { +- m_associationClass->setClassAssociationWidget(0); +- m_associationClass = 0; +- } +-} +- +-/** +- * Creates the association class connecting line. +- */ +-void AssociationWidget::createAssocClassLine() +-{ +- if (m_pAssocClassLine == NULL) { +- m_pAssocClassLine = new QGraphicsLineItem(this); +- } +- QPen pen(lineColor(), lineWidth(), Qt::DashLine); +- m_pAssocClassLine->setPen(pen); +- // decoration points +- m_pAssocClassLineSel0 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p1(), +- m_pAssocClassLine); +- m_pAssocClassLineSel1 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p2(), +- m_pAssocClassLine); +- computeAssocClassLine(); +- selectAssocClassLine(false); +-} +- +-/** +- * Creates the association class connecting line using the specified +- * ClassifierWidget. +- * +- * @param classifier The ClassifierWidget to use. +- * @param linePathSegmentIndex The index of the segment where the +- * association class is created. +- */ +-void AssociationWidget::createAssocClassLine(ClassifierWidget* classifier, +- int linePathSegmentIndex) +-{ +- m_nLinePathSegmentIndex = linePathSegmentIndex; +- +- if (m_nLinePathSegmentIndex < 0) { +- return; +- } +- +- m_associationClass = classifier; +- m_associationClass->setClassAssociationWidget(this); +- m_associationClass->addAssoc(this); // to get widgetMoved(...) for association classes +- +- createAssocClassLine(); +-} +- +-/** +- * Compute the end points of m_pAssocClassLine in case this +- * association has an attached association class. +- * TODO: The decoration points make no sense for now, because they are not movable. +- */ +-void AssociationWidget::computeAssocClassLine() +-{ +- if (m_associationClass == NULL || m_pAssocClassLine == NULL) { +- return; +- } +- if (m_nLinePathSegmentIndex < 0) { +- uError() << "m_nLinePathSegmentIndex is not set"; +- return; +- } +- +- QPointF segStart = m_associationLine->point(m_nLinePathSegmentIndex); +- QPointF segEnd = m_associationLine->point(m_nLinePathSegmentIndex + 1); +- const qreal midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2.0; +- const qreal midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2.0; +- QPointF segmentMidPoint(midSegX, midSegY); +- +- QLineF possibleAssocLine = QLineF(segmentMidPoint, +- m_associationClass->mapRectToScene(m_associationClass->rect()).center()); +- QPointF intersectionPoint; +- QLineF::IntersectType type = intersect(m_associationClass->mapRectToScene(m_associationClass->boundingRect()), +- possibleAssocLine, +- &intersectionPoint); +- // DEBUG(DBG_SRC) << "intersect type=" << type << " / point=" << intersectionPoint; +- +- if (type == QLineF::BoundedIntersection) { +- m_pAssocClassLine->setLine(midSegX, midSegY, +- intersectionPoint.x(), intersectionPoint.y()); +- +- if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { +- m_pAssocClassLineSel0->setPos(m_pAssocClassLine->line().p1()); +- m_pAssocClassLineSel1->setPos(m_pAssocClassLine->line().p2()); +- } +- } +-} +- +-/** +- * Renders the association class connecting line selected. +- */ +-void AssociationWidget::selectAssocClassLine(bool sel) +-{ +- if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { +- m_pAssocClassLineSel0->setVisible(sel); +- m_pAssocClassLineSel1->setVisible(sel); +- } +-} +- +-/** +- * Sets the association to be selected. +- */ +-void AssociationWidget::mousePressEvent(QGraphicsSceneMouseEvent * me) +-{ +- // clear other selected stuff on the screen of ShiftKey +- if (me->modifiers() != Qt::ShiftModifier) { +- m_scene->clearSelected(); +- } +- +- if (me->button() == Qt::LeftButton && me->modifiers() == Qt::ControlModifier) { +- if (checkRemovePoint(me->scenePos())) +- return; +- } +- +- // make sure we should be here depending on the button +- if (me->button() != Qt::RightButton && me->button() != Qt::LeftButton) { +- return; +- } +- QPointF mep = me->scenePos(); +- // see if `mep' is on the connecting line to the association class +- if (onAssocClassLine(mep)) { +- setSelected(true); +- selectAssocClassLine(); +- return; +- } +- setSelected(!isSelected()); +- associationLine()->mousePressEvent(me); +-} +- +-/** +- * Displays the right mouse buttom menu if right button is pressed. +- */ +-void AssociationWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent * me) +-{ +- associationLine()->mouseReleaseEvent(me); +-} +- +-/** +- * Handles the selection from the popup menu. +- */ +-void AssociationWidget::slotMenuSelection(QAction* action) +-{ +- QString oldText, newText; +- QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); +- Uml::AssociationType::Enum atype = associationType(); +- Uml::RoleType::Enum r = RoleType::B; +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- DEBUG(DBG_SRC) << "menu selection = " << ListPopupMenu::toString(sel); +- +- // if it's a collaboration message we now just use the code in floatingtextwidget +- // this means there's some redundant code below but that's better than duplicated code +- if (isCollaboration() && sel != ListPopupMenu::mt_Delete) { +- m_nameWidget->slotMenuSelection(action); +- return; +- } +- +- switch(sel) { +- case ListPopupMenu::mt_Properties: +- if (atype == AssociationType::Seq_Message || atype == AssociationType::Seq_Message_Self) { +- // show op dlg for seq. diagram here +- // don't worry about here, I don't think it can get here as +- // line is widget on seq. diagram +- // here just in case - remove later after testing +- DEBUG(DBG_SRC) << "mt_Properties: assoctype is " << atype; +- } else { //standard assoc dialog +- UMLApp::app()->docWindow()->updateDocumentation(false); +- showPropertiesDialog(); +- } +- break; +- +- case ListPopupMenu::mt_Add_Point: +- checkAddPoint(m_eventScenePos); +- break; +- +- case ListPopupMenu::mt_Delete_Point: +- checkRemovePoint(m_eventScenePos); +- break; +- +- case ListPopupMenu::mt_Delete: +- if (m_pAssocClassLineSel0) +- removeAssocClassLine(); +- else if (association()) +- m_scene->removeAssocInViewAndDoc(this); +- else +- m_scene->removeAssoc(this); +- break; +- +- case ListPopupMenu::mt_Rename_MultiA: +- r = RoleType::A; // fall through +- case ListPopupMenu::mt_Rename_MultiB: +- if (m_role[r].multiplicityWidget) +- oldText = m_role[r].multiplicityWidget->text(); +- else +- oldText = QString(); +-#if QT_VERSION >= 0x050000 +- newText = QInputDialog::getText(m_scene->activeView(), +- i18n("Multiplicity"), +- i18n("Enter multiplicity:"), +- QLineEdit::Normal, +- oldText, NULL); +-#else +- newText = KInputDialog::getText(i18n("Multiplicity"), +- i18n("Enter multiplicity:"), +- oldText, NULL, m_scene->activeView(), &v); +-#endif +- if (newText != oldText) { +- if (FloatingTextWidget::isTextValid(newText)) { +- setMultiplicity(newText, r); +- } else { +- m_scene->removeWidget(m_role[r].multiplicityWidget); +- m_role[r].multiplicityWidget = NULL; +- } +- } +- break; +- +- case ListPopupMenu::mt_Rename_Name: +- if (m_nameWidget) +- oldText = m_nameWidget->text(); +- else +- oldText = QString(); +-#if QT_VERSION >= 0x050000 +- newText = QInputDialog::getText(m_scene->activeView(), +- i18n("Association Name"), +- i18n("Enter association name:"), +- QLineEdit::Normal, +- oldText, NULL); +-#else +- newText = KInputDialog::getText(i18n("Association Name"), +- i18n("Enter association name:"), +- oldText, NULL, m_scene->activeView(), &v); +-#endif +- if (newText != oldText) { +- if (FloatingTextWidget::isTextValid(newText)) { +- setName(newText); +- } else { +- m_scene->removeWidget(m_nameWidget); +- m_nameWidget = NULL; +- } +- } +- break; +- +- case ListPopupMenu::mt_Rename_RoleAName: +- r = RoleType::A; // fall through +- case ListPopupMenu::mt_Rename_RoleBName: +- if (m_role[r].roleWidget) +- oldText = m_role[r].roleWidget->text(); +- else +- oldText = QString(); +-#if QT_VERSION >= 0x050000 +- newText = QInputDialog::getText(m_scene->activeView(), +- i18n("Role Name"), +- i18n("Enter role name:"), +- QLineEdit::Normal, +- oldText, NULL); +-#else +- newText = KInputDialog::getText(i18n("Role Name"), +- i18n("Enter role name:"), +- oldText, NULL, m_scene->activeView(), &v); +-#endif +- if (newText != oldText) { +- if (FloatingTextWidget::isTextValid(newText)) { +- setRoleName(newText, r); +- } else { +- m_scene->removeWidget(m_role[r].roleWidget); +- m_role[r].roleWidget = NULL; +- } +- } +- break; +- +- case ListPopupMenu::mt_Change_Font: +- { +-#if QT_VERSION >= 0x050000 +- bool ok = false; +- QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); +- if (ok) +-#else +- QFont fnt = font(); +- if (KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) +-#endif +- lwSetFont(fnt); +- } +- break; +- +- case ListPopupMenu::mt_Line_Color: +- { +-#if QT_VERSION >= 0x050000 +- QColor newColor = QColorDialog::getColor(lineColor()); +- if (newColor != lineColor()) { +-#else +- QColor newColor; +- if (KColorDialog::getColor(newColor)) { +-#endif +- m_scene->selectionSetLineColor(newColor); +- umlDoc()->setModified(true); +- } +- } +- break; +- +- case ListPopupMenu::mt_Cut: +- m_scene->setStartedCut(); +- UMLApp::app()->slotEditCut(); +- break; +- +- case ListPopupMenu::mt_Copy: +- UMLApp::app()->slotEditCopy(); +- break; +- +- case ListPopupMenu::mt_Paste: +- UMLApp::app()->slotEditPaste(); +- break; +- +- case ListPopupMenu::mt_Reset_Label_Positions: +- resetTextPositions(); +- break; +- +- case ListPopupMenu::mt_LayoutDirect: +- m_associationLine->setLayout(AssociationLine::Direct); +- break; +- case ListPopupMenu::mt_LayoutSpline: +- m_associationLine->setLayout(AssociationLine::Spline); +- break; +- case ListPopupMenu::mt_LayoutOrthogonal: +- m_associationLine->setLayout(AssociationLine::Orthogonal); +- break; +- case ListPopupMenu::mt_LayoutPolyline: +- m_associationLine->setLayout(AssociationLine::Polyline); +- break; +- +- default: +- DEBUG(DBG_SRC) << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; +- break; +- }//end switch +-} +- +-/** +- * Return the first font found being used by any child widget. (They +- * could be different fonts, so this is a slightly misleading method.) +- */ +-QFont AssociationWidget::font() const +-{ +- //:TODO: find a general font for the association +- QFont font; +- +- if (m_role[RoleType::A].roleWidget) +- font = m_role[RoleType::A].roleWidget->font(); +- else if (m_role[RoleType::B].roleWidget) +- font = m_role[RoleType::B].roleWidget->font(); +- else if (m_role[RoleType::A].multiplicityWidget) +- font = m_role[RoleType::A].multiplicityWidget->font(); +- else if (m_role[RoleType::B].multiplicityWidget) +- font = m_role[RoleType::B].multiplicityWidget->font(); +- else if (m_role[RoleType::A].changeabilityWidget) +- font = m_role[RoleType::A].changeabilityWidget->font(); +- else if (m_role[RoleType::B].changeabilityWidget) +- font = m_role[RoleType::B].changeabilityWidget->font(); +- else if (m_nameWidget) +- font = m_nameWidget->font(); +- else +- font = m_role[RoleType::A].umlWidget->font(); +- +- return font; +-} +- +-/** +- * Set all 'owned' child widgets to this text color. +- */ +-void AssociationWidget::setTextColor(const QColor &color) +-{ +- WidgetBase::setTextColor(color); +- if (m_nameWidget) { +- m_nameWidget->setTextColor(color); +- } +- if (m_role[RoleType::A].roleWidget) { +- m_role[RoleType::A].roleWidget->setTextColor(color); +- } +- if (m_role[RoleType::B].roleWidget) { +- m_role[RoleType::B].roleWidget->setTextColor(color); +- } +- if (m_role[RoleType::A].multiplicityWidget) { +- m_role[RoleType::A].multiplicityWidget->setTextColor(color); +- } +- if (m_role[RoleType::B].multiplicityWidget) { +- m_role[RoleType::B].multiplicityWidget->setTextColor(color); +- } +- if (m_role[RoleType::A].changeabilityWidget) +- m_role[RoleType::A].changeabilityWidget->setTextColor(color); +- if (m_role[RoleType::B].changeabilityWidget) +- m_role[RoleType::B].changeabilityWidget->setTextColor(color); +-} +- +-bool AssociationWidget::checkAddPoint(const QPointF &scenePos) +-{ +- if (associationType() == AssociationType::Exception) { +- return false; +- } +- +- // if there is no point around the mouse pointer, we insert a new one +- if (m_associationLine->closestPointIndex(scenePos) < 0) { +- int i = m_associationLine->closestSegmentIndex(scenePos); +- if (i < 0) { +- DEBUG(DBG_SRC) << "no closest segment found!"; +- return false; +- } +- m_associationLine->insertPoint(i + 1, scenePos); +- if (m_nLinePathSegmentIndex == i) { +- QPointF segStart = m_associationLine->point(i); +- QPointF segEnd = m_associationLine->point(i + 2); +- const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2; +- const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2; +- /* +- DEBUG(DBG_SRC) << "segStart=" << segStart << ", segEnd=" << segEnd +- << ", midSeg=(" << midSegX << "," << midSegY +- << "), mp=" << mp; +- */ +- if (midSegX > scenePos.x() || midSegY < scenePos.y()) { +- m_nLinePathSegmentIndex++; +- DEBUG(DBG_SRC) << "setting m_nLinePathSegmentIndex to " +- << m_nLinePathSegmentIndex; +- computeAssocClassLine(); +- } +- m_associationLine->update(); +- calculateNameTextSegment(); +- umlDoc()->setModified(true); +- setSelected(true); +- } +- return true; +- } +- else { +- DEBUG(DBG_SRC) << "found point already close enough!"; +- return false; +- } +-} +- +-/** +- * Remove point close to the given point and redraw the association. +- * @param scenePos point which should be removed +- * @return success status of the remove action +- */ +-bool AssociationWidget::checkRemovePoint(const QPointF &scenePos) +-{ +- int i = m_associationLine->closestPointIndex(scenePos); +- if (i == -1) +- return false; +- +- m_associationLine->setSelected(false); +- +- // there was a point so we remove the point +- m_associationLine->removePoint(i); +- +- // Maybe reattach association class connecting line +- // to different association linepath segment. +- const int numberOfLines = m_associationLine->count() - 1; +- if (m_nLinePathSegmentIndex >= numberOfLines) { +- m_nLinePathSegmentIndex = numberOfLines - 1; +- } +- calculateEndingPoints(); +- +- // select the line path +- m_associationLine->setSelected(true); +- +- m_associationLine->update(); +- +- calculateNameTextSegment(); +- umlDoc()->setModified(true); +- return true; +-} +- +-/** +- * Moves the break point being dragged. +- */ +-void AssociationWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) +-{ +- if (me->buttons() != Qt::LeftButton) { +- return; +- } +- +- setSelected(true); +- +- associationLine()->mouseMoveEvent(me); +- moveEvent(me); +- m_scene->resizeSceneToItems(); +-} +- +-/** +- * Returns the Region the widget to line intersection is for the given +- * widget in this Association. If the given widget is not in the +- * Association then Region::Error is returned. +- * Used by @ref calculateEndingPoints to work these positions out for +- * another Association - since the number of Associations on the same +- * region for the same widget will mean the lines will need to be +- * spread out across the region. +- */ +-//Uml::Region::Enum AssociationWidget::getWidgetRegion(AssociationWidget * widget) const +-//{ +-// if (widget->widgetForRole(RoleType::A) == m_role[RoleType::A].umlWidget) +-// return m_role[RoleType::A].m_WidgetRegion; +-// if (widget->widgetForRole(RoleType::B) == m_role[RoleType::B].umlWidget) +-// return m_role[RoleType::B].m_WidgetRegion; +-// return Uml::Region::Error; +-//} +- +-/** +- * Returns the number of lines there are on the given region for +- * either widget A or B of the association. +- */ +-int AssociationWidget::getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role) +-{ +- if ((region == Uml::Region::Error) | (umlScene() == NULL)) { +- return 0; +- } +- int widgetCount = 0; +- AssociationWidgetList list = m_scene->associationList(); +- foreach (AssociationWidget* assocwidget, list) { +- //don't count this association +- if (assocwidget == this) +- continue; +- const WidgetRole& otherA = assocwidget->m_role[RoleType::A]; +- const WidgetRole& otherB = assocwidget->m_role[RoleType::B]; +- const UMLWidget *a = otherA.umlWidget; +- const UMLWidget *b = otherB.umlWidget; +- /* +- //don't count associations to self if both of their end points are on the same region +- //they are different and placement won't interfere with them +- if (a == b && otherA.m_WidgetRegion == otherB.m_WidgetRegion) +- continue; +- */ +- if (m_role[role].umlWidget == a && region == otherA.m_WidgetRegion) +- widgetCount++; +- else if (m_role[role].umlWidget == b && region == otherB.m_WidgetRegion) +- widgetCount++; +- }//end foreach +- return widgetCount; +-} +- +-/** +- * Find the border point of the given rect when a line is drawn from the +- * given point to the rect. +- * @param rect rect of a classifier +- * @param line a line to the rect +- * @param intersectionPoint the intercept point on the border of the rect +- * @return the type of the intersection @ref QLineF::IntersectType +- */ +-QLineF::IntersectType AssociationWidget::intersect(const QRectF &rect, const QLineF &line, +- QPointF* intersectionPoint) +-{ +- QList lines; +- lines << QLineF(rect.topLeft(), rect.topRight()); +- lines << QLineF(rect.topRight(), rect.bottomRight()); +- lines << QLineF(rect.bottomRight(), rect.bottomLeft()); +- lines << QLineF(rect.bottomLeft(), rect.topLeft()); +- foreach (const QLineF& rectLine, lines) { +- QLineF::IntersectType type = rectLine.intersect(line, intersectionPoint); +- if (type == QLineF::BoundedIntersection) { +- return type; +- } +- } +- return QLineF::NoIntersection; +-} +- +-/** +- * Given a rectangle and a point, findInterceptOnEdge computes the +- * connecting line between the middle point of the rectangle and +- * the point, and returns the intercept of this line with the +- * the edge of the rectangle identified by `region'. +- * When the region is North or South, the X value is returned (Y is +- * constant.) +- * When the region is East or West, the Y value is returned (X is +- * constant.) +- * @todo This is buggy. Try replacing by intersect() +- */ +-qreal AssociationWidget::findInterceptOnEdge(const QRectF &rect, +- Uml::Region::Enum region, +- const QPointF &point) +-{ +- // The Qt coordinate system has (0, 0) in the top left corner. +- // In order to go to the regular XY coordinate system with (0, 0) +- // in the bottom left corner, we swap the X and Y axis. +- // That's why the following assignments look twisted. +- const qreal rectHalfWidth = rect.height() / 2.0; +- const qreal rectHalfHeight = rect.width() / 2.0; +- const qreal rectMidX = rect.y() + rectHalfWidth; +- const qreal rectMidY = rect.x() + rectHalfHeight; +- const qreal dX = rectMidX - point.y(); +- const qreal dY = rectMidY - point.x(); +- switch (region) { +- case Uml::Region::West: +- region = Uml::Region::South; +- break; +- case Uml::Region::North: +- region = Uml::Region::West; +- break; +- case Uml::Region::East: +- region = Uml::Region::North; +- break; +- case Uml::Region::South: +- region = Uml::Region::East; +- break; +- default: +- break; +- } +- // Now we have regular coordinates with the point (0, 0) in the +- // bottom left corner. +- if (region == Uml::Region::North || region == Uml::Region::South) { +- if (dX == 0) +- return rectMidY; +- // should be rectMidX, but we go back to Qt coord.sys. +- if (dY == 0) { +- uError() << "usage error: " << "North/South (dY == 0)"; +- return -1.0; +- } +- const qreal m = dY / dX; +- qreal relativeX; +- if (region == Uml::Region::North) +- relativeX = rectHalfHeight / m; +- else +- relativeX = -rectHalfHeight / m; +- return (rectMidY + relativeX); +- // should be rectMidX, but we go back to Qt coord.sys. +- } else { +- if (dY == 0) +- return rectMidX; +- // should be rectMidY, but we go back to Qt coord.sys. +- if (dX == 0) { +- uError() << "usage error: " << "East/West (dX == 0)"; +- return -1.0; +- } +- const qreal m = dY / dX; +- qreal relativeY = m * rectHalfWidth; +- if (region == Uml::Region::West) +- relativeY = -relativeY; +- return (rectMidX + relativeY); +- // should be rectMidY, but we go back to Qt coord.sys. +- } +-} +- +-/** +- * Auxiliary method for updateAssociations(): +- * Put position into m_positions and assoc into m_ordered at the +- * correct index. +- * m_positions and m_ordered move in parallel and are sorted by +- * ascending position. +- */ +-void AssociationWidget::insertIntoLists(qreal position, const AssociationWidget* assoc) +-{ +- bool did_insertion = false; +- for (int index = 0; index < m_positions_len; ++index) { +- if (position < m_positions[index]) { +- for (int moveback = m_positions_len; moveback > index; moveback--) +- m_positions[moveback] = m_positions[moveback - 1]; +- m_positions[index] = position; +- m_ordered.insert(index, const_cast(assoc)); +- did_insertion = true; +- break; +- } +- } +- if (! did_insertion) { +- m_positions[m_positions_len] = position; +- m_ordered.append(const_cast(assoc)); +- } +- m_positions_len++; +-} +- +-/** +- * Tells all the other view associations the new count for the +- * given widget on a certain region. And also what index they should be. +- */ +-void AssociationWidget::updateAssociations(int totalCount, +- Uml::Region::Enum region, +- Uml::RoleType::Enum role) +-{ +- if ((region == Uml::Region::Error) | (umlScene() == NULL)) { +- return; +- } +- AssociationWidgetList list = m_scene->associationList(); +- +- UMLWidget *ownWidget = m_role[role].umlWidget; +- m_positions_len = 0; +- m_ordered.clear(); +- // we order the AssociationWidget list by region and x/y value +- foreach (AssociationWidget* assocwidget, list) { +- WidgetRole *roleA = &assocwidget->m_role[RoleType::A]; +- WidgetRole *roleB = &assocwidget->m_role[RoleType::B]; +- UMLWidget *wA = roleA->umlWidget; +- UMLWidget *wB = roleB->umlWidget; +- // Skip self associations. +- if (wA == wB) +- continue; +- // Now we must find out with which end the assocwidget connects +- // to the input widget (ownWidget). +- bool inWidgetARegion = (ownWidget == wA && +- region == roleA->m_WidgetRegion); +- bool inWidgetBRegion = (ownWidget == wB && +- region == roleB->m_WidgetRegion); +- if (!inWidgetARegion && !inWidgetBRegion) +- continue; +- // Determine intercept position on the edge indicated by `region'. +- UMLWidget * otherWidget = (inWidgetARegion ? wB : wA); +- AssociationLine *linepath = assocwidget->associationLine(); +- QPointF refpoint; +- if (assocwidget->linePathStartsAt(otherWidget)) +- refpoint = linepath->point(linepath->count() - 2); +- else +- refpoint = linepath->point(1); +- // The point is authoritative if we're called for the second time +- // (i.e. role==B) or it is a waypoint on the line path. +- bool pointIsAuthoritative = (role == RoleType::B || linepath->count() > 2); +- if (! pointIsAuthoritative) { +- // If the point is not authoritative then we use the other +- // widget's center. +- refpoint.setX(otherWidget->x() + otherWidget->width() / 2); +- refpoint.setY(otherWidget->y() + otherWidget->height() / 2); +- } +- qreal intercept = findInterceptOnEdge(ownWidget->rect(), region, refpoint); +- if (intercept < 0) { +- DEBUG(DBG_SRC) << "error from findInterceptOnEdge for" +- << " assocType=" << assocwidget->associationType() +- << " ownWidget=" << ownWidget->name() +- << " otherWidget=" << otherWidget->name(); +- continue; +- } +- insertIntoLists(intercept, assocwidget); +- } // while ((assocwidget = assoc_it.current())) +- +- // we now have an ordered list and we only have to call updateRegionLineCount +- int index = 1; +- foreach (AssociationWidget* assocwidget, m_ordered ) { +- if (ownWidget == assocwidget->widgetForRole(RoleType::A)) { +- assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::A); +- } else if (ownWidget == assocwidget->widgetForRole(RoleType::B)) { +- assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::B); +- } +- } // for (assocwidget = ordered.first(); ...) +-} +- +-/** +- * Called to tell the association that another association has added +- * a line to the region of one of its widgets. The widget is identified +- * by its role (A or B). +- * +- * Called by @ref updateAssociations which is called by +- * @ref calculateEndingPoints when required. +- */ +-void AssociationWidget::updateRegionLineCount(int index, int totalCount, +- Uml::Region::Enum region, +- Uml::RoleType::Enum role) +-{ +- if ((region == Uml::Region::Error) | (umlScene() == NULL)) { +- return; +- } +- // If the association is to self and the line ends are on the same region then +- // use a different calculation. +- if (isSelf() && +- m_role[RoleType::A].m_WidgetRegion == m_role[RoleType::B].m_WidgetRegion) { +- UMLWidget * pWidget = m_role[RoleType::A].umlWidget; +- qreal x = pWidget->x(); +- qreal y = pWidget->y(); +- qreal wh = pWidget->height(); +- qreal ww = pWidget->width(); +- int size = m_associationLine->count(); +- // See if above widget ok to place assoc. +- switch( m_role[RoleType::A].m_WidgetRegion ) { +- case Uml::Region::North: +- m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y ) ); +- m_associationLine->setPoint( size - 1, QPointF(x + ( ww * 3 / 4 ), y ) ); +- break; +- +- case Uml::Region::South: +- m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y + wh ) ); +- m_associationLine->setPoint( size - 1, QPointF( x + ( ww * 3 / 4 ), y + wh ) ); +- break; +- +- case Uml::Region::East: +- m_associationLine->setPoint( 0, QPointF( x + ww, y + ( wh / 4 ) ) ); +- m_associationLine->setPoint( size - 1, QPointF( x + ww, y + ( wh * 3 / 4 ) ) ); +- break; +- +- case Uml::Region::West: +- m_associationLine->setPoint( 0, QPointF( x, y + ( wh / 4 ) ) ); +- m_associationLine->setPoint( size - 1, QPointF( x, y + ( wh * 3 / 4 ) ) ); +- break; +- default: +- break; +- }//end switch +- +- return; +- } +- +- WidgetRole& robj = m_role[role]; +- UMLWidget * pWidget = robj.umlWidget; +- +- robj.m_nIndex = index; +- robj.m_nTotalCount = totalCount; +- qreal x = pWidget->x(); +- qreal y = pWidget->y(); +- qreal ww = pWidget->width(); +- qreal wh = pWidget->height(); +- const bool angular = Settings::optionState().generalState.angularlines; +- qreal ch = 0; +- qreal cw = 0; +- if (angular) { +- uint nind = (role == RoleType::A ? 1 : m_associationLine->count() - 2); +- QPointF neighbour = m_associationLine->point(nind); +- if (neighbour.x() < x) +- cw = 0; +- else if (neighbour.x() > x + ww) +- cw = 0 + ww; +- else +- cw = neighbour.x() - x; +- if (neighbour.y() < y) +- ch = 0; +- else if (neighbour.y() > y + wh) +- ch = 0 + wh; +- else +- ch = neighbour.y() - y; +- } else { +- ch = wh * index / totalCount; +- cw = ww * index / totalCount; +- } +- +- qreal newX = x + cw; +- qreal newY = y + ch; +- +- QPointF pt; +- if (angular) { +- pt = QPointF(newX, newY); +- } else { +- UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; +- UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; +- QList polyListA = pWidgetA->shape().toSubpathPolygons(); +- QPolygonF polyA = polyListA.at(0); +- if (polyListA.size() > 1) { +- for (int i = 1; i < polyListA.size(); i++) { +- polyA = polyA.united(polyListA.at(i)); +- } +- } +- polyA = polyA.translated(pWidgetA->pos()); +- QList polyListB = pWidgetB->shape().toSubpathPolygons(); +- QPolygonF polyB = polyListB.at(0); +- if (polyListB.size() > 1) { +- for (int i = 1; i < polyListB.size(); i++) { +- polyB = polyB.united(polyListB.at(i)); +- } +- } +- polyB = polyB.translated(pWidgetB->pos()); +- QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); +- if (nearestPoints.isNull()) { +- uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; +- switch(region) { +- case Uml::Region::West: +- pt.setX(x); +- pt.setY(newY); +- break; +- case Uml::Region::North: +- pt.setX(newX); +- pt.setY(y); +- break; +- case Uml::Region::East: +- pt.setX(x + ww); +- pt.setY(newY); +- break; +- case Uml::Region::South: +- pt.setX(newX); +- pt.setY(y + wh); +- break; +- case Uml::Region::Center: +- pt.setX(x + ww / 2); +- pt.setY(y + wh / 2); +- break; +- default: +- break; +- } +- } else { +- if (role == RoleType::A) +- pt = nearestPoints.p1(); +- else +- pt = nearestPoints.p2(); +- } +- } +- if (role == RoleType::A) { +- m_associationLine->setPoint(0, pt); +- } +- else { +- m_associationLine->setPoint(m_associationLine->count() - 1, pt); +- } +-} +- +-/** +- * Sets the state of whether the widget is selected. +- * +- * @param _select The state of whether the widget is selected. +- */ +-void AssociationWidget::setSelected(bool _select /* = true */) +-{ +- WidgetBase::setSelected(_select); +- if ( m_nameWidget) +- m_nameWidget->setSelected( _select ); +- if ( m_role[RoleType::A].roleWidget ) +- m_role[RoleType::A].roleWidget->setSelected( _select ); +- if ( m_role[RoleType::B].roleWidget ) +- m_role[RoleType::B].roleWidget->setSelected( _select ); +- if ( m_role[RoleType::A].multiplicityWidget ) +- m_role[RoleType::A].multiplicityWidget->setSelected( _select ); +- if ( m_role[RoleType::B].multiplicityWidget ) +- m_role[RoleType::B].multiplicityWidget->setSelected( _select ); +- if ( m_role[RoleType::A].changeabilityWidget) +- m_role[RoleType::A].changeabilityWidget->setSelected( _select ); +- if ( m_role[RoleType::B].changeabilityWidget) +- m_role[RoleType::B].changeabilityWidget->setSelected( _select ); +- +- // Update the docwindow for this association. +- // This is done last because each of the above setSelected calls +- // overwrites the docwindow, but we want the main association doc +- // to win. +- if (_select) { +- if (m_scene->selectedCount() == 0) +- UMLApp::app()->docWindow()->showDocumentation(this, false); +- } else +- UMLApp::app()->docWindow()->updateDocumentation(true); +- +- m_associationLine->setSelected(_select); +- if (! _select) { +- // For now, if _select is true we don't make the assoc class line +- // selected. But that's certainly open for discussion. +- // At any rate, we need to deselect the assoc class line +- // if _select is false. +- selectAssocClassLine(false); +- } +- UMLApp::app()->document()->writeToStatusBar(_select ? i18n("Press Ctrl with left mouse click to delete a point") : QString()); +-} +- +-/** +- * Reimplement method from WidgetBase in order to check owned floating texts. +- * +- * @param p Point to be checked. +- * +- * @return m_nameWidget if m_nameWidget is non NULL and m_nameWidget->onWidget(p) returns non NULL; +- * m_role[0].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and +- * its onWidget(p) returns non NULL; +- * m_role[1].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and +- * its onWidget(p) returns non NULL; +- * else NULL. +- */ +-UMLWidget* AssociationWidget::onWidget(const QPointF &p) +-{ +- if (m_nameWidget && m_nameWidget->onWidget(p)) { +- return m_nameWidget; +- } +- for (int i = 0; i <= 1; i++) { +- const WidgetRole& r = m_role[i]; +- if (r.multiplicityWidget && r.multiplicityWidget->onWidget(p)) +- return r.multiplicityWidget; +- if (r.changeabilityWidget && r.changeabilityWidget->onWidget(p)) +- return r.changeabilityWidget; +- if (r.roleWidget && r.roleWidget->onWidget(p)) +- return r.roleWidget; +- } +- return NULL; +-} +- +-/** +- * Returns true if the given point is on the connecting line to +- * the association class. Returns false if there is no association +- * class attached, or if the given point is not on the connecting +- * line. +- */ +-bool AssociationWidget::onAssocClassLine(const QPointF &point) +-{ +- bool onLine = false; +- if (m_pAssocClassLine) { +-//:TODO: +-// const QPointF mapped = m_pAssocClassLine->mapFromParent(point); +-// bool onLine = m_pAssocClassLine->contains(mapped); +-// return onLine; +- UMLSceneItemList list = m_scene->collisions(point); +- UMLSceneItemList::iterator end(list.end()); +- for (UMLSceneItemList::iterator item_it(list.begin()); item_it != end; ++item_it) { +- if (*item_it == m_pAssocClassLine) { +- onLine = true; +- break; +- } +- } +- } +- DEBUG(DBG_SRC) << onLine; +- return onLine; +-} +- +-/** +- * Returns true if the given point is on the association line. +- * A circle (rectangle) around the point is used to obtain more tolerance. +- * @param point the point to check +- * @return flag whether point is on association line +- */ +-bool AssociationWidget::onAssociation(const QPointF& point) +-{ +- // check the path +- const qreal diameter(4.0); +- QPainterPath path = m_associationLine->shape(); +- if (path.contains(point)) { +- DEBUG(DBG_SRC) << "on path"; +- return true; +- } +- // check also the points +- if (m_associationLine->layout() == AssociationLine::Spline) { +- if (m_associationLine->closestPointIndex(point, diameter) > -1) { +- DEBUG(DBG_SRC) << "on spline point"; +- return true; +- } +- } +- return onAssocClassLine(point); +-} +- +-/** +- * Set all association points to x coordinate. +- */ +-void AssociationWidget::setXEntireAssoc(qreal x) +-{ +- for (int i = 0; i < m_associationLine->count(); ++i) { +- QPointF p = m_associationLine->point(i); +- p.setX(x); +- m_associationLine->setPoint(i, p); +- } +-} +- +-/** +- * Set all association points to y coordinate. +- */ +-void AssociationWidget::setYEntireAssoc(qreal y) +-{ +- for (int i = 0; i < m_associationLine->count(); ++i) { +- QPointF p = m_associationLine->point(i); +- p.setY(y); +- m_associationLine->setPoint(i, p); +- } +-} +- +-/** +- * Moves all the mid points (all expcept start /end) by the given amount. +- */ +-void AssociationWidget::moveMidPointsBy(qreal x, qreal y) +-{ +- int pos = m_associationLine->count() - 1; +- for (int i = 1; i < (int)pos; ++i) { +- QPointF p = m_associationLine->point( i ); +- qreal newX = p.x() + x; +- qreal newY = p.y() + y; +- p.setX( newX ); +- p.setY( newY ); +- m_associationLine->setPoint( i, p ); +- } +-} +- +-/** +- * Moves the entire association by the given offset. +- */ +-void AssociationWidget::moveEntireAssoc(qreal x, qreal y) +-{ +- //TODO: ADD SUPPORT FOR ASSOC. ON SEQ. DIAGRAMS WHEN NOTES BACK IN. +- moveMidPointsBy(x, y); +- calculateEndingPoints(); +- calculateNameTextSegment(); +- resetTextPositions(); +-} +- +-/** +- * Returns the bounding rectangle of all segments of the association. +- */ +-QRectF AssociationWidget::boundingRect() const +-{ +- return m_associationLine->boundingRect(); +-} +- +-/** +- * Returns the shape of all segments of the association. +- */ +-QPainterPath AssociationWidget::shape() const +-{ +- return m_associationLine->shape(); +-} +- +-/** +- * Connected to UMLClassifier::attributeRemoved() or UMLEntity::constraintRemoved() +- * in case this AssociationWidget is linked to a clasifier list item +- * (an attribute or a foreign key constraint) +- * +- * @param obj The UMLClassifierListItem removed. +- */ +-void AssociationWidget::slotClassifierListItemRemoved(UMLClassifierListItem* obj) +-{ +- if (obj != m_umlObject) { +- DEBUG(DBG_SRC) << "obj=" << obj << ": m_umlObject=" << m_umlObject; +- return; +- } +- m_umlObject = 0; +- m_scene->removeAssoc(this); +-} +- +-/** +- * Connected to UMLObject::modified() in case this +- * AssociationWidget is linked to a classifer's attribute type. +- */ +-void AssociationWidget::slotAttributeChanged() +-{ +- UMLAttribute *attr = attribute(); +- if (attr == NULL) { +- uError() << "attribute() returns NULL"; +- return; +- } +- setVisibility(attr->visibility(), RoleType::B); +- setRoleName(attr->name(), RoleType::B); +-} +- +-void AssociationWidget::clipSize() +-{ +- if (m_nameWidget) +- m_nameWidget->clipSize(); +- +- if (m_role[RoleType::A].multiplicityWidget) +- m_role[RoleType::A].multiplicityWidget->clipSize(); +- +- if (m_role[RoleType::B].multiplicityWidget) +- m_role[RoleType::B].multiplicityWidget->clipSize(); +- +- if (m_role[RoleType::A].roleWidget) +- m_role[RoleType::A].roleWidget->clipSize(); +- +- if (m_role[RoleType::B].roleWidget) +- m_role[RoleType::B].roleWidget->clipSize(); +- +- if (m_role[RoleType::A].changeabilityWidget) +- m_role[RoleType::A].changeabilityWidget->clipSize(); +- +- if (m_role[RoleType::B].changeabilityWidget) +- m_role[RoleType::B].changeabilityWidget->clipSize(); +- +- if (m_associationClass) +- m_associationClass->clipSize(); +-} +- +-/** +- * Event handler for context menu events, called from the line segments. +- */ +-void AssociationWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +-{ +- const Uml::AssociationType::Enum type = associationType(); +- ListPopupMenu::MenuType menuType = ListPopupMenu::mt_Association_Selected; +- if ((type == Uml::AssociationType::Anchor) || +- onAssocClassLine(event->scenePos())) { +- menuType = ListPopupMenu::mt_Anchor; +- } else if (isCollaboration()) { +- menuType = ListPopupMenu::mt_Collaboration_Message; +- } else if (!association()) { +- menuType = ListPopupMenu::mt_AttributeAssociation; +- } else if (AssocRules::allowRole(type)) { +- menuType = ListPopupMenu::mt_FullAssociation; +- } +- +- event->accept(); +- DEBUG(DBG_SRC) << "menue type = " << ListPopupMenu::toString(menuType) +- << " / association = " << Uml::AssociationType::toString(type); +- +- UMLScene *scene = umlScene(); +- QWidget *parent = 0; +- if (scene) { +- parent = scene->activeView(); +- } +- +- if (!isSelected() && scene && !scene->selectedItems().isEmpty()) { +- Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); +- if ((event->modifiers() & forSelection) == 0) { +- scene->clearSelection(); +- } +- } +- setSelected(true); +- m_eventScenePos = event->scenePos(); +- ListPopupMenu popup(parent, menuType, this); +- QAction *triggered = popup.exec(event->screenPos()); +- ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); +- +- if (!parentMenu) { +- uWarning() << "Action's data field does not contain ListPopupMenu pointer"; +- return; +- } +- +- WidgetBase *ownerWidget = parentMenu->ownerWidget(); +- // assert because logic is based on only WidgetBase being the owner of +- // ListPopupMenu actions executed in this context menu. +- Q_ASSERT_X(ownerWidget != 0, "AssociationWidget::contextMenuEvent", +- "ownerWidget is null which means action belonging to UMLView, UMLScene" +- " or UMLObject is the one triggered in ListPopupMenu"); +- +- ownerWidget->slotMenuSelection(triggered); +-} +- +-/** +- * Reimplemented event handler for hover enter events. +- */ +-void AssociationWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +-{ +- associationLine()->hoverEnterEvent(event); +-} +- +-/** +- * Reimplemented event handler for hover leave events. +- */ +-void AssociationWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +-{ +- associationLine()->hoverLeaveEvent(event); +-} +- +-/** +- * Reimplemented event handler for hover move events. +- */ +-void AssociationWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +-{ +- associationLine()->hoverMoveEvent(event); +-} +- +-/** +- * Saves this widget to the "assocwidget" XMI element. +- */ +-void AssociationWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +-{ +- QDomElement assocElement = qDoc.createElement(QLatin1String("assocwidget")); +- +- WidgetBase::saveToXMI(qDoc, assocElement); +- LinkWidget::saveToXMI(qDoc, assocElement); +- if (m_umlObject) { +- assocElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_umlObject->id())); +- } +- assocElement.setAttribute(QLatin1String("type"), associationType()); +- if (!association()) { +- assocElement.setAttribute(QLatin1String("visibilityA"), visibility(RoleType::A)); +- assocElement.setAttribute(QLatin1String("visibilityB"), visibility(RoleType::B)); +- assocElement.setAttribute(QLatin1String("changeabilityA"), changeability(RoleType::A)); +- assocElement.setAttribute(QLatin1String("changeabilityB"), changeability(RoleType::B)); +- if (m_umlObject == NULL) { +- assocElement.setAttribute(QLatin1String("roleAdoc"), roleDocumentation(RoleType::A)); +- assocElement.setAttribute(QLatin1String("roleBdoc"), roleDocumentation(RoleType::B)); +- assocElement.setAttribute(QLatin1String("documentation"), documentation()); +- } +- } +- assocElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(widgetIDForRole(RoleType::A))); +- assocElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(widgetIDForRole(RoleType::B))); +- assocElement.setAttribute(QLatin1String("indexa"), m_role[RoleType::A].m_nIndex); +- assocElement.setAttribute(QLatin1String("indexb"), m_role[RoleType::B].m_nIndex); +- assocElement.setAttribute(QLatin1String("totalcounta"), m_role[RoleType::A].m_nTotalCount); +- assocElement.setAttribute(QLatin1String("totalcountb"), m_role[RoleType::B].m_nTotalCount); +- m_associationLine->saveToXMI(qDoc, assocElement); +- +- if (m_nameWidget) { +- m_nameWidget->saveToXMI(qDoc, assocElement); +- } +- +- if (multiplicityWidget(RoleType::A)) { +- multiplicityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); +- } +- +- if (multiplicityWidget(RoleType::B)) { +- multiplicityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); +- } +- +- if (roleWidget(RoleType::A)) { +- roleWidget(RoleType::A)->saveToXMI(qDoc, assocElement); +- } +- +- if (roleWidget(RoleType::B)) { +- roleWidget(RoleType::B)->saveToXMI(qDoc, assocElement); +- } +- +- if (changeabilityWidget(RoleType::A)) { +- changeabilityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); +- } +- +- if (changeabilityWidget(RoleType::B)) { +- changeabilityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); +- } +- +- if (m_associationClass) { +- QString acid = Uml::ID::toString(m_associationClass->id()); +- assocElement.setAttribute(QLatin1String("assocclass"), acid); +- assocElement.setAttribute(QLatin1String("aclsegindex"), m_nLinePathSegmentIndex); +- } +- +- qElement.appendChild(assocElement); +-} +- +-/** +- * Uses the supplied widgetList for resolving +- * the role A and role B widgets. (The other loadFromXMI() queries +- * the UMLView for these widgets.) +- * Required for clipboard operations. +- */ +-bool AssociationWidget::loadFromXMI(QDomElement& qElement, +- const UMLWidgetList& widgets, +- const MessageWidgetList* messages) +-{ +- if (!WidgetBase::loadFromXMI(qElement)) { +- return false; +- } +- +- if (!LinkWidget::loadFromXMI(qElement)) { +- return false; +- } +- +- // load child widgets first +- QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); +- QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); +- Uml::ID::Type aId = Uml::ID::fromString(widgetaid); +- Uml::ID::Type bId = Uml::ID::fromString(widgetbid); +- UMLWidget *pWidgetA = Widget_Utils::findWidget(aId, widgets, messages); +- if (!pWidgetA) { +- uError() << "cannot find widget for roleA id " << Uml::ID::toString(aId); +- return false; +- } +- UMLWidget *pWidgetB = Widget_Utils::findWidget(bId, widgets, messages); +- if (!pWidgetB) { +- uError() << "cannot find widget for roleB id " << Uml::ID::toString(bId); +- return false; +- } +- setWidgetForRole(pWidgetA, RoleType::A); +- setWidgetForRole(pWidgetB, RoleType::B); +- +- QString type = qElement.attribute(QLatin1String("type"), QLatin1String("-1")); +- Uml::AssociationType::Enum aType = Uml::AssociationType::fromInt(type.toInt()); +- +- QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); +- bool oldStyleLoad = false; +- if (id == QLatin1String("-1")) { +- // xmi.id not present, ergo either a pure widget association, +- // or old (pre-1.2) style: +- // Everything is loaded from the AssociationWidget. +- // UMLAssociation may or may not be saved - if it is, it's a dummy. +- // Create the UMLAssociation if both roles are UML objects; +- // else load the info locally. +- +- if (Uml::AssociationType::hasUMLRepresentation(aType)) { +- // lack of an association in our widget AND presence of +- // both uml objects for each role clearly identifies this +- // as reading in an old-school file. Note it as such, and +- // create, and add, the UMLAssociation for this widget. +- // Remove this special code when backwards compatibility +- // with older files isn't important anymore. -b.t. +- UMLObject* umlRoleA = pWidgetA->umlObject(); +- UMLObject* umlRoleB = pWidgetB->umlObject(); +- if (!m_umlObject && umlRoleA && umlRoleB) { +- oldStyleLoad = true; // flag for further special config below +- if (aType == AssociationType::Aggregation || aType == AssociationType::Composition) { +- uWarning()<<" Old Style save file? swapping roles on association widget"<umlObject(); +- umlRoleB = pWidgetB->umlObject(); +- } +- +- setUMLAssociation(umlDoc()->createUMLAssociation(umlRoleA, umlRoleB, aType)); +- } +- } +- +- setDocumentation(qElement.attribute(QLatin1String("documentation"))); +- setRoleDocumentation(qElement.attribute(QLatin1String("roleAdoc")), RoleType::A); +- setRoleDocumentation(qElement.attribute(QLatin1String("roleBdoc")), RoleType::B); +- +- // visibility defaults to Public if it cant set it here.. +- QString visibilityA = qElement.attribute(QLatin1String("visibilityA"), QLatin1String("0")); +- int vis = visibilityA.toInt(); +- if (vis >= 200) { // bkwd compat. +- vis -= 200; +- } +- setVisibility((Uml::Visibility::Enum)vis, RoleType::A); +- +- QString visibilityB = qElement.attribute(QLatin1String("visibilityB"), QLatin1String("0")); +- vis = visibilityB.toInt(); +- if (vis >= 200) { // bkwd compat. +- vis -= 200; +- } +- setVisibility((Uml::Visibility::Enum)vis, RoleType::B); +- +- // Changeability defaults to "Changeable" if it cant set it here.. +- QString changeabilityA = qElement.attribute(QLatin1String("changeabilityA"), QLatin1String("0")); +- if (changeabilityA.toInt() > 0) +- setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); +- +- QString changeabilityB = qElement.attribute(QLatin1String("changeabilityB"), QLatin1String("0")); +- if (changeabilityB.toInt() > 0) +- setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); +- +- } else { +- +- // we should disconnect any prior association (can this happen??) +- if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { +- UMLAssociation *umla = association(); +- umla->disconnect(this); +- umla->nrof_parent_widgets--; +- } +- +- // New style: The xmi.id is a reference to the UMLAssociation. +- // If the UMLObject is not found right now, we try again later +- // during the type resolution pass - see activate(). +- m_nId = Uml::ID::fromString(id); +- UMLObject *myObj = umlDoc()->findObjectById(m_nId); +- if (myObj) { +- const UMLObject::ObjectType ot = myObj->baseType(); +- if (ot != UMLObject::ot_Association) { +- setUMLObject(myObj); +- } else { +- UMLAssociation * myAssoc = static_cast(myObj); +- setUMLAssociation(myAssoc); +- if (type == QLatin1String("-1")) +- aType = myAssoc->getAssocType(); +- } +- } +- } +- +- setAssociationType(aType); +- +- QString indexa = qElement.attribute(QLatin1String("indexa"), QLatin1String("0")); +- QString indexb = qElement.attribute(QLatin1String("indexb"), QLatin1String("0")); +- QString totalcounta = qElement.attribute(QLatin1String("totalcounta"), QLatin1String("0")); +- QString totalcountb = qElement.attribute(QLatin1String("totalcountb"), QLatin1String("0")); +- m_role[RoleType::A].m_nIndex = indexa.toInt(); +- m_role[RoleType::B].m_nIndex = indexb.toInt(); +- m_role[RoleType::A].m_nTotalCount = totalcounta.toInt(); +- m_role[RoleType::B].m_nTotalCount = totalcountb.toInt(); +- +- QString assocclassid = qElement.attribute(QLatin1String("assocclass")); +- if (! assocclassid.isEmpty()) { +- Uml::ID::Type acid = Uml::ID::fromString(assocclassid); +- UMLWidget *w = Widget_Utils::findWidget(acid, widgets); +- if (w) { +- ClassifierWidget* aclWidget = static_cast(w); +- QString aclSegIndex = qElement.attribute(QLatin1String("aclsegindex"), QLatin1String("0")); +- createAssocClassLine(aclWidget, aclSegIndex.toInt()); +- } else { +- uError() << "cannot find assocclass " << assocclassid; +- } +- } +- +- //now load child elements +- QDomNode node = qElement.firstChild(); +- QDomElement element = node.toElement(); +- while (!element.isNull()) { +- QString tag = element.tagName(); +- if (tag == QLatin1String("linepath")) { +- if (!m_associationLine->loadFromXMI(element)) { +- return false; +- } +- } else if (tag == QLatin1String("floatingtext") || +- tag == QLatin1String("UML:FloatingTextWidget")) { // for bkwd compatibility +- QString r = element.attribute(QLatin1String("role"), QLatin1String("-1")); +- if (r == QLatin1String("-1")) +- return false; +- Uml::TextRole::Enum role = Uml::TextRole::fromInt(r.toInt()); +- FloatingTextWidget *ft = new FloatingTextWidget(m_scene, role, QString(), Uml::ID::Reserved); +- if (! ft->loadFromXMI(element)) { +- // Most likely cause: The FloatingTextWidget is empty. +- delete ft; +- node = element.nextSibling(); +- element = node.toElement(); +- continue; +- } +- // always need this +- ft->setParentItem(this); +- ft->setLink(this); +- ft->setSequenceNumber(m_SequenceNumber); +- ft->setFontCmd(ft->font()); +- +- switch(role) { +- case Uml::TextRole::MultiA: +- m_role[RoleType::A].multiplicityWidget = ft; +- if (oldStyleLoad) +- setMultiplicity(m_role[RoleType::A].multiplicityWidget->text(), RoleType::A); +- break; +- +- case Uml::TextRole::MultiB: +- m_role[RoleType::B].multiplicityWidget = ft; +- if (oldStyleLoad) +- setMultiplicity(m_role[RoleType::B].multiplicityWidget->text(), RoleType::B); +- break; +- +- case Uml::TextRole::ChangeA: +- m_role[RoleType::A].changeabilityWidget = ft; +- break; +- +- case Uml::TextRole::ChangeB: +- m_role[RoleType::B].changeabilityWidget = ft; +- break; +- +- case Uml::TextRole::Name: +- m_nameWidget = ft; +- if (oldStyleLoad) +- setName(m_nameWidget->text()); +- break; +- +- case Uml::TextRole::Coll_Message: +- case Uml::TextRole::Coll_Message_Self: +- m_nameWidget = ft; +- ft->setLink(this); +- ft->setActivated(); +- if (FloatingTextWidget::isTextValid(ft->text())) +- ft->show(); +- else +- ft->hide(); +- break; +- +- case Uml::TextRole::RoleAName: +- m_role[RoleType::A].roleWidget = ft; +- setRoleName(ft->text(), RoleType::A); +- break; +- case Uml::TextRole::RoleBName: +- m_role[RoleType::B].roleWidget = ft; +- setRoleName(ft->text(), RoleType::B); +- break; +- default: +- DEBUG(DBG_SRC) << "unexpected FloatingTextWidget (TextRole::Enum " << role << ")"; +- delete ft; +- break; +- } +- } +- node = element.nextSibling(); +- element = node.toElement(); +- } +- +- return true; +-} +- +-/** +- * Queries the UMLView for resolving the role A and role B widgets. +- * .... +- */ +-bool AssociationWidget::loadFromXMI(QDomElement& qElement) +-{ +- UMLScene *scene = umlScene(); +- if (scene) { +- const UMLWidgetList& widgetList = scene->widgetList(); +- const MessageWidgetList& messageList = scene->messageList(); +- return loadFromXMI(qElement, widgetList, &messageList); +- } +- else { +- DEBUG(DBG_SRC) << "This isn't on UMLScene yet, so can neither fetch" +- "messages nor widgets on umlscene"; +- return false; +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.h umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,328 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ASSOCIATIONWIDGET_H +-#define ASSOCIATIONWIDGET_H +- +-#include "associationwidgetlist.h" +-#include "linkwidget.h" +-#include "messagewidgetlist.h" +-#include "umlwidgetlist.h" +-#include "widgetbase.h" +- +-class AssociationLine; +-class ClassifierWidget; +-class UMLScene; +-class UMLAssociation; +-class UMLAttribute; +-class UMLClassifierListItem; +-class UMLOperation; +- +-/** +- * This class represents an association inside a diagram. +- * +- * Constructor is made non accessible: +- * Users shall use the static create() methods for constructing AssociationWidgets. +- * +- * Associations exist not only between UML objects. For example, when a Note is +- * attached to a UML object, the Note itself is not a UML object. +- * This class supports both kinds of associations. An association where one or +- * both roles are not a UML object is called a "pure widget association". +- * +- * An AssociationWidget where both roles are UML objects has a corresponding +- * UMLAssociation. The UMLAssociation can be retrieved using the getAssociation +- * method. +- * A pure widget association does not have a corresponding UMLAssociation. +- * The getAssociation method returns NULL in this case. +- * +- * @author Gustavo Madrigal +- * @author Gopala Krishna +- * @short This class represents an association inside a diagram. +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class AssociationWidget : public WidgetBase, public LinkWidget +-{ +- Q_OBJECT +-public: +- static AssociationWidget* create(UMLScene *scene); +- static AssociationWidget* create +- (UMLScene *scene, UMLWidget* WidgetA, +- Uml::AssociationType::Enum assocType, UMLWidget* WidgetB, +- UMLObject *umlobject = NULL); +- +- virtual ~AssociationWidget(); +- +- virtual void setUMLObject(UMLObject *obj); +- +- //---------- LinkWidget Interface methods implementation from now on. +- +- virtual void lwSetFont(QFont font); +- virtual UMLClassifier *operationOwner(); +- +- virtual UMLOperation *operation(); +- virtual void setOperation(UMLOperation *op); +- +- virtual QString customOpText(); +- virtual void setCustomOpText(const QString &opText); +- +- virtual void resetTextPositions(); +- +- virtual void setMessageText(FloatingTextWidget *ft); +- virtual void setText(FloatingTextWidget *ft, const QString &newText); +- +- virtual void showPropertiesDialog(); +- +- virtual QString lwOperationText(); +- virtual UMLClassifier *lwClassifier(); +- virtual void setOperationText(const QString &op); +- +- virtual void constrainTextPos(qreal &textX, qreal &textY, +- qreal textWidth, qreal textHeight, +- Uml::TextRole::Enum tr); +- +- virtual void calculateNameTextSegment(); +- +- //---------- End LinkWidget Interface methods implementation. +- +- UMLAssociation* association() const; +- UMLAttribute* attribute() const; +- +-// AssociationWidget& operator=(const AssociationWidget& other); +- bool operator==(const AssociationWidget& other) const; +- bool operator!=(AssociationWidget& other) const; +- +- FloatingTextWidget* textWidgetByRole(Uml::TextRole::Enum tr) const; +- +- FloatingTextWidget* nameWidget() const; +- QString name() const; +- void setName(const QString &strRole); +- void setStereotype(const QString &stereo); +- +- FloatingTextWidget* roleWidget(Uml::RoleType::Enum role) const; +- QString roleName(Uml::RoleType::Enum role) const; +- void setRoleName(const QString &strRole, Uml::RoleType::Enum role); +- +- QString roleDocumentation(Uml::RoleType::Enum role) const; +- void setRoleDocumentation(const QString& doc, Uml::RoleType::Enum role); +- +- FloatingTextWidget* multiplicityWidget(Uml::RoleType::Enum role) const; +- QString multiplicity(Uml::RoleType::Enum role) const; +- void setMultiplicity(const QString& text, Uml::RoleType::Enum role); +- +- Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; +- void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); +- +- FloatingTextWidget* changeabilityWidget(Uml::RoleType::Enum role) const; +- Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; +- void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); +- +- Uml::ID::Type widgetIDForRole(Uml::RoleType::Enum role) const; +- Uml::ID::Type widgetLocalIDForRole(Uml::RoleType::Enum role) const; +- UMLWidget* widgetForRole(Uml::RoleType::Enum role) const; +- void setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role); +- +- bool setWidgets(UMLWidget* widgetA, Uml::AssociationType::Enum assocType, UMLWidget* widgetB); +- +- bool containsAsEndpoint(UMLWidget* widget); +- +- Uml::AssociationType::Enum associationType() const; +- void setAssociationType(Uml::AssociationType::Enum type); +- +- bool isCollaboration() const; +- bool isSelf() const; +- +- QString toString() const; +- +- bool isActivated() const; +- void setActivated(bool active); +- +- AssociationLine* associationLine() const; +- +- virtual bool activate(); +- virtual QRectF boundingRect() const; +- virtual QPainterPath shape() const; +- +- void widgetMoved(UMLWidget* widget, qreal x, qreal y); +- +- void saveIdealTextPositions(); +- +- UMLWidget* onWidget(const QPointF &p); +- bool onAssociation(const QPointF& point); +- bool onAssocClassLine(const QPointF& point); +- +- void createAssocClassLine(); +- void createAssocClassLine(ClassifierWidget* classifierWidget, +- int linePathSegmentIndex); +- +- void selectAssocClassLine(bool sel = true); +- void removeAssocClassLine(); +- void computeAssocClassLine(); +- +- void setXEntireAssoc(qreal x); +- void setYEntireAssoc(qreal y); +- +- void moveMidPointsBy(qreal x, qreal y); +- void moveEntireAssoc(qreal x, qreal y); +- +- QFont font() const; +- +- virtual void setTextColor(const QColor &color); +- +- void calculateEndingPoints(); +- +- void clipSize(); +- +- bool loadFromXMI(QDomElement& qElement, const UMLWidgetList& widgets, +- const MessageWidgetList* messages); +- virtual bool loadFromXMI(QDomElement& qElement); +- virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); +- +- void cleanup(); +- +- bool isPointAddable(); +- bool isPointRemovable(); +- +- //:TODO: the following four methods should be protected +- virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); +- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); +- virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); +- virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); +- +- virtual void setSelected(bool _select); +-public Q_SLOTS: //:TODO: all virtual? +- virtual void slotMenuSelection(QAction* action); +- void slotClassifierListItemRemoved(UMLClassifierListItem* obj); +- void slotAttributeChanged(); +- +- void syncToModel(); +- +-protected: +- virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); +- +- virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); +- virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); +- virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); +- +-private: +- QPointF calculateTextPosition(Uml::TextRole::Enum role); +- void setTextPosition(Uml::TextRole::Enum role); +- void setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition); +- void setFloatingText(Uml::TextRole::Enum role, const QString& text, FloatingTextWidget* &ft); +- +- AssociationWidget(UMLScene *scene); +- +- void setUMLAssociation(UMLAssociation * assoc); +- +- void mergeAssociationDataIntoUMLRepresentation(); +- +- static Uml::Region::Enum findPointRegion(const QRectF& rect, const QPointF& pos); +- static qreal findInterceptOnEdge(const QRectF &rect, Uml::Region::Enum region, const QPointF &point); +- static QLineF::IntersectType intersect(const QRectF &rect, const QLineF &line, +- QPointF* intersectionPoint); +- +- void moveEvent(QGraphicsSceneMouseEvent *me); +- +- Uml::TextRole::Enum calculateNameType(Uml::TextRole::Enum defaultRoleType); +- +- static QPointF swapXY(const QPointF &p); +- +- // not used at the moment +- // static QPointF calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance); +- // static QPointF calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance); +- // static float perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, QPointF& ResultingPoint); +- +- static QPointF midPoint(const QPointF& p0, const QPointF& p1); +- +- void createPointsSelfAssociation(); +- void updatePointsSelfAssociation(); +- void createPointsException(); +- void updatePointsException(); +- +- /** +- * The WidgetRole struct gathers all information pertaining to the role. +- * The AssociationWidget class contains two WidgetRole objects, one for each +- * side of the association (A and B). +- */ +- struct WidgetRole { +- +- FloatingTextWidget* multiplicityWidget; ///< information regarding multiplicity +- FloatingTextWidget* changeabilityWidget; ///< information regarding changeability +- FloatingTextWidget* roleWidget; ///< role's label of this association +- +- UMLWidget* umlWidget; ///< UMLWidget at this role's side of this association +- +- Uml::Region::Enum m_WidgetRegion; ///< region of this role's widget +- +- int m_nIndex; ///< the index of where the line is on the region for this role +- int m_nTotalCount; ///< total amount of associations on the region this role's line is on +- +- // The following items are only used if m_pObject is not set. +- Uml::Visibility::Enum visibility; +- Uml::Changeability::Enum changeability; +- QString roleDocumentation; +- +- }; +- +- void updateRegionLineCount(int index, int totalCount, +- Uml::Region::Enum region, Uml::RoleType::Enum role); +- +- void updateAssociations(int totalCount, Uml::Region::Enum region, Uml::RoleType::Enum role); +- +- int getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role); +- +- void doUpdates(const QPointF &otherP, Uml::RoleType::Enum role); +- +- void setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role); +- +- bool checkAddPoint(const QPointF &scenePos); +- bool checkRemovePoint(const QPointF &scenePos); +- +- bool linePathStartsAt(const UMLWidget* widget); +- +- void insertIntoLists(qreal position, const AssociationWidget* assoc); +- +- qreal m_positions[100]; ///< auxiliary variable for updateAssociations() +- int m_positions_len; ///< auxiliary variable for updateAssociations() +- AssociationWidgetList m_ordered; ///< auxiliary variable for updateAssociations() +- +- bool m_activated; ///< flag which is true if the activate method has been called for this class instance +- +- /** +- * When the association has a Role Floating Text this text should move +- * when the AssociationLine moves but only if the closest segment to the +- * role text moves. +- * This segment is: +- * m_associationLine[m_unNameLineSegment] -- m_associationLine[m_unNameLineSegment+1] +- */ +- int m_unNameLineSegment; +- +- QPointF m_oldNamePoint; ///< Position of name floatingtext saved by saveIdealTextPositions() +- QPointF m_oldMultiAPoint; ///< Position of role A multiplicity floatingtext saved by saveIdealTextPositions() +- QPointF m_oldMultiBPoint; ///< Position of role B multiplicity floatingtext saved by saveIdealTextPositions() +- QPointF m_oldChangeAPoint; ///< Position of role A changeability floatingtext saved by saveIdealTextPositions() +- QPointF m_oldChangeBPoint; ///< Position of role B changeability floatingtext saved by saveIdealTextPositions() +- QPointF m_oldRoleAPoint; ///< Position of role A name floatingtext saved by saveIdealTextPositions() +- QPointF m_oldRoleBPoint; ///< Position of role B name floatingtext saved by saveIdealTextPositions() +- +- int m_nLinePathSegmentIndex; ///< anchor for m_pAssocClassLine +- QGraphicsLineItem *m_pAssocClassLine; ///< used for connecting assoc. class +- QGraphicsRectItem *m_pAssocClassLineSel0; ///< selection decoration for the start point of the assoc. class line +- QGraphicsRectItem *m_pAssocClassLineSel1; ///< selection decoration for the end point of the assoc. class line +- +- AssociationLine *m_associationLine; ///< the definition points for the association line +- ClassifierWidget *m_associationClass; ///< used if we have an assoc. class +- Uml::AssociationType::Enum m_associationType; ///< is only used if m_pObject is not set +- WidgetRole m_role[2]; +- FloatingTextWidget* m_nameWidget; ///< displays the name of this association +- QPointF m_eventScenePos; ///< holds scene pos of contextMenuEvent() +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,79 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "boxwidget.h" +- +-// app includes +-#include "uml.h" +-#include "umldoc.h" +- +-// qt includes +-#include +- +-/** +- * Constructs a BoxWidget. +- * +- * @param scene The parent to this widget. +- * @param id The ID to assign (-1 will prompt a new ID.) +- * @param type The WidgetType (wt_Box.) +- */ +-BoxWidget::BoxWidget(UMLScene * scene, Uml::ID::Type id, WidgetType type) +- : UMLWidget(scene, type, id) +-{ +- setSize(100, 80); +- m_usesDiagramLineColor = false; // boxes be black +- m_lineColor = QColor("black"); +- setZValue(-10); +-} +- +-/** +- * Destructor. +- */ +-BoxWidget::~BoxWidget() +-{ +-} +- +-/** +- * Draws a rectangle. +- */ +-void BoxWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- setPenFromSettings(painter); +- painter->drawRect(0, 0, width(), height()); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Saves the widget to the "boxwidget" XMI element. +- * Note: For loading from XMI, the inherited parent method is used. +- */ +-void BoxWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement boxElement = qDoc.createElement(QLatin1String("boxwidget")); +- UMLWidget::saveToXMI(qDoc, boxElement); +- qElement.appendChild(boxElement); +-} +- +-/** +- * Show a properties dialog for a BoxWidget. +- */ +-void BoxWidget::showPropertiesDialog() +-{ +- QColor newColor = QColorDialog::getColor(lineColor()); // krazy:exclude=qclasses +- if (newColor != lineColor()) { +- setLineColor(newColor); +- setUsesDiagramLineColor(false); +- umlDoc()->setModified(true); +- } +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.h umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,39 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef BOXWIDGET_H +-#define BOXWIDGET_H +- +-//app includes +-#include "umlwidget.h" +- +-/** +- * Displays a rectangular box. +- * These widgets are diagram specific. They will still need a unique id +- * from the @ref UMLDoc class for deletion and other purpose-kf6s. +- * +- * @short Displays a box. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class BoxWidget : public UMLWidget +-{ +-public: +- explicit BoxWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, WidgetType type = WidgetBase::wt_Box); +- virtual ~BoxWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- virtual void showPropertiesDialog(); +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,148 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header file +-#include "categorywidget.h" +- +-// local includes +-#include "category.h" +-#include "debug_utils.h" +-#include "umlview.h" +-#include "listpopupmenu.h" +- +-// qt includes +-#include +- +-/** +- * Creates a Category widget. +- * +- * @param scene The parent of the widget. +- * @param o The UMLCategory to represent. +- */ +-CategoryWidget::CategoryWidget(UMLScene * scene, UMLCategory *o) +- : UMLWidget(scene, WidgetBase::wt_Category, o) +-{ +- m_fixedAspectRatio = true; +-} +- +-/** +- * Destructor. +- */ +-CategoryWidget::~CategoryWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void CategoryWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- UMLWidget::setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- QFont font = UMLWidget::font(); +- font.setUnderline(false); +- font.setBold(false); +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- // the height is our radius +- const int h = height(); +- const int w = width(); +- const int r = h > w ? h : w; +- +- //int middleX = w / 2; +- const int textStartY = (r / 2) - (fontHeight / 2); +- +- // draw a circle +- painter->drawEllipse(0, 0, r, r); +- painter->setPen(textColor()); +- +- QString letterType(QLatin1Char('D')); +- switch(static_cast(m_umlObject)->getType()) { +- case UMLCategory::ct_Disjoint_Specialisation: +- letterType = QLatin1Char('D'); +- break; +- case UMLCategory::ct_Overlapping_Specialisation: +- letterType = QLatin1Char('O'); +- break; +- case UMLCategory::ct_Union: +- letterType = QLatin1Char('U'); +- break; +- default: +- break; +- } +- +- painter->drawText(UC_MARGIN, textStartY, r - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, letterType); +- UMLWidget::setPenFromSettings(painter); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF CategoryWidget::minimumSize() const +-{ +- const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); +- const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); +- const int fontHeight = fm.lineSpacing(); +- int radius = UC_RADIUS + fontHeight + UC_MARGIN; +- +- return QSizeF(radius, radius); +-} +- +-/** +- * Saves this Category to file. +- */ +-void CategoryWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement categoryElement = qDoc.createElement(QLatin1String("categorywidget")); +- UMLWidget::saveToXMI(qDoc, categoryElement); +- qElement.appendChild(categoryElement); +-} +- +-/** +- * Will be called when a menu selection has been made from the +- * popup menu. +- * +- * @param action The action that has been selected. +- */ +-void CategoryWidget::slotMenuSelection(QAction* action) +-{ +- UMLCategory* catObj = static_cast(umlObject()); +- if (!catObj) { +- uWarning() << "No UMLCategory for this widget."; +- return; +- } +- +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_DisjointSpecialisation: +- catObj->setType(UMLCategory::ct_Disjoint_Specialisation); +- break; +- +- case ListPopupMenu::mt_OverlappingSpecialisation: +- catObj->setType(UMLCategory::ct_Overlapping_Specialisation); +- break; +- +- case ListPopupMenu::mt_Union: +- catObj->setType(UMLCategory::ct_Union); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.h umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,56 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef CATEGORYWIDGET_H +-#define CATEGORYWIDGET_H +- +-#include "umlwidget.h" +- +-#define UC_MARGIN 5 +-#define UC_RADIUS 30 +- +-class UMLCategory; +- +-/** +- * This class is the graphical version of a UMLCategory. A CategoryWidget is created +- * by a @ref UMLView. An CategoryWidget belongs to only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. +- * +- * If the Category class that this CategoryWidget is displaying is deleted, the @ref UMLView will +- * make sure that this instance is also deleted. +- * +- * The CategoryWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @short A graphical version of a UMLCategory. +- * @author Sharan Rao +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class CategoryWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- CategoryWidget(UMLScene * scene, UMLCategory *o); +- virtual ~CategoryWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- // For loading we can use the loadFromXMI() inherited from UMLWidget. +- +-protected: +- QSizeF minimumSize() const; +- +-public slots: +- void slotMenuSelection(QAction* action); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1420 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "classifierwidget.h" +- +-// app includes +-#include "floatingtextwidget.h" +-#include "associationwidget.h" +-#include "associationline.h" +-#include "classifier.h" +-#include "cmds.h" +-#include "debug_utils.h" +-#include "listpopupmenu.h" +-#include "object_factory.h" +-#include "operation.h" +-#include "template.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlview.h" +- +-#define PACKAGE_MARGIN 5 +- +-// qt includes +-#include +- +-DEBUG_REGISTER_DISABLED(ClassifierWidget) +- +-const int ClassifierWidget::MARGIN = 5; +-const int ClassifierWidget::CIRCLE_SIZE = 30; +-const int ClassifierWidget::SOCKET_INCREMENT = 10; +- +-/** +- * Constructs a ClassifierWidget. +- * +- * @param scene The parent of this ClassifierWidget. +- * @param c The UMLClassifier to represent. +- */ +-ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLClassifier *c) +- : UMLWidget(scene, WidgetBase::wt_Class, c), +- m_pAssocWidget(0), m_pInterfaceName(0) +-{ +- const Settings::OptionState& ops = m_scene->optionState(); +- setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); +- setVisualPropertyCmd(ShowOperations, ops.classState.showOps); +- setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); +- setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); +- m_attributeSignature = Uml::SignatureType::ShowSig; +- /*:TODO: +- setVisualProperty(ShowOperationSignature, ops.classState.showOpSig); +- Cannot do that because we get "pure virtual method called". Open code: +- */ +- if(!ops.classState.showOpSig) { +- if (visualProperty(ShowVisibility)) +- m_operationSignature = Uml::SignatureType::NoSig; +- else +- m_operationSignature = Uml::SignatureType::NoSigNoVis; +- +- } else if (visualProperty(ShowVisibility)) +- m_operationSignature = Uml::SignatureType::ShowSig; +- else +- m_operationSignature = Uml::SignatureType::SigNoVis; +- +- setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); +- setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); +- setVisualPropertyCmd(DrawAsCircle, false); +- +- setShowAttSigs(ops.classState.showAttSig); +- +- if (c && c->isInterface()) { +- m_baseType = WidgetBase::wt_Interface; +- m_visualProperties = ShowOperations | ShowVisibility | ShowStereotype; +- setShowStereotype(true); +- updateSignatureTypes(); +- } +-} +- +-/** +- * Constructs a ClassifierWidget. +- * +- * @param scene The parent of this ClassifierWidget. +- * @param c The UMLClassifier to represent. +- */ +-ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLPackage *o) +- : UMLWidget(scene, WidgetBase::wt_Package, o), +- m_pAssocWidget(0), +- m_pInterfaceName(0) +-{ +- const Settings::OptionState& ops = m_scene->optionState(); +- setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); +- setVisualPropertyCmd(ShowOperations, ops.classState.showOps); +- setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); +- setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); +- m_attributeSignature = Uml::SignatureType::ShowSig; +- +- if(!ops.classState.showOpSig) { +- if (visualProperty(ShowVisibility)) +- m_operationSignature = Uml::SignatureType::NoSig; +- else +- m_operationSignature = Uml::SignatureType::NoSigNoVis; +- +- } else if (visualProperty(ShowVisibility)) +- m_operationSignature = Uml::SignatureType::ShowSig; +- else +- m_operationSignature = Uml::SignatureType::SigNoVis; +- +- setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); +- setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); +- setVisualPropertyCmd(DrawAsPackage, true); +- +- setShowAttSigs(ops.classState.showAttSig); +-} +- +-/** +- * Destructor. +- */ +-ClassifierWidget::~ClassifierWidget() +-{ +- if (m_pAssocWidget) +- m_pAssocWidget->removeAssocClassLine(); +- if (m_pInterfaceName) { +- delete m_pInterfaceName; +- m_pInterfaceName = 0; +- } +-} +- +-/** +- * Return the UMLClassifier which this ClassifierWidget +- * represents. +- */ +-UMLClassifier *ClassifierWidget::classifier() const +-{ +- return dynamic_cast(m_umlObject); +-} +- +-/** +- * @return the visual properties +- */ +-ClassifierWidget::VisualProperties ClassifierWidget::visualProperties() const +-{ +- return m_visualProperties; +-} +- +-/** +- * Set an OR combination of properties stored in \a properties on this +- * widget. +- */ +-void ClassifierWidget::setVisualProperties(VisualProperties properties) +-{ +- // Don't do anything if the argument is equal to current status. +- if (quint32(m_visualProperties) == quint32(properties)) { +- return; +- } +- +- m_visualProperties = properties; +- updateSignatureTypes(); +-} +- +-/** +- * @return The status of the property passed in. +- * +- * @note Use @ref attributeSignature() and @ref +- * operationSignature() to get signature status. This +- * method only indicates whether signature is visible or not. +- */ +-bool ClassifierWidget::visualProperty(VisualProperty property) const +-{ +- if (property == ShowAttributeSignature) { +- return (m_attributeSignature == Uml::SignatureType::ShowSig +- || m_attributeSignature == Uml::SignatureType::SigNoVis); +- } +- +- else if(property == ShowOperationSignature) { +- return (m_operationSignature == Uml::SignatureType::ShowSig +- || m_operationSignature == Uml::SignatureType::SigNoVis); +- } +- +- return m_visualProperties.testFlag(property); +-} +- +-/** +- * A convenient method to set and reset individual VisualProperty +- * +- * Undo command. +- * +- * @param property The property to be set/reset. +- * @param enable True/false to set/reset. (default = true) +- * +- * @note This method handles ShowAttributeSignature and +- * ShowOperationSignature specially. +- */ +-void ClassifierWidget::setVisualProperty(VisualProperty property, bool enable) +-{ +- if (visualProperty(property) != enable) { +- UMLApp::app()->executeCommand(new Uml::CmdChangeVisualProperty(this, property, enable)); +- } +-} +- +-/** +- * A convenient method to set and reset individual VisualProperty +- * +- * @param property The property to be set/reset. +- * @param enable True/false to set/reset. (default = true) +- * +- * @note This method handles ShowAttributeSignature and +- * ShowOperationSignature specially. +- */ +-void ClassifierWidget::setVisualPropertyCmd(VisualProperty property, bool enable) +-{ +- // Handle ShowAttributeSignature and ShowOperationSignature +- // specially. +- +- if (property == ShowAttributeSignature) { +- if (!enable) { +- m_attributeSignature = visualProperty(ShowVisibility) ? +- Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; +- } else { +- m_attributeSignature = visualProperty(ShowVisibility) ? +- Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; +- } +- //:TODO: updateTextItemGroups(); +- updateSignatureTypes(); +- } +- +- else if (property == ShowOperationSignature) { +- if (!enable) { +- m_operationSignature = visualProperty(ShowVisibility) ? +- Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; +- } else { +- m_operationSignature = visualProperty(ShowVisibility) ? +- Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; +- } +- //:TODO: updateTextItemGroups(); +- updateSignatureTypes(); +- } +- +- else if (property == ShowStereotype) { +- // Now just update flag and use base method for actual work. +- if (enable) { +- m_visualProperties |= property; +- } else { +- m_visualProperties &= ~property; +- } +- setShowStereotype(enable); +- } +- +- else if (property == DrawAsCircle) { +- // Don't do anything if the flag status is same. +- if (visualProperty(property) == enable) +- return; +- if (enable) { +- m_visualProperties |= property; +- } else { +- m_visualProperties &= ~property; +- } +- setDrawAsCircle(enable); +- } +- +- // Some other flag. +- else { +- // Don't do anything if the flag status is same. +- if (visualProperty(property) == enable) { +- return; +- } +- +- // Call setVisualProperties appropriately based on enbable. +- if (enable) { +- setVisualProperties(visualProperties() | property); +- } else { +- setVisualProperties(visualProperties() & ~property); +- } +- } +-} +- +-/** +- * A convenient method to toggle individual VisualProperty of this +- * widget. +- * +- * @param property The property to be toggled. +- * +- * @note This method handles ShowAttributeSignature and +- * ShowOperationSignature specially. +- */ +-void ClassifierWidget::toggleVisualProperty(VisualProperty property) +-{ +- bool oppositeStatus; +- if (property == ShowOperationSignature) { +- oppositeStatus = !(m_operationSignature == Uml::SignatureType::ShowSig +- || m_operationSignature == Uml::SignatureType::SigNoVis); +- } +- else if (property == ShowAttributeSignature) { +- oppositeStatus = !(m_attributeSignature == Uml::SignatureType::ShowSig +- || m_attributeSignature == Uml::SignatureType::SigNoVis); +- } +- else { +- oppositeStatus = !visualProperty(property); +- } +- +- DEBUG(DBG_SRC) << "VisualProperty: " << property << " to opposite status " << oppositeStatus; +- setVisualProperty(property, oppositeStatus); +-} +- +-/** +- * Updates m_operationSignature to match m_showVisibility. +- */ +-void ClassifierWidget::updateSignatureTypes() +-{ +- //turn on scope +- if (visualProperty(ShowVisibility)) { +- if (m_operationSignature == Uml::SignatureType::NoSigNoVis) { +- m_operationSignature = Uml::SignatureType::NoSig; +- } else if (m_operationSignature == Uml::SignatureType::SigNoVis) { +- m_operationSignature = Uml::SignatureType::ShowSig; +- } +- } +- //turn off scope +- else { +- if (m_operationSignature == Uml::SignatureType::ShowSig) { +- m_operationSignature = Uml::SignatureType::SigNoVis; +- } else if (m_operationSignature == Uml::SignatureType::NoSig) { +- m_operationSignature = Uml::SignatureType::NoSigNoVis; +- } +- } +- if (visualProperty(ShowVisibility)) { +- if (m_attributeSignature == Uml::SignatureType::NoSigNoVis) +- m_attributeSignature = Uml::SignatureType::NoSig; +- else if (m_attributeSignature == Uml::SignatureType::SigNoVis) +- m_attributeSignature = Uml::SignatureType::ShowSig; +- } else { +- if (m_attributeSignature == Uml::SignatureType::ShowSig) +- m_attributeSignature = Uml::SignatureType::SigNoVis; +- else if(m_attributeSignature == Uml::SignatureType::NoSig) +- m_attributeSignature = Uml::SignatureType::NoSigNoVis; +- } +- updateGeometry(); +- update(); +-} +- +-/** +- * Returns whether to show attribute signatures. +- * Only applies when m_umlObject->getBaseType() is ot_Class. +- * +- * @return Status of how attribute signatures are shown. +- */ +-Uml::SignatureType::Enum ClassifierWidget::attributeSignature() const +-{ +- return m_attributeSignature; +-} +- +-/** +- * Sets the type of signature to display for an attribute. +- * Only applies when m_umlObject->getBaseType() is ot_Class. +- * +- * @param sig Type of signature to display for an attribute. +- */ +-void ClassifierWidget::setAttributeSignature(Uml::SignatureType::Enum sig) +-{ +- m_attributeSignature = sig; +- updateSignatureTypes(); +- updateGeometry(); +- update(); +-} +- +-/** +- * @return The Uml::SignatureType::Enum value for the operations. +- */ +-Uml::SignatureType::Enum ClassifierWidget::operationSignature() const +-{ +- return m_operationSignature; +-} +- +-/** +- * Set the type of signature to display for an Operation +- * +- * @param sig Type of signature to display for an operation. +- */ +-void ClassifierWidget::setOperationSignature(Uml::SignatureType::Enum sig) +-{ +- m_operationSignature = sig; +- updateSignatureTypes(); +- updateGeometry(); +- update(); +-} +- +-/** +- * Sets whether to show attribute signature +- * Only applies when m_umlObject->getBaseType() is ot_Class. +- * +- * @param _status True if attribute signatures shall be shown. +- */ +-void ClassifierWidget::setShowAttSigs(bool _status) +-{ +- if(!_status) { +- if (visualProperty(ShowVisibility)) +- m_attributeSignature = Uml::SignatureType::NoSig; +- else +- m_attributeSignature = Uml::SignatureType::NoSigNoVis; +- } +- else if (visualProperty(ShowVisibility)) +- m_attributeSignature = Uml::SignatureType::ShowSig; +- else +- m_attributeSignature = Uml::SignatureType::SigNoVis; +- if (UMLApp::app()->document()->loading()) +- return; +- updateGeometry(); +- update(); +-} +- +-/** +- * Toggles whether to show attribute signatures. +- * Only applies when m_umlObject->getBaseType() is ot_Class. +- */ +-void ClassifierWidget::toggleShowAttSigs() +-{ +- if (m_attributeSignature == Uml::SignatureType::ShowSig || +- m_attributeSignature == Uml::SignatureType::SigNoVis) { +- if (visualProperty(ShowVisibility)) { +- m_attributeSignature = Uml::SignatureType::NoSig; +- } else { +- m_attributeSignature = Uml::SignatureType::NoSigNoVis; +- } +- } else if (visualProperty(ShowVisibility)) { +- m_attributeSignature = Uml::SignatureType::ShowSig; +- } else { +- m_attributeSignature = Uml::SignatureType::SigNoVis; +- } +- updateGeometry(); +- update(); +-} +- +-/** +- * Return the number of displayed members of the given ObjectType. +- * Takes into consideration m_showPublicOnly but not other settings. +- */ +-int ClassifierWidget::displayedMembers(UMLObject::ObjectType ot) const +-{ +- int count = 0; +- UMLClassifier *umlc = this->classifier(); +- if (!umlc) +- return count; +- UMLClassifierListItemList list = umlc->getFilteredList(ot); +- foreach (UMLClassifierListItem *m, list) { +- if (!(visualProperty(ShowPublicOnly) && m->visibility() != Uml::Visibility::Public)) +- count++; +- } +- return count; +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF ClassifierWidget::minimumSize() const +-{ +- return calculateSize(); +-} +- +-/** +- * Calculate content related size of widget. +- * Overrides method from UMLWidget. +- */ +-QSizeF ClassifierWidget::calculateSize(bool withExtensions /* = true */) const +-{ +- if (!m_umlObject) { +- return UMLWidget::minimumSize(); +- } +- if (m_umlObject->baseType() == UMLObject::ot_Package) { +- return calculateAsPackageSize(); +- } +- UMLClassifier *umlc = this->classifier(); +- if (!umlc) { +- uError() << "Internal error - classifier() returns NULL"; +- return UMLWidget::minimumSize(); +- } +- if (umlc->isInterface() && visualProperty(DrawAsCircle)) { +- return calculateAsCircleSize(); +- } +- +- const bool showNameOnly = !visualProperty(ShowAttributes) && +- !visualProperty(ShowOperations) && +- !visualProperty(ShowDocumentation); +- +- const QFontMetrics &fm = getFontMetrics(UMLWidget::FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- // width is the width of the longest 'word' +- int width = 0, height = 0; +- // consider stereotype +- if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { +- height += fontHeight; +- // ... width +- const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD); +- const int stereoWidth = bfm.size(0, m_umlObject->stereotype(true)).width(); +- if (stereoWidth > width) +- width = stereoWidth; +- } else if (showNameOnly) { +- height += MARGIN; +- } +- +- // consider name +- height += fontHeight; +- // ... width +- QString displayedName; +- if (visualProperty(ShowPackage)) +- displayedName = m_umlObject->fullyQualifiedName(); +- else +- displayedName = m_umlObject->name(); +- const UMLWidget::FontType nft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); +- const int nameWidth = UMLWidget::getFontMetrics(nft).size(0, displayedName).width(); +- if (nameWidth > width) +- width = nameWidth; +- +-#ifdef ENABLE_WIDGET_SHOW_DOC +- // consider documentation +- if (visualProperty(ShowDocumentation)) { +- if (!documentation().isEmpty()) { +- QRect brect = fm.boundingRect(QRect(0, 0, this->width()-2*MARGIN, this->height()-height), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); +- height += brect.height(); +- if (!visualProperty(ShowOperations) && !visualProperty(ShowAttributes)) { +- if (brect.width() >= width) +- width = brect.width(); +- } +- } +- else +- height += fontHeight / 2; +- } +-#endif +- +- // consider attributes +- if (visualProperty(ShowAttributes)) { +- const int numAtts = displayedAttributes(); +- if (numAtts > 0) { +- height += fontHeight * numAtts; +- // calculate width of the attributes +- UMLClassifierListItemList list = umlc->getFilteredList(UMLObject::ot_Attribute); +- foreach (UMLClassifierListItem *a, list) { +- if (visualProperty(ShowPublicOnly) && a->visibility() != Uml::Visibility::Public) +- continue; +- const int attWidth = fm.size(0, a->toString(m_attributeSignature)).width(); +- if (attWidth > width) +- width = attWidth; +- } +- } +- else +- height += fontHeight / 2; +- } +- +- // consider operations +- if (visualProperty(ShowOperations)) { +- const int numOps = displayedOperations(); +- if (numOps > 0) { +- height += numOps * fontHeight; +- // ... width +- UMLOperationList list(umlc->getOpList()); +- foreach (UMLOperation* op, list) { +- if (visualProperty(ShowPublicOnly) && op->visibility() != Uml::Visibility::Public) +- continue; +- const QString displayedOp = op->toString(m_operationSignature); +- UMLWidget::FontType oft; +- oft = (op->isAbstract() ? UMLWidget::FT_ITALIC : UMLWidget::FT_NORMAL); +- const int w = UMLWidget::getFontMetrics(oft).size(0, displayedOp).width(); +- if (w > width) +- width = w; +- } +- } +- else +- height += fontHeight / 2; +- } +- +- if (withExtensions) { +- // consider template box _as last_ ! +- QSize templatesBoxSize = calculateTemplatesBoxSize(); +- if (templatesBoxSize.width() != 0) { +- // add width to largest 'word' +- width += templatesBoxSize.width() / 2; +- } +- if (templatesBoxSize.height() != 0) { +- height += templatesBoxSize.height() - MARGIN; +- } +- } +- +- // allow for height margin +- if (showNameOnly) { +- height += MARGIN; +- } +- +- // allow for width margin +- width += MARGIN * 2; +- +- return QSizeF(width, height); +-} +- +-/** +- * Calculcates the size of the templates box in the top left +- * if it exists, returns QSize(0, 0) if it doesn't. +- * +- * @return QSize of the templates flap. +- */ +-QSize ClassifierWidget::calculateTemplatesBoxSize() const +-{ +- if (!classifier()) +- return QSize(0, 0); +- UMLTemplateList list = classifier()->getTemplateList(); +- int count = list.count(); +- if (count == 0) { +- return QSize(0, 0); +- } +- +- QFont font = UMLWidget::font(); +- font.setItalic(false); +- font.setUnderline(false); +- font.setBold(false); +- const QFontMetrics fm(font); +- +- int width = 0; +- int height = count * fm.lineSpacing() + (MARGIN*2); +- +- foreach (UMLTemplate *t, list) { +- int textWidth = fm.size(0, t->toString()).width(); +- if (textWidth > width) +- width = textWidth; +- } +- +- width += (MARGIN*2); +- return QSize(width, height); +-} +- +-/** +- * Return the number of displayed attributes. +- */ +-int ClassifierWidget::displayedAttributes() const +-{ +- if (!visualProperty(ShowAttributes)) +- return 0; +- return displayedMembers(UMLObject::ot_Attribute); +-} +- +-/** +- * Return the number of displayed operations. +- */ +-int ClassifierWidget::displayedOperations() const +-{ +- if (!visualProperty(ShowOperations)) +- return 0; +- return displayedMembers(UMLObject::ot_Operation); +-} +- +-/** +- * Set the AssociationWidget when this ClassWidget acts as +- * an association class. +- */ +-void ClassifierWidget::setClassAssociationWidget(AssociationWidget *assocwidget) +-{ +- if (!classifier()) { +- uError() << "Class association cannot be applied to package"; +- return; +- } +- m_pAssocWidget = assocwidget; +- UMLAssociation *umlassoc = NULL; +- if (assocwidget) +- umlassoc = assocwidget->association(); +- classifier()->setClassAssoc(umlassoc); +-} +- +-/** +- * Return the AssociationWidget when this classifier acts as +- * an association class (else return NULL.) +- */ +-AssociationWidget *ClassifierWidget::classAssociationWidget() const +-{ +- return m_pAssocWidget; +-} +- +-/** +- * Overrides standard method. +- * Auxiliary to reimplementations in the derived classes. +- */ +-void ClassifierWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- else { +- painter->setBrush(m_scene->backgroundColor()); +- } +- if (m_umlObject->baseType() == UMLObject::ot_Package) { +- drawAsPackage(painter, option); +- UMLWidget::paint(painter, option, widget); +- return; +- } +- UMLClassifier *umlc = this->classifier(); +- if (!umlc) { +- uError() << "Internal error - classifier() returns NULL"; +- return; +- } +- if (umlc->isInterface() && visualProperty(DrawAsCircle)) { +- drawAsCircle(painter, option); +- UMLWidget::paint(painter, option, widget); +- return; +- } +- +- // Draw the bounding rectangle +- QSize templatesBoxSize = calculateTemplatesBoxSize(); +- int bodyOffsetY = 0; +- if (templatesBoxSize.height() > 0) +- bodyOffsetY += templatesBoxSize.height() - MARGIN; +- int w = width(); +- if (templatesBoxSize.width() > 0) +- w -= templatesBoxSize.width() / 2; +- int h = height(); +- if (templatesBoxSize.height() > 0) +- h -= templatesBoxSize.height() - MARGIN; +- painter->drawRect(0, bodyOffsetY, w, h); +- +- QFont font = UMLWidget::font(); +- font.setUnderline(false); +- font.setItalic(false); +- const QFontMetrics &fm = UMLWidget::getFontMetrics(UMLWidget::FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- +- //If there are any templates then draw them +- UMLTemplateList tlist = umlc->getTemplateList(); +- if (tlist.count() > 0) { +- setPenFromSettings(painter); +- QPen pen = painter->pen(); +- pen.setStyle(Qt::DotLine); +- painter->setPen(pen); +- painter->drawRect(width() - templatesBoxSize.width(), 0, +- templatesBoxSize.width(), templatesBoxSize.height()); +- painter->setPen(QPen(textColor())); +- font.setBold(false); +- painter->setFont(font); +- const int x = width() - templatesBoxSize.width() + MARGIN; +- int y = MARGIN; +- foreach (UMLTemplate *t, tlist) { +- QString text = t->toString(); +- painter->drawText(x, y, fm.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); +- y += fontHeight; +- } +- } +- +- const int textX = MARGIN; +- const int textWidth = w - MARGIN * 2; +- +- painter->setPen(QPen(textColor())); +- +- // draw stereotype +- font.setBold(true); +- const bool showNameOnly = !visualProperty(ShowAttributes) && +- !visualProperty(ShowOperations) && +- !visualProperty(ShowDocumentation); +- +- int nameHeight = fontHeight; +- if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { +- painter->setFont(font); +- painter->drawText(textX, bodyOffsetY, textWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); +- bodyOffsetY += fontHeight; +- } else if (showNameOnly) { +- nameHeight = h; +- } +- +- // draw name +- QString name; +- if (visualProperty(ShowPackage)) { +- name = m_umlObject->fullyQualifiedName(); +- } else { +- name = this->name(); +- } +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- painter->drawText(textX, bodyOffsetY, textWidth, nameHeight, Qt::AlignCenter, name); +- bodyOffsetY += fontHeight; +- font.setBold(false); +- font.setItalic(false); +- painter->setFont(font); +- +-#ifdef ENABLE_WIDGET_SHOW_DOC +- // draw documentation +- if (visualProperty(ShowDocumentation)) { +- setPenFromSettings(painter); +- painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); +- painter->setPen(textColor()); +- +- if (!documentation().isEmpty()) { +- QRect brect = fm.boundingRect(QRect(0, 0, w-2*MARGIN, h-bodyOffsetY), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); +- if (brect.width() > width() + 2*MARGIN) +- brect.setWidth(width()-2*MARGIN); +- brect.adjust(textX, bodyOffsetY, textX, bodyOffsetY); +- painter->drawText(brect, Qt::AlignCenter | Qt::TextWordWrap, documentation()); +- bodyOffsetY += brect.height(); +- } +- else +- bodyOffsetY += fontHeight / 2; +- } +-#endif +- // draw attributes +- if (visualProperty(ShowAttributes)) { +- // draw dividing line between doc/name and attributes +- setPenFromSettings(painter); +- painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); +- painter->setPen(textColor()); +- +- const int numAtts = displayedAttributes(); +- if (numAtts > 0) { +- drawMembers(painter, UMLObject::ot_Attribute, m_attributeSignature, textX, +- bodyOffsetY, fontHeight); +- bodyOffsetY += fontHeight * numAtts; +- } +- else +- bodyOffsetY += fontHeight / 2; +- } +- +- // draw operations +- if (visualProperty(ShowOperations)) { +- // draw dividing line between attributes and operations +- setPenFromSettings(painter); +- painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); +- painter->setPen(QPen(textColor())); +- +- const int numOps = displayedOperations(); +- if (numOps >= 0) { +- drawMembers(painter, UMLObject::ot_Operation, m_operationSignature, textX, +- bodyOffsetY, fontHeight); +- } +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * @return The shape of the ClassifierWidget. +- */ +-QPainterPath ClassifierWidget::shape() const +-{ +- QPainterPath path; +- if (classifier() && classifier()->isInterface() && visualProperty(DrawAsCircle)) { +- path.addEllipse(rect()); +- return path; +- } +-#ifdef ENABLE_WIDGET_SHOW_DOC +- QSizeF mainSize = rect().size(); +-#else +- QSizeF mainSize = calculateSize(false); +-#endif +- QSize templatesBoxSize = calculateTemplatesBoxSize(); +- qreal mainY = 0.0; +- if (templatesBoxSize.height() > 0) { +- mainY += templatesBoxSize.height() - MARGIN; +- path.addRect(QRectF(mainSize.width() - templatesBoxSize.width() / 2, 0.0, +- templatesBoxSize.width(), templatesBoxSize.height())); +- } +- path.addRect(QRectF(0.0, mainY, mainSize.width(), mainSize.height())); +- return path; +-} +- +-/** +- * Draws the interface as a circle. +- * Only applies when m_umlObject->getBaseType() is ot_Interface. +- */ +-void ClassifierWidget::drawAsCircle(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- const int w = width(); +- +- if (m_Assocs.size() > 1) { +- painter->drawEllipse(w/2 - CIRCLE_SIZE/2, SOCKET_INCREMENT / 2, CIRCLE_SIZE, CIRCLE_SIZE); +- // Draw socket for required interface. +- const qreal angleSpan = 180; // 360.0 / (m_Assocs.size() + 1.0); +- const int arcDiameter = CIRCLE_SIZE + SOCKET_INCREMENT; +- QRect requireArc(w/2 - arcDiameter/2, 0, arcDiameter, arcDiameter); +- const QPointF center(x() + w/2, y() + arcDiameter/2); +- const qreal cX = center.x(); +- const qreal cY = center.y(); +- foreach (AssociationWidget *aw, m_Assocs) { +- const Uml::AssociationType::Enum aType = aw->associationType(); +- if (aType == Uml::AssociationType::UniAssociation || +- aType == Uml::AssociationType::Association) // provider +- continue; +- UMLWidget *otherEnd = aw->widgetForRole(Uml::RoleType::A); +- const WidgetBase::WidgetType oType = otherEnd->baseType(); +- if (oType != WidgetBase::wt_Component && oType != WidgetBase::wt_Port) +- continue; +- +- AssociationLine *assocLine = aw->associationLine(); +- const QPointF p(assocLine->endPoint()); +- const qreal tolerance = 18.0; +- bool drawArc = true; +- qreal midAngle; +- if (p.x() < cX - tolerance) { +- if (p.y() < cY - tolerance) +- midAngle = 135; +- else if (p.y() > cY + tolerance) +- midAngle = 225; +- else +- midAngle = 180; +- } else if (p.x() > cX + tolerance) { +- if (p.y() < cY - tolerance) +- midAngle = 45; +- else if (p.y() > cY + tolerance) +- midAngle = 315; +- else +- midAngle = 0; +- } else { +- if (p.y() < cY - tolerance) +- midAngle = 90; +- else if (p.y() > cY + tolerance) +- midAngle = 270; +- else +- drawArc = false; +- } +- if (drawArc) { +- // uDebug() << "number of assocs: " << m_Assocs.size() +- // << ", p: " << p << ", center: " << center +- // << ", midAngle: " << midAngle << ", angleSpan: " << angleSpan; +- painter->drawArc(requireArc, 16 * (midAngle - angleSpan/2), 16 * angleSpan); +- } else { +- uError() << "socket: assocLine endPoint " << p +- << " too close to own center" << center; +- } +- } +- } +- else +- painter->drawEllipse(w/2 - CIRCLE_SIZE/2, 0, CIRCLE_SIZE, CIRCLE_SIZE); +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * Calculates the size of the object when drawn as a circle. +- * Only applies when m_umlObject->getBaseType() is ot_Interface. +- */ +-QSize ClassifierWidget::calculateAsCircleSize() const +-{ +- int circleSize = CIRCLE_SIZE; +- if (m_Assocs.size() > 1) +- circleSize += SOCKET_INCREMENT; +- return QSize(circleSize, circleSize); +-} +- +-void ClassifierWidget::drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- Q_UNUSED(option); +- +- int w = width(); +- int h = height(); +- QFont font = UMLWidget::font(); +- font.setBold(true); +- //FIXME italic is true when a package is first created until you click elsewhere, not sure why +- font.setItalic(false); +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- +- painter->drawRect(0, 0, 50, fontHeight); +- if (m_umlObject->stereotype() == QLatin1String("subsystem")) { +- const int fHalf = fontHeight / 2; +- const int symY = fHalf; +- const int symX = 38; +- painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg +- painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg +- painter->drawLine(symX, symY, symX + 8, symY); // waist +- painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head +- } +- painter->drawRect(0, fontHeight - 1, w, h - fontHeight); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- int lines = 1; +- QString stereotype = m_umlObject->stereotype(); +- if (!stereotype.isEmpty()) { +- painter->drawText(0, fontHeight + PACKAGE_MARGIN, +- w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); +- lines = 2; +- } +- +- painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, +- w, fontHeight, Qt::AlignCenter, name()); +-} +- +-QSize ClassifierWidget::calculateAsPackageSize() const +-{ +- const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); +- const int fontHeight = fm.lineSpacing(); +- +- int lines = 1; +- +- int width = fm.width(m_umlObject->name()); +- +- int tempWidth = 0; +- if (!m_umlObject->stereotype().isEmpty()) { +- tempWidth = fm.width(m_umlObject->stereotype(true)); +- lines = 2; +- } +- if (tempWidth > width) +- width = tempWidth; +- width += PACKAGE_MARGIN * 2; +- if (width < 70) +- width = 70; // minumin width of 70 +- +- int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); +- +- return QSize(width, height); +-} +- +-/** +- * Auxiliary method for draw() of child classes: +- * Draw the attributes or operations. +- * +- * @param p QPainter to paint to. +- * @param ot Object type to draw, either ot_Attribute or ot_Operation. +- * @param sigType Governs details of the member display. +- * @param x X coordinate at which to draw the texts. +- * @param y Y coordinate at which text drawing commences. +- * @param fontHeight The font height. +- */ +-void ClassifierWidget::drawMembers(QPainter * painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, +- int x, int y, int fontHeight) +-{ +- UMLClassifier *umlc = classifier(); +- if (!umlc) { +- return; +- } +- QFont f = UMLWidget::font(); +- f.setBold(false); +- UMLClassifierListItemList list = umlc->getFilteredList(ot); +- painter->setClipping(true); +- painter->setClipRect(rect()); +- foreach (UMLClassifierListItem *obj, list) { +- if (visualProperty(ShowPublicOnly) && obj->visibility() != Uml::Visibility::Public) +- continue; +- QString text = obj->toString(sigType); +- f.setItalic(obj->isAbstract()); +- f.setUnderline(obj->isStatic()); +- painter->setFont(f); +- QFontMetrics fontMetrics(f); +- painter->drawText(x, y, fontMetrics.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); +- f.setItalic(false); +- f.setUnderline(false); +- painter->setFont(f); +- y += fontHeight; +- } +- painter->setClipping(false); +-} +- +-/** +- * Override method from UMLWidget in order to additionally check m_pInterfaceName. +- * +- * @param p Point to be checked. +- * +- * @return 'this' if UMLWidget::onWidget(p) returns non NULL; +- * m_pInterfaceName if m_pName is non NULL and +- * m_pInterfaceName->onWidget(p) returns non NULL; else NULL. +- */ +-UMLWidget* ClassifierWidget::onWidget(const QPointF &p) +-{ +- if (UMLWidget::onWidget(p) != NULL) +- return this; +- if (getDrawAsCircle() && m_pInterfaceName) { +- uDebug() << "floatingtext: " << m_pInterfaceName->text(); +- return m_pInterfaceName->onWidget(p); +- } +- return NULL; +-} +- +-/** +- * Reimplement function from UMLWidget. +- */ +-UMLWidget* ClassifierWidget::widgetWithID(Uml::ID::Type id) +-{ +- if (UMLWidget::widgetWithID(id)) +- return this; +- if (getDrawAsCircle() && m_pInterfaceName && m_pInterfaceName->widgetWithID(id)) +- return m_pInterfaceName; +- return NULL; +-} +- +-void ClassifierWidget::setDocumentation(const QString &doc) +-{ +- WidgetBase::setDocumentation(doc); +- updateGeometry(); +-} +- +-/** +- * Sets whether to draw as circle. +- * Only applies when m_umlObject->getBaseType() is ot_Interface. +- * +- * @param drawAsCircle True if widget shall be drawn as circle. +- */ +-void ClassifierWidget::setDrawAsCircle(bool drawAsCircle) +-{ +- setVisualPropertyCmd(DrawAsCircle, drawAsCircle); +- const int circleSize = CIRCLE_SIZE + SOCKET_INCREMENT; +- if (drawAsCircle) { +- setX(x() + (width()/2 - circleSize/2)); +- setY(y() + (height()/2 - circleSize/2)); +- setSize(circleSize, circleSize); +- if (m_pInterfaceName) { +- m_pInterfaceName->show(); +- } else { +- m_pInterfaceName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); +- m_pInterfaceName->setParentItem(this); +- m_pInterfaceName->setText(name()); // to get geometry update +- m_pInterfaceName->setX(circleSize/2 - m_pInterfaceName->width() / 2); +- m_pInterfaceName->setY(circleSize + SOCKET_INCREMENT); +- } +- m_resizable = false; +- } else { +- setSize(ClassifierWidget::minimumSize()); +- setX(x() - (width()/2 - circleSize/2)); +- setY(y() - (height()/2 - circleSize/2)); +- if (m_pInterfaceName) +- m_pInterfaceName->hide(); +- m_resizable = true; +- } +- updateGeometry(); +- update(); +-} +- +-/** +- * Returns whether to draw as circle. +- * Only applies when m_umlObject->getBaseType() is ot_Interface. +- * +- * @return True if widget is drawn as circle. +- */ +-bool ClassifierWidget::getDrawAsCircle() const +-{ +- return visualProperty(DrawAsCircle); +-} +- +-/** +- * Toggles whether to draw as circle. +- * Only applies when m_umlObject->getBaseType() is ot_Interface. +- */ +-void ClassifierWidget::toggleDrawAsCircle() +-{ +- toggleVisualProperty(DrawAsCircle); +- updateSignatureTypes(); +- updateGeometry(); +- update(); +-} +- +-/** +- * Changes this classifier from an interface to a class. +- * Attributes and stereotype visibility is got from the view OptionState. +- * This widget is also updated. +- */ +-void ClassifierWidget::changeToClass() +-{ +- m_baseType = WidgetBase::wt_Class; +- m_umlObject->setBaseType(UMLObject::ot_Class); +- setVisualPropertyCmd(DrawAsCircle, false); +- const Settings::OptionState& ops = m_scene->optionState(); +- setVisualProperty(ShowAttributes, ops.classState.showAtts); +- setVisualProperty(ShowStereotype, ops.classState.showStereoType); +- +- updateGeometry(); +- update(); +-} +- +-/** +- * Changes this classifier from a class to an interface. +- * Attributes are hidden and stereotype is shown. +- * This widget is also updated. +- */ +-void ClassifierWidget::changeToInterface() +-{ +- m_baseType = WidgetBase::wt_Interface; +- m_umlObject->setBaseType(UMLObject::ot_Interface); +- +- setVisualProperty(ShowAttributes, false); +- setVisualProperty(ShowStereotype, true); +- +- updateGeometry(); +- update(); +-} +- +-/** +- * Changes this classifier from an "class-or-package" to a package. +- * This widget is also updated. +- */ +-void ClassifierWidget::changeToPackage() +-{ +- m_baseType = WidgetBase::wt_Package; +- m_umlObject->setBaseType(UMLObject::ot_Package); +- +- setVisualProperty(ShowAttributes, false); +- setVisualProperty(ShowStereotype, true); +- +- updateGeometry(); +- update(); +-} +- +-/** +- * Extends base method to adjust also the association of a class +- * association. +- * Executes the base method and then, if file isn't loading and the +- * classifier acts as a class association, the association position is +- * updated. +- * TODO: This is never called. +- * +- * param x The x-coordinate. +- * param y The y-coordinate. +- */ +-//void ClassifierWidget::adjustAssociations(int x, int y) +-//{ +-// DEBUG(DBG_SRC) << "x=" << x << " / y=" << y; +-// UMLWidget::adjustAssocs(x, y); +- +-// if (m_doc->loading() || m_pAssocWidget == 0) { +-// return; +-// } +- +-// //:TODO: the following is also called from UMLWidgetr::ajdustAssocs(...) +-// // and then AssociationWidget::widgetMoved(...) +-// //m_pAssocWidget->computeAssocClassLine(); +-//} +- +-/** +- * Loads the "classwidget" or "interfacewidget" XML element. +- */ +-bool ClassifierWidget::loadFromXMI(QDomElement & qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) { +- return false; +- } +- +- QString showatts = qElement.attribute(QLatin1String("showattributes"), QLatin1String("0")); +- QString showops = qElement.attribute(QLatin1String("showoperations"), QLatin1String("1")); +- QString showpubliconly = qElement.attribute(QLatin1String("showpubliconly"), QLatin1String("0")); +- QString showattsigs = qElement.attribute(QLatin1String("showattsigs"), QLatin1String("600")); +- QString showopsigs = qElement.attribute(QLatin1String("showopsigs"), QLatin1String("600")); +- QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); +- QString showscope = qElement.attribute(QLatin1String("showscope"), QLatin1String("0")); +- QString drawascircle = qElement.attribute(QLatin1String("drawascircle"), QLatin1String("0")); +-#ifdef ENABLE_WIDGET_SHOW_DOC +- QString showDocumentation = qElement.attribute(QLatin1String("showdocumentation"), QLatin1String("0")); +-#endif +- +- setVisualPropertyCmd(ShowAttributes, (bool)showatts.toInt()); +- setVisualPropertyCmd(ShowOperations, (bool)showops.toInt()); +- setVisualPropertyCmd(ShowPublicOnly, (bool)showpubliconly.toInt()); +- setVisualPropertyCmd(ShowPackage, (bool)showpackage.toInt()); +- setVisualPropertyCmd(ShowVisibility, (bool)showscope.toInt()); +- setVisualPropertyCmd(DrawAsCircle, (bool)drawascircle.toInt()); +-#ifdef ENABLE_WIDGET_SHOW_DOC +- setVisualPropertyCmd(ShowDocumentation, (bool)showDocumentation.toInt()); +-#endif +- +- m_attributeSignature = Uml::SignatureType::fromInt(showattsigs.toInt()); +- m_operationSignature = Uml::SignatureType::fromInt(showopsigs.toInt()); +- +- if (!getDrawAsCircle()) +- return true; +- +- // Optional child element: floatingtext +- QDomNode node = qElement.firstChild(); +- QDomElement element = node.toElement(); +- if (!element.isNull()) { +- QString tag = element.tagName(); +- if (tag == QLatin1String("floatingtext")) { +- if (m_pInterfaceName == NULL) { +- m_pInterfaceName = new FloatingTextWidget(m_scene, +- Uml::TextRole::Floating, +- name(), Uml::ID::Reserved); +- m_pInterfaceName->setParentItem(this); +- } +- if (!m_pInterfaceName->loadFromXMI(element)) { +- // Most likely cause: The FloatingTextWidget is empty. +- delete m_pInterfaceName; +- m_pInterfaceName = NULL; +- } else { +- m_pInterfaceName->activate(); +- m_pInterfaceName->update(); +- } +- } else { +- uError() << "unknown tag " << tag; +- } +- } +- +- return true; +-} +- +-/** +- * Creates the "classwidget" or "interfacewidget" XML element. +- */ +-void ClassifierWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement conceptElement; +- UMLClassifier *umlc = classifier(); +- if (umlc && umlc->isInterface()) +- conceptElement = qDoc.createElement(QLatin1String("interfacewidget")); +- else +- conceptElement = qDoc.createElement(QLatin1String("classwidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- conceptElement.setAttribute(QLatin1String("showoperations"), visualProperty(ShowOperations)); +- conceptElement.setAttribute(QLatin1String("showpubliconly"), visualProperty(ShowPublicOnly)); +- conceptElement.setAttribute(QLatin1String("showopsigs"), m_operationSignature); +- conceptElement.setAttribute(QLatin1String("showpackage"), visualProperty(ShowPackage)); +- conceptElement.setAttribute(QLatin1String("showscope"), visualProperty(ShowVisibility)); +- conceptElement.setAttribute(QLatin1String("showattributes"), visualProperty(ShowAttributes)); +- conceptElement.setAttribute(QLatin1String("showattsigs"), m_attributeSignature); +-#ifdef ENABLE_WIDGET_SHOW_DOC +- conceptElement.setAttribute(QLatin1String("showdocumentation"),visualProperty(ShowDocumentation)); +-#endif +- if (umlc && (umlc->isInterface() || umlc->isAbstract())) { +- conceptElement.setAttribute(QLatin1String("drawascircle"), visualProperty(DrawAsCircle)); +- if (visualProperty(DrawAsCircle) && m_pInterfaceName) { +- m_pInterfaceName->saveToXMI(qDoc, conceptElement); +- } +- } +- qElement.appendChild(conceptElement); +-} +- +-/** +- * Will be called when a menu selection has been made from the +- * popup menu. +- * +- * @param action The action that has been selected. +- */ +-void ClassifierWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch (sel) { +- case ListPopupMenu::mt_Attribute: +- case ListPopupMenu::mt_Operation: +- case ListPopupMenu::mt_Template: +- { +- UMLObject::ObjectType ot = ListPopupMenu::convert_MT_OT(sel); +- UMLClassifier *umlc = classifier(); +- if (!umlc) { +- uError() << "Internal error - classifier() returns NULL"; +- return; +- } +- if (Object_Factory::createChildObject(umlc, ot)) { +- updateGeometry(); +- update(); +- UMLApp::app()->document()->setModified(); +- } +- break; +- } +- case ListPopupMenu::mt_Show_Operations: +- toggleVisualProperty(ShowOperations); +- break; +- +- case ListPopupMenu::mt_Show_Attributes: +- toggleVisualProperty(ShowAttributes); +- break; +- +- case ListPopupMenu::mt_Show_Documentation: +- toggleVisualProperty(ShowDocumentation); +- break; +- +- case ListPopupMenu::mt_Show_Public_Only: +- toggleVisualProperty(ShowPublicOnly); +- break; +- +- case ListPopupMenu::mt_Show_Operation_Signature: +- toggleVisualProperty(ShowOperationSignature); +- break; +- +- case ListPopupMenu::mt_Show_Attribute_Signature: +- toggleVisualProperty(ShowAttributeSignature); +- break; +- +- case ListPopupMenu::mt_Visibility: +- toggleVisualProperty(ShowVisibility); +- break; +- +- case ListPopupMenu::mt_Show_Packages: +- toggleVisualProperty(ShowPackage); +- break; +- +- case ListPopupMenu::mt_Show_Stereotypes: +- toggleVisualProperty(ShowStereotype); +- break; +- +- case ListPopupMenu::mt_DrawAsCircle: +- toggleVisualProperty(DrawAsCircle); +- break; +- +- case ListPopupMenu::mt_ChangeToClass: +- changeToClass(); +- break; +- +- case ListPopupMenu::mt_ChangeToInterface: +- changeToInterface(); +- break; +- +- case ListPopupMenu::mt_ChangeToPackage: +- changeToPackage(); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- break; +- } +-} +- +-/** +- * Slot to show/hide attributes based on \a state. +- */ +-void ClassifierWidget::slotShowAttributes(bool state) +-{ +- setVisualProperty(ShowAttributes, state); +-} +- +-/** +- * Slot to show/hide operations based on \a state. +- */ +-void ClassifierWidget::slotShowOperations(bool state) +-{ +- setVisualProperty(ShowOperations, state); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.h umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,146 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef CLASSIFIERWIDGET_H +-#define CLASSIFIERWIDGET_H +- +-#include "basictypes.h" +-#include "umlobject.h" +-#include "umlwidget.h" +- +-class AssociationWidget; +-class FloatingTextWidget; +-class QPainter; +-class UMLClassifier; +- +-/** +- * @short Common implementation for class widget and interface widget +- * +- * @author Oliver Kellogg +- * @author Gopala Krishna +- * +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ClassifierWidget : public UMLWidget +-{ +- Q_OBJECT +- Q_ENUMS(VisualProperty) +-public: +- /** +- * This enumeration lists the visual properties that can be easily +- * set, reset and toggled and all these operate on an integer +- * which stores all the flag status. +- */ +- enum VisualProperty { +- ShowStereotype = 0x1, +- ShowOperations = 0x2, +- ShowPublicOnly = 0x4, +- ShowVisibility = 0x8, +- ShowPackage = 0x10, +- ShowAttributes = 0x20, +- DrawAsCircle = 0x40, +- ShowOperationSignature = 0x60, ///< only in setter +- ShowAttributeSignature = 0x80, ///< only in setter +- DrawAsPackage = 0x100, +- ShowDocumentation = 0x200, +- }; +- +- Q_DECLARE_FLAGS(VisualProperties, VisualProperty) +- +- ClassifierWidget(UMLScene * scene, UMLClassifier * o); +- ClassifierWidget(UMLScene * scene, UMLPackage * o); +- virtual ~ClassifierWidget(); +- +- UMLClassifier *classifier() const; +- +- VisualProperties visualProperties() const; +- void setVisualProperties(VisualProperties properties); +- +- bool visualProperty(VisualProperty property) const; +- void setVisualProperty(VisualProperty property, bool enable = true); +- void setVisualPropertyCmd(VisualProperty property, bool enable = true); +- void toggleVisualProperty(VisualProperty property); +- +- int displayedAttributes() const; +- int displayedOperations() const; +- +- Uml::SignatureType::Enum attributeSignature() const; +- void setAttributeSignature(Uml::SignatureType::Enum sig); +- +- Uml::SignatureType::Enum operationSignature() const; +- void setOperationSignature(Uml::SignatureType::Enum sig); +- +- void setShowAttSigs(bool _show); +- void toggleShowAttSigs(); +- +- bool getDrawAsCircle() const; +- void setDrawAsCircle(bool drawAsCircle); +- void toggleDrawAsCircle(); +- +- void changeToClass(); +- void changeToInterface(); +- void changeToPackage(); +- +- AssociationWidget *classAssociationWidget() const; +- void setClassAssociationWidget(AssociationWidget *assocwidget); +-// virtual void adjustAssociations(int x, int y); +- +- UMLWidget* onWidget(const QPointF& p); +- UMLWidget* widgetWithID(Uml::ID::Type id); +- +- virtual void setDocumentation(const QString& doc); +- +- QSizeF calculateSize(bool withExtensions = true) const; +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- virtual QPainterPath shape() const; +- +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- virtual bool loadFromXMI(QDomElement & qElement); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-private Q_SLOTS: +- void slotShowAttributes(bool state); +- void slotShowOperations(bool state); +- +-private: +- void updateSignatureTypes(); +- QSize calculateTemplatesBoxSize() const; +- +- QSizeF minimumSize() const; +- +- void drawAsCircle(QPainter *p, const QStyleOptionGraphicsItem *option); +- QSize calculateAsCircleSize() const; +- +- void drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option); +- QSize calculateAsPackageSize() const; +- +- int displayedMembers(UMLObject::ObjectType ot) const; +- void drawMembers(QPainter *painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, +- int x, int y, int fontHeight); +- +- static const int MARGIN; ///< text width margin +- static const int CIRCLE_SIZE; ///< size of circle when interface is rendered as such +- static const int SOCKET_INCREMENT; ///< augmentation of circle for socket (required interface) +- +- VisualProperties m_visualProperties; +- Uml::SignatureType::Enum m_attributeSignature; ///< Loaded/saved item. +- Uml::SignatureType::Enum m_operationSignature; ///< Loaded/saved item. +- AssociationWidget *m_pAssocWidget; ///< related AssociationWidget in case this classifier acts as an association class +- FloatingTextWidget *m_pInterfaceName; ///< Separate widget for name in case of interface drawn as circle +- +-}; +- +-Q_DECLARE_OPERATORS_FOR_FLAGS(ClassifierWidget::VisualProperties) +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,477 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "combinedfragmentwidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "dialog_utils.h" +-#include "listpopupmenu.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +-#include +- +-/** +- * Creates a Combined Fragment widget. +- * +- * @param scene The parent of the widget. +- * @param combinedfragmentType The type of combined fragment. +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-CombinedFragmentWidget::CombinedFragmentWidget(UMLScene * scene, CombinedFragmentType combinedfragmentType, Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_CombinedFragment, id) +-{ +- setCombinedFragmentType(combinedfragmentType); +-} +- +-/** +- * Destructor. +- */ +-CombinedFragmentWidget::~CombinedFragmentWidget() +-{ +- for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { +- delete(*it); +- } +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void CombinedFragmentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- int w = width(); +- int h = height(); +- int line_width = 45; +- int old_Y; +- +- setPenFromSettings(painter); +- +- if (m_CombinedFragment == Ref) { +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } +- } +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const QString combined_fragment_value = name(); +- int textStartY = (h / 2) - (fontHeight / 2); +- painter->drawRect(0, 0, w, h); +- +- painter->setPen(textColor()); +- painter->setFont(UMLWidget::font()); +- QString temp = QLatin1String("loop"); +- +- switch (m_CombinedFragment) +- { +- case Ref : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, textStartY, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignCenter, combined_fragment_value); +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("ref")); +- break; +- +- case Opt : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("opt")); +- break; +- +- case Break : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("break")); +- break; +- +- case Loop : +- if (combined_fragment_value != QLatin1String("-")) +- { +- temp += QLatin1String(" [") + combined_fragment_value + QLatin1Char(']'); +- line_width += (combined_fragment_value.size() + 2) * 8; +- } +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); +- +- break; +- +- case Neg : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("neg")); +- break; +- +- case Crit : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("critical")); +- break; +- +- case Ass : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("assert")); +- break; +- +- case Alt : +- if (combined_fragment_value != QLatin1String("-")) +- { +- temp = QLatin1Char('[') + combined_fragment_value + QLatin1Char(']'); +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 20, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); +- if (m_dashLines.size() == 1 && m_dashLines.first()->y() < y() + 20 + fontHeight) +- m_dashLines.first()->setY(y() + h/2); +- } +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("alt")); +- // dash lines +- //m_dashLines.first()->paint(painter); +- // TODO: move to UMLWidget::calculateSize api +- for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { +- (*it)->setX(x()); +- old_Y = (*it)->getYMin(); +- (*it)->setYMin(y()); +- (*it)->setYMax(y() + height()); +- (*it)->setY(y() + (*it)->y() - old_Y); +- (*it)->setSize(w, (*it)->height()); +- (*it)->setLineColor(lineColor()); +- (*it)->setLineWidth(lineWidth()); +- } +- +- break; +- +- case Par : +- painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, +- w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("parallel")); +- // dash lines +- if (m_dashLines.size() != 0) { +- //m_dashLines.first()->paint(painter); +- // TODO: move to UMLWidget::calculateSize api +- for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { +- (*it)->setX(x()); +- old_Y = (*it)->getYMin(); +- (*it)->setYMin(y()); +- (*it)->setYMax(y() + height()); +- (*it)->setY(y() + (*it)->y() - old_Y); +- (*it)->setSize(w, (*it)->height()); +- (*it)->setLineColor(lineColor()); +- (*it)->setLineWidth(lineWidth()); +- } +- } +- break; +- +- default : break; +- } +- +- setPenFromSettings(painter); +- painter->drawLine(0, 20, line_width, 20); +- painter->drawLine(line_width, 20, line_width + 10, 10); +- painter->drawLine(line_width + 10, 10, line_width + 10, 0); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF CombinedFragmentWidget::minimumSize() const +-{ +- int width = 10, height = 10; +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int textWidth = fm.width(name()); +- height = fontHeight; +- width = textWidth + 60 > COMBINED_FRAGMENT_WIDTH ? textWidth + 60: COMBINED_FRAGMENT_WIDTH; +- if (m_CombinedFragment == Loop) +- width += int((float)textWidth * 0.4f); +- if (m_CombinedFragment == Alt) +- height += fontHeight + 40; +- height = height > COMBINED_FRAGMENT_HEIGHT ? height : COMBINED_FRAGMENT_HEIGHT; +- width += COMBINED_FRAGMENT_MARGIN * 2; +- height += COMBINED_FRAGMENT_MARGIN * 2; +- +- return QSizeF(width, height); +-} +- +-/** +- * Returns the type of combined fragment. +- */ +-CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType() const +-{ +- return m_CombinedFragment; +-} +- +-/** +- * Sets the type of combined fragment. +- */ +-void CombinedFragmentWidget::setCombinedFragmentType(CombinedFragmentType combinedfragmentType) +-{ +- m_CombinedFragment = combinedfragmentType; +- UMLWidget::m_resizable = true ; //(m_CombinedFragment == Normal); +- // creates a dash line if the combined fragment type is alternative or parallel +- if (m_CombinedFragment == Alt && m_dashLines.isEmpty()) +- { +- m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); +- if (m_CombinedFragment == Alt) +- { +- m_dashLines.back()->setText(QLatin1String("else")); +- } +- // TODO: move to UMLWidget::calculateSize api +- m_dashLines.back()->setX(x()); +- m_dashLines.back()->setYMin(y()); +- m_dashLines.back()->setYMax(y() + height()); +- m_dashLines.back()->setY(y() + height()/2); +- m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); +- m_scene->widgetList().append(m_dashLines.back()); +- } +-} +- +-/** +- * Returns the type of combined fragment. +- */ +-CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType(const QString& type) const +-{ +- if (type == QLatin1String("Reference")) +- return (CombinedFragmentWidget::Ref); +- if (type == QLatin1String("Option")) +- return (CombinedFragmentWidget::Opt); +- if (type == QLatin1String("Break")) +- return (CombinedFragmentWidget::Break); +- if (type == QLatin1String("Loop")) +- return (CombinedFragmentWidget::Loop); +- if (type == QLatin1String("Negative")) +- return (CombinedFragmentWidget::Neg); +- if (type == QLatin1String("Critical")) +- return (CombinedFragmentWidget::Crit); +- if (type == QLatin1String("Assertion")) +- return (CombinedFragmentWidget::Ass); +- if (type == QLatin1String("Alternative")) +- return (CombinedFragmentWidget::Alt); +- if (type == QLatin1String("Parallel")) +- return (CombinedFragmentWidget::Par); +- // Shouldn't happen +- Q_ASSERT(0); +- return (CombinedFragmentWidget::Ref); +-} +- +-/** +- * Sets the type of combined fragment. +- */ +-void CombinedFragmentWidget::setCombinedFragmentType(const QString& combinedfragmentType) +-{ +- setCombinedFragmentType(combinedFragmentType(combinedfragmentType)); +-} +- +-/** +- * ... +- */ +-void CombinedFragmentWidget::askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, +- const QString& dialogPrompt, const QString& defaultName) +-{ +- Q_UNUSED(defaultName); +- bool pressedOK = false; +- const QStringList list = QStringList() +- << QLatin1String("Reference") +- << QLatin1String("Option") +- << QLatin1String("Break") +- << QLatin1String("Loop") +- << QLatin1String("Negative") +- << QLatin1String("Critical") +- << QLatin1String("Assertion") +- << QLatin1String("Alternative") +- << QLatin1String("Parallel") ; +-#if QT_VERSION >= 0x050000 +- QPointer inputDlg = new QInputDialog(); +- inputDlg->setComboBoxItems(list); +- inputDlg->setOptions(QInputDialog::UseListViewForComboBoxItems); +- inputDlg->setWindowTitle(dialogTitle); +- inputDlg->setLabelText(dialogPrompt); +- pressedOK = inputDlg->exec(); +- QStringList result; +- result.append(inputDlg->textValue()); +- delete inputDlg; +-#else +- const QStringList select = list; +- QStringList result = KInputDialog::getItemList (dialogTitle, dialogPrompt, list, select, false, &pressedOK, UMLApp::app()); +-#endif +- if (pressedOK) { +- QString type = result.join(QString()); +- dynamic_cast(targetWidget)->setCombinedFragmentType(type); +- if (type == QLatin1String("Reference")) +- Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the diagram referenced"), i18n("Enter the name of the diagram referenced"), i18n("Diagram name")); +- else if (type == QLatin1String(QLatin1String("Loop"))) +- Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop"), i18n("-")); +- else if (type == QLatin1String("Alternative")) +- Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the first alternative name"), i18n("Enter the first alternative name"), i18n("-")); +- } else { +- targetWidget->cleanup(); +- delete targetWidget; +- targetWidget = NULL; +- } +-} +- +-/** +- * Saves the widget to the "combinedFragmentwidget" XMI element. +- */ +-void CombinedFragmentWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement combinedFragmentElement = qDoc.createElement(QLatin1String("combinedFragmentwidget")); +- UMLWidget::saveToXMI(qDoc, combinedFragmentElement); +- combinedFragmentElement.setAttribute(QLatin1String("combinedFragmentname"), m_Text); +- combinedFragmentElement.setAttribute(QLatin1String("documentation"), m_Doc); +- combinedFragmentElement.setAttribute(QLatin1String("CombinedFragmenttype"), m_CombinedFragment); +- +- // save the corresponding floating dash lines +- for (QList::iterator it = m_dashLines.begin() ; it != m_dashLines.end() ; ++it) { +- (*it)-> saveToXMI(qDoc, combinedFragmentElement); +- } +- +- qElement.appendChild(combinedFragmentElement); +-} +- +-/** +- * Loads the widget from the "CombinedFragmentwidget" XMI element. +- */ +-bool CombinedFragmentWidget::loadFromXMI(QDomElement & qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) +- return false; +- m_Text = qElement.attribute(QLatin1String("combinedFragmentname")); +- m_Doc = qElement.attribute(QLatin1String("documentation")); +- QString type = qElement.attribute(QLatin1String("CombinedFragmenttype")); +- +- //now load child elements +- QDomNode node = qElement.firstChild(); +- QDomElement element = node.toElement(); +- while (!element.isNull()) { +- QString tag = element.tagName(); +- if (tag == QLatin1String("floatingdashlinewidget")) { +- FloatingDashLineWidget * fdlwidget = new FloatingDashLineWidget(m_scene, Uml::ID::None, this); +- m_dashLines.push_back(fdlwidget); +- if (!fdlwidget->loadFromXMI(element)) { +- // Most likely cause: The FloatingTextWidget is empty. +- delete m_dashLines.back(); +- return false; +- } +- else { +- m_scene->widgetList().append(fdlwidget); +- fdlwidget->clipSize(); +- } +- } else { +- uError() << "unknown tag " << tag; +- } +- node = node.nextSibling(); +- element = node.toElement(); +- } +- // m_dashLines = listline; +- setCombinedFragmentType((CombinedFragmentType)type.toInt()); +- +- return true; +-} +- +-void CombinedFragmentWidget::removeDashLine(FloatingDashLineWidget *line) +-{ +- if (m_dashLines.contains(line)) +- m_dashLines.removeOne(line); +-} +- +-/** +- * Overrides the function from UMLWidget. Deletes all FloatingDashLineWidgets +- * that are associated with this instance. +- */ +-void CombinedFragmentWidget::cleanup() +-{ +- foreach (FloatingDashLineWidget* w, m_dashLines) +- { +- if (!w->isSelected()) { +- // no need to make this undoable, since the dashlines will be +- // reconstructed when deleting the combined fragment is undone. +- umlScene()->removeWidgetCmd(w); +- } +- } +-} +- +-/** +- * Overrides the function from UMLWidget. +- * +- * @param action The command to be executed. +- */ +-void CombinedFragmentWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch (sel) { +- // for alternative or parallel combined fragments +- case ListPopupMenu::mt_AddInteractionOperand: +- m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); +- if (m_CombinedFragment == Alt) +- { +- m_dashLines.back()->setText(QLatin1String("else")); +- } +- // TODO: move to UMLWidget::calculateSize api +- m_dashLines.back()->setX(x()); +- m_dashLines.back()->setYMin(y()); +- m_dashLines.back()->setYMax(y() + height()); +- m_dashLines.back()->setY(y() + height() / 2); +- m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); +- m_scene->setupNewWidget(m_dashLines.back()); +- break; +- +- case ListPopupMenu::mt_Rename: +- { +- bool ok = false; +- QString name = m_Text; +- +-#if QT_VERSION >= 0x050000 +- if (m_CombinedFragment == Alt) { +- name = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter first alternative"), i18n("Enter first alternative :"), +- QLineEdit::Normal, +- m_Text, &ok); +- } +- else if (m_CombinedFragment == Ref) { +- name = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), +- QLineEdit::Normal, +- m_Text, &ok); +- } +- else if (m_CombinedFragment == Loop) { +- name = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), +- QLineEdit::Normal, +- m_Text, &ok); +- } +-#else +- if (m_CombinedFragment == Alt) { +- name = KInputDialog::getText(i18n("Enter first alternative"), i18n("Enter first alternative :"), m_Text, &ok); +- } +- else if (m_CombinedFragment == Ref) { +- name = KInputDialog::getText(i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), m_Text, &ok); +- } +- else if (m_CombinedFragment == Loop) { +- name = KInputDialog::getText(i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), m_Text, &ok); +- } +-#endif +- if (ok && name.length() > 0) +- m_Text = name; +- } +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.h umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,91 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef COMBINEDFRAGMENTWIDGET_H +-#define COMBINEDFRAGMENTWIDGET_H +- +-#include "umlwidget.h" +-#include "worktoolbar.h" +-#include "floatingdashlinewidget.h" +- +-#include +- +-#define COMBINED_FRAGMENT_MARGIN 5 +-#define COMBINED_FRAGMENT_WIDTH 100 +-#define COMBINED_FRAGMENT_HEIGHT 50 +- +-/** +- * This class is the graphical version of a UML combined fragment. A combinedfragmentWidget is created +- * by a @ref UMLView. An combinedfragmentWidget belongs to only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. +- * +- * The combinedfragmentWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @short A graphical version of a UML combined fragment. +- * @author Hassan KOUCH +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class CombinedFragmentWidget : public UMLWidget +-{ +- Q_OBJECT +- +-public: +- enum CombinedFragmentType +- { +- Ref = 0, +- Opt, +- Break, +- Loop, +- Neg, +- Crit, +- Ass, +- Alt, +- Par +- }; +- +- explicit CombinedFragmentWidget(UMLScene * scene, +- CombinedFragmentType combinedfragmentType = Ref, +- Uml::ID::Type id = Uml::ID::None); +- virtual ~CombinedFragmentWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- CombinedFragmentType combinedFragmentType() const; +- CombinedFragmentType combinedFragmentType(const QString& combinedfragmentType) const; +- void setCombinedFragmentType(CombinedFragmentType combinedfragmentType); +- void setCombinedFragmentType(const QString& combinedfragmentType); +- +- void askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, +- const QString& dialogPrompt, const QString& defaultName); +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- bool loadFromXMI(QDomElement & qElement); +- void removeDashLine(FloatingDashLineWidget *line); +- +- virtual void cleanup(); +- +-public slots: +- void slotMenuSelection(QAction* action); +- +- +-protected: +- QSizeF minimumSize() const; +- +- /// Type of CombinedFragment. +- CombinedFragmentType m_CombinedFragment; +- +-private: +- /// Dash lines of an alternative or parallel combined fragment +- QList m_dashLines ; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,207 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "componentwidget.h" +- +-// app includes +-#include "component.h" +-#include "debug_utils.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "optionstate.h" +-#include "umldoc.h" +-#include "package.h" +-#include "portwidget.h" +- +-/** +- * Constructs a ComponentWidget. +- * +- * @param scene The parent of this ComponentWidget. +- * @param c The UMLComponent this will be representing. +- */ +-ComponentWidget::ComponentWidget(UMLScene * scene, UMLComponent *c) +- : UMLWidget(scene, WidgetBase::wt_Component, c) +-{ +- setSize(100, 30); +- //set defaults from m_scene +- if (m_scene) { +- //check to see if correct +- const Settings::OptionState& ops = m_scene->optionState(); +- m_showStereotype = ops.classState.showStereoType; +- } +-} +- +-/** +- * Destructor. +- */ +-ComponentWidget::~ComponentWidget() +-{ +-} +- +-/** +- * Reimplemented from UMLWidget::paint to paint component +- * widget. +- */ +-void ComponentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- UMLComponent *umlcomp = static_cast(m_umlObject); +- if (umlcomp == NULL) +- return; +- setPenFromSettings(painter); +- QPen origPen = painter->pen(); +- QPen pen = origPen; +- if (umlcomp->getExecutable()) { +- pen.setWidth(origPen.width() + 2); +- painter->setPen(pen); +- } +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } else { +- painter->setBrush(m_scene->backgroundColor()); +- } +- +- const int w = width(); +- const int h = height(); +- const int halfHeight = h / 2; +- int textXOffset = 0; +- QFont font = UMLWidget::font(); +- font.setBold(true); +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- QString nameStr = name(); +- const QString stereotype = m_umlObject->stereotype(); +- +- if (Settings::optionState().generalState.uml2) { +- painter->drawRect(0, 0, w, h); +- // draw small component symbol in upper right corner +- painter->setPen(origPen); +- painter->drawRect(w - 17, 5, 11, 13); +- painter->drawRect(w - 19, 7, 2, 2); +- painter->drawRect(w - 19, 11, 2, 2); +- painter->setPen(pen); +- } else { +- painter->drawRect(2*COMPONENT_MARGIN, 0, w - 2*COMPONENT_MARGIN, h); +- painter->drawRect(0, halfHeight - fontHeight/2 - fontHeight, COMPONENT_MARGIN*4, fontHeight); +- painter->drawRect(0, halfHeight + fontHeight/2, COMPONENT_MARGIN*4, fontHeight); +- textXOffset = COMPONENT_MARGIN * 4; +- } +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- int lines = 1; +- +- if (!stereotype.isEmpty()) { +- painter->drawText(textXOffset, halfHeight - fontHeight, +- w - textXOffset, fontHeight, Qt::AlignCenter, +- m_umlObject->stereotype(true)); +- lines = 2; +- } +- +- if (UMLWidget::isInstance()) { +- font.setUnderline(true); +- painter->setFont(font); +- nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; +- } +- +- if (lines == 1) { +- painter->drawText(textXOffset, halfHeight - (fontHeight/2), +- w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); +- } else { +- painter->drawText(textXOffset, halfHeight, +- w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overridden from UMLWidget due to emission of signal sigCompMoved() +- */ +-void ComponentWidget::moveWidgetBy(qreal diffX, qreal diffY) +-{ +- UMLWidget::moveWidgetBy(diffX, diffY); +- emit sigCompMoved(diffX, diffY); +-} +- +-/** +- * Override method from UMLWidget for adjustment of attached PortWidgets. +- */ +-void ComponentWidget::adjustAssocs(qreal dx, qreal dy) +-{ +- if (m_doc->loading()) { +- // don't recalculate the assocs during load of XMI +- // -> return immediately without action +- return; +- } +- UMLWidget::adjustAssocs(dx, dy); +- UMLPackage *comp = static_cast(m_umlObject); +- foreach (UMLObject *o, comp->containedObjects()) { +- uIgnoreZeroPointer(o); +- if (o->baseType() != UMLObject::ot_Port) +- continue; +- UMLWidget *portW = m_scene->widgetOnDiagram(o->id()); +- if (portW) +- portW->adjustAssocs(dx, dy); +- } +-} +- +-/** +- * Saves to the "componentwidget" XMI element. +- */ +-void ComponentWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("componentwidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- qElement.appendChild(conceptElement); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF ComponentWidget::minimumSize() const +-{ +- if (!m_umlObject) { +- return QSizeF(70, 70); +- } +- const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); +- const int fontHeight = fm.lineSpacing(); +- +- QString name = m_umlObject->name(); +- if (UMLWidget::isInstance()) { +- name = UMLWidget::instanceName() + QLatin1String(" : ") + name; +- } +- +- int width = fm.width(name); +- +- int stereoWidth = 0; +- if (!m_umlObject->stereotype().isEmpty()) { +- stereoWidth = fm.width(m_umlObject->stereotype(true)); +- } +- if (stereoWidth > width) +- width = stereoWidth; +- width += COMPONENT_MARGIN * 6; +- width = 70>width ? 70 : width; //minumin width of 70 +- +- int height = (2*fontHeight) + (COMPONENT_MARGIN * 3); +- +- UMLComponent *umlcomp = static_cast(m_umlObject); +- if (umlcomp && umlcomp->getExecutable()) { +- width += 2; +- height += 2; +- } +- +- return QSizeF(width, height); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.h umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,58 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef COMPONENTWIDGET_H +-#define COMPONENTWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLComponent; +- +-#define COMPONENT_MARGIN 10 +- +-/** +- * Defines a graphical version of the Component. Most of the functionality +- * will come from the @ref UMLComponent class. +- * +- * @short A graphical version of a Component. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ComponentWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- ComponentWidget(UMLScene * scene, UMLComponent *c); +- virtual ~ComponentWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- virtual void moveWidgetBy(qreal diffX, qreal diffY); +- virtual void adjustAssocs(qreal dx, qreal dy); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-signals: +- /** +- * Emitted when the component widget is moved. +- * Provides the delta X and delta Y amount by which the widget was moved +- * relative to the previous position. +- * Slots into PortWidget::slotCompMoved() +- * @param diffX The difference between previous and new X value. +- * @param diffY The difference between previous and new Y value. +- */ +- void sigCompMoved(qreal diffX, qreal diffY); +- +-protected: +- QSizeF minimumSize() const; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,129 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "datatypewidget.h" +- +-// app includes +-#include "classifier.h" +-#include "classifierlistitem.h" +-#include "debug_utils.h" +-#include "operation.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// qt includes +-#include +- +-/** +- * Constructs an DatatypeWidget. +- * +- * @param scene The parent of this DatatypeWidget. +- * @param d The UMLClassifier this will be representing. +- */ +-DatatypeWidget::DatatypeWidget(UMLScene *scene, UMLClassifier *d) +- : UMLWidget(scene, WidgetBase::wt_Datatype, d) +-{ +- setSize(100, 30); +-} +- +-/** +- * Standard deconstructor. +- */ +-DatatypeWidget::~DatatypeWidget() +-{ +-} +- +-/** +- * Overrides standard method. +- */ +-void DatatypeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } else { +- painter->setBrush(m_scene->backgroundColor()); +- } +- +- int w = width(); +- int h = height(); +- +- QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- int fontHeight = fm.lineSpacing(); +- +- painter->drawRect(0, 0, w, h); +- painter->setPen(textColor()); +- +- QFont font = UMLWidget::font(); +- font.setBold(true); +- painter->setFont(font); +- painter->drawText(DATATYPE_MARGIN, 0, +- w - DATATYPE_MARGIN* 2, fontHeight, +- Qt::AlignCenter, m_umlObject->stereotype(true)); +- +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- painter->drawText(DATATYPE_MARGIN, fontHeight, +- w - DATATYPE_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Loads from a "datatypewidget" XMI element. +- */ +-bool DatatypeWidget::loadFromXMI(QDomElement & qElement) +-{ +- return UMLWidget::loadFromXMI(qElement); +-} +- +-/** +- * Saves to the "datatypewidget" XMI element. +- */ +-void DatatypeWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("datatypewidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- qElement.appendChild(conceptElement); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF DatatypeWidget::minimumSize() const +-{ +- if (!m_umlObject) { +- return UMLWidget::minimumSize(); +- } +- int width, height; +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- +- int lines = 1;//always have one line - for name +- lines++; //for the stereotype +- +- height = width = 0; +- height += lines * fontHeight; +- +- //now set the width of the concept +- //set width to name to start with +- //set width to name to start with +- width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); +- int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); +- +- width = w > width?w:width; +- +- //allow for width margin +- width += DATATYPE_MARGIN * 2; +- +- return QSizeF(width, height); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.h umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,48 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef DATATYPEWIDGET_H +-#define DATATYPEWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLClassifier; +- +-#define DATATYPE_MARGIN 5 +- +-/** +- * Defines a graphical version of the datatype. Most of the functionality +- * will come from the @ref UMLWidget class from which class inherits from. +- * +- * @short A graphical version of an datatype. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class DatatypeWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- DatatypeWidget(UMLScene *scene, UMLClassifier *d); +- virtual ~DatatypeWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- bool loadFromXMI(QDomElement& qElement); +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-public Q_SLOTS: +- +-protected: +- QSizeF minimumSize() const; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,246 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "entitywidget.h" +- +-// app includes +-#include "classifier.h" +-#include "classifierlistitem.h" +-#include "debug_utils.h" +-#include "entity.h" +-#include "entityattribute.h" +-#include "foreignkeyconstraint.h" +-#include "listpopupmenu.h" +-#include "object_factory.h" +-#include "uml.h" +-#include "umlclassifierlistitemlist.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "uniqueconstraint.h" +- +-/** +- * Constructs an EntityWidget. +- * +- * @param scene The parent of this EntityWidget. +- * @param o The UMLObject this will be representing. +- */ +-EntityWidget::EntityWidget(UMLScene *scene, UMLObject* o) +- : UMLWidget(scene, WidgetBase::wt_Entity, o) +-{ +- setSize(100, 30); +-} +- +-/** +- * Destructor. +- */ +-EntityWidget::~EntityWidget() +-{ +-} +- +-/** +- * Draws the entity as a rectangle with a box underneith with a list of literals +- */ +-void EntityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- setPenFromSettings(painter); +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- else +- painter->setBrush(m_scene->backgroundColor()); +- +- const int w = width(); +- const int h = height(); +- +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- int fontHeight = fm.lineSpacing(); +- const QString name = this->name(); +- +- painter->drawRect(0, 0, w, h); +- painter->setPen(textColor()); +- +- QFont font = UMLWidget::font(); +- font.setBold(true); +- painter->setFont(font); +- int y = 0; +- if (!m_umlObject->stereotype().isEmpty()) { +- painter->drawText(ENTITY_MARGIN, 0, +- w - ENTITY_MARGIN * 2, fontHeight, +- Qt::AlignCenter, m_umlObject->stereotype(true)); +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- painter->drawText(ENTITY_MARGIN, fontHeight, +- w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); +- font.setBold(false); +- font.setItalic(false); +- painter->setFont(font); +- y = fontHeight * 2; +- } else { +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- painter->drawText(ENTITY_MARGIN, 0, +- w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); +- font.setBold(false); +- font.setItalic(false); +- painter->setFont(font); +- +- y = fontHeight; +- } +- +- setPenFromSettings(painter); +- +- painter->drawLine(0, y, w, y); +- +- QFontMetrics fontMetrics(font); +- UMLClassifier *classifier = (UMLClassifier*)m_umlObject; +- UMLClassifierListItem* entityattribute = 0; +- UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); +- foreach (entityattribute, list) { +- QString text = entityattribute->name(); +- painter->setPen(textColor()); +- UMLEntityAttribute* casted = dynamic_cast(entityattribute); +- if(casted && casted->indexType() == UMLEntityAttribute::Primary) +- { +- font.setUnderline(true); +- painter->setFont(font); +- font.setUnderline(false); +- } +- painter->drawText(ENTITY_MARGIN, y, +- fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); +- painter->setFont(font); +- y+=fontHeight; +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Saves to the "entitywidget" XMI element. +- */ +-void EntityWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("entitywidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- qElement.appendChild(conceptElement); +-} +- +-/** +- * Will be called when a menu selection has been made from the popup +- * menu. +- * +- * @param action The action that has been selected. +- */ +-void EntityWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_EntityAttribute: +- if (Object_Factory::createChildObject(static_cast(m_umlObject), +- UMLObject::ot_EntityAttribute)) { +- UMLApp::app()->document()->setModified(); +- } +- break; +- +- case ListPopupMenu::mt_PrimaryKeyConstraint: +- case ListPopupMenu::mt_UniqueConstraint: +- if (UMLObject* obj = Object_Factory::createChildObject(static_cast(m_umlObject), +- UMLObject::ot_UniqueConstraint)) { +- UMLApp::app()->document()->setModified(); +- +- if (sel == ListPopupMenu::mt_PrimaryKeyConstraint) { +- UMLUniqueConstraint* uc = static_cast(obj); +- static_cast(m_umlObject)->setAsPrimaryKey(uc); +- } +- } +- break; +- +- case ListPopupMenu::mt_ForeignKeyConstraint: +- if (Object_Factory::createChildObject(static_cast(m_umlObject), +- UMLObject::ot_ForeignKeyConstraint)) { +- UMLApp::app()->document()->setModified(); +- +- } +- break; +- +- case ListPopupMenu::mt_CheckConstraint: +- if (Object_Factory::createChildObject(static_cast(m_umlObject), +- UMLObject::ot_CheckConstraint)) { +- UMLApp::app()->document()->setModified(); +- +- } +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF EntityWidget::minimumSize() const +-{ +- if (!m_umlObject) { +- return UMLWidget::minimumSize(); +- } +- +- int width, height; +- QFont font = UMLWidget::font(); +- font.setItalic(false); +- font.setUnderline(false); +- font.setBold(false); +- const QFontMetrics fm(font); +- +- const int fontHeight = fm.lineSpacing(); +- +- int lines = 1;//always have one line - for name +- if (!m_umlObject->stereotype().isEmpty()) { +- lines++; +- } +- +- const int numberOfEntityAttributes = ((UMLEntity*)m_umlObject)->entityAttributes(); +- +- height = width = 0; +- //set the height of the entity +- +- lines += numberOfEntityAttributes; +- if (numberOfEntityAttributes == 0) { +- height += fontHeight / 2; //no entity literals, so just add a bit of space +- } +- +- height += lines * fontHeight; +- +- //now set the width of the concept +- //set width to name to start with +- // FIXME spaces to get round beastie with font width, +- // investigate UMLWidget::getFontMetrics() +- width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(QLatin1Char(' ') + name() + +- QLatin1Char(' ')).width(); +- const int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); +- +- width = w > width ? w : width; +- +- UMLClassifier* classifier = (UMLClassifier*)m_umlObject; +- UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); +- UMLClassifierListItem* listItem = 0; +- foreach (listItem, list) { +- int w = fm.width(listItem->name()); +- width = w > width?w:width; +- } +- +- //allow for width margin +- width += ENTITY_MARGIN * 2; +- +- return QSizeF(width, height); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.h umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,49 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENTITYWIDGET_H +-#define ENTITYWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLScene; +- +-#define ENTITY_MARGIN 5 +- +-/** +- * Defines a graphical version of the entity. Most of the functionality +- * will come from the @ref UMLWidget class from which class inherits from. +- * +- * @short A graphical version of an entity. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class EntityWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- explicit EntityWidget(UMLScene *scene, UMLObject* o); +- virtual ~EntityWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- // UMLWidget::loadFromXMI is used to load this widget. +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-protected: +- QSizeF minimumSize() const; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,262 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "enumwidget.h" +- +-// app includes +-#include "classifier.h" +-#include "classifierlistitem.h" +-#include "debug_utils.h" +-#include "enum.h" +-#include "enumliteral.h" +-#include "listpopupmenu.h" +-#include "object_factory.h" +-#include "uml.h" +-#include "umlclassifierlistitemlist.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-/** +- * Constructs an instance of EnumWidget. +- * +- * @param scene The parent of this EnumWidget. +- * @param o The UMLObject this will be representing. +- */ +-EnumWidget::EnumWidget(UMLScene *scene, UMLObject* o) +- : UMLWidget(scene, WidgetBase::wt_Enum, o), +- m_showPackage(false) +-{ +- setSize(100, 30); +- //set defaults from m_scene +- if (m_scene) { +- //check to see if correct +- const Settings::OptionState& ops = m_scene->optionState(); +- m_showPackage = ops.classState.showPackage; +- } else { +- // For completeness only. Not supposed to happen. +- m_showPackage = false; +- } +-} +- +-/** +- * Destructor. +- */ +-EnumWidget::~EnumWidget() +-{ +-} +- +-/** +- * Returns the status of whether to show Package. +- * +- * @return True if package is shown. +- */ +-bool EnumWidget::showPackage() const +-{ +- return m_showPackage; +-} +- +-/** +- * Set the status of whether to show Package. +- * +- * @param _status True if package shall be shown. +- */ +-void EnumWidget::setShowPackage(bool _status) +-{ +- m_showPackage = _status; +- updateGeometry(); +- update(); +-} +- +-/** +- * Toggles the status of whether to show package. +- */ +-void EnumWidget::toggleShowPackage() +-{ +- m_showPackage = !m_showPackage; +- updateGeometry(); +- update(); +-} +- +-/** +- * Draws the enum as a rectangle with a box underneith with a list of literals +- * Reimplemented from UMLWidget::paint +- */ +-void EnumWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- setPenFromSettings(painter); +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- else +- painter->setBrush(m_scene->backgroundColor()); +- +- const int w = width(); +- const int h = height(); +- +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- QString name; +- if (m_showPackage) { +- name = m_umlObject->fullyQualifiedName(); +- } else { +- name = this->name(); +- } +- +- painter->drawRect(0, 0, w, h); +- painter->setPen(textColor()); +- +- QFont font = UMLWidget::font(); +- font.setBold(true); +- painter->setFont(font); +- painter->drawText(ENUM_MARGIN, 0, +- w - ENUM_MARGIN * 2, fontHeight, +- Qt::AlignCenter, m_umlObject->stereotype(true)); +- +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- painter->drawText(ENUM_MARGIN, fontHeight, +- w - ENUM_MARGIN * 2, fontHeight, Qt::AlignCenter, name); +- font.setBold(false); +- font.setItalic(false); +- painter->setFont(font); +- +- int y = fontHeight * 2; +- +- setPenFromSettings(painter); +- +- painter->drawLine(0, y, w, y); +- +- QFontMetrics fontMetrics(font); +- UMLClassifier *classifier = (UMLClassifier*)m_umlObject; +- UMLClassifierListItem* enumLiteral = 0; +- UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); +- foreach (enumLiteral, list) { +- QString text = enumLiteral->name(); +- painter->setPen(textColor()); +- painter->drawText(ENUM_MARGIN, y, +- fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); +- y+=fontHeight; +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Loads from an "enumwidget" XMI element. +- */ +-bool EnumWidget::loadFromXMI(QDomElement & qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) { +- return false; +- } +- QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); +- +- m_showPackage = (bool)showpackage.toInt(); +- +- return true; +-} +- +-/** +- * Saves to the "enumwidget" XMI element. +- */ +-void EnumWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("enumwidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- +- conceptElement.setAttribute(QLatin1String("showpackage"), m_showPackage); +- qElement.appendChild(conceptElement); +-} +- +-/** +- * Will be called when a menu selection has been made from the +- * popup menu. +- * +- * @param action The action that has been selected. +- */ +-void EnumWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- if (sel == ListPopupMenu::mt_EnumLiteral) { +- if (Object_Factory::createChildObject(static_cast(m_umlObject), +- UMLObject::ot_EnumLiteral)) { +- /* I don't know why it works without these calls: +- updateComponentSize(); +- update(); +- */ +- UMLApp::app()->document()->setModified(); +- } +- return; +- } +- UMLWidget::slotMenuSelection(action); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF EnumWidget::minimumSize() const +-{ +- if (!m_umlObject) { +- return UMLWidget::minimumSize(); +- } +- +- int width, height; +- QFont font = UMLWidget::font(); +- font.setItalic(false); +- font.setUnderline(false); +- font.setBold(false); +- const QFontMetrics fm(font); +- +- const int fontHeight = fm.lineSpacing(); +- +- int lines = 1;//always have one line - for name +- lines++; //for the stereotype +- +- const int numberOfEnumLiterals = ((UMLEnum*)m_umlObject)->enumLiterals(); +- +- height = width = 0; +- //set the height of the enum +- +- lines += numberOfEnumLiterals; +- if (numberOfEnumLiterals == 0) { +- height += fontHeight / 2; //no enum literals, so just add a bit of space +- } +- +- height += lines * fontHeight; +- +- //now set the width of the concept +- //set width to name to start with +- if (m_showPackage) { +- width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); +- } else { +- width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(name()).width(); +- } +- int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); +- +- +- width = w > width?w:width; +- +- UMLClassifier *classifier = (UMLClassifier*)m_umlObject; +- UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); +- UMLClassifierListItem* listItem = 0; +- foreach (listItem, list) { +- int w = fm.width(listItem->name()); +- width = w > width?w:width; +- } +- +- //allow for width margin +- width += ENUM_MARGIN * 2; +- +- return QSizeF(width, height); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.h umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,52 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef ENUMWIDGET_H +-#define ENUMWIDGET_H +- +-#include "umlwidget.h" +- +-#define ENUM_MARGIN 5 +- +-/** +- * Defines a graphical version of the enum. Most of the functionality +- * will come from the @ref UMLWidget class from which class inherits from. +- * +- * @short A graphical version of an enum. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class EnumWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- explicit EnumWidget(UMLScene *scene, UMLObject* o); +- virtual ~EnumWidget(); +- +- bool showPackage() const; +- void setShowPackage(bool _status); +- void toggleShowPackage(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- virtual bool loadFromXMI(QDomElement& qElement); +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-protected: +- QSizeF minimumSize() const; +- +- bool m_showPackage; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,199 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +-// own header +-#include "floatingdashlinewidget.h" +-#include "combinedfragmentwidget.h" +- +-//kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +- +-//app includes +-#include "debug_utils.h" +-#include "umlview.h" +-#include "widget_utils.h" +-#include "listpopupmenu.h" +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +- +-DEBUG_REGISTER_DISABLED(FloatingDashLineWidget) +- +-/** +- * Creates a floating dash line. +- * @param scene The parent of the widget +- * @param id The ID to assign (-1 will prompt a new ID) +- * @param parent The CombinedFragmentWidget which acts as the parent +- */ +-FloatingDashLineWidget::FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id, CombinedFragmentWidget *parent) +- : UMLWidget(scene, WidgetBase::wt_FloatingDashLine, id), +- m_yMin(0), +- m_yMax(0), +- m_parent(parent) +-{ +- m_resizable = false; +- m_Text = QString(); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- setSize(10, fontHeight); +-} +- +-/** +- * Destructor. +- */ +-FloatingDashLineWidget::~FloatingDashLineWidget() +-{ +- if (m_parent) +- m_parent->removeDashLine(this); +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void FloatingDashLineWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- painter->setPen(textColor()); +- painter->setFont(UMLWidget::font()); +- painter->drawText(FLOATING_DASH_LINE_TEXT_MARGIN, 0, +- width() - FLOATING_DASH_LINE_TEXT_MARGIN * 2, fontHeight, +- Qt::AlignLeft, QLatin1Char('[') + m_Text + QLatin1Char(']')); +- painter->setPen(QPen(UMLWidget::lineColor(), 0, Qt::DashLine)); +- painter->drawLine(0, 0, width(), 0); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Sets m_text. +- */ +-void FloatingDashLineWidget::setText(const QString& text) +-{ +- m_Text = text; +-} +- +-/** +- * Returns true if the given point is near the floatingdashline. +- */ +-bool FloatingDashLineWidget::onLine(const QPointF& point) +-{ +- // check if the given point is the start or end point of the line +- if (((abs((long)(y() + height() - point.y()))) <= POINT_DELTA) || (abs((long)(y() - point.y())) <= POINT_DELTA)) { +- return true; +- } +- // check if the given point is the start or end point of the line +- return false; +-} +- +-void FloatingDashLineWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Rename: +- { +- bool ok = false; +- QString name = m_Text; +-#if QT_VERSION >= 0x050000 +- name = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter alternative Name"), i18n("Enter the alternative:"), +- QLineEdit::Normal, +- m_Text, &ok); +-#else +- name = KInputDialog::getText(i18n("Enter alternative Name"), i18n("Enter the alternative:"), m_Text, &ok); +-#endif +- if (ok && name.length() > 0) +- m_Text = name; +- } +- break; +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-/** +- * Overrides the setY method. +- */ +-void FloatingDashLineWidget::setY(qreal y) +-{ +- if(y >= m_yMin + FLOATING_DASH_LINE_MARGIN && y <= m_yMax - FLOATING_DASH_LINE_MARGIN) +- UMLWidget::setY(y); +-} +- +-/** +- * Sets m_yMin. +- */ +-void FloatingDashLineWidget::setYMin(qreal yMin) +-{ +- m_yMin = yMin; +-} +- +-/** +- * Sets m_yMax. +- */ +-void FloatingDashLineWidget::setYMax(qreal yMax) +-{ +- m_yMax = yMax; +-} +- +-/** +- * Returns m_yMin. +- */ +-qreal FloatingDashLineWidget::getYMin() const +-{ +- return m_yMin; +-} +- +-/** +- * Returns the difference between the y-coordinate of the dash line and m_yMin. +- */ +-qreal FloatingDashLineWidget::getDiffY() const +-{ +- return (y() - getYMin()); +-} +- +-/** +- * Creates the "floatingdashline" XMI element. +- */ +-void FloatingDashLineWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement textElement = qDoc.createElement(QLatin1String("floatingdashlinewidget")); +- UMLWidget::saveToXMI(qDoc, textElement); +- textElement.setAttribute(QLatin1String("text"), m_Text); +- textElement.setAttribute(QLatin1String("y"), y()); +- textElement.setAttribute(QLatin1String("minY"), m_yMin); +- textElement.setAttribute(QLatin1String("maxY"), m_yMax); +- +- qElement.appendChild(textElement); +-} +- +-/** +- * Loads the "floatingdashline" XMI element. +- */ +-bool FloatingDashLineWidget::loadFromXMI(QDomElement & qElement) +-{ +- if(!UMLWidget::loadFromXMI(qElement)) { +- return false; +- } +- DEBUG(DBG_SRC) << "load......."; +- m_yMax = qElement.attribute(QLatin1String("maxY")).toFloat(); +- m_yMin = qElement.attribute(QLatin1String("minY")).toFloat(); +- m_Text = qElement.attribute(QLatin1String("text")); +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.h umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,77 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef FLOATINGDASHLINEWIDGET_H +-#define FLOATINGDASHLINEWIDGET_H +- +-#include "umlwidget.h" +-class CombinedFragmentWidget; +- +-#define FLOATING_DASH_LINE_MARGIN 25 +-#define FLOATING_DASH_LINE_TEXT_MARGIN 5 +- +-/* how many pixels a user could click around a point */ +-#define POINT_DELTA 5 +- +-/** +- * This class is used to draw dash lines for UML combined fragments. A FloatingDashLineWidget +- * belongs to one @ref CombinedFragmentWidget instance. +- * +- * The FloatingDashLineWidget class inherits from the @ref UMLWidget class. +- * +- * @short A dash line for UML combined fragments. +- * @author Thomas GALLINARI +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class FloatingDashLineWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- explicit FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, CombinedFragmentWidget *parent = 0); +- ~FloatingDashLineWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option = 0, QWidget *widget = 0); +- +- void slotMenuSelection(QAction* action); +- +- bool onLine(const QPointF& point); +- +- void setText(const QString& text); +- +- void setY(qreal y); +- void setYMin(qreal yMin); +- void setYMax(qreal yMax); +- qreal getYMin() const; +- qreal getDiffY() const; +- +- void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- bool loadFromXMI(QDomElement & qElement); +- +-private: +- /** +- * Text associated to the dash line +- */ +- QString m_text; +- +- /** +- * Minimum value of the Y-coordinate of the dash line +- * (= y-coordinate of the combined fragment) +- */ +- int m_yMin; +- +- /** +- * Maximum value of the Y-coordinate of the dash line +- * (= y-coordinate of the combined fragment + height of the combined fragment) +- */ +- int m_yMax; +- CombinedFragmentWidget *m_parent; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,854 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "floatingtextwidget.h" +- +-// local includes +-#include "association.h" +-#include "associationwidget.h" +-#include "associationpropertiesdialog.h" +-#include "classifier.h" +-#include "cmds.h" +-#include "debug_utils.h" +-#include "linkwidget.h" +-#include "classifierwidget.h" +-#include "listpopupmenu.h" +-#include "messagewidget.h" +-#include "model_utils.h" +-#include "object_factory.h" +-#include "operation.h" +-#include "selectoperationdialog.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlview.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#include +-#endif +-#include +-#include +-#include +-#include +- +-DEBUG_REGISTER_DISABLED(FloatingTextWidget) +- +-/** +- * Constructs a FloatingTextWidget instance. +- * +- * @param scene The parent of this FloatingTextWidget. +- * @param role The role this FloatingTextWidget will take up. +- * @param text The main text to display. +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-FloatingTextWidget::FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role, const QString& text, Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_Text, id), +- m_linkWidget(0), +- m_preText(QString()), +- m_postText(QString()), +- m_textRole(role), +- m_unconstrainedPositionX(0), +- m_unconstrainedPositionY(0), +- m_movementDirectionX(0), +- m_movementDirectionY(0) +-{ +- m_Text = text; +- m_resizable = false; +- setZValue(10); //make sure always on top. +-} +- +-/** +- * Destructor. +- */ +-FloatingTextWidget::~FloatingTextWidget() +-{ +-} +- +-/** +- * Use to get the _main body_ of text (e.g. prepended and appended +- * text is omitted) as currently displayed by the widget. +- * +- * @return The main text currently being displayed by the widget. +- */ +-QString FloatingTextWidget::text() const +-{ +- // test to make sure not just the ":" between the seq number and +- // the actual message widget +- +- // hmm. this section looks like it could have been avoided by +- // using pre-, post- text instead of storing in the main body of +- // the text -b.t. +- if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self || +- m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self) { +- if (m_Text.length() <= 1 || m_Text == QLatin1String(": ")) +- return QString(); +- } +- return m_Text; +-} +- +-/** +- * Set the main body of text to display. +- * +- * @param t The text to display. +- */ +-void FloatingTextWidget::setText(const QString &t) +-{ +- if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { +- QString op; +- if (m_linkWidget) +- op = m_linkWidget->lwOperationText(); +- if (op.length() > 0) { +- if (!m_scene->showOpSig()) +- op.replace(QRegExp(QLatin1String("\\(.*\\)")), QLatin1String("()")); +- m_Text = op; +- } +- else +- m_Text = t; +- } +- else { +- m_Text = t; +- } +- +- QSizeF s = minimumSize(); +- setSize(s.width(), s.height()); +- +- updateGeometry(); +- update(); +-} +- +-/** +- * Set some text to be prepended to the main body of text. +- * @param t The text to prepend to main body which is displayed. +- */ +-void FloatingTextWidget::setPreText(const QString &t) +-{ +- m_preText = t; +- updateGeometry(); +- update(); +-} +- +-/** +- * Set some text to be appended to the main body of text. +- * @param t The text to append to main body which is displayed. +- */ +-void FloatingTextWidget::setPostText(const QString &t) +-{ +- m_postText = t; +- updateGeometry(); +- update(); +-} +- +-/** +- * Use to get the total text (prepended + main body + appended) +- * currently displayed by the widget. +- * +- * @return The text currently being displayed by the widget. +- */ +-QString FloatingTextWidget::displayText() const +-{ +- QString displayText; +- if (!m_SequenceNumber.isEmpty()) +- displayText = m_SequenceNumber + QLatin1String(": ") + m_Text; +- else +- displayText = m_Text; +- displayText.prepend(m_preText); +- displayText.append(m_postText); +- return displayText; +-} +- +-/** +- * Return state if no pre, post and main text is empty +- * @return true if widget contains no text +- */ +-bool FloatingTextWidget::isEmpty() +-{ +- return m_Text.isEmpty() && m_preText.isEmpty() && m_postText.isEmpty(); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF FloatingTextWidget::minimumSize() const +-{ +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- int h = fm.lineSpacing(); +- int w = fm.width(displayText()); +- return QSizeF(w + 8, h + 4); // give a small margin +-} +- +-/** +- * Method used by setText: its called by cmdsetTxt, Don't use it! +- * +- * @param t The text to display. +- */ +-void FloatingTextWidget::setTextcmd(const QString &t) +-{ +- UMLApp::app()->executeCommand(new Uml::CmdSetTxt(this, t)); +-} +- +-/** +- * Displays a dialog box to change the text. +- */ +-void FloatingTextWidget::showChangeTextDialog() +-{ +- bool ok = false; +-#if QT_VERSION >= 0x050000 +- QString newText = QInputDialog::getText(m_scene->activeView(), +- i18n("Change Text"), i18n("Enter new text:"), +- QLineEdit::Normal, +- text(), &ok); +-#else +- QString newText = KInputDialog::getText(i18n("Change Text"), i18n("Enter new text:"), text(), &ok, m_scene->activeView()); +-#endif +- if (ok && newText != text() && isTextValid(newText)) { +- setText(newText); +- setVisible(!text().isEmpty()); +- updateGeometry(); +- update(); +- } +- if (!isTextValid(newText)) +- hide(); +-} +- +-/** +- * Shows an operation dialog box. +- * +- * @param enableAutoIncrement Enable auto increment checkbox +- */ +-void FloatingTextWidget::showOperationDialog(bool enableAutoIncrement) +-{ +- if (!m_linkWidget) { +- uError() << "m_linkWidget is NULL"; +- return; +- } +- QString seqNum = m_linkWidget->sequenceNumber(); +- UMLClassifier* c = m_linkWidget->lwClassifier(); +- QString opText = m_linkWidget->lwOperationText(); +- if (!c) { +- uError() << "m_linkWidget->lwClassifier() returns a NULL classifier"; +- return; +- } +- +- QPointer selectDialog = new SelectOperationDialog(m_scene->activeView(), c, enableAutoIncrement); +- if (enableAutoIncrement && m_scene->autoIncrementSequence()) { +- seqNum = m_scene->autoIncrementSequenceValue(); +- selectDialog->setAutoIncrementSequence(true); +- } +- selectDialog->setSeqNumber(seqNum); +- if (m_linkWidget->operation() == 0) { +- selectDialog->setCustomOp(opText); +- } else { +- selectDialog->setClassOp(opText); +- } +- if (selectDialog->exec()) { +- seqNum = selectDialog->getSeqNumber(); +- opText = selectDialog->getOpText(); +- if (selectDialog->isClassOp()) { +- Model_Utils::OpDescriptor od; +- Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, c); +- if (st == Model_Utils::PS_OK) { +- UMLClassifierList selfAndAncestors = c->findSuperClassConcepts(); +- selfAndAncestors.prepend(c); +- UMLOperation *op = 0; +- foreach (UMLClassifier *cl, selfAndAncestors) { +- op = cl->findOperation(od.m_name, od.m_args); +- if (op) { +- break; +- } +- } +- if (!op) { +- // The op does not yet exist. Create a new one. +- UMLObject *o = c->createOperation(od.m_name, 0, &od.m_args); +- op = static_cast(o); +- } +- if (od.m_pReturnType) { +- op->setType(od.m_pReturnType); +- } +- +- m_linkWidget->setOperation(op); +- opText.clear(); +- } else { +- m_linkWidget->setOperation(0); +- } +- } else { +- m_linkWidget->setOperation(0); +- } +- m_linkWidget->setSequenceNumber(seqNum); +- m_linkWidget->setOperationText(opText); +- if (enableAutoIncrement) { +- m_scene->setAutoIncrementSequence(selectDialog->autoIncrementSequence()); +- } +- setMessageText(); +- } +- delete selectDialog; +-} +- +-/** +- * Show the properties for a FloatingTextWidget. +- * Depending on the role of the floating text wiget, the options dialog +- * for the floating text widget, the rename dialog for floating text or +- * the options dialog for the link widget are shown. +- */ +-void FloatingTextWidget::showPropertiesDialog() +-{ +- 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(false); +- } else if (m_textRole == Uml::TextRole::Floating) { +- // double clicking on a text line opens the dialog to change the text +- handleRename(); +- } else if (m_linkWidget) { +- m_linkWidget->showPropertiesDialog(); +- } +-} +- +-/** +- * Use to get the pre-text which is prepended to the main body of +- * text to be displayed. +- * +- * @return The pre-text currently displayed by the widget. +- */ +-QString FloatingTextWidget::preText() const +-{ +- return m_preText; +-} +- +-/** +- * Use to get the post-text which is appended to the main body of +- * text to be displayed. +- * +- * @return The post-text currently displayed by the widget. +- */ +-QString FloatingTextWidget::postText() const +-{ +- return m_postText; +-} +- +-/** +- * Activate the FloatingTextWidget after the saved data has been loaded +- * +- * @param ChangeLog Pointer to the IDChangeLog. +- * @return true for success +- */ +-bool FloatingTextWidget::activate(IDChangeLog* ChangeLog /*= 0 */) +-{ +- if (! UMLWidget::activate(ChangeLog)) +- return false; +- update(); +- return true; +-} +- +-/** +- * Set the LinkWidget that this FloatingTextWidget is related to. +- * +- * @param l The related LinkWidget. +- */ +-void FloatingTextWidget::setLink(LinkWidget * l) +-{ +- m_linkWidget = l; +-} +- +-/** +- * Returns the LinkWidget this floating text is related to. +- * +- * @return The LinkWidget this floating text is related to. +- */ +-LinkWidget * FloatingTextWidget::link() const +-{ +- return m_linkWidget; +-} +- +-/** +- * Sets the role type of this FloatingTextWidget. +- * +- * @param role The TextRole::Enum of this FloatingTextWidget. +- */ +-void FloatingTextWidget::setTextRole(Uml::TextRole::Enum role) +-{ +- m_textRole = role; +-} +- +-/** +- * Return the role of the text widget +- * @return The TextRole::Enum of this FloatingTextWidget. +- */ +-Uml::TextRole::Enum FloatingTextWidget::textRole() const +-{ +- return m_textRole; +-} +- +-/** +- * Handle the ListPopupMenu::mt_Rename case of the slotMenuSelection. +- * Given an own method because it requires rather lengthy code. +- */ +-void FloatingTextWidget::handleRename() +-{ +- QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); +- QString t; +- if (m_textRole == Uml::TextRole::RoleAName || m_textRole == Uml::TextRole::RoleBName) { +- t = i18n("Enter role name:"); +- } else if (m_textRole == Uml::TextRole::MultiA || m_textRole == Uml::TextRole::MultiB) { +- t = i18n("Enter multiplicity:"); +- /* +- // NO! shouldn't be allowed +- } else if (m_textRole == Uml::TextRole::ChangeA || m_textRole == Uml::TextRole::ChangeB) { +- t = i18n("Enter changeability"); +- */ +- } else if (m_textRole == Uml::TextRole::Name) { +- t = i18n("Enter association name:"); +- } else if (m_textRole == Uml::TextRole::Floating) { +- t = i18n("Enter new text:"); +- } else { +- t = i18n("ERROR"); +- } +- bool ok = false; +-#if QT_VERSION >= 0x050000 +- QString newText = QInputDialog::getText(m_scene->activeView(), +- i18n("Rename"), t, +- QLineEdit::Normal, +- text(), &ok); +-#else +- QString newText = KInputDialog::getText(i18n("Rename"), t, text(), &ok, m_scene->activeView(), &v); +-#endif +- if (!ok || newText == text()) { +- return; +- } +- +- UMLApp::app()->executeCommand(new Uml::CmdHandleRename(this, newText)); +-} +- +-/** +- * Changes the text of linked widget. +- * @param newText the new text +- */ +-void FloatingTextWidget::changeName(const QString& newText) +-{ +- if (m_linkWidget && !isTextValid(newText)) { +- AssociationWidget *assoc = dynamic_cast(m_linkWidget); +- if (assoc) { +- switch (m_textRole) { +- case Uml::TextRole::MultiA: +- assoc->setMultiplicity(QString(), Uml::RoleType::A); +- break; +- case Uml::TextRole::MultiB: +- assoc->setMultiplicity(QString(), Uml::RoleType::B); +- break; +- case Uml::TextRole::RoleAName: +- assoc->setRoleName(QString(), Uml::RoleType::A); +- break; +- case Uml::TextRole::RoleBName: +- assoc->setRoleName(QString(), Uml::RoleType::B); +- break; +- case Uml::TextRole::ChangeA: +- assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::A); +- break; +- case Uml::TextRole::ChangeB: +- assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::B); +- break; +- default: +- assoc->setName(QString()); +- break; +- } +- } +- else { +- MessageWidget *msg = dynamic_cast(m_linkWidget); +- if (msg) { +- msg->setName(QString()); +- m_scene->removeWidget(this); +- } +- } +- return; +- } +- +- if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message +- && m_textRole != Uml::TextRole::Seq_Message_Self) { +- m_linkWidget->setText(this, newText); +- } +- else { +- setText(newText); +- UMLApp::app()->document()->setModified(true); +- } +- +- setVisible(true); +- updateGeometry(); +- update(); +-} +- +-/** +- * 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. +- * +- * @param text The string to analyze. +- * @return True if the given text is valid. +- */ +-bool FloatingTextWidget::isTextValid(const QString &text) +-{ +- int length = text.length(); +- if(length < 1) +- return false; +- for(int i=0;iconstrainTextPos(newX, newY, width(), height(), textRole()); +- } +- +- return QPointF(newX, newY); +-} +- +-/** +- * Overridden from UMLWidget. +- * Moves the widget to a new position using the difference between the +- * current position and the new position. +- * If the floating text widget is part of a sequence message, and the +- * message widget is selected, it does nothing: the message widget will +- * update the text position when it's moved. +- * In any other case, the floating text widget constrains its move using +- * constrainPosition. When the position of the floating text is constrained, +- * it's kept at that position until it can be moved to another valid +- * position (m_unconstrainedPositionX/Y and m_movementDirectionX/Y are +- * used for that). +- * Moreover, if is part of a sequence message (and the message widget +- * isn't selected), it updates the position of the message widget. +- * @see constrainPosition +- * +- * @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 FloatingTextWidget::moveWidgetBy(qreal diffX, qreal diffY) +-{ +- if (textRole() == Uml::TextRole::Seq_Message_Self) +- return; +- +- if (textRole() == Uml::TextRole::Seq_Message +- && ((MessageWidget*)link())->isSelected()) { +- return; +- } +- +- m_unconstrainedPositionX += diffX; +- m_unconstrainedPositionY += diffY; +- QPointF constrainedPosition = constrainPosition(diffX, diffY); +- +- qreal newX = constrainedPosition.x(); +- qreal newY = constrainedPosition.y(); +- +- if (!m_movementDirectionX) { +- if (m_unconstrainedPositionX != constrainedPosition.x()) { +- m_movementDirectionX = (diffX > 0)? 1: -1; +- } +- } else if ((m_movementDirectionX < 0 && m_unconstrainedPositionX > x()) || +- (m_movementDirectionX > 0 && m_unconstrainedPositionX < x()) ) { +- newX = m_unconstrainedPositionX; +- m_movementDirectionX = 0; +- } +- +- if (!m_movementDirectionY) { +- if (m_unconstrainedPositionY != constrainedPosition.y()) { +- m_movementDirectionY = (diffY > 0)? 1: -1; +- } +- } else if ((m_movementDirectionY < 0 && m_unconstrainedPositionY > y()) || +- (m_movementDirectionY > 0 && m_unconstrainedPositionY < y()) ) { +- newY = m_unconstrainedPositionY; +- m_movementDirectionY = 0; +- } +- +- setX(newX); +- setY(newY); +- +- if (link()) { +- link()->calculateNameTextSegment(); +- if (textRole() == Uml::TextRole::Seq_Message) { +- MessageWidget* messageWidget = (MessageWidget*)link(); +- messageWidget->setY(newY + height()); +- } +- } +-} +- +-/** +- * Overridden from UMLWidget. +- * Modifies the value of the diffX and diffY variables used to move the +- * widgets. +- * The values are constrained using constrainPosition. +- * @see constrainPosition +- * +- * @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 FloatingTextWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +-{ +- QPointF constrainedPosition = constrainPosition(diffX, diffY); +- +- diffX = constrainedPosition.x() - x(); +- diffY = constrainedPosition.y() - y(); +-} +- +-/** +- * Override method from UMLWidget in order to additionally check widget parentage. +- * +- * @param p Point to be checked. +- * +- * @return 'this' if UMLWidget::onWidget(p) returns non NULL; +- * else NULL. +- */ +-UMLWidget* FloatingTextWidget::onWidget(const QPointF &p) +-{ +- WidgetBase *pw = dynamic_cast(parentItem()); +- if (pw == NULL) { +- return WidgetBase::onWidget(p); +- } +- const WidgetBase::WidgetType t = pw->baseType(); +- bool isWidgetChild = false; +- if (t == WidgetBase::wt_Interface) { +- ClassifierWidget *cw = static_cast(pw); +- isWidgetChild = cw->getDrawAsCircle(); +- } else if (t == wt_Association || +- t == WidgetBase::wt_Port || t == WidgetBase::wt_Pin) { +- isWidgetChild = true; +- } +- if (!isWidgetChild) { +- return WidgetBase::onWidget(p); +- } +- const qreal w = width(); +- const qreal h = height(); +- const qreal left = pw->x() + x(); +- const qreal right = left + w; +- const qreal top = pw->y() + y(); +- const qreal bottom = top + h; +- // uDebug() << "child_of_pw; p=(" << p.x() << "," << p.y() << "), " +- // << "x=" << left << ", y=" << top << ", w=" << w << ", h=" << h +- // << "; right=" << right << ", bottom=" << bottom; +- if (p.x() >= left && p.x() <= right && +- p.y() >= top && p.y() <= bottom) { // Qt coord.sys. origin in top left corner +- // uDebug() << "floatingtext: " << m_Text; +- return this; +- } +- return NULL; +-} +- +-/** +- * Overrides default method +- */ +-void FloatingTextWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- int w = width(); +- int h = height(); +- painter->setFont(UMLWidget::font()); +- painter->setPen(textColor()); +- painter->drawText(0, 0, w, h, Qt::AlignCenter, displayText()); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Loads the "floatingtext" XMI element. +- */ +-bool FloatingTextWidget::loadFromXMI(QDomElement & qElement) +-{ +- if(!UMLWidget::loadFromXMI(qElement)) +- return false; +- +- m_unconstrainedPositionX = x(); +- m_unconstrainedPositionY = y(); +- QString role = qElement.attribute(QLatin1String("role")); +- if(!role.isEmpty()) +- m_textRole = Uml::TextRole::fromInt(role.toInt()); +- +- m_preText = qElement.attribute(QLatin1String("pretext")); +- m_postText = qElement.attribute(QLatin1String("posttext")); +- setText(qElement.attribute(QLatin1String("text"))); // use setText for geometry update +- // If all texts are empty then this is a useless widget. +- // In that case we return false. +- // CAVEAT: The caller should not interpret the false return value +- // as an indication of failure since previous umbrello-kf6 versions +- // saved lots of these empty FloatingTexts. +- bool usefulWidget = !isEmpty(); +- return usefulWidget; +-} +- +-/** +- * Reimplemented from UMLWidget::saveToXMI to save the widget +- * data into XMI 'floatingtext' element. +- */ +-void FloatingTextWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- if (isEmpty()) +- return; +- +- QDomElement textElement = qDoc.createElement(QLatin1String("floatingtext")); +- UMLWidget::saveToXMI(qDoc, textElement); +- textElement.setAttribute(QLatin1String("text"), m_Text); +- textElement.setAttribute(QLatin1String("pretext"), m_preText); +- textElement.setAttribute(QLatin1String("posttext"), m_postText); +- +- /* No need to save these - the messagewidget already did it. +- m_Operation = qElement.attribute("operation"); +- m_SeqNum = qElement.attribute("seqnum"); +- */ +- +- textElement.setAttribute(QLatin1String("role"), m_textRole); +- qElement.appendChild(textElement); +-} +- +-/** +- * Called when a menu selection has been made. +- * +- * @param action The action that has been selected. +- */ +-void FloatingTextWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Properties: +- showPropertiesDialog(); +- break; +- +- case ListPopupMenu::mt_Delete: +- hide(); // This is only a workaround; if set then m_linkWidget should +- // really delete this FloatingTextWidget. +- update(); +- m_scene->removeWidget(this); +- break; +- +- case ListPopupMenu::mt_New_Operation: // needed by AssociationWidget +- case ListPopupMenu::mt_Operation: +- { +- if (m_linkWidget == 0) { +- DEBUG(DBG_SRC) << "mt_Operation: m_linkWidget is NULL"; +- return; +- } +- UMLClassifier* c = m_linkWidget->operationOwner(); +- if (c == 0) { +- bool ok = false; +-#if QT_VERSION >= 0x050000 +- QString opText = QInputDialog::getText(m_scene->activeView(), +- i18nc("operation name", "Name"), +- i18n("Enter operation name:"), +- QLineEdit::Normal, +- text(), &ok); +-#else +- QString opText = KInputDialog::getText(i18nc("operation name", "Name"), +- i18n("Enter operation name:"), +- text(), &ok, m_scene->activeView()); +-#endif +- if (ok) +- m_linkWidget->setCustomOpText(opText); +- return; +- } +- UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, UMLObject::ot_Operation); +- if (umlObj) { +- UMLOperation* newOperation = static_cast(umlObj); +- m_linkWidget->setOperation(newOperation); +- } +- } +- break; +- +- case ListPopupMenu::mt_Select_Operation: +- showOperationDialog(false); +- break; +- +- case ListPopupMenu::mt_Rename: +- handleRename(); +- break; +- +- case ListPopupMenu::mt_Change_Font: +- { +-#if QT_VERSION >= 0x050000 +- bool ok = false; +- QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); +- if (ok) { +-#else +- QFont fnt = font(); +- if(KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) { +-#endif +- if(m_textRole == Uml::TextRole::Floating || m_textRole == Uml::TextRole::Seq_Message) { +- setFont(fnt); +- } else if (m_linkWidget) { +- m_linkWidget->lwSetFont(fnt); +- } +- } +- } +- break; +- +- case ListPopupMenu::mt_Reset_Label_Positions: +- if (m_linkWidget) +- m_linkWidget->resetTextPositions(); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- break; +- }//end switch +-} +- +-/** +- * Sets the text for this label if it is acting as a sequence diagram +- * message or a collaboration diagram message. +- */ +-void FloatingTextWidget::setMessageText() +-{ +- if (m_linkWidget) { +- m_linkWidget->setMessageText(this); +- QSizeF s = minimumSize(); +- setSize(s.width(), s.height()); +- +- } +- setVisible(!text().isEmpty()); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.h umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,131 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef FLOATINGTEXTWIDGET_H +-#define FLOATINGTEXTWIDGET_H +- +-#include "basictypes.h" +-#include "umlwidget.h" +- +-class LinkWidget; +-class UMLScene; +- +-/** +- * @short Displays a line of text or an operation. +- * +- * This is a multipurpose-kf6 class. In its simplest form it will display a +- * line of text. +- * It can also be setup to be the text for an operation with regard to the +- * @ref MessageWidget on the sequence diagram. +- * It is also used for the text required for an association. +- * +- * The differences between all these different uses will be the popup menu +- * that is associated with it. +- * +- * @author Paul Hensgen +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class FloatingTextWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- explicit FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role = Uml::TextRole::Floating, +- const QString& text = QString(), Uml::ID::Type id = Uml::ID::None); +- virtual ~FloatingTextWidget(); +- +- QString text() const; +- void setText(const QString &t); +- +- void setTextcmd(const QString &t); +- +- QString preText() const; +- void setPreText(const QString &t); +- +- QString postText() const; +- void setPostText(const QString &t); +- +- QString displayText() const; +- +- bool isEmpty(); +- +- void showChangeTextDialog(); +- void showOperationDialog(bool enableAutoIncrement = true); +- virtual void showPropertiesDialog(); +- +- LinkWidget* link() const; +- void setLink(LinkWidget * l); +- +- bool activate(IDChangeLog* ChangeLog = 0); +- +- Uml::TextRole::Enum textRole() const; +- void setTextRole(Uml::TextRole::Enum role); +- +- void handleRename(); +- void changeName(const QString& newText); +- +- void setSequenceNumber(const QString &sequenceNumber); +- QString sequenceNumber() const; +- +- static bool isTextValid(const QString &text); +- +- UMLWidget* onWidget(const QPointF& p); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- virtual bool loadFromXMI(QDomElement& qElement); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- void setMessageText(); +- +-protected: +- QSizeF minimumSize() const; +- +- virtual void moveWidgetBy(qreal diffX, qreal diffY); +- virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); +- +-private: +- QPointF constrainPosition(qreal diffX, qreal diffY); +- +- /// The association or message widget we may be linked to. +- LinkWidget * m_linkWidget; +- +- //////////////////// Data loaded/saved: +- +- /// Prepended text (such as for scope of association Role or method) +- QString m_preText; +- /// Ending text (such as bracket on changability notation for association Role) +- QString m_postText; +- /// The role the text widget will enact. +- Uml::TextRole::Enum m_textRole; +- +- //////// +- +- /// The horizontal position the widget would have if its move wasn't constrained. +- qreal m_unconstrainedPositionX; +- +- /// The vertical position the widget would have if its move wasn't constrained. +- qreal m_unconstrainedPositionY; +- +- /// The X direction the widget was moved when the constrain was applied. +- /// -1 means left, 1 means right. +- int m_movementDirectionX; +- +- /// The Y direction the widget was moved when the constrain was applied. +- /// -1 means up, 1 means down. +- int m_movementDirectionY; +- +- /// Contains sequence number for sequence or collaboration diagram message. +- QString m_SequenceNumber; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,205 +0,0 @@ +-/*************************************************************************** +- * This program is free software; you can redistribute it and/or modify * +- * it under the terms of the GNU General Public License as published by * +- * the Free Software Foundation; either version 2 of the License, or * +- * (at your option) any later version. * +- * * +- * copyright (C) 2005-2014 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "forkjoinwidget.h" +- +-//app includes +-#include "debug_utils.h" +-#include "umlview.h" +-#include "umldoc.h" +-#include "listpopupmenu.h" +- +-// qt includes +-#include +- +-/** +- * Constructs a ForkJoinWidget. +- * +- * @param scene The parent to this widget. +- * @param ori Whether to draw the plate horizontally or vertically. +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-ForkJoinWidget::ForkJoinWidget(UMLScene * scene, Qt::Orientation ori, Uml::ID::Type id) +- : BoxWidget(scene, id, WidgetBase::wt_ForkJoin), +- m_orientation(ori) +-{ +- setSize(10, 40); +- m_usesDiagramFillColor = false; +- setFillColorCmd(QColor("black")); +-} +- +-/** +- * Destructor. +- */ +-ForkJoinWidget::~ForkJoinWidget() +-{ +-} +- +-/** +- * Get whether to draw the plate vertically or horizontally. +- */ +-Qt::Orientation ForkJoinWidget::orientation() const +-{ +- return m_orientation; +-} +- +-/** +- * Set whether to draw the plate vertically or horizontally. +- */ +-void ForkJoinWidget::setOrientation(Qt::Orientation ori) +-{ +- m_orientation = ori; +- updateGeometry(); +- UMLWidget::adjustAssocs(x(), y()); +-} +- +-/** +- * Reimplemented from UMLWidget::paint to draw the plate of +- * fork join. +- */ +-void ForkJoinWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- painter->fillRect(0, 0, width(), height(), fillColor()); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Reimplemented from UMLWidget::loadFromXMI to load widget +- * info from XMI element - 'forkjoin'. +- */ +-bool ForkJoinWidget::loadFromXMI(QDomElement& qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) { +- return false; +- } +- +- QString drawVerticalStr = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("0")); +- bool drawVertical = (bool)drawVerticalStr.toInt(); +- if (drawVertical) { +- setOrientation(Qt::Vertical); +- } +- else { +- setOrientation(Qt::Horizontal); +- } +- +- return true; +-} +- +-/** +- * Reimplemented from UMLWidget::saveToXMI to save widget info +- * into XMI element - 'forkjoin'. +- */ +-void ForkJoinWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement fjElement = qDoc.createElement(QLatin1String("forkjoin")); +- UMLWidget::saveToXMI(qDoc, fjElement); +- bool drawVertical = true; +- if (m_orientation == Qt::Horizontal) { +- drawVertical = false; +- } +- fjElement.setAttribute(QLatin1String("drawvertical"), drawVertical); +- qElement.appendChild(fjElement); +-} +- +-/** +- * Show a properties dialog for a Fork/Join Widget. +- */ +-void ForkJoinWidget::showPropertiesDialog() +-{ +- QColor newColor = QColorDialog::getColor(fillColor()); // krazy:exclude=qclasses +- if (newColor != fillColor()) { +- setFillColor(newColor); +- setUsesDiagramFillColor(false); +- umlDoc()->setModified(true); +- } +-} +- +-/** +- * Reimplemented form UMLWidget::slotMenuSelection to handle +- * Flip action. +- */ +-void ForkJoinWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch (sel) { +- case ListPopupMenu::mt_Fill_Color: +- showPropertiesDialog(); +- break; +- +- case ListPopupMenu::mt_Flip: +- switch (m_orientation) { +- case Qt::Vertical: +- setOrientation(Qt::Horizontal); +- break; +- case Qt::Horizontal: +- default: +- setOrientation(Qt::Vertical); +- break; +- } +- break; +- default: +- break; +- } +-} +- +-/** +- * Overrides the function from UMLWidget. +- */ +-QSizeF ForkJoinWidget::minimumSize() const +-{ +- if (m_orientation == Qt::Vertical) { +- return QSizeF(4, 40); +- } else { +- return QSizeF(40, 4); +- } +-} +- +-/** +- * Reimplement method from UMLWidget to suppress the resize corner. +- * Although the ForkJoinWidget supports resizing, we suppress the +- * resize corner because it is too large for this very slim widget. +- */ +-void ForkJoinWidget::paintSelected(QPainter * p, int offsetX, int offsetY) +-{ +- Q_UNUSED(p); +- Q_UNUSED(offsetX); +- Q_UNUSED(offsetY); +-} +- +-/** +- * Reimplement method from UMLWidget. +- */ +-void ForkJoinWidget::constrain(qreal& width, qreal& height) +-{ +- if (m_orientation == Qt::Vertical) { +- if (width < 4) +- width = 4; +- else if (width > 10) +- width = 10; +- if (height < 40) +- height = 40; +- else if (height > 100) +- height = 100; +- } else { +- if (height < 4) +- height = 4; +- else if (height > 10) +- height = 10; +- if (width < 40) +- width = 40; +- else if (width > 100) +- width = 100; +- } +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.h umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,57 +0,0 @@ +-/*************************************************************************** +- * This program is free software; you can redistribute it and/or modify * +- * it under the terms of the GNU General Public License as published by * +- * the Free Software Foundation; either version 2 of the License, or * +- * (at your option) any later version. * +- * * +- * copyright (C) 2005-2014 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef FORKJOINWIDGET_H +-#define FORKJOINWIDGET_H +- +-//app includes +-#include "boxwidget.h" +- +-/** +- * @short Displays a fork/join plate in a state diagram. +- * +- * @author Oliver Kellogg +- * +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ForkJoinWidget : public BoxWidget +-{ +- Q_OBJECT +- Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) +-public: +- explicit ForkJoinWidget(UMLScene * scene, Qt::Orientation ori = Qt::Horizontal, Uml::ID::Type id = Uml::ID::None); +- virtual ~ForkJoinWidget(); +- +- Qt::Orientation orientation() const; +- void setOrientation(Qt::Orientation ori); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- virtual bool loadFromXMI(QDomElement & qElement); +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +- void showPropertiesDialog(); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-protected: +- QSizeF minimumSize() const; +- +- virtual void paintSelected(QPainter * p, int offsetX = 0, int offsetY = 0); +- +- void constrain(qreal& width, qreal& height); +- +-private: +- Qt::Orientation m_orientation; ///< whether to draw the plate horizontally or vertically +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.cpp umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,113 +0,0 @@ +-/*************************************************************************** +- * Copyright (C) 2011 by Andi Fischer * +- * Copyright (C) 2012 by Ralf Habacker * +- * * +- * This 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, or (at your option) * +- * any later version. * +- * * +- * This software is distributed in the hope that it will be useful, * +- * but WITHOUT ANY WARRANTY; without even the implied warranty of * +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * +- * GNU General Public License for more details. * +- * * +- * You should have received a copy of the GNU General Public License * +- * along with this package; see the file COPYING. If not, write to * +- * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * +- * Boston, MA 02110-1301, USA. * +- ***************************************************************************/ +- +-#include "layoutgrid.h" +- +-#include "debug_utils.h" +-#include "umlscene.h" +- +-#include +-#include +- +-#define DBG_LOG() DEBUG(QLatin1String("LayoutGrid")) +-DEBUG_REGISTER_DISABLED(LayoutGrid) +- +-/** +- * Constructor. +- */ +-LayoutGrid::LayoutGrid(UMLScene *scene) +- : m_scene(scene), +- m_gridSpacingX(25), +- m_gridSpacingY(25), +- m_gridDotColor(Qt::gray), +- m_isVisible(false) +-{ +-} +- +-/** +- * Destructor. +- */ +-LayoutGrid::~LayoutGrid() +-{ +-} +- +-void LayoutGrid::paint(QPainter *painter, const QRectF &rect) +-{ +- if (!isVisible()) +- return; +- +- int gridSizeX = gridSpacingX(); +- int gridSizeY = gridSpacingY(); +- +- qreal left = int(rect.left()) - (int(rect.left()) % gridSizeX); +- qreal top = int(rect.top()) - (int(rect.top()) % gridSizeY); +- +- QVarLengthArray lines; +- +- for (qreal x = left; x < rect.right(); x += gridSizeX) +- lines.append(QLineF(x, rect.top(), x, rect.bottom())); +- for (qreal y = top; y < rect.bottom(); y += gridSizeY) +- lines.append(QLineF(rect.left(), y, rect.right(), y)); +- +- painter->setPen(m_gridDotColor); +- painter->drawLines(lines.data(), lines.size()); +-} +- +-int LayoutGrid::gridSpacingX() const +-{ +- return m_gridSpacingX; +-} +- +-int LayoutGrid::gridSpacingY() const +-{ +- return m_gridSpacingY; +-} +- +-void LayoutGrid::setGridSpacing(int sizeX, int sizeY) +-{ +- DBG_LOG() << "x = " << sizeX << " / y = " << sizeY; +- m_gridSpacingX= sizeX; +- m_gridSpacingY= sizeY; +-} +- +-const QColor& LayoutGrid::gridDotColor() const +-{ +- return m_gridDotColor; +-} +- +-void LayoutGrid::setGridDotColor(const QColor& color) +-{ +- DBG_LOG() << "color = " << color; +- m_gridDotColor = color; +-} +- +-bool LayoutGrid::isVisible() const +-{ +- return m_isVisible; +-} +- +-void LayoutGrid::setVisible(bool visible) +-{ +- if (m_isVisible != visible) { +- DBG_LOG() << "visible = " << visible; +- m_isVisible = visible; +- m_scene->update(); +- } +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.h umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,76 +0,0 @@ +-/*************************************************************************** +- * Copyright (C) 2011 by Andi Fischer * +- * Copyright (C) 2012 by Ralf Habacker * +- * * +- * This 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, or (at your option) * +- * any later version. * +- * * +- * This software is distributed in the hope that it will be useful, * +- * but WITHOUT ANY WARRANTY; without even the implied warranty of * +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * +- * GNU General Public License for more details. * +- * * +- * You should have received a copy of the GNU General Public License * +- * along with this package; see the file COPYING. If not, write to * +- * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * +- * Boston, MA 02110-1301, USA. * +- ***************************************************************************/ +- +-#ifndef LAYOUTGRID_H +-#define LAYOUTGRID_H +- +-#include +-#include +- +-class UMLScene; +-class QRectF; +- +-/** +- * @author Andi Fischer +- * This class handles the layout grid, which is drawn in the background +- * of the scene. It is used only in UMLScene. +- */ +-class LayoutGrid +-{ +-public: +- explicit LayoutGrid(UMLScene *scene); +- ~LayoutGrid(); +- +- void paint(QPainter *painter, const QRectF &rect); +- +- QRect gridRect() const; +- void setGridRect(const QRect& rect); +- +- int gridSpacingX() const; +- int gridSpacingY() const; +- void setGridSpacing(int sizeX, int sizeY); +- +- const QColor& gridDotColor() const; +- void setGridDotColor(const QColor& color); +- +- const QColor& gridCrossColor() const; +- void setGridCrossColor(const QColor& color); +- +- const QColor& textColor() const; +- void setTextColor(const QColor& color); +- +- QFont textFont() const; +- void setTextFont(const QFont& font); +- +- bool isVisible() const; +- void setVisible(bool visible); +- +- bool isTextVisible() const; +- void setTextVisible(bool visible); +- +-private: +- UMLScene *m_scene; +- int m_gridSpacingX; +- int m_gridSpacingY; +- QColor m_gridDotColor; +- bool m_isVisible; +-}; +- +-#endif // LAYOUTGRID_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,121 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "linkwidget.h" +- +-// app includes +-#include "classifier.h" +-#include "operation.h" +-#include "uml.h" +-#include "umlobject.h" +-#include "umlview.h" +- +-LinkWidget::LinkWidget() +-{ +-} +- +-LinkWidget::~LinkWidget() +-{ +-} +- +-/** +- * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) +- */ +-UMLClassifier *LinkWidget::operationOwner() +-{ +- UMLOperation *op = operation(); +- if (op == NULL) +- return NULL; +- return static_cast(op->parent()); +-} +- +-/** +- * Return the operation text. +- * When no scene parameter is given, the scene of the current view +- * is taken instead. +- * @param scene the given scene +- * @return the operation text +- */ +-QString LinkWidget::operationText(UMLScene *scene) +-{ +- UMLOperation *op = operation(); +- if (op == NULL) +- return customOpText(); +- if (scene == NULL) +- scene = UMLApp::app()->currentView()->umlScene(); +- Uml::SignatureType::Enum sigType; +- if (scene && scene->showOpSig()) +- sigType = Uml::SignatureType::SigNoVis; +- else +- sigType = Uml::SignatureType::NoSigNoVis; +- QString opText = op->toString(sigType); +- return opText; +-} +- +-/** +- * Motivated by FloatingTextWidget::slotMenuSelection(mt_Reset_Label_Positions) +- * Only applies to AssociationWidget. +- */ +-void LinkWidget::resetTextPositions() +-{ +-} +- +-/** +- * Motivated by FloatingTextWidget::mouseDoubleClickEvent() +- * Only applies to AssociationWidget. +- */ +-void LinkWidget::showPropertiesDialog() +-{ +-} +- +-/** +- * Motivated by FloatingTextWidget::setLink(). +- * Only applies to AssociationWidget. +- */ +-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(QLatin1String("seqnum")); +- return true; +-} +- +-/** +- * Save data to XMI. +- */ +-void LinkWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +-{ +- Q_UNUSED(qDoc); +- +- qElement.setAttribute(QLatin1String("seqnum"), m_SequenceNumber); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.h umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,123 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef LINKWIDGET_H +-#define LINKWIDGET_H +- +-#include "basictypes.h" +-#include "umlscene.h" +- +-#include +- +-// forward declarations +-class UMLClassifier; +-class UMLOperation; +-class FloatingTextWidget; +- +-/** +- * This is an interface realized by AssociationWidget and MessageWidget. +- * The design of this interface was driven by the requirements of +- * class FloatingTextWidget. As the architecture of umbrello-kf6 evolves (for +- * example, if the class FloatingTextWidget is redesigned), it can be +- * cleaned up. +- * +- * @short Interface to FloatingTextWidget for AssociationWidget and MessageWidget. +- * @author Oliver Kellogg +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class LinkWidget +-{ +-public: +- LinkWidget(); +- virtual ~LinkWidget(); +- +- /** +- * Sets the font the widget is to use. +- * Abstract operation implemented by inheriting classes. +- * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) +- * +- * @param font Font to be set. +- */ +- virtual void lwSetFont(QFont font) = 0; +- +- virtual UMLClassifier *operationOwner(); +- +- /** +- * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) +- */ +- virtual UMLOperation *operation() = 0; +- +- /** +- * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) +- */ +- virtual void setOperation(UMLOperation *op) = 0; +- +- /** +- * Motivated by getOperationText() +- */ +- virtual QString customOpText() = 0; +- +- /** +- * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) +- */ +- virtual void setCustomOpText(const QString &opText) = 0; +- +- QString operationText(UMLScene *scene = 0); +- +- virtual void resetTextPositions(); +- +- /** +- * Motivated by FloatingTextWidget::setMessageText() +- */ +- virtual void setMessageText(FloatingTextWidget *ft) = 0; +- +- /** +- * Motivated by FloatingTextWidget::handleRename() +- */ +- virtual void setText(FloatingTextWidget *ft, const QString &newText) = 0; +- +- virtual void showPropertiesDialog(); +- +- /** +- * Motivated by FloatingTextWidget::showOpDialog() +- */ +- virtual QString lwOperationText() = 0; +- +- /** +- * Motivated by FloatingTextWidget::showOpDialog() +- */ +- virtual UMLClassifier *lwClassifier() = 0; +- +- /** +- * Motivated by FloatingTextWidget::showOpDialog() +- */ +- virtual void setOperationText(const QString &op) = 0; +- +- /** +- * Abstract operation implemented by inheriting classes. +- * Motivated by FloatingTextWidget::mouseMoveEvent() +- */ +- virtual void constrainTextPos(qreal &textX, qreal &textY, +- qreal textWidth, qreal textHeight, +- Uml::TextRole::Enum tr) = 0; +- +- 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1385 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// onw header +-#include "messagewidget.h" +- +-//app includes +-#include "classifier.h" +-#include "debug_utils.h" +-#include "floatingtextwidget.h" +-#include "listpopupmenu.h" +-#include "objectwidget.h" +-#include "operation.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlview.h" +-#include "uniqueid.h" +-#include "idchangelog.h" +- +-//qt includes +-#include +-#include +-#include +-#include +- +-//kde includes +-#include +- +-DEBUG_REGISTER_DISABLED(MessageWidget) +- +-static const int circleWidth = 10; +- +-/** +- * Constructs a MessageWidget. +- * +- * This method is used for creation, synchronous and synchronous message types. +- * +- * @param scene The parent to this class. +- * @param a The role A widget for this message. +- * @param b The role B widget for this message. +- * @param y The vertical position to display this message. +- * @param sequenceMessageType Whether synchronous or asynchronous +- * @param id A unique id used for deleting this object cleanly. +- * The default (-1) will prompt generation of a new ID. +- */ +-MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, +- int y, Uml::SequenceMessage::Enum sequenceMessageType, +- Uml::ID::Type id /* = Uml::id_None */) +- : UMLWidget(scene, WidgetBase::wt_Message, id) +-{ +- init(); +- m_pOw[Uml::RoleType::A] = a; +- m_pOw[Uml::RoleType::B] = b; +- m_sequenceMessageType = sequenceMessageType; +- if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { +- y -= m_pOw[Uml::RoleType::B]->height() / 2; +- m_pOw[Uml::RoleType::B]->setY(y); +- } +- updateResizability(); +- calculateWidget(); +- y = y < getMinY() ? getMinY() : y; +- y = y > getMaxY() ? getMaxY() : y; +- setY(y); +- +- this->activate(); +-} +- +-/** +- * Constructs a MessageWidget. +- * +- * @param scene The parent to this class. +- * @param seqMsgType The Uml::SequenceMessage::Enum of this message widget +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-MessageWidget::MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum seqMsgType, +- Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_Message, id) +-{ +- init(); +- m_sequenceMessageType = seqMsgType; +-} +- +-/** +- * Constructs a Lost or Found MessageWidget. +- * +- * @param scene The parent to this class. +- * @param a The role A widget for this message. +- * @param xclick The horizontal position clicked by the user +- * @param yclick The vertical position clicked by the user +- * @param sequenceMessageType Whether lost or found +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, +- Uml::SequenceMessage::Enum sequenceMessageType, +- Uml::ID::Type id /*= Uml::id_None*/) +- : UMLWidget(scene, WidgetBase::wt_Message, id) +-{ +- init(); +- m_pOw[Uml::RoleType::A] = a; +- m_pOw[Uml::RoleType::B] = a; +- +- m_sequenceMessageType = sequenceMessageType; +- +- m_xclicked = xclick; +- m_yclicked = yclick; +- +- updateResizability(); +- calculateWidget(); +- yclick = yclick < getMinY() ? getMinY() : yclick; +- yclick = yclick > getMaxY() ? getMaxY() : yclick; +- setY(yclick); +- m_yclicked = yclick; +- +- this->activate(); +-} +- +-/** +- * Initializes key variables of the class. +- */ +-void MessageWidget::init() +-{ +- m_xclicked = -1; +- m_yclicked = -1; +- m_ignoreSnapToGrid = true; +- m_ignoreSnapComponentSizeToGrid = true; +- m_pOw[Uml::RoleType::A] = m_pOw[Uml::RoleType::B] = NULL; +- m_pFText = NULL; +-} +- +-/** +- * Standard destructor. +- */ +-MessageWidget::~MessageWidget() +-{ +-} +- +-/** +- * Sets the y-coordinate. +- * Reimplemented from UMLWidget. +- * +- * @param y The y-coordinate to be set. +- */ +-void MessageWidget::setY(qreal y) +-{ +- if (y < getMinY()) { +- DEBUG(DBG_SRC) << "got out of bounds y position, check the reason" << this->y() << getMinY(); +- return; +- } +- +- UMLWidget::setY(y); +- if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { +- const qreal objWidgetHalfHeight = m_pOw[Uml::RoleType::B]->height() / 2; +- m_pOw[Uml::RoleType::B]->setY(y - objWidgetHalfHeight); +- } +- +- if (m_pFText && !UMLApp::app()->document()->loading()) { +- setTextPosition(); +- emit sigMessageMoved(); +- } +-} +- +-/** +- * Update the UMLWidget::m_resizable flag according to the +- * charactersitics of this message. +- */ +-void MessageWidget::updateResizability() +-{ +- if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) +- UMLWidget::m_resizable = true; +- else +- UMLWidget::m_resizable = false; +-} +- +-/** +- * Overridden from UMLWidget. +- * Returns the cursor to be shown when resizing the widget. +- * The cursor shown is KCursor::sizeVerCursor(). +- * +- * @return The cursor to be shown when resizing the widget. +- */ +-QCursor MessageWidget::resizeCursor() const +-{ +- return Qt::SizeVerCursor; +-} +- +-/** +- * Overridden from UMLWidget. +- * Resizes the height of the message widget and emits the message moved signal. +- * Message widgets can only be resized vertically, so width isn't modified. +- * +- * @param newW The new width for the widget (isn't used). +- * @param newH The new height for the widget. +- */ +-void MessageWidget::resizeWidget(qreal newW, qreal newH) +-{ +- if (sequenceMessageType() == Uml::SequenceMessage::Creation) +- setSize(width(), newH); +- else { +- qreal x1 = m_pOw[Uml::RoleType::A]->x(); +- qreal x2 = getxclicked(); +- qreal diffX = 0; +- if (x1 < x2) { +- diffX = x2 + (newW - width()); +- } +- else { +- diffX = x2 - (newW - width()); +- } +- if (diffX <= 0 ) +- diffX = 10; +- setxclicked (diffX); +- setSize(newW, newH); +- calculateWidget(); +- +- } +- emit sigMessageMoved(); +-} +- +-/** +- * Constrains the vertical position of the message widget so it doesn't go +- * upper than the bottom side of the lower object. +- * The height of the floating text widget in the message is taken in account +- * if there is any and isn't empty. +- * +- * @param diffY The difference between current Y position and new Y position. +- * @return The new Y position, constrained. +- */ +-qreal MessageWidget::constrainPositionY(qreal diffY) +-{ +- qreal newY = y() + diffY; +- +- qreal minY = getMinY(); +- if (m_pFText && !m_pFText->displayText().isEmpty()) { +- minY += m_pFText->height(); +- } +- +- if (newY < minY) { +- newY = minY; +- } +- +- return newY; +-} +- +-/** +- * Overridden from UMLWidget. +- * Moves the widget to a new position using the difference between the +- * current position and the new position. X position is ignored, and widget +- * is only moved along Y axis. If message goes upper than the object, it's +- * kept at this position until it should be lowered again (the unconstrained +- * Y position is saved to know when it's the time to lower it again). +- * If the message is a creation message, the object created is also moved to +- * the new vertical position. +- * @see constrainPositionY +- * +- * @param diffX The difference between current X position and new X position +- * (isn't used). +- * @param diffY The difference between current Y position and new Y position. +- */ +-void MessageWidget::moveWidgetBy(qreal diffX, qreal diffY) +-{ +- Q_UNUSED(diffX); +- qreal newY = constrainPositionY(diffY); +- setY(newY); +-} +- +-/** +- * Overridden from UMLWidget. +- * Modifies the value of the diffX and diffY variables used to move the widgets. +- * All the widgets are constrained to be moved only in Y axis (diffX is set to 0). +- * @see constrainPositionY +- * +- * @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 MessageWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +-{ +- diffX = 0; +- diffY = constrainPositionY(diffY) - y(); +-} +- +-/** +- * Reimplemented from UMLWidget and calls other paint...() methods +- * depending on the message type. +- */ +-void MessageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { +- return; +- } +- setPenFromSettings(painter); +- if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { +- paintSynchronous(painter, option); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { +- paintAsynchronous(painter, option); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { +- paintCreation(painter, option); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { +- paintLost(painter, option); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { +- paintFound(painter, option); +- } else { +- uWarning() << "Unknown message type"; +- } +-} +- +-/** +- * Draw a solid-kf6 (triangular) arrowhead pointing in the given direction. +- * The direction can be either Qt::LeftArrow or Qt::RightArrow. +- */ +-void MessageWidget::paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction) +-{ +- int arrowheadExtentX = 4; +- if (direction == Qt::RightArrow) { +- arrowheadExtentX = -arrowheadExtentX; +- } +- QPolygon points; +- points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3); +- p->setBrush(QBrush(p->pen().color())); +- p->drawPolygon(points); +-} +- +-/** +- * Draw an arrow pointing in the given direction. +- * The arrow head is not solid-kf6, i.e. it is made up of two lines +- * like so: ---> +- * The direction can be either Qt::LeftArrow or Qt::RightArrow. +- */ +-void MessageWidget::paintArrow(QPainter *p, int x, int y, int w, +- Qt::ArrowType direction, bool useDottedLine /* = false */) +-{ +- if (w > 3) { +- int arrowheadStartX = x; +- int arrowheadExtentX = 4; +- if (direction == Qt::RightArrow) { +- arrowheadStartX += w; +- arrowheadExtentX = -arrowheadExtentX; +- } +- // draw upper half of arrowhead +- p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3); +- // draw lower half of arrowhead +- p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3); +- } +- // draw arrow line +- if (useDottedLine) { +- QPen pen = p->pen(); +- pen.setStyle(Qt::DotLine); +- p->setPen(pen); +- } +- p->drawLine(x, y, x + w, y); +-} +- +-/** +- * Draws the calling arrow with filled in arrowhead, the +- * timeline box and the returning arrow with a dashed line and +- * stick arrowhead. +- */ +-void MessageWidget::paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- int x1 = m_pOw[Uml::RoleType::A]->x(); +- int x2 = m_pOw[Uml::RoleType::B]->x(); +- int w = width() - 1; +- int h = height(); +- int offsetX = 0; +- int offsetY = 0; +- +- bool messageOverlaps = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); +- const int boxWidth = 17; +- const int wr = w < boxWidth ? w : boxWidth; +- const int arrowWidth = 4; +- +- if(isSelf()) { +- painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box +- painter->drawRect(offsetX, offsetY, wr, h); //box +- offsetX += wr; +- w -= wr; +- offsetY += 3; +- const int lowerLineY = offsetY + h - 6; +- // draw upper line segment (leaving the life line) +- painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); +- // draw line segment parallel to (and at the right of) the life line +- painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); +- // draw lower line segment (back to the life line) +- paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); +- offsetX -= wr; +- offsetY -= 3; +- } else if(x1 < x2) { +- if (messageOverlaps) { +- offsetX += 8; +- w -= 8; +- } +- QPen pen = painter->pen(); +- int startX = offsetX + w - wr + 1; +- painter->fillRect(startX, offsetY, wr, h, QBrush(Qt::white)); //box +- painter->drawRect(startX, offsetY, wr, h); //box +- painter->drawLine(offsetX, offsetY + arrowWidth, startX, offsetY + arrowWidth); //arrow line +- if (w > boxWidth + arrowWidth) +- paintsolid-kf6Arrowhead(painter, startX - 1, offsetY + arrowWidth, Qt::RightArrow); +- paintArrow(painter, offsetX, offsetY + h - arrowWidth + 1, w - wr + 1, Qt::LeftArrow, true); // return arrow +- if (messageOverlaps) { +- offsetX -= 8; //reset for drawSelected() +- } +- } else { +- if (messageOverlaps) { +- w -=8; +- } +- QPen pen = painter->pen(); +- painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box +- painter->drawRect(offsetX, offsetY, wr, h); //box +- painter->drawLine(offsetX + wr + 1, offsetY + arrowWidth, offsetX + w, offsetY + arrowWidth); //arrow line +- if (w > boxWidth + arrowWidth) +- paintsolid-kf6Arrowhead(painter, offsetX + wr, offsetY + arrowWidth, Qt::LeftArrow); +- paintArrow(painter, offsetX + wr + 1, offsetY + h - arrowWidth + 1, w - wr - 1, Qt::RightArrow, true); // return arrow +- } +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * Draws a solid-kf6 arrow line and a stick arrow head. +- */ +-void MessageWidget::paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- int x1 = m_pOw[Uml::RoleType::A]->x(); +- int x2 = m_pOw[Uml::RoleType::B]->x(); +- int w = width() - 1; +- int h = height() - 1; +- int offsetX = 0; +- int offsetY = 0; +- bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); +- //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); +- +- if(isSelf()) { +- if (messageOverlapsA) { +- offsetX += 7; +- w -= 7; +- } +- const int lowerLineY = offsetY + h - 3; +- // draw upper line segment (leaving the life line) +- painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); +- // draw line segment parallel to (and at the right of) the life line +- painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); +- // draw lower line segment (back to the life line) +- paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); +- if (messageOverlapsA) { +- offsetX -= 7; //reset for drawSelected() +- } +- } else if(x1 < x2) { +- if (messageOverlapsA) { +- offsetX += 7; +- w -= 7; +- } +- paintArrow(painter, offsetX, offsetY + 4, w, Qt::RightArrow); +- if (messageOverlapsA) { +- offsetX -= 7; +- } +- } else { +- if (messageOverlapsA) { +- w -= 7; +- } +- paintArrow(painter, offsetX, offsetY + 4, w, Qt::LeftArrow); +- } +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * Draws a solid-kf6 arrow line and a stick arrow head to the +- * edge of the target object widget instead of to the +- * sequence line. +- */ +-void MessageWidget::paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- int x1 = m_pOw[Uml::RoleType::A]->x(); +- int x2 = m_pOw[Uml::RoleType::B]->x(); +- int w = width(); +- //int h = height() - 1; +- int offsetX = 0; +- int offsetY = 0; +- bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); +- //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); +- +- const int lineY = offsetY + 4; +- if (x1 < x2) { +- if (messageOverlapsA) { +- offsetX += 7; +- w -= 7; +- } +- paintArrow(painter, offsetX, lineY, w, Qt::RightArrow); +- if (messageOverlapsA) { +- offsetX -= 7; +- } +- } else { +- if (messageOverlapsA) { +- w -= 7; +- } +- paintArrow(painter, offsetX, lineY, w, Qt::LeftArrow); +- } +- +- UMLWidget::paint(painter, option); +-} +- +- +-/** +- * Draws a solid-kf6 arrow line and a stick arrow head +- * and a circle +- */ +-void MessageWidget::paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_xclicked; +- int w = width(); +- int h = height(); +- int offsetX = 0; +- int offsetY = 0; +- bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); +- //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); +- +- if(x1 < x2) { +- if (messageOverlapsA) { +- offsetX += 7; +- w -= 7; +- } +- +- setPenFromSettings(painter); +- painter->setBrush(WidgetBase::lineColor()); +- painter->drawEllipse(offsetX + w - h, offsetY, h, h); +- paintArrow(painter, offsetX, offsetY + h/2, w - h, Qt::RightArrow); +- +- if (messageOverlapsA) { +- offsetX -= 7; +- } +- } else { +- setPenFromSettings(painter); +- painter->setBrush(WidgetBase::lineColor()); +- painter->drawEllipse(offsetX, offsetY, h, h); +- paintArrow(painter, offsetX + h, offsetY + h/2, w - h, Qt::LeftArrow); +- } +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * Draws a circle and a solid-kf6 arrow line and a stick arrow head. +- */ +-void MessageWidget::paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option) +-{ +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_xclicked; +- int w = width(); +- int h = height(); +- int offsetX = 0; +- int offsetY = 0; +- bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); +- //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); +- +- if(x1 < x2) { +- if (messageOverlapsA) { +- offsetX += 7; +- w -= 7; +- } +- setPenFromSettings(painter); +- painter->setBrush(WidgetBase::lineColor()); +- painter->drawEllipse(offsetX + w - h, offsetY, h, h); +- paintArrow(painter, offsetX, offsetY + h/2, w, Qt::LeftArrow); +- if (messageOverlapsA) { +- offsetX -= 7; +- } +- } else { +- if (messageOverlapsA) { +- w -= 7; +- } +- setPenFromSettings(painter); +- painter->setBrush(WidgetBase::lineColor()); +- painter->drawEllipse(offsetX, offsetY, h, h); +- paintArrow(painter, offsetX, offsetY + h/2, w, Qt::RightArrow); +- } +- +- UMLWidget::paint(painter, option); +-} +- +-/** +- * Overrides operation from UMLWidget. +- * +- * @param p Point to be checked. +- * +- * @return 'this' if the point is on a part of the MessageWidget. +- * NB In case of a synchronous message, the empty space +- * between call line and return line does not count, i.e. if +- * the point is located in that space the function returns NULL. +- */ +-UMLWidget* MessageWidget::onWidget(const QPointF& p) +-{ +- if (m_sequenceMessageType != Uml::SequenceMessage::Synchronous) { +- return UMLWidget::onWidget(p); +- } +- // Synchronous message: +- // Consists of top arrow (call) and bottom arrow (return.) +- if (p.x() < x() || p.x() > x() + width()) +- return NULL; +- const int tolerance = 5; // pixels +- const int pY = p.y(); +- const int topArrowY = y() + 3; +- const int bottomArrowY = y() + height() - 3; +- if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance) +- return NULL; +- if (height() <= 2 * tolerance) +- return this; +- if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance) +- return NULL; +- return this; +-} +- +-/** +- * Sets the text position relative to the sequence message. +- */ +-void MessageWidget::setTextPosition() +-{ +- if (m_pFText == NULL) { +- DEBUG(DBG_SRC) << "m_pFText is NULL"; +- return; +- } +- if (m_pFText->displayText().isEmpty()) { +- return; +- } +- m_pFText->updateGeometry(); +- int ftX = constrainX(m_pFText->x(), m_pFText->width(), m_pFText->textRole()); +- int ftY = y() - m_pFText->height(); +- m_pFText->setX(ftX); +- m_pFText->setY(ftY); +-} +- +-/** +- * Returns the textX arg with constraints applied. +- * Auxiliary to setTextPosition() and constrainTextPos(). +- */ +-int MessageWidget::constrainX(int textX, int textWidth, Uml::TextRole::Enum tr) +-{ +- int result = textX; +- const int minTextX = x() + 5; +- if (textX < minTextX || tr == Uml::TextRole::Seq_Message_Self) { +- result = minTextX; +- } else { +- ObjectWidget *objectAtRight = NULL; +- if (m_pOw[Uml::RoleType::B]->x() > m_pOw[Uml::RoleType::A]->x()) +- objectAtRight = m_pOw[Uml::RoleType::B]; +- else +- objectAtRight = m_pOw[Uml::RoleType::A]; +- const int objRight_seqLineX = objectAtRight->centerX(); +- const int maxTextX = objRight_seqLineX - textWidth - 5; +- if (maxTextX <= minTextX) +- result = minTextX; +- else if (textX > maxTextX) +- result = maxTextX; +- } +- return result; +-} +- +-/** +- * Constrains the FloatingTextWidget X and Y values supplied. +- * Overrides operation from LinkWidget. +- * +- * @param textX candidate X value (may be modified by the constraint) +- * @param textY candidate Y value (may be modified by the constraint) +- * @param textWidth width of the text +- * @param textHeight height of the text +- * @param tr Uml::TextRole::Enum of the text +- */ +-void MessageWidget::constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, +- Uml::TextRole::Enum tr) +-{ +- textX = constrainX(textX, textWidth, tr); +- // Constrain Y. +- const qreal minTextY = getMinY(); +- const qreal maxTextY = getMaxY() - textHeight - 5; +- if (textY < minTextY) +- textY = minTextY; +- else if (textY > maxTextY) +- textY = maxTextY; +-// setY(textY + textHeight); // NB: side effect +-} +- +-/** +- * Shortcut for calling m_pFText->setLink() followed by +- * this->setTextPosition(). +- */ +-void MessageWidget::setLinkAndTextPos() +-{ +- if (m_pFText) { +- m_pFText->setLink(this); +- setTextPosition(); +- } +-} +- +-void MessageWidget::resizeEvent(QResizeEvent* /*re*/) +-{ +-} +- +-/** +- * Calculate the geometry of the widget. +- */ +-void MessageWidget::calculateWidget() +-{ +- setMessageText(m_pFText); +- calculateDimensions(); +- setVisible(true); +-} +- +-void MessageWidget::slotWidgetMoved(Uml::ID::Type id) +-{ +- const Uml::ID::Type idA = m_pOw[Uml::RoleType::A]->localID(); +- const Uml::ID::Type idB = m_pOw[Uml::RoleType::B]->localID(); +- if (idA != id && idB != id) { +- DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA) +- << ", idB=" << Uml::ID::toString(idB); +- return; +- } +- qreal y = this->y(); +- if (y < getMinY()) +- y = getMinY(); +- if (y > getMaxY()) +- y = getMaxY(); +- setPos(x(), y); +- calculateWidget(); +- if(!m_pFText) +- return; +- if (m_scene->selectedCount(true) > 1) +- return; +- setTextPosition(); +-} +- +-/** +- * Check to see if the given ObjectWidget is involved in the message. +- * +- * @param w The ObjectWidget to check for. +- * @return true - if is contained, false - not contained. +- */ +-bool MessageWidget::hasObjectWidget(ObjectWidget * w) +-{ +- if(m_pOw[Uml::RoleType::A] == w || m_pOw[Uml::RoleType::B] == w) +- return true; +- else +- return false; +-} +- +-/** +- * This method determines whether the message is for "Self" for +- * an ObjectWidget. +- * +- * @retval True If both ObjectWidgets for this widget exists and +- * are same. +- */ +-bool MessageWidget::isSelf() const +-{ +- return (m_pOw[Uml::RoleType::A] && m_pOw[Uml::RoleType::B] && +- m_pOw[Uml::RoleType::A] == m_pOw[Uml::RoleType::B]); +-} +- +-void MessageWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- if (sel == ListPopupMenu::mt_Delete) { +- // This will clean up this widget and the text widget: +- m_scene->removeWidget(this); +- } else { +- +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-/** +- * Activates a MessageWidget. Connects its m_pOw[] pointers +- * to UMLObjects and also send signals about its FloatingTextWidget. +- */ +-bool MessageWidget::activate(IDChangeLog * /*Log = 0*/) +-{ +- m_scene->resetPastep-kf6oint(); +- // UMLWidget::activate(Log); CHECK: I don't think we need this ? +- if (m_pOw[Uml::RoleType::A] == NULL) { +- UMLWidget *pWA = m_scene->findWidget(m_widgetAId); +- if (pWA == NULL) { +- DEBUG(DBG_SRC) << "role A object " << Uml::ID::toString(m_widgetAId) << " not found"; +- return false; +- } +- m_pOw[Uml::RoleType::A] = dynamic_cast(pWA); +- if (m_pOw[Uml::RoleType::A] == NULL) { +- DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) +- << " is not an ObjectWidget"; +- return false; +- } +- } +- if (m_pOw[Uml::RoleType::B] == NULL) { +- UMLWidget *pWB = m_scene->findWidget(m_widgetBId); +- if (pWB == NULL) { +- DEBUG(DBG_SRC) << "role B object " << Uml::ID::toString(m_widgetBId) << " not found"; +- return false; +- } +- m_pOw[Uml::RoleType::B] = dynamic_cast(pWB); +- if (m_pOw[Uml::RoleType::B] == NULL) { +- DEBUG(DBG_SRC) << "role B widget " << Uml::ID::toString(m_widgetBId) +- << " is not an ObjectWidget"; +- return false; +- } +- } +- updateResizability(); +- +- UMLClassifier *c = dynamic_cast(m_pOw[Uml::RoleType::B]->umlObject()); +- UMLOperation *op = NULL; +- if (c && !m_CustomOp.isEmpty()) { +- Uml::ID::Type opId = Uml::ID::fromString(m_CustomOp); +- op = dynamic_cast(c->findChildObjectById(opId, true)); +- if (op) { +- // If the UMLOperation is set, m_CustomOp isn't used anyway. +- // Just setting it empty for the sake of sanity. +- m_CustomOp.clear(); +- } +- } +- +- if(!m_pFText) { +- Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; +- if (isSelf()) +- tr = Uml::TextRole::Seq_Message_Self; +- m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene)); +- m_scene->addFloatingTextWidget(m_pFText); +- m_pFText->setFontCmd(UMLWidget::font()); +- } +- if (op) +- setOperation(op); // This requires a valid m_pFText. +- setLinkAndTextPos(); +- m_pFText->setText(QString()); +- m_pFText->setActivated(); +- QString messageText = m_pFText->text(); +- m_pFText->setVisible(messageText.length() > 1); +- +- connect(m_pOw[Uml::RoleType::A], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); +- connect(m_pOw[Uml::RoleType::B], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); +- +- connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); +- connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); +- m_pOw[Uml::RoleType::A]->messageAdded(this); +- if (!isSelf()) +- m_pOw[Uml::RoleType::B]->messageAdded(this); +- +- // Calculate the size and position of the message widget +- calculateDimensions(); +- +- // Position the floating text accordingly +- setTextPosition(); +- +- emit sigMessageMoved(); +- return true; +-} +- +-/** +- * Resolve references of this message so they reference the correct +- * new object widgets after paste. +- */ +-void MessageWidget::resolveObjectWidget(IDChangeLog* log) { +- m_widgetAId = log->findNewID(m_widgetAId); +- m_widgetBId = log->findNewID(m_widgetBId); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @param ft The text widget which to update. +- */ +-void MessageWidget::setMessageText(FloatingTextWidget *ft) +-{ +- if (ft == NULL) +- return; +- ft->setSequenceNumber(m_SequenceNumber); +- ft->setText(operationText(m_scene)); +- setTextPosition(); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @param ft The text widget which to update. +- * @param newText The new text to set. +- */ +-void MessageWidget::setText(FloatingTextWidget *ft, const QString &newText) +-{ +- ft->setText(newText); +- UMLApp::app()->document()->setModified(true); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * +- * @param op The new operation string to set. +- */ +-void MessageWidget::setOperationText(const QString &op) +-{ +- m_CustomOp = op; ///FIXME m_pOperation +-} +- +-/** +- * Implements operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-void MessageWidget::lwSetFont (QFont font) +-{ +- UMLWidget::setFont(font); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- * @todo Move to LinkWidget. +- */ +-UMLClassifier *MessageWidget::operationOwner() +-{ +- UMLObject *pObject = m_pOw[Uml::RoleType::B]->umlObject(); +- if (pObject == NULL) +- return NULL; +- UMLClassifier *c = dynamic_cast(pObject); +- return c; +-} +- +-/** +- * Implements operation from LinkWidget. +- * Motivated by FloatingTextWidget. +- */ +-UMLOperation *MessageWidget::operation() +-{ +- return static_cast(m_umlObject); +-} +- +-/** +- * Implements operation from LinkWidget. +- * Motivated by FloatingTextWidget. +- */ +-void MessageWidget::setOperation(UMLOperation *op) +-{ +- if (m_umlObject && m_pFText) +- disconnect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); +- m_umlObject = op; +- if (m_umlObject && m_pFText) { +- connect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); +- m_pFText->setMessageText(); +- } +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-QString MessageWidget::customOpText() +-{ +- return m_CustomOp; +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-void MessageWidget::setCustomOpText(const QString &opText) +-{ +- m_CustomOp = opText; +- m_pFText->setMessageText(); +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-QString MessageWidget::lwOperationText() +-{ +- UMLOperation *pOperation = operation(); +- if (pOperation != NULL) { +- return pOperation->toString(Uml::SignatureType::SigNoVis); +- } else { +- return customOpText(); +- } +-} +- +-/** +- * Overrides operation from LinkWidget. +- * Required by FloatingTextWidget. +- */ +-UMLClassifier *MessageWidget::lwClassifier() +-{ +- UMLObject *o = m_pOw[Uml::RoleType::B]->umlObject(); +- UMLClassifier *c = dynamic_cast(o); +- return c; +-} +- +-/** +- * Calculates the size of the widget by calling +- * calculateDimensionsSynchronous(), +- * calculateDimensionsAsynchronous(), or +- * calculateDimensionsCreation() +- */ +-void MessageWidget::calculateDimensions() +-{ +- if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { +- calculateDimensionsSynchronous(); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { +- calculateDimensionsAsynchronous(); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { +- calculateDimensionsCreation(); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { +- calculateDimensionsLost(); +- } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { +- calculateDimensionsFound(); +- } else { +- uWarning() << "Unknown message type"; +- } +- if (! UMLApp::app()->document()->loading()) { +- adjustAssocs(x(), y()); // adjust assoc lines +- } +-} +- +-/** +- * Calculates and sets the size of the widget for a synchronous message. +- */ +-void MessageWidget::calculateDimensionsSynchronous() +-{ +- int x = 0; +- +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_pOw[Uml::RoleType::B]->centerX(); +- +- int widgetWidth = 0; +- int widgetHeight = 0; +- if(isSelf()) { +- widgetWidth = 50; +- x = x1 - 2; +- } else if(x1 < x2) { +- x = x1; +- widgetWidth = x2 - x1 + 8; +- } else { +- x = x2 - 8; +- widgetWidth = x1 - x2 + 8; +- } +- +- if (height() < 20) { +- widgetHeight = 20; +- } else { +- widgetHeight = height(); +- } +- +- setX(x); +- setSize(widgetWidth, widgetHeight); +-} +- +-/** +- * Calculates and sets the size of the widget for an asynchronous message. +- */ +-void MessageWidget::calculateDimensionsAsynchronous() +-{ +- int x = 0; +- +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_pOw[Uml::RoleType::B]->centerX(); +- +- int widgetWidth = 0; +- int widgetHeight = 8; +- if(isSelf()) { +- widgetWidth = 50; +- x = x1; +- if(height() < 20) { +- widgetHeight = 20; +- } else { +- widgetHeight = height(); +- } +- } else if(x1 < x2) { +- x = x1; +- widgetWidth = x2 - x1; +- } else { +- x = x2; +- widgetWidth = x1 - x2; +- } +- x += 1; +- widgetWidth -= 2; +- setX(x); +- setSize(widgetWidth, widgetHeight); +-} +- +-/** +- * Calculates and sets the size of the widget for a creation message. +- */ +-void MessageWidget::calculateDimensionsCreation() +-{ +- int x = 0; +- +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_pOw[Uml::RoleType::B]->x(); +- int w2 = m_pOw[Uml::RoleType::B]->width(); +- +- if (x1 > x2) +- x2 += w2; +- +- int widgetWidth = 0; +- int widgetHeight = 8; +- if (x1 < x2) { +- x = x1; +- widgetWidth = x2 - x1; +- } else { +- x = x2; +- widgetWidth = x1 - x2; +- } +- x += 1; +- widgetWidth -= 2; +- setPos(x, m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height() / 2); +- setSize(widgetWidth, widgetHeight); +-} +- +-/** +- * Calculates and sets the size of the widget for a lost message. +- */ +-void MessageWidget::calculateDimensionsLost() +-{ +- int x = 0; +- +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_xclicked; +- +- int widgetWidth = 0; +- int widgetHeight = 10; +- if(x1 < x2) { +- x = x1; +- widgetWidth = x2 - x1 + circleWidth/2; +- } else { +- x = x2 - circleWidth/2; +- widgetWidth = x1 - x2 + circleWidth/2; +- } +- setX(x); +- setSize(widgetWidth, widgetHeight); +-} +- +-/** +- * Calculates and sets the size of the widget for a found message. +- */ +-void MessageWidget::calculateDimensionsFound() +-{ +- int x = 0; +- +- int x1 = m_pOw[Uml::RoleType::A]->centerX(); +- int x2 = m_xclicked; +- +- int widgetWidth = 0; +- int widgetHeight = 10; +- if(x1 < x2) { +- x = x1; +- widgetWidth = x2 - x1 + circleWidth/2; +- } else { +- x = x2 - circleWidth/2; +- widgetWidth = x1 - x2 + circleWidth/2; +- } +- +- setX(x); +- setSize(widgetWidth, widgetHeight); +-} +- +-/** +- * Used to cleanup any other widget it may need to delete. +- */ +-void MessageWidget::cleanup() +-{ +- if (m_pOw[Uml::RoleType::A]) { +- disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); +- m_pOw[Uml::RoleType::A]->messageRemoved(this); +- } +- if (m_pOw[Uml::RoleType::B]) { +- disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); +- m_pOw[Uml::RoleType::B]->messageRemoved(this); +- } +- +- UMLWidget::cleanup(); +- if (m_pFText) { +- m_scene->removeWidgetCmd(m_pFText); +- m_pFText = NULL; +- } +-} +- +-/** +- * Sets the state of whether the widget is selected. +- * +- * @param _select True if the widget is selected. +- */ +-void MessageWidget::setSelected(bool _select) +-{ +- UMLWidget::setSelected(_select); +- if(!m_pFText || m_pFText->displayText().isEmpty()) +- return; +- if(isSelected() && m_pFText->isSelected()) +- return; +- if(!isSelected() && !m_pFText->isSelected()) +- return; +- +- m_pFText->setSelected(isSelected()); +-} +- +-/** +- * 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 MessageWidget::getMinY() +-{ +- if (!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { +- return 0; +- } +- if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { +- return m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); +- } +- int heightA = m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); +- int heightB = m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height(); +- int height = heightA; +- if(heightA < heightB) { +- height = heightB; +- } +- return height; +-} +- +-/** +- * 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 MessageWidget::getMaxY() +-{ +- if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { +- return 0; +- } +- int heightA = (int)((ObjectWidget*)m_pOw[Uml::RoleType::A])->getEndLineY(); +- int heightB = (int)((ObjectWidget*)m_pOw[Uml::RoleType::B])->getEndLineY(); +- int height = heightA; +- if(heightA > heightB) { +- height = heightB; +- } +- return (height - this->height()); +-} +- +-/** +- * Sets the related widget on the given side. +- * +- * @param ow The ObjectWidget we are related to. +- * @param role The Uml::RoleType::Enum to be set for the ObjectWidget +- */ +-void MessageWidget::setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) +-{ +- m_pOw[role] = ow; +- updateResizability(); +-} +- +-/** +- * Returns the related widget on the given side. +- * +- * @return The ObjectWidget we are related to. +- */ +-ObjectWidget* MessageWidget::objectWidget(Uml::RoleType::Enum role) +-{ +- return m_pOw[role]; +-} +- +-/** +- * Set the xclicked +- */ +-void MessageWidget::setxclicked(int xclick) +-{ +- m_xclicked = xclick; +-} +- +-/** +- * Set the yclicked +- */ +-void MessageWidget::setyclicked(int yclick) +-{ +- m_yclicked = yclick; +-} +- +-/** +- * Event handler for mouse double click events. +- * @param event QGraphicsSceneMouseEvent which triggered the double click event +- */ +-void MessageWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +-{ +- Q_UNUSED(event) +- DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET!"; +- if (m_pFText != NULL) { +- DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET - on floating text widget!"; +-// QAction* action = m_pMenu->getAction(ListPopupMenu::mt_Select_Operation); +-// m_pFText->slotMenuSelection(action); +- } +-} +- +-/** +- * Saves to the "messagewidget" XMI element. +- */ +-void MessageWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement messageElement = qDoc.createElement(QLatin1String("messagewidget")); +- UMLWidget::saveToXMI(qDoc, messageElement); +- LinkWidget::saveToXMI(qDoc, messageElement); +- if (m_pOw[Uml::RoleType::A]) +- messageElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_pOw[Uml::RoleType::A]->localID())); +- if (m_pOw[Uml::RoleType::B]) +- messageElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(m_pOw[Uml::RoleType::B]->localID())); +- UMLOperation *pOperation = operation(); +- if (pOperation) +- messageElement.setAttribute(QLatin1String("operation"), Uml::ID::toString(pOperation->id())); +- else +- messageElement.setAttribute(QLatin1String("operation"), m_CustomOp); +- messageElement.setAttribute(QLatin1String("sequencemessagetype"), m_sequenceMessageType); +- if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { +- messageElement.setAttribute(QLatin1String("xclicked"), m_xclicked); +- messageElement.setAttribute(QLatin1String("yclicked"), m_yclicked); +- } +- +- // save the corresponding message text +- if (m_pFText && !m_pFText->text().isEmpty()) { +- messageElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pFText->id())); +- m_pFText->saveToXMI(qDoc, messageElement); +- } +- +- qElement.appendChild(messageElement); +-} +- +-/** +- * Loads from the "messagewidget" XMI element. +- */ +-bool MessageWidget::loadFromXMI(QDomElement& qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) { +- return false; +- } +- if (!LinkWidget::loadFromXMI(qElement)) { +- return false; +- } +- QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); +- QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); +- QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); +- m_CustomOp = qElement.attribute(QLatin1String("operation")); +- QString sequenceMessageType = qElement.attribute(QLatin1String("sequencemessagetype"), QLatin1String("1001")); +- m_sequenceMessageType = Uml::SequenceMessage::fromInt(sequenceMessageType.toInt()); +- if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { +- m_xclicked = qElement.attribute(QLatin1String("xclicked"), QLatin1String("-1")).toFloat(); +- m_yclicked = qElement.attribute(QLatin1String("yclicked"), QLatin1String("-1")).toFloat(); +- } +- +- m_widgetAId = Uml::ID::fromString(widgetaid); +- m_widgetBId = Uml::ID::fromString(widgetbid); +- m_textId = Uml::ID::fromString(textid); +- +- Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; +- if (m_widgetAId == m_widgetBId) +- tr = Uml::TextRole::Seq_Message_Self; +- +- //now load child elements +- QDomNode node = qElement.firstChild(); +- QDomElement element = node.toElement(); +- if (!element.isNull()) { +- QString tag = element.tagName(); +- if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { +- m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene), m_textId); +- m_scene->addFloatingTextWidget(m_pFText); +- if(! m_pFText->loadFromXMI(element)) { +- // Most likely cause: The FloatingTextWidget is empty. +- delete m_pFText; +- m_pFText = NULL; +- } +- else +- m_pFText->setSequenceNumber(m_SequenceNumber); +- } else { +- uError() << "unknown tag " << tag; +- } +- } +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.h umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,212 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef MESSAGEWIDGET_H +-#define MESSAGEWIDGET_H +- +-#include "umlwidget.h" +-#include "linkwidget.h" +- +-// forward declarations +-class FloatingTextWidget; +-class ObjectWidget; +-class QResizeEvent; +-class UMLOperation; +- +-/** +- * Used to display a message on a sequence diagram. The message +- * could be between two objects or a message that calls itself on +- * an object. This class will only display the line that is +- * required and the text will be setup by the @ref FloatingTextWidget +- * widget that is passed in the constructor. A message can be +- * synchronous (calls a method and gains control back on return, +- * as happens in most programming languages) or asynchronous +- * (calls a method and gains back control immediately). +- * +- * @short Displays a message. +- * @author Paul Hensgen +- * @see UMLWidget +- * @see ObjectWidget +- * @see FloatingTextWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class MessageWidget : public UMLWidget, public LinkWidget +-{ +- Q_OBJECT +-public: +- MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, +- int y, Uml::SequenceMessage::Enum sequenceMessageType, +- Uml::ID::Type id = Uml::ID::None); +- MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum sequenceMessageType, +- Uml::ID::Type id = Uml::ID::None); +- MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, +- Uml::SequenceMessage::Enum sequenceMessageType, +- Uml::ID::Type id = Uml::ID::None); +- virtual ~MessageWidget(); +- +- virtual void setY(qreal y); +- +- //---------- LinkWidget Interface methods implemementation from now on. +- +- virtual void lwSetFont (QFont font); +- virtual UMLClassifier *operationOwner(); +- +- virtual UMLOperation *operation(); +- virtual void setOperation(UMLOperation *op); +- +- virtual QString customOpText(); +- virtual void setCustomOpText(const QString &opText); +- +- virtual void setMessageText(FloatingTextWidget *ft); +- virtual void setText(FloatingTextWidget *ft, const QString &newText); +- +- virtual QString lwOperationText(); +- virtual UMLClassifier *lwClassifier(); +- virtual void setOperationText(const QString &op); +- +- virtual void constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, +- Uml::TextRole::Enum tr); +- +- //---------- End LinkWidget Interface methods implemementation. +- +- /// @return Whether the message is synchronous or asynchronous +- Uml::SequenceMessage::Enum sequenceMessageType() const { +- return m_sequenceMessageType; +- } +- +- bool hasObjectWidget(ObjectWidget * w); +- +- ObjectWidget* objectWidget(Uml::RoleType::Enum role); +- void setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) ; +- +- bool isSelf() const; +- +- /** +- * Returns the text widget it is related to. +- * +- * @return The text widget we are related to. +- */ +- FloatingTextWidget * floatingTextWidget() { +- return m_pFText; +- } +- +- /** +- * Sets the text widget it is related to. +- * +- * @param f The text widget we are related to. +- */ +- void setFloatingTextWidget(FloatingTextWidget * f) { +- m_pFText = f; +- } +- +- void calculateWidget(); +- +- virtual bool activate(IDChangeLog * Log = 0); +- void resolveObjectWidget(IDChangeLog* log); +- +- void calculateDimensions(); +- void calculateDimensionsSynchronous(); +- void calculateDimensionsAsynchronous(); +- void calculateDimensionsCreation(); +- void calculateDimensionsLost(); +- void calculateDimensionsFound(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- void setTextPosition(); +- +- void cleanup(); +- +- void setSelected(bool _select); +- +- int getMinY(); +- int getMaxY(); +- +- UMLWidget* onWidget(const QPointF& p); +- +- virtual void resizeWidget(qreal newW, qreal newH); +- +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- virtual bool loadFromXMI(QDomElement & qElement); +- +- void setxclicked(int xclick); +- void setyclicked(int yclick); +- +- /** +- * Return the xclicked +- */ +- int getxclicked() const { +- return m_xclicked; +- } +- +-protected: +- virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); +- +- virtual void moveWidgetBy(qreal diffX, qreal diffY); +- virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); +- +- virtual QCursor resizeCursor() const; +- +- void setLinkAndTextPos(); +- +- int constrainX(int textX, int textWidth, Uml::TextRole::Enum tr); +- +- static void paintArrow(QPainter *p, int x, int y, int w, +- Qt::ArrowType direction, bool useDottedLine = false); +- static void paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction); +- +- void updateResizability(); +- +- void paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option); +- void paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option); +- +- // Data loaded/saved +- QString m_CustomOp; +- /** +- * Whether the message is synchronous or asynchronous +- */ +- Uml::SequenceMessage::Enum m_sequenceMessageType; +- +-private: +- void resizeEvent(QResizeEvent *re); +- +- qreal constrainPositionY(qreal diffY); +- +- void init(); +- +- ObjectWidget * m_pOw[2]; +- FloatingTextWidget * m_pFText; +- +- int m_xclicked; +- int m_yclicked; +- +- /** +- * The following variables are used by loadFromXMI() as an intermediate +- * store. activate() resolves the IDs, i.e. after activate() the variables +- * m_pOw[] and m_pFText can be used. +- */ +- Uml::ID::Type m_widgetAId, m_widgetBId, m_textId; +- +-public slots: +- void slotWidgetMoved(Uml::ID::Type id); +- void slotMenuSelection(QAction* action); +- +-signals: +- /** +- * emitted when the message widget is moved up or down +- * slots into ObjectWidget::slotMessageMoved() +- */ +- void sigMessageMoved(); +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,156 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "nodewidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "node.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// qt includes +-#include +-#include +- +-DEBUG_REGISTER_DISABLED(NodeWidget) +- +-/** +- * Constructs a NodeWidget. +- * +- * @param scene The parent of this NodeWidget. +- * @param n The UMLNode this will be representing. +- */ +-NodeWidget::NodeWidget(UMLScene * scene, UMLNode *n) +- : UMLWidget(scene, WidgetBase::wt_Node, n) +-{ +- setSize(100, 30); +- setZValue(1); // above box but below UMLWidget because may embed widgets +-} +- +-/** +- * Destructor. +- */ +-NodeWidget::~NodeWidget() +-{ +-} +- +-/** +- * Overrides standard method. +- */ +-void NodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } else { +- painter->setBrush(m_scene->backgroundColor()); +- } +- const int w = width(); +- const int h = height(); +- const int wDepth = (w/3 > DEPTH ? DEPTH : w/3); +- const int hDepth = (h/3 > DEPTH ? DEPTH : h/3); +- const int bodyOffsetY = hDepth; +- const int bodyWidth = w - wDepth; +- const int bodyHeight = h - hDepth; +- QFont font = UMLWidget::font(); +- font.setBold(true); +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- QString nameStr = name(); +- +- QPolygon pointArray(5); +- pointArray.setPoint(0, 0, bodyOffsetY); +- pointArray.setPoint(1, wDepth, 0); +- pointArray.setPoint(2, w, 0); +- pointArray.setPoint(3, w, bodyHeight); +- pointArray.setPoint(4, bodyWidth, h); +- painter->drawPolygon(pointArray); +- painter->drawRect(0, bodyOffsetY, bodyWidth, bodyHeight); +- painter->drawLine(w, 0, bodyWidth, bodyOffsetY); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- int lines = 1; +- if (m_umlObject) { +- QString stereotype = m_umlObject->stereotype(); +- if (!stereotype.isEmpty()) { +- painter->drawText(0, bodyOffsetY + (bodyHeight/2) - fontHeight, +- bodyWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); +- lines = 2; +- } +- } +- +- if (UMLWidget::isInstance()) { +- font.setUnderline(true); +- painter->setFont(font); +- nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; +- } +- +- if (lines == 1) { +- painter->drawText(0, bodyOffsetY + (bodyHeight/2) - (fontHeight/2), +- bodyWidth, fontHeight, Qt::AlignCenter, nameStr); +- } else { +- painter->drawText(0, bodyOffsetY + (bodyHeight/2), +- bodyWidth, fontHeight, Qt::AlignCenter, nameStr); +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF NodeWidget::minimumSize() const +-{ +- if (m_umlObject == NULL) { +- DEBUG(DBG_SRC) << "m_umlObject is NULL"; +- return UMLWidget::minimumSize(); +- } +- +- const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); +- const int fontHeight = fm.lineSpacing(); +- +- QString name = m_umlObject->name(); +- if (UMLWidget::isInstance()) { +- name = UMLWidget::instanceName() + QLatin1String(" : ") + name; +- } +- +- int width = fm.width(name) + 2 * defaultMargin; +- +- int tempWidth = 0; +- if (!m_umlObject->stereotype().isEmpty()) { +- tempWidth = fm.width(m_umlObject->stereotype(true)); +- } +- if (tempWidth > width) +- width = tempWidth; +- width += DEPTH; +- +- int height = (2*fontHeight) + DEPTH; +- +- return QSizeF(width, height); +-} +- +-/** +- * Saves to the "nodewidget" XMI element. +- * Note: For loading we use the method inherited from UMLWidget. +- */ +-void NodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("nodewidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- qElement.appendChild(conceptElement); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.h umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,44 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef NODEWIDGET_H +-#define NODEWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLNode; +- +-/** +- * Defines a graphical version of the Node. Most of the functionality +- * will come from the @ref UMLNode class. +- * +- * @short A graphical version of a Node. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class NodeWidget : public UMLWidget +-{ +-public: +- +- NodeWidget(UMLScene * scene, UMLNode *n); +- virtual ~NodeWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-protected: +- QSizeF minimumSize() const; +- +- static const int DEPTH = 30; ///< pixels on Z axis +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/notewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/notewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,517 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "notewidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "listpopupmenu.h" +-#include "notedialog.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#include +-#endif +- +-// qt includes +-#include +-#if QT_VERSION >= 0x050000 +-#include +-#include +-#endif +- +-NoteWidget * NoteWidget::s_pCurrentNote; +- +-/** +- * Constructs a NoteWidget. +- * +- * @param scene The parent to this widget. +- * @param noteType The NoteWidget::NoteType of this NoteWidget +- * @param id The unique id of the widget. +- * The default (-1) will prompt a new ID. +- */ +-NoteWidget::NoteWidget(UMLScene * scene, NoteType noteType , Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_Note, id), +- m_diagramLink(Uml::ID::None), +- m_noteType(noteType) +-{ +- setZValue(20); //make sure always on top. +-} +- +-/** +- * Destructor. +- */ +-NoteWidget::~NoteWidget() +-{ +-} +- +-/** +- * Override default method. +- */ +-void NoteWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- const int margin = 10; +- int w = width(); +- int h = height(); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- QPolygon poly(6); +- poly.setPoint(0, 0, 0); +- poly.setPoint(1, 0, h); +- poly.setPoint(2, w, h); +- poly.setPoint(3, w, margin); +- poly.setPoint(4, w - margin, 0); +- poly.setPoint(5, 0, 0); +- +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) { +- QBrush brush(UMLWidget::fillColor()); +- painter->setBrush(brush); +- painter->drawPolygon(poly); +- } else +- painter->drawPolyline(poly); +- painter->drawLine(w - margin, 0, w - margin, margin); +- painter->drawLine(w - margin, margin, w, margin); +- painter->setPen(textColor()); +- switch(m_noteType) { +- case NoteWidget::PreCondition : +- painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< precondition >>")); +- break; +- case NoteWidget::PostCondition : +- painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< postcondition >>")); +- break; +- case NoteWidget::Transformation : +- painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< transformation >>")); +- break; +- case NoteWidget::Normal : +- default : +- break; +- } +- +- UMLWidget::paint(painter, option, widget); +- +-// paintText(&p, 0, 0); +- paintTextWordWrap(painter); +-} +- +-/** +- * Returns the type of note. +- */ +-NoteWidget::NoteType NoteWidget::noteType() const +-{ +- return m_noteType; +-} +- +-/** +- * Converts a string to NoteWidget::NoteType. +- */ +-NoteWidget::NoteType NoteWidget::stringToNoteType(const QString& noteType) +-{ +- if (noteType == QLatin1String("Precondition")) +- return NoteWidget::PreCondition; +- else if (noteType == QLatin1String("Postcondition")) +- return NoteWidget::PostCondition; +- else if (noteType == QLatin1String("Transformation")) +- return NoteWidget::Transformation; +- else +- return NoteWidget::Normal; +-} +- +-/** +- * Sets the type of note. +- */ +-void NoteWidget::setNoteType(NoteType noteType) +-{ +- m_noteType = noteType; +-} +- +-/** +- * Sets the type of note. +- */ +-void NoteWidget::setNoteType(const QString& noteType) +-{ +- setNoteType(stringToNoteType(noteType)); +-} +- +-/** +- * Return the ID of the diagram hyperlinked to this note. +- * +- * @return ID of an UMLView, or Uml::ID::None if no +- * hyperlink is set. +- */ +-Uml::ID::Type NoteWidget::diagramLink() const +-{ +- return m_diagramLink; +-} +- +-/** +- * Set the ID of the diagram hyperlinked to this note. +- * To switch off the hyperlink, set this to Uml::id_None. +- * +- * @param viewID ID of an UMLScene. +- */ +-void NoteWidget::setDiagramLink(Uml::ID::Type viewID) +-{ +- UMLDoc *umldoc = UMLApp::app()->document(); +- UMLView *view = umldoc->findView(viewID); +- if (view == NULL) { +- uError() << "no view found for viewID " << Uml::ID::toString(viewID); +- return; +- } +- QString linkText(QLatin1String("Diagram: ") + view->umlScene()->name()); +- setDocumentation(linkText); +- m_diagramLink = viewID; +- update(); +-} +- +-/** +- * Display a dialog box to allow the user to choose the note's type. +- */ +-void NoteWidget::askForNoteType(UMLWidget* &targetWidget) +-{ +- static const QStringList list = QStringList() << i18n("Precondition") +- << i18n("Postcondition") +- << i18n("Transformation"); +- bool pressedOK = false; +- +-#if QT_VERSION >= 0x050000 +- QString type = QInputDialog::getItem (UMLApp::app(), +- i18n("Note Type"), i18n("Select the Note Type"), list, +- 0, false, &pressedOK); +-#else +- QString type = KInputDialog::getItem (i18n("Note Type"), i18n("Select the Note Type"), list, +- 0, false, &pressedOK, UMLApp::app()); +-#endif +- +- if (pressedOK) { +- dynamic_cast(targetWidget)->setNoteType(type); +- } else { +- targetWidget->cleanup(); +- delete targetWidget; +- targetWidget = 0; +- } +-} +- +-/** +- * Loads a "notewidget" XMI element. +- */ +-bool NoteWidget::loadFromXMI(QDomElement & qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) +- return false; +- setZValue(20); //make sure always on top. +- setDocumentation(qElement.attribute(QLatin1String("text"))); +- QString diagramlink = qElement.attribute(QLatin1String("diagramlink")); +- if (!diagramlink.isEmpty()) +- m_diagramLink = Uml::ID::fromString(diagramlink); +- QString type = qElement.attribute(QLatin1String("noteType")); +- setNoteType((NoteType)type.toInt()); +- return true; +-} +- +-/** +- * Saves to the "notewidget" XMI element. +- */ +-void NoteWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement noteElement = qDoc.createElement(QLatin1String("notewidget")); +- UMLWidget::saveToXMI(qDoc, noteElement); +- noteElement.setAttribute(QLatin1String("text"), documentation()); +- if (m_diagramLink != Uml::ID::None) +- noteElement.setAttribute(QLatin1String("diagramlink"), Uml::ID::toString(m_diagramLink)); +- noteElement.setAttribute(QLatin1String("noteType"), m_noteType); +- qElement.appendChild(noteElement); +-} +- +-/** +- * Show a properties dialog for a NoteWidget. +- */ +-void NoteWidget::showPropertiesDialog() +-{ +- NoteDialog * dlg = 0; +- UMLApp::app()->docWindow()->updateDocumentation(false); +- dlg = new NoteDialog(umlScene()->activeView(), this); +- if (dlg->exec()) { +- UMLApp::app()->docWindow()->showDocumentation(this, true); +- UMLApp::app()->document()->setModified(true); +- update(); +- } +- delete dlg; +-} +- +-/** +- * Will be called when a menu selection has been made from the popup +- * menu. +- * +- * @param action The action that has been selected. +- */ +-void NoteWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Rename: +- showPropertiesDialog(); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- break; +- } +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF NoteWidget::minimumSize() const +-{ +- int width = 60; +- int height = 30; +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int textWidth = fm.width(documentation()); +- if (m_noteType == PreCondition) { +- const int widthtemp = fm.width(QLatin1String("<< precondition >>")); +- width = textWidth > widthtemp ? textWidth : widthtemp; +- width += 10; +- } +- else if (m_noteType == PostCondition) { +- const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); +- width = textWidth > widthtemp ? textWidth : widthtemp; +- width += 10; +- } +- else if (m_noteType == Transformation) { +- const int widthtemp = fm.width(QLatin1String("<< transformation >>")); +- width = textWidth > widthtemp ? textWidth : widthtemp; +- width += 10; +- } +- return QSizeF(width, height); +-} +- +-/** +- * Calculate content related size of widget. +- * Overrides method from UMLWidget. +- */ +-QSizeF NoteWidget::calculateSize(bool withExtensions /* = true */) const +-{ +- Q_UNUSED(withExtensions) +- int width = this->width(); +- int height = this->height(); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int margin = fm.width(QLatin1String("W")); +- QSize size = fm.size (0, documentation()); +- const int textWidth = size.width(); +- if (m_noteType == PreCondition) { +- const int widthtemp = fm.width(QLatin1String("<< precondition >>")); +- width = textWidth > widthtemp ? textWidth : widthtemp; +- width += 2 * margin; +- } +- else if (m_noteType == PostCondition) { +- const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); +- width = textWidth > widthtemp ? textWidth : widthtemp; +- width += 2 * margin; +- } +- else if (m_noteType == Transformation) { +- const int widthtemp = fm.width(QLatin1String("<< transformation >>")); +- width = textWidth > widthtemp ? textWidth : widthtemp; +- width += 2 * margin; +- } +- return QSizeF(width, height); +-} +- +-/** +- * Paints the text. Auxiliary to paint(). +- * Implemented without word wrap. +- */ +-void NoteWidget::paintText(QPainter *painter) +-{ +- if (painter == 0) { +- return; +- } +- +- QString text = documentation(); +- if (text.length() == 0) { +- return; +- } +- +- painter->setPen(Qt::black); +- QFont font = UMLWidget::font(); +- painter->setFont(font); +- +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int margin = fm.width(QLatin1String("W")); +- const QSize textSize = fm.size(Qt::TextExpandTabs, text); +- +- const int width = this->width() - margin * 2; +- const int height = this->height() - fontHeight; +- int textY = fontHeight / 2; +- int textX = margin; +- +- if ((textSize.width() < width) && (textSize.height() < height)) { +- // the entire text is small enough - draw it +- painter->drawText(textX, textY, +- textSize.width(), textSize.height(), +- Qt::AlignLeft, text); +- } +- else { +- // not all text can be drawn +- QStringList lines = text.split(QLatin1Char('\n')); +- foreach(const QString& line, lines) { +- int lineWidth = fm.width(line); +- if (lineWidth < width) { +- // line is small enough - draw it +- painter->drawText(textX, textY, +- textSize.width(), fontHeight, +- Qt::AlignLeft, line); +- } +- else { +- // draw a smaller line +- for(int len = line.length(); len > 0; --len) { +- QString smallerLine = line.left(len); +- int smallerLineWidth = fm.width(smallerLine); +- if (smallerLineWidth < width) { +- // line is small enough - draw it +- painter->drawText(textX, textY, +- width, fontHeight, +- Qt::AlignLeft, smallerLine); +- } +- } +- } +- textY += fontHeight; +- if (textY > height) { +- // skip the next lines - size is not enough +- break; +- } +- } +- } +-} +- +-/** +- * Paints the text. Auxiliary to paint(). +- * Implemented with word wrap. +- */ +-void NoteWidget::paintTextWordWrap(QPainter *painter) +-{ +- if (painter == 0) { +- return; +- } +- QString text = documentation(); +- if (text.length() == 0) { +- return; +- } +- // Implement word wrap for text as follows: +- // wrap at width on whole words. +- // if word is wider than width then clip word +- // if reach height exit and don't print anymore +- // start new line on \n character +- painter->setPen(Qt::black); +- QFont font = UMLWidget::font(); +- painter->setFont(font); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- QString word; +- QString fullLine; +- QString testCombineLine; +- const int margin = fm.width(QLatin1String("W")); +- int textY = fontHeight / 2; +- int textX = margin; +- const int width = this -> width() - margin * 2; +- const int height = this -> height() - fontHeight; +- QChar returnChar = QChar::fromLatin1('\n'); +- QChar c; +- +- for (int i = 0; i <= text.length(); ++i) { +- if (i < text.length()) { +- c = text[i]; +- } else { +- // all chars of text have been handled already -> +- // perform this last run to spool current content of "word" +- c = returnChar; +- } +- if (c == returnChar || c.isSpace()) { +- // new word delimiter found -> it is time to decide on word wrap +- testCombineLine = fullLine + QLatin1Char(' ') + word; +- int textWidth = fm.width(testCombineLine); +- if (textX + textWidth > width) { +- // combination of "fullLine" and "word" doesn't fit into one line -> +- // print "fullLine" in current line, update write position to next line +- // and decide then on following actions +- painter->drawText(textX, textY, +- textWidth, fontHeight, Qt::AlignLeft, fullLine); +- fullLine = word; +- word = QString(); +- // update write position +- textX = margin; +- textY += fontHeight; +- if (textY > height) +- return; +- // in case of c==newline -> +- // print "word" and set write position one additional line lower +- if (c == returnChar) { +- // print "word" - which is now "fullLine" and set to next line +- painter->drawText(textX, textY, +- textWidth, fontHeight, Qt::AlignLeft, fullLine); +- fullLine = QString(); +- textX = margin; +- textY += fontHeight; +- if(textY > height) return; +- } +- } +- else if (c == returnChar) { +- // newline found and combination of "fullLine" and "word" fits +- // in one line +- painter->drawText(textX, textY, +- textWidth, fontHeight, Qt::AlignLeft, testCombineLine); +- fullLine = word = QString(); +- textX = margin; +- textY += fontHeight; +- if (textY > height) +- return; +- } else { +- // word delimiter found, and combination of "fullLine", space and "word" fits into one line +- fullLine = testCombineLine; +- word = QString(); +- } +- } else { +- // no word delimiter found --> add current char to "word" +- if (c != QLatin1Char('\0')) +- word += c; +- } +- }//end for +-} +- +-/** +- * Event handler for moude double click events. +- * +- * @param event The QGraphicsSceneMouseEvent event. +- */ +-void NoteWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +-{ +- if (event->button() == Qt::LeftButton) { +- if (m_diagramLink == Uml::ID::None) { +- showPropertiesDialog(); +- } else { +- UMLDoc *umldoc = UMLApp::app()->document(); +- umldoc->changeCurrentView(m_diagramLink); +- } +- event->accept(); +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.h umbrello-kf6-15.08.1/umbrello/widgets/notewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/notewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,83 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef NOTEWIDGET_H +-#define NOTEWIDGET_H +- +-//app includes +-#include "umlwidget.h" +- +-// Qt forward declarations +-class QPainter; +- +-/** +- * Displays a note box to allow multiple lines of text to be displayed. +- * These widgets are diagram specific. They will still need a unique id +- * from the @ref UMLDoc class for deletion and other purpose-kf6s. +- * +- * @short Displays a note box. +- * @author Paul Hensgen +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class NoteWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- +- /// This enum type is used to specify the type of note. +- enum NoteType +- { +- Normal, +- PreCondition, +- PostCondition, +- Transformation +- }; +- +- explicit NoteWidget(UMLScene * scene, NoteWidget::NoteType noteType = Normal, +- Uml::ID::Type id = Uml::ID::None); +- virtual ~NoteWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- static NoteType stringToNoteType(const QString& noteType); +- +- NoteType noteType() const; +- void setNoteType(NoteType noteType); +- void setNoteType(const QString& noteType); +- +- Uml::ID::Type diagramLink() const; +- void setDiagramLink(Uml::ID::Type viewID); +- +- void askForNoteType(UMLWidget* &targetWidget); +- +- virtual void showPropertiesDialog(); +- +- virtual bool loadFromXMI(QDomElement & qElement); +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +- static NoteWidget *s_pCurrentNote; +- +-public Q_SLOTS: +- void slotMenuSelection(QAction* action); +- +-protected: +- virtual QSizeF minimumSize() const; +- virtual QSizeF calculateSize(bool withExtensions = true) const; +- void paintText(QPainter *painter); +- void paintTextWordWrap(QPainter *painter); +- virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); +- +-private: +- Uml::ID::Type m_diagramLink; ///< The diagram/scene this note links to. +- NoteType m_noteType; ///< The type of note. @see NoteWidget::NoteType +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,377 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "objectnodewidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "dialog_utils.h" +-#include "listpopupmenu.h" +-#include "objectnodedialog.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +-#include +- +-#define OBJECTNODE_MARGIN 5 +-#define OBJECTNODE_WIDTH 30 +-#define OBJECTNODE_HEIGHT 10 +- +-/** +- * Creates a Object Node widget. +- * +- * @param scene The parent of the widget. +- * @param objectNodeType The type of object node +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-ObjectNodeWidget::ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType, Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_ObjectNode, id) +-{ +- setObjectNodeType(objectNodeType); +- setState(QString()); +-} +- +-/** +- * Destructor. +- */ +-ObjectNodeWidget::~ObjectNodeWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void ObjectNodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- int w = width(); +- int h = height(); +- +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- int textStartY = (h / 2) - (fontHeight / 2); +- +- setPenFromSettings(painter); +- +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } +- +- painter->drawRect(0, 0, w, h); +- painter->setFont(UMLWidget::font()); +- +- switch (m_objectNodeType) +- { +- case Normal : break; +- case Buffer : +- { +- painter->setPen(textColor()); +- painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< centralBuffer >>")); +- painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); +- } +- break; +- case Data : +- { +- painter->setPen(textColor()); +- painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< datastore >>")); +- painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); +- } +- break; +- case Flow : +- { +- QString objectflow_value; +- if (state() == QLatin1String("-") || state().isEmpty()) +- { +- objectflow_value = QLatin1Char(' '); +- } +- else +- { +- objectflow_value = QLatin1Char('[') + state() + QLatin1Char(']'); +- } +- +- painter->drawLine(10, h/2, w-10, h/2); +- painter->setPen(textColor()); +- painter->setFont(UMLWidget::font()); +- painter->drawText(OBJECTNODE_MARGIN, textStartY/2 - OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); +- painter->drawText(OBJECTNODE_MARGIN, textStartY/2 + textStartY + OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, objectflow_value); +- } +- break; +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget. +- */ +-QSizeF ObjectNodeWidget::minimumSize() const +-{ +- int widthtmp = 10, height = 10, width=10; +- if (m_objectNodeType == Buffer) { +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int textWidth = fm.width(QLatin1String("<< centralBuffer >>")); +- const int namewidth = fm.width(name()); +- height = fontHeight * 2; +- widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; +- width = namewidth > widthtmp ? namewidth : widthtmp; +- height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; +- width += OBJECTNODE_MARGIN * 2; +- height += OBJECTNODE_MARGIN * 2 + 5; +- } else if (m_objectNodeType == Data) { +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int textWidth = fm.width(QLatin1String("<< datastore >>")); +- const int namewidth = fm.width(name()); +- height = fontHeight * 2; +- widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; +- width = namewidth > widthtmp ? namewidth : widthtmp; +- height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; +- width += OBJECTNODE_MARGIN * 2; +- height += OBJECTNODE_MARGIN * 2 + 5; +- } else if (m_objectNodeType == Flow) { +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int textWidth = fm.width(QLatin1Char('[') + state() + QLatin1Char(']')); +- const int namewidth = fm.width(name()); +- height = fontHeight * 2; +- widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; +- width = namewidth > widthtmp ? namewidth : widthtmp; +- height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; +- width += OBJECTNODE_MARGIN * 2; +- height += OBJECTNODE_MARGIN * 4; +- } +- +- return QSizeF(width, height); +-} +- +-/** +- * Returns the type of object node. +- */ +-ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::objectNodeType() const +-{ +- return m_objectNodeType; +-} +- +-/** +- * Returns the type of object node. +- */ +-ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::toObjectNodeType(const QString& type) +-{ +- if (type == QLatin1String("Central buffer")) +- return ObjectNodeWidget::Buffer; +- if (type == QLatin1String("Data store")) +- return ObjectNodeWidget::Data; +- if (type == QLatin1String("Object Flow")) +- return ObjectNodeWidget::Flow; +- // Shouldn't happen +- Q_ASSERT(0); +- return ObjectNodeWidget::Flow; +-} +- +-/** +- * Sets the type of object node. +- */ +-void ObjectNodeWidget::setObjectNodeType(ObjectNodeType objectNodeType) +-{ +- m_objectNodeType = objectNodeType; +- UMLWidget::m_resizable = true; +-} +- +-/** +- * Sets the type of object node. +- */ +-void ObjectNodeWidget::setObjectNodeType(const QString& type) +-{ +- setObjectNodeType(ObjectNodeWidget::toObjectNodeType(type)); +-} +- +-/** +- * Sets the state of an object node when it's an objectflow. +- */ +-void ObjectNodeWidget::setState(const QString& state) +-{ +- m_state = state; +- updateGeometry(); +-} +- +-/** +- * Returns the state of object node. +- */ +-QString ObjectNodeWidget::state() const +-{ +- return m_state; +-} +- +-/** +- * Captures any popup menu signals for menus it created. +- */ +-void ObjectNodeWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Rename: +- { +- bool ok = false; +- QString text = name(); +-#if QT_VERSION >= 0x050000 +- text = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter Object Node Name"), +- i18n("Enter the name of the object node :"), +- QLineEdit::Normal, +- name(), &ok); +-#else +- text = KInputDialog::getText(i18n("Enter Object Node Name"), +- i18n("Enter the name of the object node :"), +- name(), &ok); +-#endif +- if (ok && !text.isEmpty()) { +- setName(text); +- } +- } +- break; +- +- case ListPopupMenu::mt_Properties: +- showPropertiesDialog(); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-/** +- * Show a properties dialog for an ObjectNodeWidget. +- */ +-void ObjectNodeWidget::showPropertiesDialog() +-{ +- UMLApp::app()->docWindow()->updateDocumentation(false); +- +- QPointer dialog = new ObjectNodeDialog(UMLApp::app()->currentView(), this); +- if (dialog->exec() && dialog->getChangesMade()) { +- UMLApp::app()->docWindow()->showDocumentation(this, true); +- UMLApp::app()->document()->setModified(true); +- } +- delete dialog; +-} +- +-/** +- * Saves the widget to the "objectnodewidget" XMI element. +- */ +-void ObjectNodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement objectNodeElement = qDoc.createElement(QLatin1String("objectnodewidget")); +- UMLWidget::saveToXMI(qDoc, objectNodeElement); +- objectNodeElement.setAttribute(QLatin1String("objectnodename"), m_Text); +- objectNodeElement.setAttribute(QLatin1String("documentation"), m_Doc); +- objectNodeElement.setAttribute(QLatin1String("objectnodetype"), m_objectNodeType); +- objectNodeElement.setAttribute(QLatin1String("objectnodestate"), m_state); +- qElement.appendChild(objectNodeElement); +-} +- +-/** +- * Loads the widget from the "objectnodewidget" XMI element. +- */ +-bool ObjectNodeWidget::loadFromXMI(QDomElement& qElement) +-{ +- if(!UMLWidget::loadFromXMI(qElement) ) +- return false; +- m_Text = qElement.attribute(QLatin1String("objectnodename")); +- m_Doc = qElement.attribute(QLatin1String("documentation")); +- QString type = qElement.attribute(QLatin1String("objectnodetype"), QLatin1String("1")); +- m_state = qElement.attribute(QLatin1String("objectnodestate")); +- setObjectNodeType((ObjectNodeType)type.toInt()); +- return true; +-} +- +-/** +- * Open a dialog box to select the objectNode type (Data, Buffer or Flow). +- */ +-void ObjectNodeWidget::askForObjectNodeType(UMLWidget* &targetWidget) +-{ +- bool pressedOK = false; +- int current = 0; +- const QStringList list = QStringList() +- << QLatin1String("Central buffer") +- << QLatin1String("Data store") +- << QLatin1String("Object Flow"); +- +-#if QT_VERSION >= 0x050000 +- QString type = QInputDialog::getItem (UMLApp::app(), +- i18n("Select Object node type"), i18n("Select the object node type"), +- list, current, false, &pressedOK); +- +-#else +- QString type = KInputDialog::getItem (i18n("Select Object node type"), i18n("Select the object node type"), list, current, false, &pressedOK, UMLApp::app()); +-#endif +- +- if (pressedOK) { +- dynamic_cast(targetWidget)->setObjectNodeType(type); +- if (type == QLatin1String("Data store")) +- Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the data store node"), i18n("Enter the name of the data store node"), i18n("data store name")); +- if (type == QLatin1String("Central buffer")) +- Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the buffer node"), i18n("Enter the name of the buffer"), i18n("centralBuffer")); +- if (type == QLatin1String("Object Flow")) { +- Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the object flow"), i18n("Enter the name of the object flow"), i18n("object flow")); +- askStateForWidget(); +- } +- } else { +- targetWidget->cleanup(); +- delete targetWidget; +- targetWidget = NULL; +- } +-} +- +-/** +- * Open a dialog box to input the state of the widget. +- * This box is shown only if m_objectNodeType = Flow. +- */ +-void ObjectNodeWidget::askStateForWidget() +-{ +- bool pressedOK = false; +-#if QT_VERSION >= 0x050000 +- QString state = QInputDialog::getText(UMLApp::app(), +- i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), +- QLineEdit::Normal, +- i18n("-"), &pressedOK); +-#else +- QString state = KInputDialog::getText(i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), i18n("-"), &pressedOK, UMLApp::app()); +-#endif +- +- if (pressedOK) { +- setState(state); +- } else { +- cleanup(); +- } +-} +- +-void ObjectNodeWidget::slotOk() +-{ +- // kdialog-kf6::accept(); +-} +- +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.h umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,76 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef OBJECTNODEWIDGET_H +-#define OBJECTNODEWIDGET_H +- +-#include "umlwidget.h" +- +-/** +- * This class is the graphical version of a UML Object Node. A ObjectNodeWidget is created +- * by a @ref UMLView. An ObjectNodeWidget belongs to only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. +- * +- * The ObjectNodeWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @short A graphical version of a UML Activity. +- * @author Florence Mattler +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ObjectNodeWidget : public UMLWidget +-{ +- Q_OBJECT +- +-public: +- enum ObjectNodeType +- { +- Normal, +- Data, +- Buffer, +- Flow +- }; +- +- explicit ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType = Normal, Uml::ID::Type id = Uml::ID::None); +- virtual ~ObjectNodeWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- ObjectNodeType objectNodeType() const; +- static ObjectNodeType toObjectNodeType(const QString& type); +- +- void setObjectNodeType(ObjectNodeType objectNodeType); +- void setObjectNodeType(const QString& type) ; +- +- void setState(const QString& state); +- QString state() const; +- +- virtual void showPropertiesDialog(); +- +- void askStateForWidget(); +- void askForObjectNodeType(UMLWidget* &targetWidget); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- virtual bool loadFromXMI(QDomElement& qElement); +- +-protected: +- QSizeF minimumSize() const; +- +-public slots: +- void slotMenuSelection(QAction* action); +- void slotOk(); +- +-private: +- ObjectNodeType m_objectNodeType; ///< type of object node +- QString m_state; ///< state of object node when it's an objectFlow +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,710 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header file +-#include "objectwidget.h" +- +-// local includes +-#include "classpropertiesdialog.h" +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "listpopupmenu.h" +-#include "messagewidget.h" +-#include "seqlinewidget.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlobject.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +-#include +-#include +- +-#define O_MARGIN 5 +-#define O_WIDTH 40 +-#define A_WIDTH 20 +-#define A_HEIGHT 40 +-#define A_MARGIN 5 +- +-DEBUG_REGISTER_DISABLED(ObjectWidget) +- +-/** +- * The number of pixels margin between the lowest message +- * and the bottom of the vertical line +- */ +-static const int sequenceLineMargin = 20; +- +-/** +- * Creates an ObjectWidget. +- * +- * @param scene The parent to this object. +- * @param o The object it will be representing. +- */ +-ObjectWidget::ObjectWidget(UMLScene * scene, UMLObject *o) +- : UMLWidget(scene, WidgetBase::wt_Object, o), +- m_multipleInstance(false), +- m_drawAsActor(false), +- m_showDestruction(false), +- m_isOnDestructionBox(false) +-{ +- if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { +- m_pLine = new SeqLineWidget( m_scene, this ); +- m_pLine->setStartPoint(x() + width() / 2, y() + height()); +- } else { +- m_pLine = 0; +- } +-} +- +-/** +- * Destructor. +- */ +-ObjectWidget::~ObjectWidget() +-{ +- cleanup(); +-} +- +-/** +- * Sets whether representing a multi-instance object. +- * +- * @param multiple Object state. true- multi, false - single. +- */ +-void ObjectWidget::setMultipleInstance(bool multiple) +-{ +- //make sure only calling this in relation to an object on a collab. diagram +- if (m_scene && (m_scene->type() == Uml::DiagramType::Collaboration)) { +- m_multipleInstance = multiple; +- updateGeometry(); +- update(); +- } +-} +- +-/** +- * Returns whether object is representing a multi-object. +- * +- * @return True if object is representing a multi-object. +- */ +-bool ObjectWidget::multipleInstance() const +-{ +- return m_multipleInstance; +-} +- +-/** +- * Overridden from UMLWidget. +- * Moves the widget to a new position using the difference between the +- * current position and the new position. +- * Y position is ignored, and widget is only moved along X axis. +- * +- * @param diffX The difference between current X position and new X position. +- * @param diffY The difference between current Y position and new Y position +- * (isn't used). +- */ +-void ObjectWidget::moveWidgetBy(qreal diffX, qreal diffY) +-{ +- setX(x() + diffX); +- if (m_scene && (m_scene->type() != Uml::DiagramType::Sequence)) { +- setY(y() + diffY); +- } +-} +- +-/** +- * Overridden from UMLWidget. +- * Modifies the value of the diffX and diffY variables used to move the widgets. +- * All the widgets are constrained to be moved only in X axis (diffY is set to 0). +- * +- * @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 ObjectWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +-{ +- Q_UNUSED(diffX); +- if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { +- diffY = 0; +- } +-} +- +-/** +- * Override default method. +- */ +-void ObjectWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- if (m_drawAsActor) +- paintActor(painter); +- else +- paintObject(painter); +- +- setPenFromSettings(painter); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Handles a popup menu selection. +- */ +-void ObjectWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Rename_Object: +- { +- bool ok; +- QRegExpValidator* validator = new QRegExpValidator(QRegExp(QLatin1String(".*")), 0); +-#if QT_VERSION >= 0x050000 +- QString name = QInputDialog::getText(m_scene->activeView(), +- i18n("Rename Object"), +- i18n("Enter object name:"), +- QLineEdit::Normal, +- m_instanceName, +- &ok); +-#else +- QString name = KInputDialog::getText +- (i18n("Rename Object"), +- i18n("Enter object name:"), +- m_instanceName, +- &ok, +- m_scene->activeView(), +- validator); +-#endif +- if (ok) { +- m_instanceName = name; +- updateGeometry(); +- moveEvent(0); +- update(); +- UMLApp::app()->document()->setModified(true); +- } +- delete validator; +- break; +- } +- case ListPopupMenu::mt_Properties: +- showPropertiesDialog(); +- updateGeometry(); +- moveEvent(0); +- update(); +- break; +- +- case ListPopupMenu::mt_Up: +- tabUp(); +- break; +- +- case ListPopupMenu::mt_Down: +- tabDown(); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- break; +- } +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF ObjectWidget::minimumSize() const +-{ +- int width, height; +- const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); +- const int fontHeight = fm.lineSpacing(); +- const QString t = m_instanceName + QLatin1String(" : ") + name(); +- const int textWidth = fm.width(t); +- if (m_drawAsActor) { +- width = textWidth > A_WIDTH?textWidth:A_WIDTH; +- height = A_HEIGHT + fontHeight + A_MARGIN; +- width += A_MARGIN * 2; +- } else { +- width = textWidth > O_WIDTH?textWidth:O_WIDTH; +- height = fontHeight + O_MARGIN * 2; +- width += O_MARGIN * 2; +- if (m_multipleInstance) { +- width += 10; +- height += 10; +- } +- }//end else drawasactor +- +- return QSizeF(width, height); +-} +- +-/** +- * Sets whether to draw as an Actor. +- * +- * @param drawAsActor True if widget shall be drawn as an actor. +- */ +-void ObjectWidget::setDrawAsActor(bool drawAsActor) +-{ +- m_drawAsActor = drawAsActor; +- updateGeometry(); +-} +- +-/** +- * Returns whether to draw as an Actor or not. +- * +- * @return True if widget is drawn as an actor. +- */ +-bool ObjectWidget::drawAsActor() const +-{ +- return m_drawAsActor; +-} +- +-/** +- * Activate the object after serializing it from a QDataStream +- */ +-bool ObjectWidget::activate(IDChangeLog* ChangeLog /*= 0*/) +-{ +- if (! UMLWidget::activate(ChangeLog)) +- return false; +- if (m_showDestruction && m_pLine) +- m_pLine->setupDestructionBox(); +- moveEvent(0); +- return true; +-} +- +-/** +- * Sets the x-coordinate. +- * Reimplements the method from UMLWidget. +- * +- * @param x The x-coordinate to be set. +- */ +-void ObjectWidget::setX(qreal x) +-{ +- UMLWidget::setX(x); +- moveEvent(0); +-} +- +-/** +- * Sets the y-coordinate. +- * Reimplements the method from UMLWidget. +- * +- * @param y The y-coordinate to be set. +- */ +-void ObjectWidget::setY(qreal y) +-{ +- UMLWidget::setY(y); +- if (!UMLApp::app()->document()->loading()) +- moveEvent(0); +-} +- +-/** +- * Return the x coordinate of the widgets center. +- * @return The x-coordinate of the widget center. +- */ +-qreal ObjectWidget::centerX() +-{ +- return x() + width()/2; +-} +- +-/** +- * Overrides the standard operation. +- */ +-void ObjectWidget::moveEvent(QGraphicsSceneMouseEvent *event) +-{ +- Q_UNUSED(event) +- emit sigWidgetMoved(m_nLocalID); +- if (m_pLine) { +- m_pLine->setStartPoint(x() + width() / 2, y() + height()); +- } +-} +- +-/** +- * Overrides the standard operation. +- */ +-void ObjectWidget::mousePressEvent(QGraphicsSceneMouseEvent *me) +-{ +- UMLWidget::mousePressEvent(me); +- m_isOnDestructionBox = false; +- if (m_pLine && m_pLine->onDestructionBox(me->scenePos())) { +- m_isOnDestructionBox = true; +- qreal oldX = x() + width() / 2; +- qreal oldY = getEndLineY() - 10; +- m_oldPos = QPointF(oldX, oldY); +- } +-} +- +-/** +- * Overrides the standard operation. +- */ +-void ObjectWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) +-{ +- if (m_inResizeArea) { +- DEBUG(DBG_SRC) << "resizing..."; +- resize(me); +- moveEvent(0); +- return; +- } +- +- if (m_isOnDestructionBox) { +- qreal diffY = me->scenePos().y() - m_oldPos.y(); +- moveDestructionBy(diffY); +- } +- else { +- UMLWidget::mouseMoveEvent(me); +- } +-} +- +-/** +- * Moves the destruction Box to a new position using the difference between the +- * current position and the new position. +- * The destruction box is only moved along Y axis. +- * +- * @param diffY The difference between current Y position and new Y position +- */ +-void ObjectWidget::moveDestructionBy(qreal diffY) +-{ +- // endLine = length of the life line + diffY - 10 to center on the destruction box +- qreal endLine = getEndLineY() + diffY - 10; +- SeqLineWidget *pLine = sequentialLine(); +- pLine->setEndOfLine(endLine); +- m_oldPos.setY(endLine); +-} +- +-/** +- * Handles a color change signal. +- */ +-void ObjectWidget::slotFillColorChanged(Uml::ID::Type /*viewID*/) +-{ +- UMLWidget::setFillColor(m_scene->fillColor()); +- UMLWidget::setLineColor(m_scene->lineColor()); +- +- if(m_pLine) +- m_pLine->setPen(QPen(UMLWidget::lineColor(), UMLWidget::lineWidth(), Qt::DashLine)); +-} +- +-/** +- * Used to cleanup any other widget it may need to delete. +- */ +-void ObjectWidget::cleanup() +-{ +- UMLWidget::cleanup(); +- if(m_pLine) { +- m_pLine->cleanup(); +- delete m_pLine; +- m_pLine = 0; +- } +-} +- +-/** +- * Show a properties dialog for an ObjectWidget. +- */ +-void ObjectWidget::showPropertiesDialog() +-{ +- UMLApp::app()->docWindow()->updateDocumentation(false); +- QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); +- if (dlg->exec()) { +- UMLApp::app()->docWindow()->showDocumentation(this, true); +- UMLApp::app()->document()->setModified(true); +- } +- dlg->close(); +- delete dlg; +-} +- +-/** +- * Draw the object as an object (default). +- */ +-void ObjectWidget::paintObject(QPainter *painter) +-{ +- QFont oldFont = painter->font(); +- QFont font = UMLWidget::font(); +- font.setUnderline(true); +- painter->setFont(font); +- +- setPenFromSettings(painter); +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- else +- painter->setBrush(m_scene->backgroundColor()); +- const int w = width(); +- const int h = height(); +- +- const QString t = m_instanceName + QLatin1String(" : ") + name(); +- int multiInstOfst = 0; +- if (m_multipleInstance) { +- painter->drawRect(10, 10, w - 10, h - 10); +- painter->drawRect(5, 5, w - 10, h - 10); +- multiInstOfst = 10; +- } +- painter->drawRect(0, 0, w - multiInstOfst, h - multiInstOfst); +- painter->setPen(textColor()); +- painter->drawText(O_MARGIN, O_MARGIN, +- w - O_MARGIN * 2 - multiInstOfst, h - O_MARGIN * 2 - multiInstOfst, +- Qt::AlignCenter, t); +- +- painter->setFont(oldFont); +-} +- +-/** +- * Draw the object as an actor. +- */ +-void ObjectWidget::paintActor(QPainter *painter) +-{ +- const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); +- +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- const int w = width(); +- const int textStartY = A_HEIGHT + A_MARGIN; +- const int fontHeight = fm.lineSpacing(); +- +- const int middleX = w / 2; +- const int thirdH = A_HEIGHT / 3; +- +- //draw actor +- painter->drawEllipse(middleX - A_WIDTH / 2, 0, A_WIDTH, thirdH);//head +- painter->drawLine(middleX, thirdH, middleX, thirdH * 2);//body +- painter->drawLine(middleX, 2 * thirdH, +- middleX - A_WIDTH / 2, A_HEIGHT);//left leg +- painter->drawLine(middleX, 2 * thirdH, +- middleX + A_WIDTH / 2, A_HEIGHT);//right leg +- painter->drawLine(middleX - A_WIDTH / 2, thirdH + thirdH / 2, +- middleX + A_WIDTH / 2, thirdH + thirdH / 2);//arms +- //draw text +- painter->setPen(textColor()); +- QString t = m_instanceName + QLatin1String(" : ") + name(); +- painter->drawText(A_MARGIN, textStartY, +- w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, t); +-} +- +-/** +- * Move the object up on a sequence diagram. +- */ +-void ObjectWidget::tabUp() +-{ +- int newY = y() - height(); +- if (newY < topMargin()) +- newY = topMargin(); +- setY(newY); +- adjustAssocs(x(), newY); +-} +- +-/** +- * Move the object down on a sequence diagram. +- */ +-void ObjectWidget::tabDown() +-{ +- int newY = y() + height(); +- setY(newY); +- adjustAssocs(x(), newY); +-} +- +-/** +- * Returns the top margin constant (Y axis value) +- * +- * @return Y coordinate of the space between the diagram top +- * and the upper edge of the ObjectWidget. +- */ +-int ObjectWidget::topMargin() +-{ +- return 80 - height(); +-} +- +-/** +- * Returns whether or not the widget can be moved vertically up. +- * +- * @return True if widget can be moved upwards vertically. +- */ +-bool ObjectWidget::canTabUp() +-{ +- return (y() > topMargin()); +-} +- +-/** +- * Sets whether to show deconstruction on sequence line. +- * +- * @param bShow True if destruction on line shall be shown. +- */ +-void ObjectWidget::setShowDestruction(bool bShow) +-{ +- m_showDestruction = bShow; +- if(m_pLine) +- m_pLine->setupDestructionBox(); +-} +- +-/** +- * Returns whether to show deconstruction on sequence line. +- * +- * @return True if destruction on sequence line is shown. +- */ +-bool ObjectWidget::showDestruction() const +-{ +- return m_showDestruction; +-} +- +-/** +- * Sets the y position of the bottom of the vertical line. +- * +- * @param yPosition The y coordinate for the bottom of the line. +- */ +-void ObjectWidget::setEndLine(int yPosition) +-{ +- if (m_pLine) { +- m_pLine->setEndOfLine(yPosition); +- } +-} +- +-/** +- * Returns the end Y co-ord of the sequence line. +- * +- * @return Y coordinate of the endpoint of the sequence line. +- */ +-int ObjectWidget::getEndLineY() +-{ +- int y = this->y() + height(); +- if(m_pLine) +- y += m_pLine->getLineLength(); +- if (m_showDestruction) +- y += 10; +- return y; +-} +- +-/** +- * Add a message widget to the list. +- * +- * @param message Pointer to the MessageWidget to add. +- */ +-void ObjectWidget::messageAdded(MessageWidget* message) +-{ +- if (m_messages.count(message)) { +- uError() << message->name() << ": duplicate entry !"; +- return ; +- } +- m_messages.append(message); +-} +- +-/** +- * Remove a message widget from the list. +- * +- * @param message Pointer to the MessageWidget to remove. +- */ +-void ObjectWidget::messageRemoved(MessageWidget* message) +-{ +- if (m_messages.removeAll(message) == false) { +- uError() << message->name() << ": missing entry !"; +- return ; +- } +-} +- +-/** +- * Called when a message widget with an end on this object has +- * moved up or down. +- * Sets the bottom of the line to a nice position. +- */ +-void ObjectWidget::slotMessageMoved() +-{ +- if (m_pLine) { +- int lowestMessage = 0; +- foreach (MessageWidget* message, m_messages) { +- int messageHeight = message->y() + message->height(); +- if (lowestMessage < messageHeight) { +- lowestMessage = messageHeight; +- } +- } +- m_pLine->setEndOfLine(lowestMessage + sequenceLineMargin); +- } +-} +- +-/** +- * Returns whether a message is overlapping with another message. +- * Used by MessageWidget::paint() methods. +- * +- * @param y top of your message +- * @param messageWidget pointer to your message so it doesn't check against itself +- */ +-bool ObjectWidget::messageOverlap(qreal y, MessageWidget* messageWidget) +-{ +- foreach (MessageWidget* message, m_messages) { +- if (message == messageWidget) { +- continue; +- } +- const qreal msgY = message->y(); +- const qreal msgHeight = msgY + message->height(); +- if (y >= msgY && y <= msgHeight) { +- return true; +- } +- } +- return false; +-} +- +-/** +- * Return the SeqLineWidget. +- * Returns a non NULL pointer if this ObjectWidget is part of a +- * sequence diagram. +- */ +-SeqLineWidget *ObjectWidget::sequentialLine() const +-{ +- return m_pLine; +-} +- +-/** +- * Overridden from UMLWidget. +- * Returns the cursor to be shown when resizing the widget. +- * The cursor shown is KCursor::sizeHorCursor(). +- * +- * @return The cursor to be shown when resizing the widget. +- */ +-QCursor ObjectWidget::resizeCursor() const +-{ +- return Qt::SizeHorCursor; +-} +- +-/** +- * Overridden from UMLWidget. +- * Resizes the width of the object widget. +- * Object widgets can only be resized horizontally, so height isn't modified. +- * +- * @param newW The new width for the widget. +- * @param newH The new height for the widget (isn't used). +- */ +-void ObjectWidget::resizeWidget(qreal newW, qreal newH) +-{ +- Q_UNUSED(newH); +- setSize(newW, height()); +-} +- +-/** +- * Saves to the "objectwidget" XMI element. +- */ +-void ObjectWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement objectElement = qDoc.createElement(QLatin1String("objectwidget")); +- UMLWidget::saveToXMI(qDoc, objectElement); +- objectElement.setAttribute(QLatin1String("drawasactor"), m_drawAsActor); +- objectElement.setAttribute(QLatin1String("multipleinstance"), m_multipleInstance); +- objectElement.setAttribute(QLatin1String("decon"), m_showDestruction); +- qElement.appendChild(objectElement); +-} +- +-/** +- * Loads from a "objectwidget" XMI element. +- */ +-bool ObjectWidget::loadFromXMI(QDomElement& qElement) +-{ +- if(!UMLWidget::loadFromXMI(qElement)) +- return false; +- QString draw = qElement.attribute(QLatin1String("drawasactor"), QLatin1String("0")); +- QString multi = qElement.attribute(QLatin1String("multipleinstance"), QLatin1String("0")); +- QString decon = qElement.attribute(QLatin1String("decon"), QLatin1String("0")); +- +- m_drawAsActor = (bool)draw.toInt(); +- m_multipleInstance = (bool)multi.toInt(); +- m_showDestruction = (bool)decon.toInt(); +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.h umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,115 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef OBJECTWIDGET_H +-#define OBJECTWIDGET_H +- +-#include "messagewidgetlist.h" +-#include "umlwidget.h" +- +-class MessageWidget; +-class SeqLineWidget; +-class UMLScene; +- +-/** +- * Displays an instance UMLObject of a concept. +- * +- * The local ID is needed as a it can represent a class +- * that has many objects representing it. +- * +- * @short Displays an instance of a Concept. +- * @author Paul Hensgen +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class ObjectWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- ObjectWidget(UMLScene *scene, UMLObject *o); +- virtual ~ObjectWidget(); +- +- virtual void setX(qreal x); +- virtual void setY(qreal y); +- +- qreal centerX(); +- +- void setMultipleInstance(bool multiple); +- bool multipleInstance() const; +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- bool activate(IDChangeLog* ChangeLog = 0); +- +- void cleanup(); +- +- void showPropertiesDialog(); +- +- void setDrawAsActor(bool drawAsActor); +- bool drawAsActor() const; +- +- void setShowDestruction(bool bShow); +- bool showDestruction() const; +- +- int topMargin(); +- +- void setEndLine(int yPosition); +- int getEndLineY(); +- +- void messageAdded(MessageWidget* message); +- void messageRemoved(MessageWidget* message); +- +- bool canTabUp(); +- +- bool messageOverlap(qreal y, MessageWidget* messageWidget); +- +- SeqLineWidget *sequentialLine() const; +- +- virtual void resizeWidget(qreal newW, qreal newH); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- virtual bool loadFromXMI(QDomElement& qElement); +- +-public slots: +- void slotMenuSelection(QAction* action); +- virtual void slotFillColorChanged(Uml::ID::Type viewID); +- void slotMessageMoved(); +- +-protected: +- virtual void mousePressEvent(QGraphicsSceneMouseEvent *me); +- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *me); +- +- QSizeF minimumSize() const; +- +- virtual void moveEvent(QGraphicsSceneMouseEvent *event); +- virtual void moveWidgetBy(qreal diffX, qreal diffY); +- virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); +- +- virtual QCursor resizeCursor() const; +- +- void paintActor(QPainter *p); +- void paintObject(QPainter *p); +- +-private: +- void tabUp(); +- void tabDown(); +- +- void moveDestructionBy(qreal diffY); +- +- SeqLineWidget* m_pLine; +- bool m_multipleInstance; ///< draw an object as a multiple object +- bool m_drawAsActor; ///< object should be drawn as an Actor or an Object +- bool m_showDestruction; ///< show object destruction on sequence diagram line +- bool m_isOnDestructionBox; ///< true when a click occurred on the destruction box +- MessageWidgetList m_messages; ///< message widgets with an end on this widget +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,149 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "packagewidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "package.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlobject.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-// qt includes +-#include +- +-/** +- * Constructs a PackageWidget. +- * +- * @param scene The parent of this PackageWidget. +- * @param o The UMLObject this will be representing. +- */ +-PackageWidget::PackageWidget(UMLScene * scene, UMLPackage *o) +- : UMLWidget(scene, WidgetBase::wt_Package, o), +- m_pMenu(0) +-{ +- setSize(100, 30); +- setZValue(1); // above box but below UMLWidget because may embed widgets +- //set defaults from m_scene +- if (m_scene) { +- //check to see if correct +- const Settings::OptionState& ops = m_scene->optionState(); +- m_showStereotype = ops.classState.showStereoType; +- } +-} +- +-/** +- * Destructor. +- */ +-PackageWidget::~PackageWidget() +-{ +-} +- +-/** +- * Overrides standard method. +- */ +-void PackageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- else +- painter->setBrush(m_scene->backgroundColor()); +- +- int w = width(); +- int h = height(); +- QFont font = UMLWidget::font(); +- font.setBold(true); +- //FIXME italic is true when a package is first created until you click elsewhere, not sure why +- font.setItalic(false); +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- +- painter->drawRect(0, 0, 50, fontHeight); +- if (m_umlObject != NULL +- && m_umlObject->stereotype() == QLatin1String("subsystem")) { +- +- const int fHalf = fontHeight / 2; +- const int symY = fHalf; +- const int symX = 38; +- painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg +- painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg +- painter->drawLine(symX, symY, symX + 8, symY); // waist +- painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head +- } +- painter->drawRect(0, fontHeight - 1, w, h - fontHeight); +- +- painter->setPen(textColor()); +- painter->setFont(font); +- +- int lines = 1; +- if (m_umlObject != NULL) { +- QString stereotype = m_umlObject->stereotype(); +- if (!stereotype.isEmpty()) { +- painter->drawText(0, fontHeight + PACKAGE_MARGIN, +- w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); +- lines = 2; +- } +- } +- +- painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, +- w, fontHeight, Qt::AlignCenter, name()); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF PackageWidget::minimumSize() const +-{ +- if (!m_umlObject) { +- return UMLWidget::minimumSize(); +- } +- +- const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); +- const int fontHeight = fm.lineSpacing(); +- +- int lines = 1; +- +- int width = fm.width(m_umlObject->name()); +- +- int tempWidth = 0; +- if (!m_umlObject->stereotype().isEmpty()) { +- tempWidth = fm.width(m_umlObject->stereotype(true)); +- lines = 2; +- } +- if (tempWidth > width) +- width = tempWidth; +- width += PACKAGE_MARGIN * 2; +- if (width < 70) +- width = 70; // minumin width of 70 +- +- int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); +- +- return QSizeF(width, height); +-} +- +-/** +- * Saves to the "packagewidget" XMI element. +- */ +-void PackageWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement conceptElement = qDoc.createElement(QLatin1String("packagewidget")); +- UMLWidget::saveToXMI(qDoc, conceptElement); +- qElement.appendChild(conceptElement); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.h umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,47 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PACKAGEWIDGET_H +-#define PACKAGEWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLPackage; +-class ListPopupMenu; +- +-#define PACKAGE_MARGIN 5 +- +-/** +- * Defines a graphical version of the Package. Most of the +- * functionality will come from the @ref UMLPackage class. +- * +- * @short A graphical version of a Package. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class PackageWidget : public UMLWidget +-{ +-public: +- explicit PackageWidget(UMLScene * scene, UMLPackage * o); +- virtual ~PackageWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- +-protected: +- QSizeF minimumSize() const; +- +-private: +- ListPopupMenu* m_pMenu; ///< the right mouse button menu +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.cpp umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,378 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "pinportbase.h" +- +-// app includes +-#include "port.h" +-#include "package.h" +-#include "debug_utils.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "floatingtextwidget.h" +- +-// qt includes +-#include +-#include +- +-// sys includes +-#include +- +-PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o) +- : UMLWidget(scene, type, o) +-{ +- init(); +-} +- +-PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id) +- : UMLWidget(scene, type, id) +-{ +- init(a); +-} +- +-/** +- * Standard destructor. +- */ +-PinPortBase::~PinPortBase() +-{ +-} +- +-/** +- * Performs initializations which are common to PinWidget and PortWidget. +- */ +-void PinPortBase::init(UMLWidget *owner) +-{ +- m_ignoreSnapToGrid = true; +- m_ignoreSnapComponentSizeToGrid = true; +- m_resizable = false; +- m_pOw = owner; +- m_pName = NULL; +- m_motionConnected = false; +- const int edgeLength = 15; // old: (m_baseType == wt_Pin ? 10 : 15); +- const QSizeF FixedSize(edgeLength, edgeLength); +- setMinimumSize(FixedSize); +- setMaximumSize(FixedSize); +- setSize(FixedSize); +-} +- +-UMLWidget* PinPortBase::ownerWidget() +-{ +- return m_pOw; +-} +- +-/** +- * Overrides method from UMLWidget in order to set a tooltip. +- * The tooltip is set to the name(). +- * The reason for using a tooltip for the name is that the size of this +- * widget is not large enough to accommodate the average name. +- */ +-void PinPortBase::updateWidget() +-{ +- QString strName = name(); +- uDebug() << " port name is " << strName; +- if (m_pName) { +- m_pName->setText(strName); +- } else { +- setToolTip(strName); +- } +-} +- +-/** +- * Overrides method from UMLWidget to set the name. +- */ +-void PinPortBase::setName(const QString &strName) +-{ +- UMLWidget::setName(strName); +- updateGeometry(); +- if (m_pName) { +- m_pName->setText(strName); +- } +-} +- +-/** +- * Overridden from UMLWidget. +- * Moves the widget to a new position using the difference between the +- * current position and the new position. +- * Movement is constrained such that the port is always attached to its +- * owner widget. +- * +- * @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 PinPortBase::moveWidgetBy(qreal diffX, qreal diffY) +-{ +- UMLWidget* owner = ownerWidget(); +- qreal newX = x() + diffX; +- qreal newY = y() + diffY; +- uDebug() << "PinPortBase::moveWidgetBy " << diffX << "," << diffY; +- if (owner == NULL) { +- uError() << "PinPortBase::moveWidgetBy: ownerWidget() returns NULL"; +- setX(newX); +- setY(newY); +- return; +- } +- const qreal deltaTop = fabs(y() + height() - owner->y()); +- const qreal deltaBottom = fabs(owner->y() + owner->height() - y()); +- const qreal deltaLeft = fabs(x() + width() - owner->x()); +- const qreal deltaRight = fabs(owner->x() + owner->width() - x()); +- bool didAnyMovement = false; +- if (deltaTop < 1.0 || deltaBottom < 1.0) { +- if (newX < owner->x() - width()) +- newX = owner->x() - width(); +- else if (newX > owner->x() + owner->width()) +- newX = owner->x() + owner->width(); +- setX(newX); +- didAnyMovement = true; +- } +- if (deltaLeft < 1.0 || deltaRight < 1.0) { +- if (newY < owner->y() - height()) +- newY = owner->y() - height(); +- else if (newY > owner->y() + owner->height()) +- newY = owner->y() + owner->height(); +- setY(newY); +- didAnyMovement = true; +- } +- if (!didAnyMovement) { +- uDebug() << "constraint failed for (" << diffX << ", " << diffY << ")"; +- setX(newX); +- setY(newY); +- } +-} +- +-/** +- * Align this widget's position such that it is attached at one of the +- * sides of its owner's widget. +- */ +-void PinPortBase::attachToOwner() { +- UMLWidget *owner = ownerWidget(); +- const QPointF scenePos = m_scene->pos(); +- if (owner == NULL) { +- uError() << "PinPortBase::attachToOwner: ownerWidget() returns NULL"; +- setX(scenePos.x()); +- setY(scenePos.y()); +- return; +- } +- bool xIsWithinOwner = false; +- if (scenePos.x() < owner->x() - width()) { +- setX(owner->x() - width()); +- } else if (scenePos.x() <= owner->x() + owner->width()) { +- setX(scenePos.x()); +- xIsWithinOwner = true; +- } else { +- setX(owner->x() + owner->width()); +- } +- if (scenePos.y() < owner->y() - height()) { +- setY(owner->y() - height()); +- } else if (scenePos.y() <= owner->y() + owner->height()) { +- if (xIsWithinOwner) { +- if (scenePos.y() <= owner->y() + owner->height() / 2.0) +- setY(owner->y() - height()); +- else +- setY(owner->y() + owner->height()); +- } else { +- setY(scenePos.y()); +- } +- } else { +- setY(owner->y() + owner->height()); +- } +- +- if (m_motionConnected) { +- uDebug() << "connectOwnerMotion was already done"; +- } else { +- connectOwnerMotion(); +- m_motionConnected = true; +- } +-} +- +-/** +- * Overrides standard method. +- */ +-void PinPortBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } else { +- painter->setBrush(m_scene->backgroundColor()); +- } +- +- int w = width(); +- int h = height(); +- +- painter->drawRect(0, 0, w, h); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-void PinPortBase::slotOwnerMoved(qreal diffX, qreal diffY) +-{ +- setX(x() + diffX); +- setY(y() + diffY); +-} +- +-/** +- * Captures any popup menu signals for menus it created. +- */ +-void PinPortBase::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_NameAsTooltip: +- if (m_pName) { +- action->setChecked(true); +- delete m_pName; +- m_pName = NULL; +- setToolTip(name()); +- } else { +- action->setChecked(false); +- 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(); +- UMLWidget* owner = ownerWidget(); +- if (owner == NULL) { +- uError() << "PinPortBase::slotMenuSelection: ownerWidget() returns NULL"; +- setX(x()); +- setY(y()); +- } else { +- const qreal w = width(); +- const qreal h = height(); +- if (x() < owner->x()) +- m_pName->setX(-m_pName->width()); +- else if (x() >= owner->x() + owner->width()) +- m_pName->setX(w); +- else +- m_pName->setX(-m_pName->width() / 2.0 + w / 2.0); +- if (y() < owner->y()) +- m_pName->setY(-m_pName->height() - 2); +- else if (y() >= owner->y() + owner->height()) +- m_pName->setY(h); +- else +- m_pName->setY(-m_pName->height() / 2.0 + h / 2.0); +- } +- m_pName->update(); +- setToolTip(QString()); +- QToolTip::hideText(); +- } +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-FloatingTextWidget *PinPortBase::floatingTextWidget() { +- return m_pName; +-} +- +-void PinPortBase::setFloatingTextWidget(FloatingTextWidget *ft) { +- m_pName = ft; +- if (m_pName) +- m_pName->setParentItem(this); +-} +- +-/** +- * Override method from UMLWidget in order to additionally check m_pName. +- * +- * @param p Point to be checked. +- * +- * @return 'this' if UMLWidget::onWidget(p) returns non NULL; +- * m_pName if m_pName is non NULL and m_pName->onWidget(p) returns non NULL; +- * else NULL. +- */ +-UMLWidget* PinPortBase::onWidget(const QPointF &p) +-{ +- if (UMLWidget::onWidget(p) != NULL) +- return this; +- if (m_pName) { +- uDebug() << "floatingtext: " << m_pName->text(); +- return m_pName->onWidget(p); +- } +- return NULL; +-} +- +-/** +- * Reimplement function from UMLWidget +- */ +-UMLWidget* PinPortBase::widgetWithID(Uml::ID::Type id) +-{ +- if (UMLWidget::widgetWithID(id)) +- return this; +- if (m_pName && m_pName->widgetWithID(id)) +- return m_pName; +- return NULL; +-} +- +- +-/** +- * Saves the widget to the "pinwidget" or "portwidget" XMI element. +- */ +-void PinPortBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement element = qDoc.createElement(m_baseType == wt_Pin ? QLatin1String("pinwidget") +- : QLatin1String("portwidget")); +- element.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(ownerWidget()->id())); +- UMLWidget::saveToXMI(qDoc, element); +- if (m_pName && !m_pName->text().isEmpty()) { +- m_pName->saveToXMI(qDoc, element); +- } +- qElement.appendChild(element); +-} +- +-/** +- * Loads from a "pinwidget" or from a "portwidget" XMI element. +- */ +-bool PinPortBase::loadFromXMI(QDomElement & qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) +- return false; +- +- QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); +- Uml::ID::Type aId = Uml::ID::fromString(widgetaid); +- UMLWidget *owner = m_scene->findWidget(aId); +- if (owner == NULL) { +- DEBUG(DBG_SRC) << "owner object " << Uml::ID::toString(aId) << " not found"; +- return false; +- } +- m_pOw = owner; +- +- // Optional child element: floatingtext +- QDomNode node = qElement.firstChild(); +- QDomElement element = node.toElement(); +- if (!element.isNull()) { +- QString tag = element.tagName(); +- if (tag == QLatin1String("floatingtext")) { +- m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, +- name(), Uml::ID::Reserved); +- if (!m_pName->loadFromXMI(element)) { +- // Most likely cause: The FloatingTextWidget is empty. +- delete m_pName; +- m_pName = NULL; +- } else { +- m_pName->setParentItem(this); +- m_pName->activate(); +- m_pName->update(); +- } +- } else { +- uError() << "unknown tag " << tag; +- } +- } +- +- if (m_motionConnected) { +- uDebug() << "connectOwnerMotion was already done"; +- } else { +- connectOwnerMotion(); +- m_motionConnected = true; +- } +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.h umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,63 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PINPORTBASE_H +-#define PINPORTBASE_H +- +-#include "umlwidget.h" +- +-class FloatingTextWidget; +- +-/** +- * @short Abstract base class for PinWidget and PortWidget +- * @author Oliver Kellogg +- * @see UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class PinPortBase : public UMLWidget +-{ +- Q_OBJECT +-public: +- PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o); +- PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id = Uml::ID::None); +- virtual ~PinPortBase(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- virtual UMLWidget* ownerWidget(); +- virtual void connectOwnerMotion() = 0; +- +- void setName(const QString &strName); +- void updateWidget(); +- void moveWidgetBy(qreal diffX, qreal diffY); +- void attachToOwner(); +- +- UMLWidget* onWidget(const QPointF& p); +- UMLWidget* widgetWithID(Uml::ID::Type id); +- +- FloatingTextWidget *floatingTextWidget(); +- void setFloatingTextWidget(FloatingTextWidget *ft); +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- bool loadFromXMI(QDomElement& qElement); +- +-public slots: +- void slotOwnerMoved(qreal diffX, qreal diffY); +- virtual void slotMenuSelection(QAction* action); +- +-protected: +- void init(UMLWidget *owner = 0); +- +- UMLWidget* m_pOw; +- FloatingTextWidget *m_pName; +- bool m_motionConnected; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,103 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "pinwidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "floatingtextwidget.h" +-#include "listpopupmenu.h" +-#include "umlscene.h" +-#include "activitywidget.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +- +-DEBUG_REGISTER_DISABLED(PinWidget) +- +-/** +- * Creates a Pin widget. +- * +- * @param scene The parent of the widget. +- * @param a 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* a, Uml::ID::Type id) +- : PinPortBase(scene, WidgetBase::wt_Pin, a, 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() +-{ +-} +- +-/** +- * Implement abstract function from PinPortWidget. +- */ +-void PinWidget::connectOwnerMotion() +-{ +- ActivityWidget *owner = static_cast(ownerWidget()); +- connect(owner, SIGNAL(sigActMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); +-} +- +-/** +- * 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: +- { +- bool ok = false; +- QString name = m_Text; +-#if QT_VERSION >= 0x050000 +- name = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter Pin Name"), +- i18n("Enter the pin name :"), +- QLineEdit::Normal, +- m_Text, &ok); +-#else +- name = KInputDialog::getText(i18n("Enter Pin Name"), +- i18n("Enter the pin name :"), +- m_Text, &ok); +-#endif +- if (ok) { +- setName(name); +- } +- } +- break; +- +- default: +- PinPortBase::slotMenuSelection(action); +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.h umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,46 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PINWIDGET_H +-#define PINWIDGET_H +- +-#include "pinportbase.h" +- +-/** +- * This class is the graphical version of a UML Pin. A pinWidget is created +- * by a @ref UMLView. An pinWidget belongs to only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. +- * +- * The pinWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @short A graphical version of a UML pin. +- * @author Hassan KOUCH +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class PinWidget : public PinPortBase +-{ +- Q_OBJECT +-public: +- +- PinWidget(UMLScene* scene, UMLWidget* a, Uml::ID::Type id = Uml::ID::None); +- virtual ~PinWidget(); +- +- void connectOwnerMotion(); +- // int getMinY(); +- +-public slots: +- void slotMenuSelection(QAction* action); +- +-// private: +- // int m_nY; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/portwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/portwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,106 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "portwidget.h" +- +-// app includes +-#include "port.h" +-#include "package.h" +-#include "debug_utils.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "componentwidget.h" +-#include "floatingtextwidget.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#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) +- : PinPortBase(scene, WidgetBase::wt_Port, d) +-{ +- setToolTip(d->name()); +-} +- +-/** +- * Standard deconstructor. +- */ +-PortWidget::~PortWidget() +-{ +-} +- +-/** +- * Override function from PinPortWidget. +- */ +-UMLWidget* PortWidget::ownerWidget() +-{ +- if (m_pOw == NULL) { +- const Uml::ID::Type compWidgetId = m_umlObject->umlPackage()->id(); +- m_pOw = m_scene->widgetOnDiagram(compWidgetId); +- } +- return m_pOw; +-} +- +-/** +- * Implement abstract function from PinPortWidget. +- */ +-void PortWidget::connectOwnerMotion() +-{ +- ComponentWidget *owner = static_cast(ownerWidget()); +- connect(owner, SIGNAL(sigCompMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); +-} +- +-/** +- * 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: +- { +- bool ok = false; +- QString newName; +-#if QT_VERSION >= 0x050000 +- newName = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter Port Name"), i18n("Enter the port name :"), +- QLineEdit::Normal, +- name(), &ok); +-#else +- newName = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port name :"), +- name(), &ok); +-#endif +- if (ok) { +- setName(newName); +- } +- } +- break; +- +- default: +- PinPortBase::slotMenuSelection(action); +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.h umbrello-kf6-15.08.1/umbrello/widgets/portwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/portwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,42 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PORTWIDGET_H +-#define PORTWIDGET_H +- +-#include "pinportbase.h" +- +-class UMLPort; +- +-/** +- * Defines a graphical version of the UML2 port. Most of the functionality +- * comes from the @ref PinPortBase class from which this class inherits. +- * +- * @short A graphical version of a port on a component. +- * @author Oliver Kellogg +- * @see PinPortBase, UMLWidget +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class PortWidget : public PinPortBase +-{ +- Q_OBJECT +-public: +- PortWidget(UMLScene *scene, UMLPort *d); +- virtual ~PortWidget(); +- +- UMLWidget* ownerWidget(); +- void connectOwnerMotion(); +- +-public slots: +- void slotMenuSelection(QAction* action); +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,335 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "preconditionwidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "listpopupmenu.h" +-#include "objectwidget.h" +-#include "uml.h" +-#include "umlscene.h" +-#include "uniqueid.h" +-#include "idchangelog.h" +- +-// kde includes +-#if QT_VERSION < 0x050000 +-#include +-#endif +-#include +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#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->resetPastep-kf6oint(); +- 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: +- { +- bool ok = false; +- QString text = name(); +-#if QT_VERSION >= 0x050000 +- text = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter Precondition Name"), +- i18n("Enter the precondition :"), +- QLineEdit::Normal, +- text, &ok); +-#else +- text = KInputDialog::getText(i18n("Enter Precondition Name"), +- i18n("Enter the precondition :"), +- text, &ok); +-#endif +- if (ok && !text.isEmpty()) { +- setName(text); +- } +- calculateWidget(); +- } +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-/** +- * Saves the widget to the "preconditionwidget" XMI element. +- */ +-void PreconditionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement preconditionElement = qDoc.createElement(QLatin1String("preconditionwidget")); +- UMLWidget::saveToXMI(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::loadFromXMI(QDomElement& qElement) +-{ +- if(!UMLWidget::loadFromXMI(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 loadFromXMI() 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 -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.h umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,70 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef PRECONDITIONWIDGET_H +-#define PRECONDITIONWIDGET_H +- +-#include "umlwidget.h" +- +-class ObjectWidget; +- +-/** +- * @short A graphical version of a UML Precondition (new in UML 2.0). +- * +- * This class is the graphical version of a UML Precondition. A PreconditionWidget is created +- * by a @ref UMLView. An PreconditionWidget belongs to only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. +- * +- * The PreconditionWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @author Florence Mattler +- * +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class PreconditionWidget : public UMLWidget +-{ +- Q_OBJECT +-public: +- PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id = Uml::ID::None); +- virtual ~PreconditionWidget(); +- +- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- int minY() const; +- int maxY() const; +- +- bool activate(IDChangeLog* Log = 0); +- void resolveObjectWidget(IDChangeLog* log); +- +- virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- virtual bool loadFromXMI(QDomElement& qElement); +- +- void setObjectWidget(ObjectWidget* widget); +- +-public slots: +- void slotMenuSelection(QAction* action); +- void slotWidgetMoved(Uml::ID::Type id); +- +-protected: +- QSizeF minimumSize() const; +- +-private: +- void calculateWidget(); +- void calculateDimensions(); +- +- ObjectWidget* m_objectWidget; +- int m_nY; +- +- Uml::ID::Type m_widgetAId; +- void loadObjectWidget(); +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,108 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "regionwidget.h" +- +-// app includes +-#include "basictypes.h" +-#include "debug_utils.h" +- +-// kde includes +-#include +- +-#define REGION_MARGIN 5 +-#define REGION_WIDTH 90 +-#define REGION_HEIGHT 45 +- +-/** +- * Creates a Region widget. +- * +- * @param scene The parent of the widget. +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-RegionWidget::RegionWidget(UMLScene* scene, Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_Region, id) +-{ +-} +- +-/** +- * Destructor. +- */ +-RegionWidget::~RegionWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void RegionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- const int w = width(); +- const int h = height(); +- +- setPenFromSettings(painter); +- QPen pen = painter->pen(); +- pen.setColor(Qt::red); +- pen.setStyle(Qt::DashLine); +- painter->setPen(pen); +- painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF RegionWidget::minimumSize() const +-{ +- int width = 10, height = 10; +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- int textWidth = fm.width(name()); +- +- height = fontHeight; +- width = textWidth > REGION_WIDTH?textWidth:REGION_WIDTH; +- height = height > REGION_HEIGHT ? height : REGION_HEIGHT; +- width += REGION_MARGIN * 2; +- height += REGION_MARGIN * 2; +- +- return QSizeF(width, height); +-} +- +-/** +- * Saves region widget to XMI element. +- */ +-void RegionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +-{ +- QDomElement regionElement = qDoc.createElement(QLatin1String("regionwidget")); +- UMLWidget::saveToXMI(qDoc, regionElement); +- regionElement.setAttribute(QLatin1String("regionname"), name()); +- regionElement.setAttribute(QLatin1String("documentation"), documentation()); +- +- qElement.appendChild(regionElement); +-} +- +-/** +- * Loads region widget from XMI element. +- */ +-bool RegionWidget::loadFromXMI(QDomElement& qElement) +-{ +- if (!UMLWidget::loadFromXMI(qElement)) { +- return false; +- } +- setName(qElement.attribute(QLatin1String("regionname"))); +- setDocumentation(qElement.attribute(QLatin1String("documentation"))); +- return true; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.h umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,36 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +-***************************************************************************/ +- +-#ifndef REGIONWIDGET_H +-#define REGIONWIDGET_H +- +-#include "umlwidget.h" +- +-/** +- * Represents a rectangular region on Activity diagram. +- */ +-class RegionWidget: public UMLWidget +-{ +- Q_OBJECT +-public: +- explicit RegionWidget(UMLScene* scene, Uml::ID::Type id = Uml::ID::None); +- virtual ~RegionWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); +- bool loadFromXMI(QDomElement& qElement); +- +-protected: +- QSizeF minimumSize() const; +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,197 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "seqlinewidget.h" +- +-//app includes +-#include "messagewidget.h" +-#include "objectwidget.h" +-#include "umlscene.h" +-#include "umlview.h" +- +-//qt includes +-#include +- +-// class members +-int const SeqLineWidget::m_nMouseDownEpsilonX = 20; +- +-/** +- * Constructor. +- */ +-SeqLineWidget::SeqLineWidget(UMLScene *scene, ObjectWidget * pObject) +- : QGraphicsLineItem(), +- m_scene(scene) +-{ +- scene->addItem(this); +- m_pObject = pObject; +- setPen(QPen(m_pObject->lineColor(), 0, Qt::DashLine)); +- setZValue(0); +- setVisible(true); +- m_DestructionBox.line1 = 0; +- m_nLengthY = 250; +- setupDestructionBox(); +-} +- +-/** +- * Destructor. +- */ +-SeqLineWidget::~SeqLineWidget() +-{ +-} +- +-/** +- * Return whether point is on sequence line. +- * Takes into account destruction box if shown. +- * +- * @param p The point to investigate. +- * @return True if point is on this sequence line. +- */ +-bool SeqLineWidget::onWidget(const QPointF & p) +-{ +- bool isOnWidget = false; +- QPointF sp = line().p1(); +- QPointF ep = line().p2(); +- //see if on widget (for message creation) +- if (sp.x() - m_nMouseDownEpsilonX < p.x() +- && ep.x() + m_nMouseDownEpsilonX > p.x() +- && sp.y() < p.y() && ep.y() + 3 > p.y()) +- { +- isOnWidget = true; +- } +- return isOnWidget; +-} +- +-/** +- * Return whether point is on the destruction box. +- * +- * @param p The point to investigate. +- * @return True if point is on the destruction box of this sequence line. +- */ +-bool SeqLineWidget::onDestructionBox(const QPointF & p) +-{ +- bool isOnDestructionBox = false; +- int x = m_pObject->x() + m_pObject->width() / 2; +- int y = m_pObject->y() + m_pObject->height() + m_nLengthY; +- +- //see if on destruction box +- if (!m_pObject->showDestruction()) { +- return false; +- } +- if (x - 10 < p.x() && x + 10 > p.x() +- && y - 10 < p.y() && y + 10 > p.y()) +- { +- isOnDestructionBox = true; +- } +- return isOnDestructionBox; +-} +- +-/** +- * Clean up anything before deletion. +- */ +-void SeqLineWidget::cleanup() +-{ +- cleanupDestructionBox(); +-} +- +-/** +- * Set the start point of the line. +- * +- * @param startX X coordinate of the start point. +- * @param startY Y coordinate of the start point. +- */ +-void SeqLineWidget::setStartPoint(int startX, int startY) +-{ +- int endX = startX; +- int endY = startY + m_nLengthY; +- QGraphicsLineItem::setLine(startX, startY, endX, endY); +- moveDestructionBox(); +-} +- +-/** +- * Clean up destruction box. +- */ +-void SeqLineWidget::cleanupDestructionBox() +-{ +- if (m_DestructionBox.line1) { +- delete m_DestructionBox.line1; +- m_DestructionBox.line1 = 0; +- delete m_DestructionBox.line2; +- m_DestructionBox.line2 = 0; +- } +-} +- +-/** +- * Set up destruction box. +- */ +-void SeqLineWidget::setupDestructionBox() +-{ +- cleanupDestructionBox(); +- if(!m_pObject->showDestruction()) { +- return; +- } +- QRect rect; +- rect.setX(m_pObject->x() + m_pObject->width() / 2 - 10); +- rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY); +- rect.setWidth(14); +- rect.setHeight(14); +- +- m_DestructionBox.line1 = new QGraphicsLineItem; +- m_scene->addItem(m_DestructionBox.line1); +- m_DestructionBox.setLine1Points(rect); +- m_DestructionBox.line1->setVisible(true); +- m_DestructionBox.line1->setPen(QPen(m_pObject->lineColor(), 2)); +- m_DestructionBox.line1->setZValue(3); +- +- m_DestructionBox.line2 = new QGraphicsLineItem; +- m_scene->addItem(m_DestructionBox.line2); +- m_DestructionBox.setLine2Points(rect); +- m_DestructionBox.line2->setVisible(true); +- m_DestructionBox.line2->setPen(QPen(m_pObject->lineColor(), 2)); +- m_DestructionBox.line2->setZValue(3); +-} +- +-/** +- * Move destruction box. +- */ +-void SeqLineWidget::moveDestructionBox() +-{ +- if(!m_DestructionBox.line1) { +- return; +- } +- QRect rect; +- rect.setX(m_pObject->x() + m_pObject->width() / 2 - 7); +- rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY - 7); +- rect.setWidth(14); +- rect.setHeight(14); +- m_DestructionBox.setLine1Points(rect); +- m_DestructionBox.setLine2Points(rect); +-} +- +-/** +- * Sets the y position of the bottom of the vertical line. +- * +- * @param yPosition The y coordinate for the bottom of the line. +- */ +-void SeqLineWidget::setEndOfLine(int yPosition) +-{ +- QPointF sp = line().p1(); +- int newY = yPosition; +- m_nLengthY = yPosition - m_pObject->y() - m_pObject->height(); +- // normally the managing Objectwidget is responsible for the call of this function +- // but to be sure - make a double check _against current position_ +- if (m_nLengthY < 0) { +- m_nLengthY = 0; +- newY = m_pObject->y() + m_pObject->height(); +- } +- setLine(sp.x(), sp.y(), sp.x(), newY); +- moveDestructionBox(); +- m_scene->resizeSceneToItems(); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.h umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,86 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef SEQLINEWIDGET_H +-#define SEQLINEWIDGET_H +- +-#include +- +-class ObjectWidget; +-class UMLScene; +- +-/** +- * @short Widget class for graphical representation of sequence lines +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class SeqLineWidget : public QGraphicsLineItem +-{ +-public: +- SeqLineWidget(UMLScene *scene, ObjectWidget * pObject); +- virtual ~SeqLineWidget(); +- +- bool onWidget(const QPointF& p); +- +- bool onDestructionBox(const QPointF& p); +- +- void cleanup(); +- +- void setupDestructionBox(); +- +- void setStartPoint(int startX, int startY); +- +- /** +- * Gets the length of the line. +- * +- * @return Length of the line. +- */ +- int getLineLength() { +- return m_nLengthY; +- } +- +- /** +- * Returns the @ref ObjectWidget associated with this sequence line. +- * +- * @return Pointer to the associated ObjectWidget. +- */ +- ObjectWidget * getObjectWidget() { +- return m_pObject; +- } +- +- void setEndOfLine(int yPosition); +- +-protected: +- void cleanupDestructionBox(); +- +- void moveDestructionBox(); +- +- ObjectWidget* m_pObject; ///< ObjectWidget associated with this sequence line +- UMLScene* m_scene; ///< scene displayed on +- +- struct DestructionBox { +- QGraphicsLineItem * line1; +- QGraphicsLineItem * line2; +- void setLine1Points(QRect rect) { +- line1->setLine(rect.x(), rect.y(), +- rect.x() + rect.width(), rect.y() + rect.height()); +- } +- void setLine2Points(QRect rect) { +- line2->setLine(rect.x(), rect.y() + rect.height(), +- rect.x() + rect.width(), rect.y()); +- } +- } m_DestructionBox; ///< the destruction box +- +- int m_nLengthY; ///< the length of the line +- +- static int const m_nMouseDownEpsilonX; ///< margin used for mouse clicks +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,386 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "signalwidget.h" +- +-// app includes +-#include "basictypes.h" +-#include "debug_utils.h" +-#include "floatingtextwidget.h" +-#include "linkwidget.h" +-#include "listpopupmenu.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "uniqueid.h" +-#include "umlview.h" +-#include "umlwidget.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#include +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +- +-/** +- * Creates a Signal widget. +- * +- * @param scene The parent of the widget. +- * @param signalType The type of Signal. +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-SignalWidget::SignalWidget(UMLScene *scene, SignalType signalType, Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_Signal, id), +- m_oldX(0), +- m_oldY(0) +-{ +- m_signalType = signalType; +- m_pName = NULL; +- if (signalType == SignalWidget::Time) { +- m_pName = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString()); +- scene->setupNewWidget(m_pName); +- m_pName->setX(0); +- m_pName->setY(0); +- connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); +- } +-} +- +-/** +- * Destructor. +- */ +-SignalWidget::~SignalWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void SignalWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- setPenFromSettings(painter); +- const int w = width(); +- const int h = height(); +- QPolygon a; +- switch (m_signalType) +- { +- case Send : +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- { +- a.setPoints(5, 0, 0, +- (w*2)/3, 0, +- w, h/2, +- (w*2)/3, h, +- 0, h); +- painter->drawPolygon(a); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- int textStartY = (h / 2) - (fontHeight / 2); +- +- painter->setPen(textColor()); +- QFont font = UMLWidget::font(); +- font.setBold(false); +- painter->setFont(font); +- painter->drawText(SIGNAL_MARGIN, textStartY, +- w - SIGNAL_MARGIN * 2, fontHeight, +- Qt::AlignCenter, name()); +- setPenFromSettings(painter); +- } +- break; +- case Accept : +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- { +- a.setPoints(5, 0, 0, +- w/3, h/2, +- 0, h, +- w, h, +- w, 0); +- +- painter->drawPolygon(a); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- int textStartY = (h / 2) - (fontHeight / 2); +- +- painter->setPen(textColor()); +- QFont font = UMLWidget::font(); +- font.setBold(false); +- painter->setFont(font); +- painter->drawText(SIGNAL_MARGIN, textStartY, +- w - SIGNAL_MARGIN * 2 + (w/3), fontHeight, +- Qt::AlignCenter, name()); +- setPenFromSettings(painter); +- } +- break; +- case Time : +- if(UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- { +- a.setPoints(4, 0, 0, +- w, h, +- 0, h, +- w, 0); +- +- painter->drawPolygon(a); +- //const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- //const int fontHeight = fm.lineSpacing(); +- //int textStartY = (h / 2) - (fontHeight / 2); +- painter->setPen(textColor()); +- QFont font = UMLWidget::font(); +- font.setBold(false); +- painter->setFont(font); +- +- setPenFromSettings(painter); +- } +- 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(); +- } +- +- break; +- default: +- uWarning() << "Unknown signal type:" << m_signalType; +- break; +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides the UMLWidget method. +- */ +-void SignalWidget::setX(qreal newX) +-{ +- m_oldX = x(); +- UMLWidget::setX(newX); +-} +- +-/** +- * Overrides the UMLWidget method. +- */ +-void SignalWidget::setY(qreal newY) +-{ +- m_oldY = y(); +- UMLWidget::setY(newY); +-} +- +-/** +- * Sets the name of the signal. +- */ +-void SignalWidget::setName(const QString &strName) +-{ +- UMLWidget::setName(strName); +- updateGeometry(); +- if (signalType() == SignalWidget::Time) { +- 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); +- connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); +- } +- else +- m_pName->setText(m_Text); +- } +-} +- +-/** +- * Returns the type of Signal. +- */ +-SignalWidget::SignalType SignalWidget::signalType() const +-{ +- return m_signalType; +-} +- +-/** +- * Returns the type string of Signal. +- */ +-QString SignalWidget::signalTypeStr() const +-{ +- return QLatin1String(ENUM_NAME(SignalWidget, SignalType, m_signalType)); +-} +- +-/** +- * Sets the type of Signal. +- */ +-void SignalWidget::setSignalType(SignalType signalType) +-{ +- m_signalType = signalType; +-} +- +-/** +- * Show a properties dialog for a UMLWidget. +- */ +-void SignalWidget::showPropertiesDialog() +-{ +-} +- +-/** +- * Overrides mouseMoveEvent. +- */ +-void SignalWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) +-{ +- UMLWidget::mouseMoveEvent(me); +- int diffX = m_oldX - x(); +- int diffY = m_oldY - y(); +- if (m_pName!=NULL) { +- m_pName->setX(m_pName->x() - diffX); +- m_pName->setY(m_pName->y() - diffY); +- } +-} +- +-/** +- * Loads a "signalwidget" XMI element. +- */ +-bool SignalWidget::loadFromXMI(QDomElement & qElement) +-{ +- if(!UMLWidget::loadFromXMI(qElement)) +- return false; +- m_Text = qElement.attribute(QLatin1String("signalname")); +- m_Doc = qElement.attribute(QLatin1String("documentation")); +- QString type = qElement.attribute(QLatin1String("signaltype")); +- QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); +- Uml::ID::Type textId = Uml::ID::fromString(textid); +- +- setSignalType((SignalType)type.toInt()); +- if (signalType() == Time) { +- +- if (textId != Uml::ID::None) { +- UMLWidget *flotext = m_scene -> findWidget(textId); +- if (flotext != NULL) { +- // This only happens when loading files produced by +- // umbrello-kf6-1.3-beta2. +- m_pName = static_cast(flotext); +- return true; +- } +- } else { +- // no textid stored -> get unique new one +- textId = UniqueID::gen(); +- } +- } +- //now load child elements +- QDomNode node = qElement.firstChild(); +- QDomElement element = node.toElement(); +- if (!element.isNull()) { +- QString tag = element.tagName(); +- if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { +- m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, m_Text, textId); +- if(! m_pName->loadFromXMI(element)) { +- // Most likely cause: The FloatingTextWidget is empty. +- delete m_pName; +- m_pName = NULL; +- } +- else +- connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); +- } else { +- uError() << "unknown tag " << tag; +- } +- } +- return true; +-} +- +-/** +- * Creates the "signalwidget" XMI element. +- */ +-void SignalWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement signalElement = qDoc.createElement(QLatin1String("signalwidget")); +- UMLWidget::saveToXMI(qDoc, signalElement); +- signalElement.setAttribute(QLatin1String("signalname"), m_Text); +- signalElement.setAttribute(QLatin1String("documentation"), m_Doc); +- signalElement.setAttribute(QLatin1String("signaltype"), m_signalType); +- if (m_pName && !m_pName->text().isEmpty()) { +- signalElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pName->id())); +- m_pName -> saveToXMI(qDoc, signalElement); +- } +- qElement.appendChild(signalElement); +-} +- +-/** +- * Show a properties dialog for a SignalWidget. +- * +- */ +-void SignalWidget::slotMenuSelection(QAction* action) +-{ +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Rename: +- { +- bool ok = false; +- QString name = m_Text; +-#if QT_VERSION >= 0x050000 +- name = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter signal name"), +- i18n("Enter the signal name :"), +- QLineEdit::Normal, +- m_Text, &ok); +-#else +- name = KInputDialog::getText(i18n("Enter signal name"), +- i18n("Enter the signal name :"), +- m_Text, &ok); +-#endif +- if (ok && name.length() > 0) { +- setName(name); +- } +- } +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- } +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF SignalWidget::minimumSize() const +-{ +- int width = SIGNAL_WIDTH, height = SIGNAL_HEIGHT; +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- int textWidth = fm.width(name()); +- +- if (m_signalType == Accept) +- textWidth = int((float)textWidth * 1.3f); +- height = fontHeight; +- if (m_signalType != Time) +- { +- width = textWidth > SIGNAL_WIDTH?textWidth:SIGNAL_WIDTH; +- height = height > SIGNAL_HEIGHT?height:SIGNAL_HEIGHT; +- } +- width += SIGNAL_MARGIN * 2; +- height += SIGNAL_MARGIN * 2; +- +- return QSizeF(width, height); +-} +- +-/** +- * Called if user deletes text widget +- */ +-void SignalWidget::slotTextDestroyed() +-{ +- m_pName = 0; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.h umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,86 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +-***************************************************************************/ +- +-#ifndef SIGNALWIDGET_H +-#define SIGNALWIDGET_H +- +-#include "floatingtextwidget.h" +-#include "linkwidget.h" +-#include "umlwidget.h" +-#include "worktoolbar.h" +- +-#define SIGNAL_MARGIN 5 +-#define SIGNAL_WIDTH 45 +-#define SIGNAL_HEIGHT 15 +- +-/** +- * Represents a Send signal, Accept signal or Time event on an +- * Activity diagram. +- */ +-class SignalWidget : public UMLWidget +-{ +- Q_OBJECT +- Q_ENUMS(SignalType) +-public: +- /// Enumeration that codes the different types of signal. +- enum SignalType +- { +- Send = 0, +- Accept, +- Time +- }; +- +- explicit SignalWidget(UMLScene * scene, SignalType signalType = Send, Uml::ID::Type id = Uml::ID::None); +- virtual ~SignalWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- void setX(qreal newX); +- void setY(qreal newY); +- +- virtual void setName(const QString &strName); +- +- SignalType signalType() const; +- QString signalTypeStr() const; +- void setSignalType(SignalType signalType); +- +- virtual void showPropertiesDialog(); +- +- void mouseMoveEvent(QGraphicsSceneMouseEvent *me); +- +- virtual bool loadFromXMI(QDomElement & qElement); +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-protected: +- QSizeF minimumSize() const; +- +- /** +- * Save the value of the widget to know how to move the floatingtext +- */ +- int m_oldX; +- int m_oldY; +- +- // Only for the time event +- /** +- * This is a pointer to the Floating Text widget which displays the +- * name of the signal widget. +- */ +- FloatingTextWidget* m_pName; +- +- SignalType m_signalType; ///< Type of signal +- +-protected Q_SLOTS: +- void slotTextDestroyed(); +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/statewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/statewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,534 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "statewidget.h" +- +-// app includes +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "listpopupmenu.h" +-#include "statedialog.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "umlwidget.h" +- +-// kde includes +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +-#include +- +-/** +- * Creates a State widget. +- * +- * @param scene The parent of the widget. +- * @param stateType The type of state. +- * @param id The ID to assign (-1 will prompt a new ID.) +- */ +-StateWidget::StateWidget(UMLScene * scene, StateType stateType, Uml::ID::Type id) +- : UMLWidget(scene, WidgetBase::wt_State, id) +-{ +- m_stateType = stateType; +- m_drawVertical = true; +- setAspectRatioMode(); +- m_Text = QLatin1String("State"); +- QSizeF size = minimumSize(); +- setSize(size.width(), size.height()); +-} +- +-/** +- * Destructor. +- */ +-StateWidget::~StateWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void StateWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- const qreal w = width(); +- const qreal h = height(); +- if (w == 0 || h == 0) +- return; +- +- setPenFromSettings(painter); +- switch (m_stateType) { +- case StateWidget::Normal: +- { +- if (UMLWidget::useFillColor()) { +- painter->setBrush(UMLWidget::fillColor()); +- } +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- int textStartY = (h / 2) - (fontHeight / 2); +- const int count = m_Activities.count(); +- if (count == 0) { +- painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); +- painter->setPen(textColor()); +- QFont font = UMLWidget::font(); +- font.setBold(false); +- painter->setFont(font); +- painter->drawText(STATE_MARGIN, textStartY, +- w - STATE_MARGIN * 2, fontHeight, +- Qt::AlignCenter, name()); +- setPenFromSettings(painter); +- } else { +- painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); +- textStartY = STATE_MARGIN; +- painter->setPen(textColor()); +- QFont font = UMLWidget::font(); +- font.setBold(true); +- painter->setFont(font); +- painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, +- fontHeight, Qt::AlignCenter, name()); +- font.setBold(false); +- painter->setFont(font); +- setPenFromSettings(painter); +- int linePosY = textStartY + fontHeight; +- +- QStringList::Iterator end(m_Activities.end()); +- for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { +- textStartY += fontHeight; +- painter->drawLine(0, linePosY, w, linePosY); +- painter->setPen(textColor()); +- painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, +- fontHeight, Qt::AlignCenter, *it); +- setPenFromSettings(painter); +- linePosY += fontHeight; +- }//end for +- }//end else +- } +- break; +- case StateWidget::Initial : +- painter->setBrush(WidgetBase::lineColor()); +- painter->drawEllipse(0, 0, w, h); +- break; +- case StateWidget::End : +- 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 StateWidget::Fork: +- case StateWidget::Join: +- { +- painter->setPen(Qt::black); +- painter->setBrush(Qt::black); +- painter->drawRect(rect()); +- } +- break; +- case StateWidget::Junction: +- { +- painter->setPen(Qt::black); +- painter->setBrush(Qt::black); +- painter->drawEllipse(rect()); +- } +- break; +- case StateWidget::DeepHistory: +- { +- painter->setBrush(Qt::white); +- painter->drawEllipse(rect()); +- painter->setPen(Qt::black); +- painter->setFont(UMLWidget::font()); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing() / 2; +- const int xStar = fm.boundingRect(QLatin1String("H")).width(); +- const int yStar = fontHeight / 4; +- painter->drawText((w / 6), +- (h / 4) + fontHeight, QLatin1String("H")); +- painter->drawText((w / 6) + xStar, +- (h / 4) + fontHeight - yStar, QLatin1String("*")); +- } +- break; +- case StateWidget::ShallowHistory: +- { +- painter->setBrush(Qt::white); +- painter->drawEllipse(rect()); +- painter->setPen(Qt::black); +- painter->setFont(UMLWidget::font()); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing() / 2; +- painter->drawText((w / 6), +- (h / 4) + fontHeight, QLatin1String("H")); +- } +- break; +- case StateWidget::Choice: +- { +- const qreal x = w / 2; +- const qreal y = h / 2; +- QPolygonF polygon; +- polygon << QPointF(x, 0) << QPointF(w, y) +- << QPointF(x, h) << QPointF(0, y); +- painter->setBrush(UMLWidget::fillColor()); +- painter->drawPolygon(polygon); +- } +- break; +- default: +- uWarning() << "Unknown state type: " << stateTypeStr(); +- break; +- } +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF StateWidget::minimumSize() const +-{ +- int width = 10, height = 10; +- switch (m_stateType) { +- case StateWidget::Normal: +- { +- const QFontMetrics &fm = getFontMetrics(FT_BOLD); +- const int fontHeight = fm.lineSpacing(); +- int textWidth = fm.width(name()); +- const int count = m_Activities.count(); +- height = fontHeight; +- if(count > 0) { +- height = fontHeight * (count + 1); +- +- QStringList::ConstIterator end(m_Activities.end()); +- for(QStringList::ConstIterator it(m_Activities.begin()); it != end; ++it) { +- int w = fm.width(*it); +- if(w > textWidth) +- textWidth = w; +- }//end for +- }//end if +- width = textWidth > STATE_WIDTH?textWidth:STATE_WIDTH; +- height = height > STATE_HEIGHT?height:STATE_HEIGHT; +- width += STATE_MARGIN * 2; +- height += STATE_MARGIN * 2; +- break; +- } +- case StateWidget::Fork: +- case StateWidget::Join: +- if (m_drawVertical) { +- width = 8; +- height = 60; +- } else { +- width = 60; +- height = 8; +- } +- break; +- case StateWidget::Junction: +- width = 18; +- height = 18; +- break; +- case StateWidget::DeepHistory: +- case StateWidget::ShallowHistory: +- { +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- width = height = fm.lineSpacing(); +- } +- break; +- case StateWidget::Choice: +- width = 25; +- height = 25; +- break; +- default: +- break; +- } +- +- return QSizeF(width, height); +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF StateWidget::maximumSize() +-{ +- switch (m_stateType) { +- case StateWidget::Initial: +- case StateWidget::End: +- case StateWidget::Junction: +- case StateWidget::Choice: +- return QSizeF(35, 35); +- break; +- case StateWidget::DeepHistory: +- case StateWidget::ShallowHistory: +- { +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- return QSizeF(fontHeight + 10, fontHeight + 10); +- } +- break; +- default: +- break; +- } +- return UMLWidget::maximumSize(); +-} +- +-/** +- * Set the aspect ratio mode. +- * Some state types have a fixed aspect ratio +- */ +-void StateWidget::setAspectRatioMode() +-{ +- switch (m_stateType) { +- case StateWidget::Initial: +- case StateWidget::End: +- case StateWidget::Choice: +- case StateWidget::DeepHistory: +- case StateWidget::ShallowHistory: +- case StateWidget::Fork: +- case StateWidget::Join: +- case StateWidget::Junction: +- setFixedAspectRatio(true); +- break; +- default: +- setFixedAspectRatio(false); +- break; +- } +-} +- +-/** +- * Returns the type of state. +- * @return StateType +- */ +-StateWidget::StateType StateWidget::stateType() const +-{ +- return m_stateType; +-} +- +-/** +- * Returns the type string of state. +- */ +-QString StateWidget::stateTypeStr() const +-{ +- return QLatin1String(ENUM_NAME(StateWidget, StateType, m_stateType)); +-} +- +-/** +- * Sets the type of state. +- */ +-void StateWidget::setStateType(StateType stateType) +-{ +- m_stateType = stateType; +- setAspectRatioMode(); +-} +- +-/** +- * Adds an activity to this widget. +- * @return true on success +- */ +-bool StateWidget::addActivity(const QString &activity) +-{ +- m_Activities.append(activity); +- updateGeometry(); +- return true; +-} +- +-/** +- * Removes the given activity from the state. +- */ +-bool StateWidget::removeActivity(const QString &activity) +-{ +- if(m_Activities.removeAll(activity) == 0) +- return false; +- updateGeometry(); +- return true; +-} +- +-/** +- * Renames the given activity. +- */ +-bool StateWidget::renameActivity(const QString &activity, const QString &newName) +-{ +- int index = - 1; +- if((index = m_Activities.indexOf(activity)) == -1) +- return false; +- m_Activities[ index ] = newName; +- return true; +-} +- +-/** +- * Sets the states activities to the ones given. +- */ +-void StateWidget::setActivities(const QStringList &list) +-{ +- m_Activities = list; +- updateGeometry(); +-} +- +-/** +- * Returns the list of activities. +- */ +-QStringList StateWidget::activities() const +-{ +- return m_Activities; +-} +- +-/** +- * Get whether to draw a fork or join vertically. +- */ +-bool StateWidget::drawVertical() const +-{ +- return m_drawVertical; +-} +- +-/** +- * Set whether to draw a fork or join vertically. +- */ +-void StateWidget::setDrawVertical(bool to) +-{ +- m_drawVertical = to; +- setSize(height(), width()); +- updateGeometry(); +- UMLWidget::adjustAssocs(x(), y()); +-} +- +-/** +- * Show a properties dialog for a StateWidget. +- */ +-void StateWidget::showPropertiesDialog() +-{ +- UMLApp::app()->docWindow()->updateDocumentation(false); +- +- QPointer dialog = new StateDialog(m_scene->activeView(), this); +- if (dialog->exec() && dialog->getChangesMade()) { +- UMLApp::app()->docWindow()->showDocumentation(this, true); +- UMLApp::app()->document()->setModified(true); +- } +- delete dialog; +-} +- +-/** +- * Creates the "statewidget" XMI element. +- */ +-void StateWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement stateElement = qDoc.createElement(QLatin1String("statewidget")); +- UMLWidget::saveToXMI(qDoc, stateElement); +- stateElement.setAttribute(QLatin1String("statename"), m_Text); +- stateElement.setAttribute(QLatin1String("documentation"), m_Doc); +- stateElement.setAttribute(QLatin1String("statetype"), m_stateType); +- if (m_stateType == Fork || m_stateType == Join) +- stateElement.setAttribute(QLatin1String("drawvertical"), m_drawVertical); +- //save states activities +- QDomElement activitiesElement = qDoc.createElement(QLatin1String("Activities")); +- +- QStringList::Iterator end(m_Activities.end()); +- for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { +- QDomElement tempElement = qDoc.createElement(QLatin1String("Activity")); +- tempElement.setAttribute(QLatin1String("name"), *it); +- activitiesElement.appendChild(tempElement); +- }//end for +- stateElement.appendChild(activitiesElement); +- qElement.appendChild(stateElement); +-} +- +-/** +- * Loads a "statewidget" XMI element. +- */ +-bool StateWidget::loadFromXMI(QDomElement & qElement) +-{ +- if(!UMLWidget::loadFromXMI(qElement)) +- return false; +- m_Text = qElement.attribute(QLatin1String("statename")); +- m_Doc = qElement.attribute(QLatin1String("documentation")); +- QString type = qElement.attribute(QLatin1String("statetype"), QLatin1String("1")); +- m_stateType = (StateType)type.toInt(); +- setAspectRatioMode(); +- QString drawVertical = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("1")); +- m_drawVertical = (bool)drawVertical.toInt(); +- //load states activities +- QDomNode node = qElement.firstChild(); +- QDomElement tempElement = node.toElement(); +- if(!tempElement.isNull() && tempElement.tagName() == QLatin1String("Activities")) { +- QDomNode node = tempElement.firstChild(); +- QDomElement activityElement = node.toElement(); +- while(!activityElement.isNull()) { +- if(activityElement.tagName() == QLatin1String("Activity")) { +- QString name = activityElement.attribute(QLatin1String("name")); +- if(!name.isEmpty()) +- m_Activities.append(name); +- }//end if +- node = node.nextSibling(); +- activityElement = node.toElement(); +- }//end while +- }//end if +- return true; +-} +- +-/** +- * Captures any popup menu signals for menus it created. +- */ +-void StateWidget::slotMenuSelection(QAction* action) +-{ +- bool ok = false; +- QString nameNew = name(); +- +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); +- switch(sel) { +- case ListPopupMenu::mt_Rename: +-#if QT_VERSION >= 0x050000 +- nameNew = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter State Name"), +- i18n("Enter the name of the new state:"), +- QLineEdit::Normal, +- name(), &ok); +-#else +- nameNew = KInputDialog::getText(i18n("Enter State Name"), +- i18n("Enter the name of the new state:"), +- name(), &ok); +-#endif +- if (ok && nameNew.length() > 0) { +- setName(nameNew); +- } +- break; +- +- case ListPopupMenu::mt_Properties: +- showPropertiesDialog(); +- break; +- +- case ListPopupMenu::mt_New_Activity: +-#if QT_VERSION >= 0x050000 +- nameNew = QInputDialog::getText(Q_NULLPTR, +- i18n("Enter Activity"), +- i18n("Enter the name of the new activity:"), +- QLineEdit::Normal, +- i18n("new activity"), &ok); +-#else +- nameNew = KInputDialog::getText(i18n("Enter Activity"), +- i18n("Enter the name of the new activity:"), +- i18n("new activity"), &ok); +-#endif +- if (ok && nameNew.length() > 0) { +- addActivity(nameNew); +- } +- break; +- +- case ListPopupMenu::mt_Flip: +- setDrawVertical(!m_drawVertical); +- break; +- +- default: +- UMLWidget::slotMenuSelection(action); +- break; +- } +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.h umbrello-kf6-15.08.1/umbrello/widgets/statewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/statewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,99 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +-***************************************************************************/ +- +-#ifndef STATEWIDGET_H +-#define STATEWIDGET_H +- +-#include "umlwidget.h" +- +-#include +-#include +- +-#define STATE_MARGIN 5 +-#define STATE_WIDTH 30 +-#define STATE_HEIGHT 10 +- +-/** +- * This class is the graphical version of a UML State. +- * +- * A StateWidget is created by a @ref UMLView. A StateWidget belongs to +- * only one @ref UMLView instance. +- * When the @ref UMLView instance that this class belongs to is destroyed, +- * it will be automatically deleted. +- * +- * The StateWidget class inherits from the @ref UMLWidget class +- * which adds most of the functionality to this class. +- * +- * @short A graphical version of a UML State. +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class StateWidget : public UMLWidget +-{ +- Q_OBJECT +- Q_ENUMS(StateType) +-public: +- /// Enumeration that codes the different types of state. +- enum StateType +- { +- Initial = 0, // Pseudostate +- Normal, +- End, +- Fork, // Pseudostate +- Join, // Pseudostate +- Junction, // Pseudostate +- DeepHistory, // Pseudostate +- ShallowHistory, // Pseudostate +- Choice // Pseudostate +- //Terminate // Pseudostate +- //EntryPoint // Pseudostate +- //ExitPoint // Pseudostate +- }; +- +- explicit StateWidget(UMLScene * scene, StateType stateType = Normal, Uml::ID::Type id = Uml::ID::None); +- virtual ~StateWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- StateType stateType() const; +- QString stateTypeStr() const; +- void setStateType(StateType stateType); +- +- bool addActivity(const QString &activity); +- bool removeActivity(const QString &activity); +- bool renameActivity(const QString &activity, const QString &newName); +- +- QStringList activities() const; +- void setActivities(const QStringList &list); +- +- bool drawVertical() const; +- void setDrawVertical(bool to = true); +- +- virtual void showPropertiesDialog(); +- +- virtual bool loadFromXMI(QDomElement & qElement); +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- QSizeF minimumSize() const; +- QSizeF maximumSize(); +- void setAspectRatioMode(); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction* action); +- +-private: +- StateType m_stateType; ///< Type of state. +- bool m_drawVertical; ///< whether to draw the fork/join horizontally or vertically +- QStringList m_Activities; ///< List of activities for the state. +- +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.cpp umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,122 +0,0 @@ +-// vim: set tabstop=4 shiftwidth=4 noexpandtab: +-/* +-Widget taken from gwenview-kf6 +-Copyright 2007 Aurélien Gâteau +- +-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. +- +-This program is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with this program; if not, write to the Free Software +-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +- +-*/ +-// Self +-#include "statusbartoolbutton.h" +- +-// Qt +-#include +-#include +-#include +-#include +- +-// KDE +-#include +- +-StatusBarToolButton::StatusBarToolButton(QWidget* parent) +- : QToolButton(parent), +- mGroupPosition(NotGrouped) +-{ +- setToolButtonStyle(Qt::ToolButtonTextOnly); +- setFocusPolicy(Qt::NoFocus); +- setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); +-} +- +- +-QSize StatusBarToolButton::minimumSizeHint() const +-{ +- return sizeHint(); +-} +- +- +-QSize StatusBarToolButton::sizeHint() const +-{ +- QSize sh = QToolButton::sizeHint(); +- sh.setHeight(fontMetrics().height()); +- return sh; +-} +- +- +-void StatusBarToolButton::setGroupPosition(StatusBarToolButton::GroupPosition groupPosition) +-{ +- mGroupPosition = groupPosition; +-} +- +- +-void StatusBarToolButton::paintEvent(QPaintEvent* event) +-{ +- if (mGroupPosition == NotGrouped) { +- QToolButton::paintEvent(event); +- return; +- } +- QStylePainter painter(this); +- QStyleOptionToolButton opt; +- initStyleOption(&opt); +- QStyleOptionToolButton panelOpt = opt; +- +- // Panel +- QRect& panelRect = panelOpt.rect; +- switch (mGroupPosition) { +- case GroupLeft: +- panelRect.setWidth(panelRect.width() * 2); +- break; +- case GroupCenter: +- panelRect.setLeft(panelRect.left() - panelRect.width()); +- panelRect.setWidth(panelRect.width() * 3); +- break; +- case GroupRight: +- panelRect.setLeft(panelRect.left() - panelRect.width()); +- break; +- case NotGrouped: +- Q_ASSERT(0); +- } +- painter.drawPrimitive(QStyle::PE_PanelButtonTool, panelOpt); +- +- // Separator +- const int y1 = opt.rect.top() + 6; +- const int y2 = opt.rect.bottom() - 6; +- if (mGroupPosition & GroupRight) { +- const int x = opt.rect.left(); +- painter.setPen(opt.palette.color(QPalette::Light)); +- painter.drawLine(x, y1, x, y2); +- } +- if (mGroupPosition & GroupLeft) { +- const int x = opt.rect.right(); +- painter.setPen(opt.palette.color(QPalette::Mid)); +- painter.drawLine(x, y1, x, y2); +- } +- +- // Text +- painter.drawControl(QStyle::CE_ToolButtonLabel, opt); +- +- // Filtering message on tooltip text for CJK to remove accelerators. +- // Quoting ktoolbar.cpp: +- // """ +- // CJK languages use more verbose accelerator marker: they add a Latin +- // letter in parenthesis, and put accelerator on that. Hence, the default +- // removal of ampersand only may not be enough there, instead the whole +- // parenthesis construct should be removed. Provide these filtering i18n +- // messages so that translators can use Transcript for custom removal. +- // """ +- if (!actions().isEmpty()) { +- QAction* action = actions().first(); +- setToolTip(i18nc("@info:tooltip of custom toolbar button", "%1", action->toolTip())); +- } +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.h umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,58 +0,0 @@ +-// vim: set tabstop=4 shiftwidth=4 noexpandtab: +-/* +-gwenview-kf6: an image viewer +-Copyright 2007 Aurélien Gâteau +- +-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. +- +-This program is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with this program; if not, write to the Free Software +-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +- +-*/ +-#ifndef STATUSBARTOOLBUTTON_H +-#define STATUSBARTOOLBUTTON_H +- +-// Qt +-#include +- +-/** +- * A thin tool button which can be grouped with another and look like one solid-kf6 +- * bar: +- * +- * (button1 | button2) +- */ +-class StatusBarToolButton : public QToolButton +-{ +- Q_OBJECT +-public: +- enum GroupPosition { +- NotGrouped = 0, +- GroupLeft = 1, +- GroupRight = 2, +- GroupCenter = 3 +- }; +- +- explicit StatusBarToolButton(QWidget* parent = 0); +- +- virtual QSize minimumSizeHint() const; +- virtual QSize sizeHint() const; +- +- void setGroupPosition(StatusBarToolButton::GroupPosition groupPosition); +- +-protected: +- virtual void paintEvent(QPaintEvent* event); +- +-private: +- GroupPosition mGroupPosition; +-}; +- +-#endif /* STATUSBARTOOLBUTTON_H */ +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,249 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "toolbarstateonewidget.h" +- +-// app includes +-#include "activitywidget.h" +-#include "dialog_utils.h" +-#include "floatingtextwidget.h" +-#include "messagewidget.h" +-#include "objectwidget.h" +-#include "pinwidget.h" +-#include "portwidget.h" +-#include "preconditionwidget.h" +-#include "regionwidget.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlwidget.h" +-#include "object_factory.h" +-#include "package.h" +-#include "widget_factory.h" +- +-// kde includes +-#include +-#include +-#if QT_VERSION < 0x050000 +-#include +-#endif +- +-// qt includes +-#if QT_VERSION >= 0x050000 +-#include +-#endif +- +-// 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) { +- m_firstObject = 0; +- } +- +- if (m_pMouseEvent->button() != Qt::LeftButton || +- (currentWidget()->baseType() != WidgetBase::wt_Object && +- currentWidget()->baseType() != WidgetBase::wt_Activity && +- currentWidget()->baseType() != WidgetBase::wt_Component && +- currentWidget()->baseType() != WidgetBase::wt_Region)) { +- return; +- } +- +- if (!m_firstObject && type == WidgetBase::wt_Pin) { +- 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) { +- if (m_firstObject->baseType() == WidgetBase::wt_Activity) { +- umlwidget = new PinWidget(m_pUMLScene, m_firstObject); +- // Create the widget. Some setup functions can remove the widget. +- } else if (m_firstObject->baseType() == WidgetBase::wt_Component) { +- bool pressedOK = false; +-#if QT_VERSION >= 0x050000 +- QString name = QInputDialog::getText(UMLApp::app(), +- i18n("Enter Port Name"), i18n("Enter the port"), +- QLineEdit::Normal, +- i18n("new port"), +- &pressedOK); +-#else +- QString name = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port"), i18n("new port"), +- &pressedOK, UMLApp::app()); +-#endif +- if (pressedOK) { +- UMLPackage* component = static_cast(m_firstObject->umlObject()); +- UMLObject *port = Object_Factory::createUMLObject(UMLObject::ot_Port, name, component); +- umlwidget = Widget_Factory::createWidget(m_pUMLScene, port); +- } +- } +- } +- +- if (umlwidget) { +- m_pUMLScene->setupNewWidget(umlwidget); +- } +- +-} +- +-/** +- * 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; +- } +- // Shouldn't happen +- Q_ASSERT(0); +- return WidgetBase::wt_Pin; +-} +- +-/** +- * Goes back to the initial state. +- */ +-void ToolBarStateOneWidget::init() +-{ +- ToolBarStatePool::init(); +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.h umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,59 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef TOOLBARSTATEONEWIDGET_H +-#define TOOLBARSTATEONEWIDGET_H +- +-#include "toolbarstatepool.h" +-#include "widgetbase.h" +- +-/** +- * Sequence tool to create components linked with one object in sequence diagram +- * like precondition. +- * With sequence tool, one objects is selected clicking with left button on +- * it +- */ +-class ToolBarStateOneWidget : public ToolBarStatePool +-{ +- Q_OBJECT +-public: +- explicit ToolBarStateOneWidget(UMLScene *umlScene); +- virtual ~ToolBarStateOneWidget(); +- +- virtual void cleanBeforeChange(); +- +- // FIXME: obsolete +- virtual void mouseMove(QGraphicsSceneMouseEvent* ome); +- +-public Q_SLOTS: +- virtual void slotWidgetRemoved(UMLWidget* widget); +- +-protected: +- virtual void setCurrentElement(); +- +- virtual void mouseReleaseWidget(); +- virtual void mouseReleaseEmpty(); +- +- void setWidget(UMLWidget* firstObject); +- WidgetBase::WidgetType widgetType(); +- +- UMLWidget* m_firstObject; ///< The first object in the message. +- +- /** +- * If there is a current widget, it is true if the press event happened on +- * the line of an object, or false if it happened on a normal UMLWidget. +- */ +- bool m_isObjectWidgetLine; +- +-private: +- virtual void init(); +-}; +- +-#endif //TOOLBARSTATEONEWIDGET_H +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1859 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "umlwidget.h" +- +-// local includes +-#include "associationwidget.h" +-#include "classifier.h" +-#include "classpropertiesdialog.h" +-#include "cmds.h" +-#include "debug_utils.h" +-#include "docwindow.h" +-#include "floatingtextwidget.h" +-#include "idchangelog.h" +-#include "listpopupmenu.h" +-#include "settingsdialog.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umllistview.h" +-#include "umlobject.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "uniqueid.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 qreal UMLWidget::defaultMargin = 5; +- +-/** +- * 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 (m_baseType != other.m_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 != NULL && id == m_umlObject->id()) || +- id == m_nId) +- return this; +- return NULL; +-} +- +-/** +- * 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(); +- adjustUnselectedAssocs(delta.x(), delta.y()); +- +- DEBUG(DBG_SRC) << "diffX=" << diffX << " / diffY=" << diffY; +- foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { +- widget->moveWidgetBy(diffX, diffY); +- 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_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; +- } +-} +- +-/** +- * 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(); +- switch(baseType()) { +- case WidgetBase::wt_Message: // will be handled in its class +- QGraphicsItem::mouseDoubleClickEvent(event); +- break; +- default: +- showPropertiesDialog(); +- event->accept(); +- break; +- } +- } +-} +- +-/** +- * 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); +-} +- +-/** +- * When a widget changes this slot captures that signal. +- */ +-void UMLWidget::updateWidget() +-{ +- updateGeometry(); +- switch (m_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; +- +- 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; +- +- 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(m_baseType) && m_umlObject == NULL) { +- m_umlObject = m_doc->findObjectById(m_nId); +- if (m_umlObject == NULL) { +- 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->getPastep-kf6oint(); +- int x = point.x() + this->x(); +- int y = point.y() + this->y(); +- if (m_scene->type() == Uml::DiagramType::Sequence) { +- 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 pastep-kf6oint +- 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 && !m_Assocs.contains(pAssoc)) { +- m_Assocs.append(pAssoc); +- } +-} +- +-/** +- * Removes an already created association from the list of +- * associations that include this UMLWidget +- */ +-void UMLWidget::removeAssoc(AssociationWidget* pAssoc) +-{ +- if (pAssoc) { +- m_Assocs.removeAll(pAssoc); +- } +-} +- +-/** +- * 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) +-{ +- // 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, m_Assocs) { +- assocwidget->saveIdealTextPositions(); +- } +- +- foreach(AssociationWidget* assocwidget, m_Assocs) { +- 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, m_Assocs) { +- if (!assocwidget->isSelected()) +- assocwidget->saveIdealTextPositions(); +- } +- +- foreach(AssociationWidget* assocwidget, m_Assocs) { +- if (!assocwidget->isSelected()) { +- assocwidget->widgetMoved(this, dx, dy); +- } +- } +-} +- +-/** +- * Show a properties dialog for a UMLWidget. +- */ +-void UMLWidget::showPropertiesDialog() +-{ +- // 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); +- } +- dlg->close(); //wipe from memory +- delete dlg; +-} +- +-/** +- * 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) +- 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) +-{ +- // TODO the status message lies for at least MessageWidget which could only be resized vertical +- 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 resize.")); +- +- 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 = m_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); +- } +- +- // TODO: isn't this handled by toForeground() ? +- const QPoint pos(x(), y()); +- UMLWidget *bkgnd = m_scene->widgetAt(pos); +- if (bkgnd && bkgnd != this && _select) { +- DEBUG(DBG_SRC) << "setting Z to " << bkgnd->zValue() + 1.0 << ", SelectState: " << _select; +- setZValue(bkgnd->zValue() + 1.0); +- } +- +- 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(); +- } +- +- setRect(rect().x(), rect().y(), width, height); +-} +- +-/** +- * Sets the size with another size. +- */ +-void UMLWidget::setSize(const QSizeF& size) +-{ +- setSize(size.width(), size.height()); +-} +- +-/** +- * Update the size of this widget. +- */ +-void UMLWidget::updateGeometry() +-{ +- if (m_doc->loading()) { +- 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(); +- adjustAssocs(size.width()-oldW, size.height()-oldH); +-} +- +-/** +- * 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 = 4; +- 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::red); +- 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::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- /* +- Call after required actions in child class. +- Type must be set in the child class. +- */ +- WidgetBase::saveToXMI(qDoc, qElement); +- qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(id())); +- qElement.setAttribute(QLatin1String("x"), x()); +- qElement.setAttribute(QLatin1String("y"), y()); +- qElement.setAttribute(QLatin1String("width"), width()); +- qElement.setAttribute(QLatin1String("height"), height()); +- 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::loadFromXMI(QDomElement & qElement) +-{ +- QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); +- m_nId = Uml::ID::fromString(id); +- +- WidgetBase::loadFromXMI(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")); +- +- setSize(w.toFloat(), h.toFloat()); +- setX(x.toFloat()); +- setY(y.toFloat()); +- 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; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.h umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,347 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLWIDGET_H +-#define UMLWIDGET_H +- +-#include "associationwidgetlist.h" +-#include "basictypes.h" +-#include "optionstate.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-kf6-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 qreal defaultMargin; +- +- 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); +- 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); +- +- bool getIgnoreSnapToGrid() const; +- void setIgnoreSnapToGrid(bool to); +- +- void moveByLocal(qreal dx, qreal dy); +- +- void removeAssoc(AssociationWidget* pAssoc); +- void addAssoc(AssociationWidget* pAssoc); +- +- /** +- * Returns the list of associations connected to this widget. +- */ +- AssociationWidgetList & associationWidgetList() { +- return m_Assocs; +- } +- +- /** +- * 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 void showPropertiesDialog(); +- +- virtual void adjustAssocs(qreal dx, qreal dy); +- 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(); +- +- void clipSize(); +- +- void forceUpdateFontMetrics(QPainter *painter); +- void forceUpdateFontMetrics(QFont &font, QPainter *painter); +- +- virtual bool loadFromXMI(QDomElement &qElement); +- virtual void saveToXMI(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(); +- +- ///////////////// Data Loaded/Saved ///////////////////////////////// +- +- /// A list of AssociationWidgets between the UMLWidget and other UMLWidgets in the diagram +- AssociationWidgetList m_Assocs; +- +- 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(); +- void toForeground(); +- +-}; +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,96 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header file +-#include "usecasewidget.h" +- +-// app includes +-#include "usecase.h" +-#include "umlview.h" +- +-/** +- * Creates a UseCase widget. +- * @param scene The parent of the widget. +- * @param o The UMLUseCase to represent. +- */ +-UseCaseWidget::UseCaseWidget(UMLScene * scene, UMLUseCase *o) +- : UMLWidget(scene, WidgetBase::wt_UseCase, o) +-{ +-} +- +-/** +- * Destructor. +- */ +-UseCaseWidget::~UseCaseWidget() +-{ +-} +- +-/** +- * Overrides the standard paint event. +- */ +-void UseCaseWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(option); +- Q_UNUSED(widget); +- +- setPenFromSettings(painter); +- if (UMLWidget::useFillColor()) +- painter->setBrush(UMLWidget::fillColor()); +- QFont font = UMLWidget::font(); +- font.setUnderline(false); +- font.setBold(false); +- font.setItalic(m_umlObject->isAbstract()); +- painter->setFont(font); +- const QFontMetrics &fm = getFontMetrics(FT_NORMAL); +- const int fontHeight = fm.lineSpacing(); +- const int w = width(); +- const int h = height(); +- //int middleX = w / 2; +- bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); +- const int textStartY = (h / 2) - (drawStereotype ? fontHeight / 4 : fontHeight / 2); +- +- painter->drawEllipse(0, 0, w, h); +- painter->setPen(textColor()); +- if (drawStereotype) +- painter->drawText(UC_MARGIN, textStartY-fontHeight, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); +- +- painter->drawText(UC_MARGIN, textStartY, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); +- setPenFromSettings(painter); +- +- UMLWidget::paint(painter, option, widget); +-} +- +-/** +- * Saves this UseCase to file. +- */ +-void UseCaseWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +-{ +- QDomElement usecaseElement = qDoc.createElement(QLatin1String("usecasewidget")); +- UMLWidget::saveToXMI(qDoc, usecaseElement); +- qElement.appendChild(usecaseElement); +-} +- +-/** +- * Overrides method from UMLWidget +- */ +-QSizeF UseCaseWidget::minimumSize() const +-{ +- const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); +- const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); +- const int fontHeight = fm.lineSpacing(); +- const int textWidth = fm.width(name()); +- bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); +- int width = textWidth > UC_WIDTH?textWidth:UC_WIDTH; +- int height = UC_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + UC_MARGIN; +- +- width += UC_MARGIN * 2; +- +- return QSizeF(width, height); +-} +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.h umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,58 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef USECASEWIDGET_H +-#define USECASEWIDGET_H +- +-#include "umlwidget.h" +- +-class UMLUseCase; +- +-#define UC_MARGIN 5 +-#define UC_WIDTH 60 +-#define UC_HEIGHT 30 +- +- +-/** +- * This class is the graphical version of a UMLUseCase. The +- * UseCaseWidget class inherits from the @ref UMLWidget class +- * which adds most of the functionality to this class. +- +- * A UseCaseWidget is created by a @ref UMLView. An UseCaseWidget belongs to only one +- * @ref UMLView instance. When the @ref UMLView instance that this class belongs to, +- * it will be automatically deleted. +- * +- * If the @ref UMLUseCase class that this UseCaseWidget is displaying is deleted, the @ref UMLView will +- * make sure that this instance is also deleted. +- * +- * The UseCaseWidget class inherits from the @ref UMLWidget class which adds most of the functionality +- * to this class. +- * +- * @short A graphical version of a UMLUseCase. +- * @author Paul Hensgen +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class UseCaseWidget : public UMLWidget +-{ +-public: +- UseCaseWidget(UMLScene * scene, UMLUseCase *o); +- virtual ~UseCaseWidget(); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +- // For loading we can use the loadFromXMI() inherited from +- // UMLWidget. +- virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); +- +-protected: +- QSizeF minimumSize() const; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.cpp umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,1119 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#include "widgetbase.h" +- +-#include "classifier.h" +-#include "debug_utils.h" +-#include "floatingtextwidget.h" +-#include "optionstate.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlobject.h" +-#include "umlscene.h" +- +-#if QT_VERSION < 0x050000 +-#include +-#include +-#endif +-#include +- +-#include +-#if QT_VERSION >= 0x050000 +-#include +-#include +-#endif +-#include +- +-/** +- * Creates a WidgetBase 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. +- */ +-WidgetBase::WidgetBase(UMLScene *scene, WidgetType type) +- : QGraphicsObject(), +- m_baseType(type), +- m_scene(scene), +- m_umlObject(0), +- m_textColor(QColor("black")), +- m_lineColor(QColor("black")), +- m_fillColor(QColor("yellow")), +- m_brush(m_fillColor), +- m_lineWidth(0), // initialize with 0 to have valid start condition +- m_useFillColor(true), +- m_usesDiagramTextColor(true), +- m_usesDiagramLineColor(true), +- m_usesDiagramLineWidth(true) +-{ +- setSelected(false); +- scene->addItem(this); +- +- // TODO 310283 +- setFlags(ItemIsSelectable); +- //setFlags(ItemIsSelectable | ItemIsMovable |ItemSendsGeometryChanges); +- if (m_scene) { +- m_usesDiagramLineColor = true; +- m_usesDiagramLineWidth = true; +- m_usesDiagramTextColor = true; +- const Settings::OptionState& optionState = m_scene->optionState(); +- m_textColor = optionState.uiState.textColor; +- m_lineColor = optionState.uiState.lineColor; +- m_lineWidth = optionState.uiState.lineWidth; +- m_font = optionState.uiState.font; +- } else { +- uError() << "WidgetBase constructor: SERIOUS PROBLEM - m_scene is NULL"; +- } +-} +- +-/** +- * Destructor. +- */ +-WidgetBase::~WidgetBase() +-{ +-} +- +-/** +- * Read property of m_baseType. +- */ +-WidgetBase::WidgetType WidgetBase::baseType() const +-{ +- return m_baseType; +-} +- +-/** +- * @return The type used for rtti as string. +- */ +-QLatin1String WidgetBase::baseTypeStr() const +-{ +- return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, m_baseType)); +-} +- +-/* +- * Sets the state of whether the widget is selected. +- * +- * @param select The state of whether the widget is selected. +- */ +-void WidgetBase::setSelected(bool select) +-{ +- QGraphicsObject::setSelected(select); +-} +- +-/** +- * Deliver a pointer to the connected UMLView +- * (needed esp. by event handling of AssociationLine). +- */ +-UMLScene* WidgetBase::umlScene() const +-{ +- return m_scene; +-} +- +-/** +- * This is shortcut method for UMLApp::app()->document(). +- * +- * @return Pointer to the UMLDoc object. +- */ +-UMLDoc* WidgetBase::umlDoc() const +-{ +- return UMLApp::app()->document(); +-} +- +-/** +- * Returns the @ref UMLObject set to represent. +- * +- * @return the UMLObject to represent. +- */ +-UMLObject* WidgetBase::umlObject() const +-{ +- return m_umlObject; +-} +- +-/** +- * Sets the @ref UMLObject to represent. +- * +- * @param obj The object to represent. +- */ +-void WidgetBase::setUMLObject(UMLObject *obj) +-{ +- m_umlObject = obj; +-} +- +-/** +- * Write property of m_nId. +- */ +-void WidgetBase::setID(Uml::ID::Type id) +-{ +- if (m_umlObject) { +- if (m_umlObject->id() != Uml::ID::None) +- uWarning() << "changing old UMLObject " << Uml::ID::toString(m_umlObject->id()) +- << " to " << Uml::ID::toString(id); +- m_umlObject->setID(id); +- } +- m_nId = id; +-} +- +-/** +- * Read property of m_nId. +- */ +-Uml::ID::Type WidgetBase::id() const +-{ +- if (m_umlObject) +- return m_umlObject->id(); +- return m_nId; +-} +- +-/** +- * Used by some child classes to get documentation. +- * +- * @return The documentation from the UMLObject (if m_umlObject is set.) +- */ +-QString WidgetBase::documentation() const +-{ +- if (m_umlObject) +- return m_umlObject->doc(); +- return m_Doc; +-} +- +-/** +- * Returns state of documentation for the widget. +- * +- * @return false if documentation is empty +- */ +-bool WidgetBase::hasDocumentation() +-{ +- if (m_umlObject) +- return m_umlObject->hasDoc(); +- return !m_Doc.isEmpty(); +-} +- +-/** +- * Used by some child classes to set documentation. +- * +- * @param doc The documentation to be set in the UMLObject +- * (if m_umlObject is set.) +- */ +-void WidgetBase::setDocumentation(const QString& doc) +-{ +- if (m_umlObject) +- m_umlObject->setDoc(doc); +- else +- m_Doc = doc; +-} +- +-/** +- * Gets the name from the corresponding UMLObject if this widget has an +- * underlying UMLObject; if it does not, then it returns the local +- * m_Text (notably the case for FloatingTextWidget.) +- * +- * @return the currently set name +- */ +-QString WidgetBase::name() const +-{ +- if (m_umlObject) +- return m_umlObject->name(); +- return m_Text; +-} +- +-/** +- * Sets the name in the corresponding UMLObject. +- * Sets the local m_Text if m_umlObject is NULL. +- * +- * @param strName The name to be set. +- */ +-void WidgetBase::setName(const QString &strName) +-{ +- if (m_umlObject) +- m_umlObject->setName(strName); +- else +- m_Text = strName; +-} +- +-/** +- * Returns text color +- * +- * @return currently used text color +- */ +-QColor WidgetBase::textColor() const +-{ +- return m_textColor; +-} +- +-/** +- * Sets the text color +- * +- * @param color the new text color +- */ +-void WidgetBase::setTextColor(const QColor &color) +-{ +- m_textColor = color; +- m_usesDiagramTextColor = false; +-} +- +-/** +- * Returns line color +- * +- * @return currently used line color +- */ +-QColor WidgetBase::lineColor() const +-{ +- return m_lineColor; +-} +- +-/** +- * Sets the line color +- * +- * @param color The new line color +- */ +-void WidgetBase::setLineColor(const QColor &color) +-{ +- m_lineColor = color; +- m_usesDiagramLineColor = false; +-} +- +-/** +- * Returns fill color +- * +- * @return currently used fill color +- */ +-QColor WidgetBase::fillColor() const +-{ +- return m_fillColor; +-} +- +-/** +- * Sets the fill color +- * +- * @param color The new fill color +- */ +-void WidgetBase::setFillColor(const QColor &color) +-{ +- m_fillColor = color; +- m_usesDiagramFillColor = false; +-} +- +-/** +- * Returns line width +- * +- * @return currently used line with +- */ +-uint WidgetBase::lineWidth() const +-{ +- return m_lineWidth; +-} +- +-/** +- * Sets the line width +- * +- * @param width The new line width +- */ +-void WidgetBase::setLineWidth(uint width) +-{ +- m_lineWidth = width; +- m_usesDiagramLineWidth = false; +-} +- +-/** +- * Return state of fill color usage +- * +- * @return True if fill color is used +- */ +-bool WidgetBase::useFillColor() +-{ +- return m_useFillColor; +-} +- +-/** +- * Set state if fill color is used +- * +- * @param state The state to set +- */ +-void WidgetBase::setUseFillColor(bool state) +-{ +- m_useFillColor = state; +- m_usesDiagramUseFillColor = false; +-} +- +-/** +- * Returns state if diagram text color is used +- * +- * @return True means diagram text color is used +- */ +-bool WidgetBase::usesDiagramTextColor() const +-{ +- return m_usesDiagramTextColor; +-} +- +-/** +- * Set state if diagram text color is used +- * +- * @param state The state to set +- */ +-void WidgetBase::setUsesDiagramTextColor(bool state) +-{ +- if (m_usesDiagramTextColor == state) { +- return; +- } +- m_usesDiagramTextColor = state; +- setTextColor(m_textColor); +-} +- +-/** +- * Returns state of diagram line color is used +- * +- * @return True means diagrams line color is used +-*/ +-bool WidgetBase::usesDiagramLineColor() const +-{ +- return m_usesDiagramLineColor; +-} +- +-/** +- * Set state of diagram line color is used +- * +- * @param state The state to set +- */ +-void WidgetBase::setUsesDiagramLineColor(bool state) +-{ +- m_usesDiagramLineColor = state; +-} +- +-/** +- * Returns state of diagram fill color is used +- * +- * @return True means diagrams fill color is used +-*/ +-bool WidgetBase::usesDiagramFillColor() const +-{ +- return m_usesDiagramFillColor; +-} +- +-/** +- * Set state if diagram fill color is used +- * +- * @param state The state to set +- */ +-void WidgetBase::setUsesDiagramFillColor(bool state) +-{ +- m_usesDiagramFillColor = state; +-} +- +-/** +- * Returns state of diagram use fill color is used +- * +- * @return True means diagrams fill color is used +-*/ +-bool WidgetBase::usesDiagramUseFillColor() const +-{ +- return m_usesDiagramUseFillColor; +-} +- +-/** +- * Set state of diagram use fill color is used +- * +- * @param state The state to set +- */ +-void WidgetBase::setUsesDiagramUseFillColor(bool state) +-{ +- m_usesDiagramUseFillColor = state; +-} +- +-/** +- * Returns state of diagram line width is used +- * +- * @return True means diagrams line width is used +- */ +-bool WidgetBase::usesDiagramLineWidth() const +-{ +- return m_usesDiagramLineWidth; +-} +- +-/** +- * Set state of diagram line width is used +- * +- * @param state The state to set +- */ +-void WidgetBase::setUsesDiagramLineWidth(bool state) +-{ +- m_usesDiagramLineWidth = state; +-} +- +-/** +- * Returns the font used for diaplaying any text. +- * @return the font +- */ +-QFont WidgetBase::font() const +-{ +- return m_font; +-} +- +-/** +- * Set the font used to display text inside this widget. +- */ +-void WidgetBase::setFont(const QFont& font) +-{ +- m_font = font; +-} +- +-/** +- * A virtual method for the widget to display a property dialog box. +- * Subclasses should reimplment this appropriately. +- */ +-void WidgetBase::showPropertiesDialog() +-{ +-} +- +-/** +- * A virtual method to save the properties of this widget into a +- * QDomElement i.e xml. +- * +- * Subclasses should first create a new dedicated element as the child +- * of \a qElement parameter passed. Then this base method should be +- * called to save basic widget properties. +- * +- * @param qDoc A QDomDocument object representing the xml document. +- * @param qElement A QDomElement representing xml element data. +- */ +-void WidgetBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +- { +- Q_UNUSED(qDoc) +- +- qElement.setAttribute(QLatin1String("textcolor"), m_usesDiagramTextColor ? QLatin1String("none") +- : m_textColor.name()); +- if (m_usesDiagramLineColor) { +- qElement.setAttribute(QLatin1String("linecolor"), QLatin1String("none")); +- } else { +- qElement.setAttribute(QLatin1String("linecolor"), m_lineColor.name()); +- } +- if (m_usesDiagramLineWidth) { +- qElement.setAttribute(QLatin1String("linewidth"), QLatin1String("none")); +- } else { +- qElement.setAttribute(QLatin1String("linewidth"), m_lineWidth); +- } +- qElement.setAttribute(QLatin1String("usefillcolor"), m_useFillColor); +- // for consistency the following attributes now use american spelling for "color" +- qElement.setAttribute(QLatin1String("usesdiagramfillcolor"), m_usesDiagramFillColor); +- qElement.setAttribute(QLatin1String("usesdiagramusefillcolor"), m_usesDiagramUseFillColor); +- if (m_usesDiagramFillColor) { +- qElement.setAttribute(QLatin1String("fillcolor"), QLatin1String("none")); +- } else { +- qElement.setAttribute(QLatin1String("fillcolor"), m_fillColor.name()); +- } +- qElement.setAttribute(QLatin1String("font"), m_font.toString()); +-} +- +-/** +- * A virtual method to load the properties of this widget from a +- * QDomElement into this widget. +- * +- * Subclasses should reimplement this to load addtional properties +- * required, calling this base method to load the basic properties of +- * the widget. +- * +- * @param qElement A QDomElement which contains xml info for this widget. +- * +- * @todo Add support to load older version. +- */ +-bool WidgetBase::loadFromXMI(QDomElement& qElement) +-{ +- // first load from "linecolour" and then overwrite with the "linecolor" +- // attribute if that one is present. The "linecolour" name was a "typo" in +- // earlier versions of umbrello-kf6 +- QString lineColor = qElement.attribute(QLatin1String("linecolour"), QLatin1String("none")); +- lineColor = qElement.attribute(QLatin1String("linecolor"), lineColor); +- if (lineColor != QLatin1String("none")) { +- m_lineColor = QColor(lineColor); +- m_usesDiagramLineColor = false; +- } else if (m_baseType != WidgetBase::wt_Box && m_scene != NULL) { +- m_lineColor = m_scene->lineColor(); +- m_usesDiagramLineColor = true; +- } +- QString lineWidth = qElement.attribute(QLatin1String("linewidth"), QLatin1String("none")); +- if (lineWidth != QLatin1String("none")) { +- m_lineWidth = lineWidth.toInt(); +- m_usesDiagramLineWidth = false; +- } else if (m_scene) { +- m_lineWidth = m_scene->lineWidth(); +- m_usesDiagramLineWidth = true; +- } +- QString textColor = qElement.attribute(QLatin1String("textcolor"), QLatin1String("none")); +- if (textColor != QLatin1String("none")) { +- m_textColor = QColor(textColor); +- m_usesDiagramTextColor = false; +- } else if (m_scene) { +- m_textColor = m_scene->textColor(); +- m_usesDiagramTextColor = true; +- } +- QString usefillcolor = qElement.attribute(QLatin1String("usefillcolor"), QLatin1String("1")); +- m_useFillColor = (bool)usefillcolor.toInt(); +- /* +- For the next three *color attributes, there was a mixup of american and english spelling for "color". +- So first we need to keep backward compatibility and try to retrieve the *colour attribute. +- Next we overwrite this value if we find a *color, otherwise the former *colour is kept. +- */ +- QString fillColor = qElement.attribute(QLatin1String("fillcolour"), QLatin1String("none")); +- fillColor = qElement.attribute(QLatin1String("fillcolor"), fillColor); +- if (fillColor != QLatin1String("none")) { +- m_fillColor = QColor(fillColor); +- } +- +- QString usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolour"), QLatin1String("1")); +- usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolor"), usesDiagramFillColor); +- m_usesDiagramFillColor = (bool)usesDiagramFillColor.toInt(); +- +- QString usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolour"), QLatin1String("1")); +- usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolor"), usesDiagramUseFillColor); +- m_usesDiagramUseFillColor = (bool)usesDiagramUseFillColor.toInt(); +- +- QString font = qElement.attribute(QLatin1String("font")); +- if (!font.isEmpty()) { +- QFont newFont; +- newFont.fromString(font); +- m_font = newFont; +- } else { +- uWarning() << "Using default font " << m_font.toString() +- << " for widget with xmi.id " << Uml::ID::toString(m_nId); +- } +- +- return true; +-} +- +-/** +- * Assignment operator +- */ +-WidgetBase& WidgetBase::operator=(const WidgetBase& other) +-{ +- m_baseType = other.m_baseType; +- m_scene = other.m_scene; +- m_umlObject = other.m_umlObject; +- m_Doc = other.m_Doc; +- m_Text = other.m_Text; +- m_nId = other.m_nId; +- m_textColor = other.m_textColor; +- m_lineColor = other.m_lineColor; +- m_fillColor = other.m_fillColor; +- m_brush = other.m_brush; +- m_font = other.m_font; +- m_lineWidth = other.m_lineWidth; +- m_useFillColor = other.m_useFillColor; +- m_usesDiagramTextColor = other.m_usesDiagramTextColor; +- m_usesDiagramLineColor = other.m_usesDiagramLineColor; +- m_usesDiagramFillColor = other.m_usesDiagramFillColor; +- m_usesDiagramLineWidth = other.m_usesDiagramLineWidth; +- setSelected(other.isSelected()); +- +- return *this; +-} +- +-/** +- * return drawing rectangle of widget in local coordinates +- */ +-QRectF WidgetBase::rect() const +-{ +- return m_rect; +-} +- +-/** +- * set widget rectangle in item coordinates +- */ +-void WidgetBase::setRect(const QRectF& rect) +-{ +- if (m_rect == rect) +- return; +- prepareGeometryChange(); +- m_rect = rect; +- update(); +-} +- +-/** +- * set widget rectangle in item coordinates +- */ +-void WidgetBase::setRect(qreal x, qreal y, qreal width, qreal height) +-{ +- setRect(QRectF(x, y, width, height)); +-} +- +-/** +- * @return The bounding rectangle for this widget. +- * @see setRect +- */ +-QRectF WidgetBase::boundingRect() const +-{ +- int halfWidth = lineWidth()/2; +- return m_rect.adjusted(-halfWidth, -halfWidth, halfWidth, halfWidth); +-} +- +-/** +- * Test if point is inside the bounding rectangle of the widget. +- * Inheriting classes may reimplement this to test possible child widgets. +- * +- * @param p Point to be checked. +- * +- * @return 'this' if the given point is in the boundaries of the widget; +- * else NULL. +- */ +-UMLWidget* WidgetBase::onWidget(const QPointF &p) +-{ +- UMLWidget *uw = dynamic_cast(this); +- if (uw == NULL) +- return NULL; +- const qreal w = m_rect.width(); +- const qreal h = m_rect.height(); +- const qreal left = x(); // don't use m_rect.x() for this, it is always 0 +- const qreal right = left + w; +- const qreal top = y(); // don't use m_rect.y() for this, it is always 0 +- const qreal bottom = top + h; +- // uDebug() << "p=(" << p.x() << "," << p.y() +- // << "), x=" << left << ", y=" << top << ", w=" << w << ", h=" << h +- // << "; right=" << right << ", bottom=" << bottom; +- if (p.x() < left || p.x() > right || +- p.y() < top || p.y() > bottom) { // Qt coord.sys. origin in top left corner +- // uDebug() << "returning NULL"; +- return NULL; +- } +- // uDebug() << "returning this"; +- return uw; +-} +- +-/** +- * Draws the UMLWidget on the given paint device +- * +- * @param painter The painter for the drawing device +- * @param option Painting related options +- * @param widget Background widget on which to paint (optional) +- * +- */ +-void WidgetBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +-{ +- Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); +-} +- +-/** +- * Reimplemented to show appropriate context menu. +- */ +-void WidgetBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +-{ +- event->accept(); +- uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); +- +- UMLScene *scene = umlScene(); +- +- // If right-click was done on a widget that was not selected, clear the +- // current selection and select the new widget. The context menu is shown +- // with actions for that single widget. +- // If a keyboard modifier was used, add the widget to the current selection +- // and show the menu with actions for the whole selection. +- if (!isSelected()) { +- Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); +- if ((event->modifiers() & forSelection) == 0) { +- scene->clearSelected(); +- } +- +- if (umlObject() != 0) { +- scene->selectWidget(dynamic_cast(this)); +- } else { +- setSelected(true); +- } +- } +- +- int count = scene->selectedCount(true); +- +- // Determine multi state +- bool multi = (isSelected() && count > 1); +- +- ListPopupMenu popup(0, this, multi, scene->getUniqueSelectionType()); +- +- // Disable the "view code" menu for simple code generators +- if (UMLApp::app()->isSimpleCodeGeneratorActive()) { +- popup.setActionEnabled(ListPopupMenu::mt_ViewCode, false); +- } +- +- QAction *triggered = popup.exec(event->screenPos()); +- ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); +- +- if (!parentMenu) { +- uDebug() << "Action's data field does not contain ListPopupMenu pointer"; +- return; +- } +- +- WidgetBase *ownerWidget = parentMenu->ownerWidget(); +- // assert because logic is based on only WidgetBase being the owner of +- // ListPopupMenu actions executed in this context menu. +- Q_ASSERT_X(ownerWidget != 0, "WidgetBase::contextMenuEvent", +- "ownerWidget is null which means action belonging to UMLView, UMLScene" +- " or UMLObject is the one triggered in ListPopupMenu"); +- +- ownerWidget->slotMenuSelection(triggered); +-} +- +-/** +- * 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 WidgetBase::slotMenuSelection(QAction *trigger) +-{ +- if (!trigger) { +- return; +- } +- QColor newColor; +- +- const WidgetType wt = m_baseType; // short hand name +- +- ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); +- switch (sel) { +- case ListPopupMenu::mt_Rename: +- umlDoc()->renameUMLObject(umlObject()); +- break; +- +- case ListPopupMenu::mt_Properties: +- if (wt == WidgetBase::wt_Actor || wt == WidgetBase::wt_UseCase || +- wt == WidgetBase::wt_Package || wt == WidgetBase::wt_Interface || +- wt == WidgetBase::wt_Datatype || wt == WidgetBase::wt_Node || +- wt == WidgetBase::wt_Component || wt == WidgetBase::wt_Artifact || +- wt == WidgetBase::wt_Enum || wt == WidgetBase::wt_Entity || +- wt == WidgetBase::wt_Port || +- (wt == WidgetBase::wt_Class && umlScene()->type() == Uml::DiagramType::Class)) { +- +- showPropertiesDialog(); +- +- } else if (wt == WidgetBase::wt_Object) { +- m_umlObject->showPropertiesDialog(); +- } else { +- uWarning() << "making properties dialog for unknown widget type"; +- } +- break; +- +- case ListPopupMenu::mt_Line_Color: +- case ListPopupMenu::mt_Line_Color_Selection: +-#if QT_VERSION >= 0x050000 +- newColor = QColorDialog::getColor(lineColor()); +- if (newColor != lineColor()) { +-#else +- newColor = lineColor(); +- if (KColorDialog::getColor(newColor)) { +-#endif +- if (sel == ListPopupMenu::mt_Line_Color_Selection) { +- umlScene()->selectionSetLineColor(newColor); +- } else { +- setLineColor(newColor); +- } +- setUsesDiagramLineColor(false); +- umlDoc()->setModified(true); +- } +- break; +- +- case ListPopupMenu::mt_Fill_Color: +- case ListPopupMenu::mt_Fill_Color_Selection: +-#if QT_VERSION >= 0x050000 +- newColor = QColorDialog::getColor(fillColor()); +- if (newColor != fillColor()) { +-#else +- newColor = fillColor(); +- if (KColorDialog::getColor(newColor)) { +-#endif +- if (sel == ListPopupMenu::mt_Fill_Color_Selection) { +- umlScene()->selectionSetFillColor(newColor); +- } else { +- setFillColor(newColor); +- } +- umlDoc()->setModified(true); +- } +- break; +- +- case ListPopupMenu::mt_Use_Fill_Color: +- setUseFillColor(!m_useFillColor); +- break; +- +- case ListPopupMenu::mt_Set_Use_Fill_Color_Selection: +- umlScene()->selectionUseFillColor(true); +- break; +- +- case ListPopupMenu::mt_Unset_Use_Fill_Color_Selection: +- umlScene()->selectionUseFillColor(false); +- break; +- +- case ListPopupMenu::mt_Show_Attributes_Selection: +- case ListPopupMenu::mt_Hide_Attributes_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowAttributes, sel != ListPopupMenu::mt_Hide_Attributes_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Show_Operations_Selection: +- case ListPopupMenu::mt_Hide_Operations_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowOperations, sel != ListPopupMenu::mt_Hide_Operations_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Show_Visibility_Selection: +- case ListPopupMenu::mt_Hide_Visibility_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowVisibility, sel != ListPopupMenu::mt_Hide_Visibility_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Show_Operation_Signature_Selection: +- case ListPopupMenu::mt_Hide_Operation_Signature_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowOperationSignature, sel != ListPopupMenu::mt_Hide_Operation_Signature_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Show_Attribute_Signature_Selection: +- case ListPopupMenu::mt_Hide_Attribute_Signature_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowAttributeSignature, sel != ListPopupMenu::mt_Hide_Attribute_Signature_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Show_Packages_Selection: +- case ListPopupMenu::mt_Hide_Packages_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowPackage, sel != ListPopupMenu::mt_Hide_Packages_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Show_Stereotypes_Selection: +- case ListPopupMenu::mt_Hide_Stereotypes_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowStereotype, sel != ListPopupMenu::mt_Hide_Stereotypes_Selection +- ); +- break; +- +- case ListPopupMenu::mt_Hide_NonPublic_Selection: +- case ListPopupMenu::mt_Show_NonPublic_Selection: +- umlScene()->selectionSetVisualProperty( +- ClassifierWidget::ShowPublicOnly, sel != ListPopupMenu::mt_Show_NonPublic_Selection +- ); +- break; +- +- +- case ListPopupMenu::mt_ViewCode: { +- UMLClassifier *c = dynamic_cast(umlObject()); +- if (c) { +- UMLApp::app()->viewCodeDocument(c); +- } +- break; +- } +- +- case ListPopupMenu::mt_Delete: +- umlScene()->deleteSelection(); +- break; +- +- case ListPopupMenu::mt_Change_Font: +- case ListPopupMenu::mt_Change_Font_Selection: { +-#if QT_VERSION >= 0x050000 +- bool ok = false; +- QFont newFont = QFontDialog::getFont(&ok, font()); +- if (ok) { +-#else +- QFont newFont = font(); +- if (KFontDialog::getFont(newFont, KFontChooser::NoDisplayFlags, 0) == KFontDialog::Accepted) { +-#endif +- if (sel == ListPopupMenu::mt_Change_Font_Selection) { +- m_scene->selectionSetFont(newFont); +- } else { +- setFont(newFont); +- } +- } +- } +- break; +- +- case ListPopupMenu::mt_Cut: +- umlScene()->setStartedCut(); +- UMLApp::app()->slotEditCut(); +- break; +- +- case ListPopupMenu::mt_Copy: +- UMLApp::app()->slotEditCopy(); +- break; +- +- case ListPopupMenu::mt_Paste: +- UMLApp::app()->slotEditPaste(); +- break; +- +- case ListPopupMenu::mt_Refactoring: +- //check if we are operating on a classifier, or some other kind of UMLObject +- if (dynamic_cast(umlObject())) { +- UMLApp::app()->refactor(static_cast(umlObject())); +- } +- break; +- +- case ListPopupMenu::mt_Clone: +- { +- foreach (UMLWidget* widget, umlScene()->selectedWidgets()) { +- if (Model_Utils::isCloneable(widget->baseType())) { +- UMLObject *clone = widget->umlObject()->clone(); +- umlScene()->addObject(clone); +- } +- } +- } +- break; +- +- case ListPopupMenu::mt_Rename_MultiA: +- case ListPopupMenu::mt_Rename_MultiB: +- case ListPopupMenu::mt_Rename_Name: +- case ListPopupMenu::mt_Rename_RoleAName: +- case ListPopupMenu::mt_Rename_RoleBName: { +- FloatingTextWidget *ft = static_cast(this); +- ft->handleRename(); +- break; +- } +- case ListPopupMenu::mt_Align_Right: +- umlScene()->alignRight(); +- break; +- case ListPopupMenu::mt_Align_Left: +- umlScene()->alignLeft(); +- break; +- case ListPopupMenu::mt_Align_Top: +- umlScene()->alignTop(); +- break; +- case ListPopupMenu::mt_Align_Bottom: +- umlScene()->alignBottom(); +- break; +- case ListPopupMenu::mt_Align_VerticalMiddle: +- umlScene()->alignVerticalMiddle(); +- break; +- case ListPopupMenu::mt_Align_HorizontalMiddle: +- umlScene()->alignHorizontalMiddle(); +- break; +- case ListPopupMenu::mt_Align_VerticalDistribute: +- umlScene()->alignVerticalDistribute(); +- break; +- case ListPopupMenu::mt_Align_HorizontalDistribute: +- umlScene()->alignHorizontalDistribute(); +- break; +- default: +- uDebug() << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; +- break; +- } +-} +- +-/** +- * Helper function for debug output. +- * Returns the given enum value as string. +- * @param wt WidgetType of which a string representation is wanted +- * @return the WidgetType as string +- */ +-QString WidgetBase::toString(WidgetType wt) +-{ +- return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, wt)); +-} +- +-/** +- * Returns the given enum value as localized string. +- * @param wt WidgetType of which a string representation is wanted +- * @return the WidgetType as localized string +- */ +-QString WidgetBase::toI18nString(WidgetType wt) +-{ +- QString name; +- +- switch (wt) { +- case wt_Activity: +- name = i18n("Activity"); +- break; +- case wt_Actor: +- name = i18n("Actor"); +- break; +- case wt_Artifact: +- name = i18n("Artifact"); +- break; +- case wt_Association: +- name = i18n("Association"); +- break; +- case wt_Box: +- name = i18n("Box"); +- break; +- case wt_Category: +- name = i18n("Category"); +- break; +- case wt_CombinedFragment: +- name = i18n("CombinedFragment"); +- break; +- case wt_Component: +- name = i18n("Component"); +- break; +- case wt_Class: +- name = i18n("Class"); +- break; +- case wt_Datatype: +- name = i18n("Datatype"); +- break; +- case wt_Entity: +- name = i18n("Entity"); +- break; +- case wt_Enum: +- name = i18n("Enum"); +- break; +- case wt_FloatingDashLine: +- name = i18n("FloatingDashLine"); +- break; +- case wt_ForkJoin: +- name = i18n("ForkJoin"); +- break; +- case wt_Interface: +- name = i18n("Interface"); +- break; +- case wt_Message: +- name = i18n("Message"); +- break; +- case wt_Node: +- name = i18n("Node"); +- break; +- case wt_Note: +- name = i18n("Note"); +- break; +- case wt_Object: +- name = i18n("Object"); +- break; +- case wt_ObjectNode: +- name = i18n("ObjectNode"); +- break; +- case wt_Package: +- name = i18n("Package"); +- break; +- case wt_Pin: +- name = i18n("Pin"); +- break; +- case wt_Port: +- name = i18n("Port"); +- break; +- case wt_Precondition: +- name = i18n("Precondition"); +- break; +- case wt_Region: +- name = i18n("Region"); +- break; +- case wt_Signal: +- name = i18n("Signal"); +- break; +- case wt_State: +- name = i18n("State"); +- break; +- case wt_Text: +- name = i18n("Text"); +- break; +- case wt_UseCase: +- name = i18n("UseCase"); +- break; +- default: +- name = QLatin1String(" &name:"); +- uWarning() << "unknown widget type"; +- break; +- } +- return name; +-} +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.h umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,192 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef WIDGETBASE_H +-#define WIDGETBASE_H +- +-#include "basictypes.h" +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-// forward declarations +-class QAction; +-class UMLDoc; +-class UMLObject; +-class UMLScene; +-class UMLWidget; // required by function onWidget() +- +-/** +- * @short Common base class for UMLWidget and AssociationWidget +- * @author Oliver Kellogg +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-class WidgetBase : public QGraphicsObject +-{ +- Q_OBJECT +- Q_ENUMS(WidgetType) +- +-public: +- enum WidgetType +- { +- wt_UMLWidget = 300, // does not have UMLObject representation +- wt_Actor, // has UMLObject representation +- wt_UseCase, // has UMLObject representation +- wt_Class, // has UMLObject representation +- wt_Interface, // has UMLObject representation +- wt_Datatype, // has UMLObject representation +- wt_Enum, // has UMLObject representation +- wt_Entity, // has UMLObject representation +- wt_Package, // has UMLObject representation +- wt_Object, // has UMLObject representation +- wt_Note, // does not have UMLObject representation +- wt_Box, // does not have UMLObject representation +- wt_Message, // does not have UMLObject representation +- wt_Text, // does not have UMLObject representation +- wt_State, // does not have UMLObject representation +- wt_Activity, // does not have UMLObject representation +- wt_Component, // has UMLObject representation +- wt_Artifact, // has UMLObject representation +- wt_Node, // has UMLObject representation +- wt_Association, // has UMLObject representation +- wt_ForkJoin, // does not have UMLObject representation +- wt_Precondition, // does not have UMLObject representation +- wt_CombinedFragment, // does not have UMLObject representation +- wt_FloatingDashLine, // does not have UMLObject representation +- wt_Signal, // does not have UMLObject representation +- wt_Pin, +- wt_ObjectNode, +- wt_Region, +- wt_Category, // has UMLObject representation +- wt_Port // has UMLObject representation +- }; +- +- static QString toString(WidgetType wt); +- static QString toI18nString(WidgetType wt); +- +- explicit WidgetBase(UMLScene * scene, WidgetType type= wt_UMLWidget); +- virtual ~WidgetBase(); +- +- UMLObject* umlObject() const; +- virtual void setUMLObject(UMLObject *obj); +- +- Uml::ID::Type id() const; +- void setID(Uml::ID::Type id); +- +- WidgetType baseType() const; +- QLatin1String baseTypeStr() const; +- +- virtual void setSelected(bool select); +- +- UMLScene* umlScene() const; +- UMLDoc* umlDoc() const; +- +- QString documentation() const; +- bool hasDocumentation(); +- virtual void setDocumentation(const QString& doc); +- +- QString name() const; +- virtual void setName(const QString &strName); +- +- QColor lineColor() const; +- virtual void setLineColor(const QColor& color); +- +- uint lineWidth() const; +- virtual void setLineWidth(uint width); +- +- QColor textColor() const; +- virtual void setTextColor(const QColor& color); +- +- QColor fillColor() const; +- virtual void setFillColor(const QColor& color); +- +- bool usesDiagramLineColor() const; +- void setUsesDiagramLineColor(bool state); +- +- bool usesDiagramLineWidth() const; +- void setUsesDiagramLineWidth(bool state); +- +- bool useFillColor(); +- virtual void setUseFillColor(bool state); +- +- bool usesDiagramTextColor() const; +- void setUsesDiagramTextColor(bool state); +- +- bool usesDiagramFillColor() const; +- void setUsesDiagramFillColor(bool state); +- +- bool usesDiagramUseFillColor() const; +- void setUsesDiagramUseFillColor(bool state); +- +- virtual QFont font() const; +- virtual void setFont(const QFont& font); +- +- virtual void showPropertiesDialog(); +- +- virtual bool loadFromXMI(QDomElement &qElement); +- virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); +- +- WidgetBase& operator=(const WidgetBase& other); +- +- QRectF rect() const; +- void setRect(const QRectF& rect); +- void setRect(qreal x, qreal y, qreal width, qreal height); +- +- virtual QRectF boundingRect() const; +- +- virtual UMLWidget* onWidget(const QPointF &p); +- +- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +- +-public Q_SLOTS: +- virtual void slotMenuSelection(QAction *trigger); +- +-protected: +- virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); +- +- WidgetType m_baseType; ///< Type of widget. +- UMLScene *m_scene; +- UMLObject *m_umlObject; +- QString m_Doc; ///< Only used if m_umlObject is not set. +- QString m_Text; +- QRectF m_rect; ///< widget size +- +- /** +- * This ID is only used when the widget does not have a +- * corresponding UMLObject (i.e. the m_umlObject pointer is NULL.) +- * For UMLObjects, the ID from the UMLObject is used. +- */ +- Uml::ID::Type m_nId; +- +- QColor m_textColor; ///< Color of the text of the widget. Is saved to XMI. +- QColor m_lineColor; ///< Color of the lines of the widget. Is saved to XMI. +- QColor m_fillColor; ///< color of the background of the widget +- QBrush m_brush; +- QFont m_font; +- uint m_lineWidth; ///< Width of the lines of the widget. Is saved to XMI. +- bool m_useFillColor; ///< flag indicates if the UMLWidget uses the Diagram FillColour +- +- /** +- * true by default, false if the colors have +- * been explicitly set for this widget. +- * These are saved to XMI. +- */ +- bool m_usesDiagramTextColor; +- bool m_usesDiagramLineColor; +- bool m_usesDiagramFillColor; +- bool m_usesDiagramUseFillColor; +- bool m_usesDiagramLineWidth; +-}; +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.cpp umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,296 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "widget_factory.h" +- +-// app includes +-#include "activitywidget.h" +-#include "actor.h" +-#include "actorwidget.h" +-#include "artifact.h" +-#include "artifactwidget.h" +-#include "associationwidget.h" +-#include "boxwidget.h" +-#include "category.h" +-#include "categorywidget.h" +-#include "classifier.h" +-#include "classifierwidget.h" +-#include "cmds.h" +-#include "combinedfragmentwidget.h" +-#include "component.h" +-#include "componentwidget.h" +-#include "datatypewidget.h" +-#include "debug_utils.h" +-#include "entity.h" +-#include "entitywidget.h" +-#include "enum.h" +-#include "enumwidget.h" +-#include "floatingdashlinewidget.h" +-#include "floatingtextwidget.h" +-#include "folder.h" +-#include "forkjoinwidget.h" +-#include "messagewidget.h" +-#include "node.h" +-#include "nodewidget.h" +-#include "notewidget.h" +-#include "object_factory.h" +-#include "objectnodewidget.h" +-#include "objectwidget.h" +-#include "package.h" +-#include "packagewidget.h" +-#include "pinwidget.h" +-#include "port.h" +-#include "portwidget.h" +-#include "preconditionwidget.h" +-#include "regionwidget.h" +-#include "signalwidget.h" +-#include "statewidget.h" +-#include "uml.h" +-#include "umldoc.h" +-#include "umlscene.h" +-#include "umlview.h" +-#include "usecase.h" +-#include "usecasewidget.h" +- +-namespace Widget_Factory { +- +-/** +- * Create a UMLWidget in the given view and representing the given document object. +- */ +-UMLWidget *createWidget(UMLScene *scene, UMLObject *o) +-{ +- QPointF pos = scene->pos(); +- int y = pos.y(); +- Uml::DiagramType::Enum diagramType = scene->type(); +- UMLObject::ObjectType type = o->baseType(); +- UMLWidget *newWidget = NULL; +- switch (type) { +- case UMLObject::ot_Actor: +- if (diagramType == Uml::DiagramType::Sequence) { +- ObjectWidget *ow = new ObjectWidget(scene, o); +- ow->setDrawAsActor(true); +- y = ow->topMargin(); +- newWidget = ow; +- } else +- newWidget = new ActorWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_UseCase: +- newWidget = new UseCaseWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Folder: +- case UMLObject::ot_Package: +- newWidget = new ClassifierWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Component: +- newWidget = new ComponentWidget(scene, static_cast(o)); +- if (diagramType == Uml::DiagramType::Deployment) { +- newWidget->setIsInstance(true); +- } +- break; +- case UMLObject::ot_Port: +- { +- PinPortBase *pw = new PortWidget(scene, static_cast(o)); +- pw->attachToOwner(); +- newWidget = pw; +- } +- break; +- case UMLObject::ot_Node: +- newWidget = new NodeWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Artifact: +- newWidget = new ArtifactWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Datatype: +- newWidget = new DatatypeWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Enum: +- newWidget = new EnumWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Entity: +- newWidget = new EntityWidget(scene, static_cast(o)); +- break; +- case UMLObject::ot_Interface: +- if (diagramType == Uml::DiagramType::Sequence || diagramType == Uml::DiagramType::Collaboration) { +- ObjectWidget *ow = new ObjectWidget(scene, o); +- if (diagramType == Uml::DiagramType::Sequence) { +- y = ow->topMargin(); +- } +- newWidget = ow; +- } else { +- UMLClassifier *c = static_cast(o); +- ClassifierWidget* interfaceWidget = new ClassifierWidget(scene, c); +- if (diagramType == Uml::DiagramType::Component || diagramType == Uml::DiagramType::Deployment) { +- interfaceWidget->setDrawAsCircle(true); +- } +- newWidget = interfaceWidget; +- } +- break; +- case UMLObject::ot_Class: +- //see if we really want an object widget or class widget +- if (diagramType == Uml::DiagramType::Class || diagramType == Uml::DiagramType::Component) { +- UMLClassifier *c = static_cast(o); +- ClassifierWidget *cw = new ClassifierWidget(scene, c); +- if (diagramType == Uml::DiagramType::Component) +- cw->setDrawAsCircle(true); +- newWidget = cw; +- } else { +- ObjectWidget *ow = new ObjectWidget(scene, o); +- if (diagramType == Uml::DiagramType::Sequence) { +- y = ow->topMargin(); +- } +- newWidget = ow; +- } +- break; +- case UMLObject::ot_Category: +- newWidget = new CategoryWidget(scene, static_cast(o)); +- break; +- default: +- uWarning() << "trying to create an invalid widget (" << UMLObject::toString(type) << ")"; +- } +- +- if (newWidget) { +- newWidget->setX(pos.x()); +- newWidget->setY(y); +- } +- +- return newWidget; +-} +- +-bool validateObjType(UMLObject::ObjectType expected, UMLObject* &o, Uml::ID::Type id) +-{ +- if (o == NULL) { +- uDebug() << "Widget_Factory::validateObjType: creating new object of type " +- << expected; +- QString artificialName = QLatin1String("LOST_") + Uml::ID::toString(id); +- o = Object_Factory::createUMLObject(expected, artificialName, NULL, false); +- if (o == NULL) +- return false; +- o->setID(id); +- UMLPackage *parentPkg = o->umlPackage(); +- parentPkg->addObject(o); +- return true; +- } +- UMLObject::ObjectType actual = o->baseType(); +- if (actual == expected) +- return true; +- uError() << "validateObjType(" << o->name() +- << "): expected type " << UMLObject::toString(expected) << ", actual type " +- << UMLObject::toString(actual); +- return false; +-} +- +-/** +- * Create a UMLWidget according to the given XMI tag. +- */ +-UMLWidget* makeWidgetFromXMI(const QString& tag, +- const QString& idStr, UMLScene *scene) +-{ +- UMLWidget *widget = NULL; +- +- // Loading of widgets which do NOT represent any UMLObject, +- // just graphic stuff with no real model information +- //FIXME while boxes and texts are just diagram objects, activities and +- // states should be UMLObjects +- if (tag == QLatin1String("statewidget") || tag == QLatin1String("UML:StateWidget")) { +- widget = new StateWidget(scene, StateWidget::Normal, Uml::ID::Reserved); +- } else if (tag == QLatin1String("notewidget") || tag == QLatin1String("UML:NoteWidget")) { +- widget = new NoteWidget(scene, NoteWidget::Normal, Uml::ID::Reserved); +- } else if (tag == QLatin1String("boxwidget")) { +- widget = new BoxWidget(scene, Uml::ID::Reserved); +- } else if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML:FloatingTextWidget")) { +- widget = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString(), Uml::ID::Reserved); +- } else if (tag == QLatin1String("activitywidget") || tag == QLatin1String("UML:ActivityWidget")) { +- widget = new ActivityWidget(scene, ActivityWidget::Initial, Uml::ID::Reserved); +- } else if (tag == QLatin1String("messagewidget")) { +- widget = new MessageWidget(scene, Uml::SequenceMessage::Asynchronous, Uml::ID::Reserved); +- } else if (tag == QLatin1String("forkjoin")) { +- widget = new ForkJoinWidget(scene, Qt::Vertical, Uml::ID::Reserved); +- } else if (tag == QLatin1String("preconditionwidget")) { +- widget = new PreconditionWidget(scene, NULL, Uml::ID::Reserved); +- } else if (tag == QLatin1String("combinedFragmentwidget")) { +- widget = new CombinedFragmentWidget(scene, CombinedFragmentWidget::Ref, Uml::ID::Reserved); +- } else if (tag == QLatin1String("signalwidget")) { +- widget = new SignalWidget(scene, SignalWidget::Send, Uml::ID::Reserved); +- } else if (tag == QLatin1String("floatingdashlinewidget")) { +- widget = new FloatingDashLineWidget(scene, Uml::ID::Reserved); +- } else if (tag == QLatin1String("objectnodewidget")) { +- widget = new ObjectNodeWidget(scene, ObjectNodeWidget::Normal, Uml::ID::Reserved); +- } else if (tag == QLatin1String("regionwidget")) { +- widget = new RegionWidget(scene, Uml::ID::Reserved); +- } else if (tag == QLatin1String("pinwidget")) { +- PinPortBase *pw = new PinWidget(scene, NULL, Uml::ID::Reserved); +- pw->attachToOwner(); +- widget = pw; +- } +- else +- { +- // Loading of widgets which represent an UMLObject +- +- // Find the UMLObject and create the Widget to represent it +- Uml::ID::Type id = Uml::ID::fromString(idStr); +- UMLDoc *umldoc = UMLApp::app()->document(); +- UMLObject *o = umldoc->findObjectById(id); +- if (o == NULL) { +- uDebug() << "makeWidgetFromXMI: cannot find object with id " +- << Uml::ID::toString(id); +- } +- +- if (tag == QLatin1String("actorwidget") || tag == QLatin1String("UML:ActorWidget")) { +- if (validateObjType(UMLObject::ot_Actor, o, id)) +- widget = new ActorWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("usecasewidget") || tag == QLatin1String("UML:UseCaseWidget")) { +- if (validateObjType(UMLObject::ot_UseCase, o, id)) +- widget = new UseCaseWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("classwidget") || +- tag == QLatin1String("UML:ClassWidget") || tag == QLatin1String("UML:ConceptWidget")) { +- if (validateObjType(UMLObject::ot_Class, o, id)) +- widget = new ClassifierWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("packagewidget")) { +- if (validateObjType(UMLObject::ot_Package, o, id)) +- widget = new ClassifierWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("componentwidget")) { +- if (validateObjType(UMLObject::ot_Component, o, id)) +- widget = new ComponentWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("portwidget")) { +- if (validateObjType(UMLObject::ot_Port, o, id)) +- widget = new PortWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("nodewidget")) { +- if (validateObjType(UMLObject::ot_Node, o, id)) +- widget = new NodeWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("artifactwidget")) { +- if (validateObjType(UMLObject::ot_Artifact, o, id)) +- widget = new ArtifactWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("interfacewidget")) { +- if (validateObjType(UMLObject::ot_Interface, o, id)) +- widget = new ClassifierWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("datatypewidget")) { +- if (validateObjType(UMLObject::ot_Datatype, o, id)) +- widget = new DatatypeWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("enumwidget")) { +- if (validateObjType(UMLObject::ot_Enum, o, id)) +- widget = new EnumWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("entitywidget")) { +- if (validateObjType(UMLObject::ot_Entity, o, id)) +- widget = new EntityWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("categorywidget")) { +- if (validateObjType(UMLObject::ot_Category, o, id)) +- widget = new CategoryWidget(scene, static_cast(o)); +- } else if (tag == QLatin1String("objectwidget") || tag == QLatin1String("UML:ObjectWidget")) { +- widget = new ObjectWidget(scene, o); +- } else { +- uWarning() << "Trying to create an unknown widget:" << tag; +- } +- } +- return widget; +-} +- +-} // end namespace Widget_Factory +- +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.h umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,34 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef WIDGET_FACTORY_H +-#define WIDGET_FACTORY_H +- +-#include +- +-// forward declarations +-class UMLObject; +-class UMLScene; +-class UMLWidget; +- +-/** +- * Widget factory methods. +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-namespace Widget_Factory { +- +- UMLWidget *createWidget(UMLScene *scene, UMLObject *docObj); +- +- UMLWidget* makeWidgetFromXMI(const QString& tag, +- const QString& idStr, UMLScene *scene); +- +-} // end namespace Widget_Factory +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.cpp umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,157 +0,0 @@ +-/*************************************************************************** +- * 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) 2009-2014 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "widgetlist_utils.h" +- +-// app includes +-#include "debug_utils.h" +-#include "umlwidget.h" +- +-// qt/kde includes +-#include +- +-namespace WidgetList_Utils +-{ +- +-/** +- * Looks for the smallest x-value of the given UMLWidgets. +- * @param widgetList A list with UMLWidgets. +- * @return The smallest X position. +- */ +-qreal getSmallestX(const UMLWidgetList &widgetList) +-{ +- qreal smallestX = 0; +- +- int i = 1; +- foreach(UMLWidget *widget, widgetList) { +- if (i == 1) { +- smallestX = widget->x(); +- } else { +- if (smallestX > widget->x()) +- smallestX = widget->x(); +- } +- i++; +- } +- +- return smallestX; +-} +- +-/** +- * Looks for the smallest y-value of the given UMLWidgets. +- * @param widgetList A list with UMLWidgets. +- * @return The smallest Y position. +- */ +-qreal getSmallestY(const UMLWidgetList &widgetList) +-{ +- if (widgetList.isEmpty()) +- return -1; +- +- qreal smallestY = 0; +- +- int i = 1; +- foreach(UMLWidget *widget, widgetList) { +- if (i == 1) { +- smallestY = widget->y(); +- } else { +- if (smallestY > widget->y()) +- smallestY = widget->y(); +- } +- i++; +- } +- +- return smallestY; +-} +- +-/** +- * Looks for the biggest x-value of the given UMLWidgets. +- * @param widgetList A list with UMLWidgets. +- * @return The biggest X position. +- */ +-qreal getBiggestX(const UMLWidgetList &widgetList) +-{ +- if (widgetList.isEmpty()) +- return -1; +- +- qreal biggestX = 0; +- +- int i = 1; +- foreach(UMLWidget *widget, widgetList) { +- if (i == 1) { +- biggestX = widget->x(); +- biggestX += widget->width(); +- } else { +- if (biggestX < widget->x() + widget->width()) +- biggestX = widget->x() + widget->width(); +- } +- i++; +- } +- +- return biggestX; +-} +- +-/** +- * Looks for the biggest y-value of the given UMLWidgets. +- * @param widgetList A list with UMLWidgets. +- * @return The biggest Y position. +- */ +-qreal getBiggestY(const UMLWidgetList &widgetList) +-{ +- if (widgetList.isEmpty()) +- return -1; +- +- qreal biggestY = 0; +- +- int i = 1; +- foreach(UMLWidget *widget, widgetList) { +- if (i == 1) { +- biggestY = widget->y(); +- biggestY += widget->height(); +- } else { +- if (biggestY < widget->y() + widget->height()) +- biggestY = widget->y() + widget->height(); +- } +- i++; +- } +- +- return biggestY; +-} +- +-/** +- * Returns the sum of the heights of the given UMLWidgets +- * @param widgetList A list with UMLWidgets. +- */ +-qreal getHeightsSum(const UMLWidgetList &widgetList) +-{ +- qreal heightsSum = 0; +- +- foreach(UMLWidget *widget, widgetList) { +- heightsSum += widget->height(); +- } +- +- return heightsSum; +-} +- +-/** +- * Returns the sum of the widths of the given UMLWidgets. +- * @param widgetList A list with UMLWidgets. +- */ +-qreal getWidthsSum(const UMLWidgetList &widgetList) +-{ +- qreal widthsSum = 0; +- +- foreach(UMLWidget *widget, widgetList) { +- widthsSum += widget->width(); +- } +- +- return widthsSum; +-} +- +-} // namespace WidgetList_Utils +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.h umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,30 +0,0 @@ +-/*************************************************************************** +- * 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) 2009-2014 * +- * umbrello-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef WIDGETLIST_UTILS_H +-#define WIDGETLIST_UTILS_H +- +-#include "umlwidgetlist.h" +- +-/** +- * General purpose-kf6 widget list utilities. +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-namespace WidgetList_Utils +-{ +- qreal getSmallestX(const UMLWidgetList &widgetList); +- qreal getSmallestY(const UMLWidgetList &widgetList); +- qreal getBiggestX(const UMLWidgetList &widgetList); +- qreal getBiggestY(const UMLWidgetList &widgetList); +- qreal getHeightsSum(const UMLWidgetList &widgetList); +- qreal getWidthsSum(const UMLWidgetList &widgetList); +-} // namespace WidgetList_Utils +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.cpp umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.cpp +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.cpp 1970-01-01 02:00:00.000000000 +0200 +@@ -1,827 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-// own header +-#include "widget_utils.h" +- +-// app includes +-#include "debug_utils.h" +-#include "objectwidget.h" +-#include "messagewidget.h" +-#include "umlwidget.h" +- +-// qt includes +-#include +-#include +-#include +-#include +-#include +- +-// c++ include +-#include +- +-namespace Widget_Utils +-{ +- +- /** +- * Find the widget identified by the given ID in the given widget +- * or message list. +- * +- * @param id The unique ID to find. +- * @param widgets The UMLWidgetList to search in. +- * @param messages Optional pointer to a MessageWidgetList to search in. +- */ +- UMLWidget* findWidget(Uml::ID::Type id, +- const UMLWidgetList& widgets, +- const MessageWidgetList* messages /* = 0 */) +- { +- foreach (UMLWidget* obj, widgets) { +- if (obj->baseType() == WidgetBase::wt_Object) { +- if (static_cast(obj)->localID() == id) +- return obj; +- } else if (obj->id() == id) { +- return obj; +- } +- } +- +- if (messages) { +- foreach (UMLWidget* obj, *messages) { +- if (obj->id() == id) +- return obj; +- } +- } +- return NULL; +- } +- +- /** +- * Creates the decoration point. +- * @param p base point to decorate +- * @param parent parent item +- * @return decoration point +- */ +- QGraphicsRectItem* decoratePoint(const QPointF &p, QGraphicsItem* parent) +- { +- const qreal SIZE = 4.0; +- const qreal SIZE_HALF = SIZE / 2.0; +- QGraphicsRectItem *rect = new QGraphicsRectItem(p.x() - SIZE_HALF, +- p.y() - SIZE_HALF, +- SIZE, SIZE, +- parent); +- rect->setBrush(QBrush(Qt::blue)); +- rect->setPen(QPen(Qt::blue)); +- return rect; +- } +- +- /** +- * Calculates and draws a cross inside an ellipse +- * @param p Pointer to a QPainter object. +- * @param r The rectangle describing the ellipse. +- */ +- void drawCrossInEllipse(QPainter *p, const QRectF& r) +- { +- QRectF ellipse = r; +- ellipse.moveCenter(QPointF(0, 0)); +- qreal a = ellipse.width() * 0.5; +- qreal b = ellipse.height() * .5; +- qreal xc = ellipse.center().x(); +- qreal yc = ellipse.center().y(); +- +- // The first point's x value is chosen to be center.x() + 70% of x radius. +- qreal x1 = ellipse.center().x() + .7 * .5 * ellipse.width(); +- // Calculate y1 corresponding to x1 using formula. +- qreal y1_sqr = b*b*(1 - (x1 * x1) / (a*a)); +- qreal y1 = std::sqrt(y1_sqr); +- +- // Mirror x1, y1 along both the axes to get 4 points for the cross. +- QPointF p1(xc + x1, yc + y1); +- QPointF p2(xc - x1, yc + y1); +- QPointF p3(xc + x1, yc - y1); +- QPointF p4(xc - x1, yc - y1); +- +- // Translate as we calculate for ellipse with (0, 0) as center. +- p->translate(r.center().x(), r.center().y()); +- +- // Draw the cross now +- p->drawLine(QLineF(p1, p4)); +- p->drawLine(QLineF(p2, p3)); +- +- // Restore the translate on painter. +- p->translate(-r.center().x(), -r.center().y()); +- } +- +- /** +- * Draws a polygon which is almost rectangular except for the top +- * right corner. A triangle is drawn in top right corner of the +- * rectangle. +- * +- * @param painter The painter with which this shape is to be drawn. +- * @param rect The rectangle dimensions. +- * @param triSize The size of the triangle in the top-right corner. +- */ +- void drawTriangledRect(QPainter *painter, +- const QRectF &rect, const QSizeF &triSize) +- { +- // Draw outer boundary defined by polygon "poly". +- QPolygonF poly(5); +- poly[0] = rect.topLeft(); +- poly[1] = rect.topRight() - QPointF(triSize.width(), 0); +- poly[2] = rect.topRight() + QPointF(0, triSize.height()); +- poly[3] = rect.bottomRight(); +- poly[4] = rect.bottomLeft(); +- painter->drawPolygon(poly); +- +- // Now draw the triangle base and height edges. +- QLineF heightEdge(poly[1], poly[1] + QPointF(0, triSize.height())); +- painter->drawLine(heightEdge); +- QLineF baseEdge(heightEdge.p2(), poly[2]); +- painter->drawLine(baseEdge); +- } +- +-// /** +-// * Draws an arrow head with the given painter, with the arrow +-// * sharp point at \a headPos. +-// * +-// * param painter The painter with which this arrow should be drawn. +-// * param headPos The position where the head of the arrow should lie. +-// * param arrowSize This indicates the size of the arrow head. +-// * param arrowType This indicates direction of arrow as in LeftArrow, RightArrow.. +-// * param solid-kf6 If true, a solid-kf6 head is drawn. Otherwise 2 lines are drawn. +-// */ +-// void drawArrowHead(QPainter *painter, const QPointF &arrowPos, +-// const QSizeF& arrowSize, Qt::ArrowType arrowType, +-// bool solid-kf6) +-// { +-// QPolygonF poly; +-// if (arrowType == Qt::LeftArrow) { +-// poly << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) +-// << arrowPos +-// << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); +-// } +-// else if (arrowType == Qt::RightArrow) { +-// poly << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) +-// << arrowPos +-// << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); +-// } +- +-// if (solid-kf6) { +-// painter->drawPolygon(poly); +-// } +-// else { +-// painter->drawPolyline(poly); +-// } +-// } +- +-// /** +-// * Draws a rounded rect rounded at specified corners. +-// * +-// * param painter The painter with which this round rect should be drawn. +-// * param rect The rectangle to be drawn. +-// * param xRadius The x radius of rounded corner. +-// * param yRadius The y radius of rounded corner. +-// * param corners The corners to be rounded. +-// */ +-// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, +-// qreal yRadius, Uml::Corners corners) +-// { +-// if (xRadius < 0 || yRadius < 0) { +-// painter->drawRect(rect); +-// return; +-// } +-// QRectF arcRect(0, 0, 2 * xRadius, 2 * yRadius); +- +-// QPainterPath path; +-// path.moveTo(rect.left(), rect.top() + yRadius); +-// if (corners.testFlag(Uml::Corner::TopLeft)) { +-// arcRect.moveTopLeft(rect.topLeft()); +-// path.arcTo(arcRect, 180, -90); +-// } else { +-// path.lineTo(rect.topLeft()); +-// } +- +-// path.lineTo(rect.right() - xRadius, rect.top()); +- +-// if (corners.testFlag(Uml::Corner::TopRight)) { +-// arcRect.moveTopRight(rect.topRight()); +-// path.arcTo(arcRect, 90, -90); +-// } else { +-// path.lineTo(rect.topRight()); +-// } +- +-// path.lineTo(rect.right(), rect.bottom() - yRadius); +- +-// if (corners.testFlag(Uml::Corner::BottomRight)) { +-// arcRect.moveBottomRight(rect.bottomRight()); +-// path.arcTo(arcRect, 0, -90); +-// } else { +-// path.lineTo(rect.bottomRight()); +-// } +- +-// path.lineTo(rect.left() + xRadius, rect.bottom()); +- +-// if (corners.testFlag(Uml::Corner::BottomLeft)) { +-// arcRect.moveBottomLeft(rect.bottomLeft()); +-// path.arcTo(arcRect, 270, 90); +-// } else { +-// path.lineTo(rect.bottomLeft()); +-// } +- +-// path.closeSubpath(); +-// painter->drawPath(path); +-// } +- +- /** +- * Converts a point to a comma separated string i.e "x,y" +- * @param point The QPointF to convert. +- */ +- QString pointToString(const QPointF& point) +- { +- return QString::fromLatin1("%1,%2").arg(point.x()).arg(point.y()); +- } +- +- /** +- * Converts a comma separated string to point. +- */ +- QPointF stringToPoint(const QString& str) +- { +- QPointF retVal; +- QStringList list = str.split(QLatin1Char(',')); +- +- if(list.size() == 2) { +- retVal.setX(list.first().toDouble()); +- retVal.setY(list.last().toDouble()); +- } +- return retVal; +- } +- +- /** +- * Loads pixmap from xmi. +- * +- * @param pixEle The dom element from which pixmap should be loaded. +- * +- * @param pixmap The pixmap into which the image should be loaded. +- * +- * @return True or false based on success or failure of this method. +- */ +- bool loadPixmapFromXMI(QDomElement &pixEle, QPixmap &pixmap) +- { +- if (pixEle.isNull()) { +- return false; +- } +- QDomElement xpmElement = pixEle.firstChildElement(QLatin1String("xpm")); +- +- QByteArray xpmData = xpmElement.text().toLatin1(); +- QBuffer buffer(&xpmData); +- buffer.open(QIODevice::ReadOnly); +- +- QImageReader reader(&buffer, "xpm"); +- QImage image; +- if (!reader.read(&image)) { +- return false; +- } +- +- pixmap = QPixmap::fromImage(image); +- return true; +- } +- +- /** +- * Saves pixmap information into DOM element \a qElement. +- * +- * @param qDoc The DOM document object. +- * +- * @param qElement The DOM element into which the pixmap should be +- * saved. +- * +- * @param pixmap The pixmap to be saved. +- */ +- void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap) +- { +- QDomElement pixmapElement = qDoc.createElement(QLatin1String("pixmap")); +- +- QDomElement xpmElement = qDoc.createElement(QLatin1String("xpm")); +- pixmapElement.appendChild(xpmElement); +- +- QBuffer buffer; +- buffer.open(QIODevice::WriteOnly); +- pixmap.save(&buffer, "xpm"); +- buffer.close(); +- +- xpmElement.appendChild(qDoc.createTextNode(QString::fromLatin1(buffer.data()))); +- +- qElement.appendChild(pixmapElement); +- } +- +- /** +- * Loads gradient from xmi. The gradient pointer should be null +- * and the new gradient object will be created inside this method. +- * The gradient should later be deleted externally. +- * +- * @param gradientElement The DOM element from which gradient should be +- * loaded. +- * +- * @param gradient The pointer to gradient into which the gradient +- * should be loaded. (Allocated inside this +- * method) +- * +- * @return True or false based on success or failure of this method. +- */ +- bool loadGradientFromXMI(QDomElement &gradientElement, QGradient *&gradient) +- { +- if(gradientElement.isNull()) { +- return false; +- } +- +- int type_as_int; +- QGradient::Type type; +- QGradientStops stops; +- QGradient::CoordinateMode cmode = QGradient::LogicalMode; +- QGradient::Spread spread = QGradient::PadSpread; +- +- type_as_int = gradientElement.attribute(QLatin1String("type")).toInt(); +- type = QGradient::Type(type_as_int); +- type_as_int = gradientElement.attribute(QLatin1String("spread")).toInt(); +- spread = QGradient::Spread(type_as_int); +- type_as_int = gradientElement.attribute(QLatin1String("coordinatemode")).toInt(); +- cmode = QGradient::CoordinateMode(type_as_int); +- +- QDomElement stopElement = gradientElement.firstChildElement(QLatin1String("stops")); +- if(stopElement.isNull()) { +- return false; +- } +- for(QDomNode node = stopElement.firstChild(); !node.isNull(); node = node.nextSibling()) { +- QDomElement ele = node.toElement(); +- if(ele.tagName() != QLatin1String("stop")) { +- continue; +- } +- +- qreal posn = ele.attribute(QLatin1String("position")).toDouble(); +- QColor color = QColor(ele.attribute(QLatin1String("color"))); +- stops << QGradientStop(posn, color); +- } +- +- if (type == QGradient::LinearGradient) { +- QPointF p1 = stringToPoint(gradientElement.attribute(QLatin1String("start"))); +- QPointF p2 = stringToPoint(gradientElement.attribute(QLatin1String("finalstop"))); +- gradient = new QLinearGradient(p1, p2); +- } +- else if (type == QGradient::RadialGradient) { +- QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); +- QPointF focal = stringToPoint(gradientElement.attribute(QLatin1String("focalpoint"))); +- double radius = gradientElement.attribute(QLatin1String("radius")).toDouble(); +- gradient = new QRadialGradient(center, radius, focal); +- } +- else { // type == QGradient::ConicalGradient +- QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); +- double angle = gradientElement.attribute(QLatin1String("angle")).toDouble(); +- gradient = new QConicalGradient(center, angle); +- } +- +- if(gradient) { +- gradient->setStops(stops); +- gradient->setSpread(spread); +- gradient->setCoordinateMode(cmode); +- return true; +- } +- +- return false; +- } +- +- /** +- * Saves gradient information into DOM element \a qElement. +- * +- * @param qDoc The DOM document object. +- * +- * @param qElement The DOM element into which the gradient should be +- * saved. +- * +- * @param gradient The gradient to be saved. +- */ +- void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient) +- { +- QDomElement gradientElement = qDoc.createElement(QLatin1String("gradient")); +- +- gradientElement.setAttribute(QLatin1String("type"), int(gradient->type())); +- gradientElement.setAttribute(QLatin1String("spread"), int(gradient->spread())); +- gradientElement.setAttribute(QLatin1String("coordinatemode"), int(gradient->coordinateMode())); +- +- QDomElement stopsElement = qDoc.createElement(QLatin1String("stops")); +- gradientElement.appendChild(stopsElement); +- +- foreach(const QGradientStop& stop, gradient->stops()) { +- QDomElement ele = qDoc.createElement(QLatin1String("stop")); +- ele.setAttribute(QLatin1String("position"), stop.first); +- ele.setAttribute(QLatin1String("color"), stop.second.name()); +- stopsElement.appendChild(ele); +- } +- +- QGradient::Type type = gradient->type(); +- +- if(type == QGradient::LinearGradient) { +- const QLinearGradient *lg = static_cast(gradient); +- gradientElement.setAttribute(QLatin1String("start"), pointToString(lg->start())); +- gradientElement.setAttribute(QLatin1String("finalstop"), pointToString(lg->finalStop())); +- } +- else if(type == QGradient::RadialGradient) { +- const QRadialGradient *rg = static_cast(gradient); +- gradientElement.setAttribute(QLatin1String("center"), pointToString(rg->center())); +- gradientElement.setAttribute(QLatin1String("focalpoint"), pointToString(rg->focalPoint())); +- gradientElement.setAttribute(QLatin1String("radius"), rg->radius()); +- } +- else { //type == QGradient::ConicalGradient +- const QConicalGradient *cg = static_cast(gradient); +- gradientElement.setAttribute(QLatin1String("center"), pointToString(cg->center())); +- gradientElement.setAttribute(QLatin1String("angle"), cg->angle()); +- } +- +- qElement.appendChild(gradientElement); +- } +- +- /** +- * Extracts the QBrush properties into brush from the XMI xml +- * element qElement. +- * +- * @param qElement The DOM element from which the xmi info should +- * be extracted. +- * +- * @param brush The QBrush object into which brush details should +- * be read into. +- */ +- bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush) +- { +- if(qElement.isNull()) { +- return false; +- } +- +- quint8 style = qElement.attribute(QLatin1String("style")).toShort(); +- const QString colorString = qElement.attribute(QLatin1String("color")); +- QColor color; +- color.setNamedColor(colorString); +- +- if(style == Qt::TexturePattern) { +- QPixmap pixmap; +- QDomElement pixElement = qElement.firstChildElement(QLatin1String("pixmap")); +- if(!loadPixmapFromXMI(pixElement, pixmap)) { +- return false; +- } +- brush = QBrush(color, pixmap); +- } +- +- else if(style == Qt::LinearGradientPattern +- || style == Qt::RadialGradientPattern +- || style == Qt::ConicalGradientPattern) { +- QGradient *gradient = 0; +- QDomElement gradElement = qElement.firstChildElement(QLatin1String("gradient")); +- +- if(!loadGradientFromXMI(gradElement, gradient) || !gradient) { +- delete gradient; +- return false; +- } +- +- brush = QBrush(*gradient); +- delete gradient; +- } +- +- else { +- brush = QBrush(color, (Qt::BrushStyle)style); +- } +- +- //TODO: Checks if transform needs to be loaded. +- +- return true; +- } +- +- /** +- * Saves the brush info as xmi into the DOM element \a qElement. +- * +- * @param qDoc The QDomDocument object pointing to the xmi document. +- * +- * @param qElement The element into which the pen, brush and font +- * info should be saved. +- * +- * @param brush The QBrush whose details should be saved. +- */ +- void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, +- const QBrush& brush) +- { +- QDomElement brushElement = qDoc.createElement(QLatin1String("brush")); +- +- brushElement.setAttribute(QLatin1String("style"), (quint8)brush.style()); +- brushElement.setAttribute(QLatin1String("color"), brush.color().name()); +- +- if(brush.style() == Qt::TexturePattern) { +- savePixmapToXMI(qDoc, brushElement, brush.texture()); +- } +- else if(brush.style() == Qt::LinearGradientPattern +- || brush.style() == Qt::RadialGradientPattern +- || brush.style() == Qt::ConicalGradientPattern) { +- saveGradientToXMI(qDoc, brushElement, brush.gradient()); +- } +- +- //TODO: Check if transform of this brush needs to be saved. +- qElement.appendChild(brushElement); +- } +- +- /** +- * Returns true if the first widget's X is smaller than second's. +- * Used for sorting the UMLWidgetList. +- * @param widget1 The widget to compare. +- * @param widget2 The widget to compare with. +- */ +- bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2) +- { +- return widget1->x() < widget2->x(); +- } +- +- /** +- * Returns true if the first widget's Y is smaller than second's. +- * Used for sorting the UMLWidgetList. +- * @param widget1 The widget to compare. +- * @param widget2 The widget to compare with. +- */ +- bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2) +- { +- return widget1->y() < widget2->y(); +- } +- +- /** +- * Find the region in which the rectangle \a other lies with respect to +- * the rectangle \a self. +- * Beware that the Qt coordinate system has its origin point (0,0) in +- * the upper left corner with Y values growing downwards, thus the Y +- * related comparisons might look inverted if your are used to the +- * natural coordinate system with (0,0) in the lower left corner. +- */ +- Uml::Region::Enum findRegion(const QRectF& self, const QRectF &other) +- { +- const qreal ownX = self.x(); +- const qreal ownY = self.y(); +- const qreal ownWidth = self.width(); +- const qreal ownHeight = self.height(); +- const qreal otherX = other.x(); +- const qreal otherY = other.y(); +- const qreal otherWidth = other.width(); +- const qreal otherHeight = other.height(); +- Uml::Region::Enum region = Uml::Region::Center; +- if (otherX + otherWidth < ownX) { +- if (otherY + otherHeight < ownY) +- region = Uml::Region::NorthWest; +- else if (otherY > ownY + ownHeight) +- region = Uml::Region::SouthWest; +- else +- region = Uml::Region::West; +- } else if (otherX > ownX + ownWidth) { +- if (otherY + otherHeight < ownY) +- region = Uml::Region::NorthEast; +- else if (otherY > ownY + ownHeight) +- region = Uml::Region::SouthEast; +- else +- region = Uml::Region::East; +- } else { +- if (otherY + otherHeight < ownY) +- region = Uml::Region::North; +- else if (otherY > ownY + ownHeight) +- region = Uml::Region::South; +- else +- region = Uml::Region::Center; +- } +- return region; +- } +- +- /** +- * Return the point in \a poly which precedes the point at index \a index. +- * If \a index is 0 then return the last (or, if \a poly.isClosed() is +- * true, the second to last) point. +- */ +- QPointF prevPoint(int index, const QPolygonF& poly) { +- if (poly.size() < 3 || index >= poly.size()) +- return QPoint(); +- if (index == 0) +- return poly.at(poly.size() - 1 - (int)poly.isClosed()); +- return poly.at(index - 1); +- } +- +- /** +- * Return the point in \a poly which follows the point at index \a index. +- * If \a index is the last index then return the first (or, if +- * \a poly.isClosed() is true, the second) point. +- */ +- QPointF nextPoint(int index, const QPolygonF& poly) { +- if (poly.size() < 3 || index >= poly.size()) +- return QPoint(); +- if (index == poly.size() - 1) +- return poly.at((int)poly.isClosed()); +- return poly.at(index + 1); +- } +- +- /** +- * Return the middle value between \a a and \a b. +- */ +- qreal middle(qreal a, qreal b) +- { +- return (a + b) / 2.0; +- } +- +- /** +- * Auxiliary type for function findLine() +- */ +- enum Axis_Type { X , Y }; +- +- /** +- * Auxiliary type for function findLine() +- */ +- enum Comparison_Type { Smallest, Largest }; +- +- /** +- * Find the line of \a poly with the smallest or largest value (controlled by \a seek) +- * along the axis controlled by \a axis. +- * In case \a axis is X, do not consider lines whose Y values lie outside the Y values +- * defined by \a boundingRect. +- * In case \a axis is Y, do not consider lines whose X values lie outside the X values +- * defined by \a boundingRect. +- */ +- QLineF findLine(const QPolygonF& poly, Axis_Type axis, Comparison_Type seek, const QRectF& boundingRect) +- { +- const int lastIndex = poly.size() - 1 - (int)poly.isClosed(); +- QPointF prev = poly.at(lastIndex), curr; +- QPointF p1(seek == Smallest ? QPointF(1.0e6, 1.0e6) : QPointF(-1.0e6, -1.0e6)); +- QPointF p2; +- for (int i = 0; i <= lastIndex; i++) { +- curr = poly.at(i); +- // uDebug() << " poly[" << i << "] = " << curr; +- if (axis == X) { +- if (fmin(prev.y(), curr.y()) > boundingRect.y() + boundingRect.height() || +- fmax(prev.y(), curr.y()) < boundingRect.y()) { +- // line is outside Y-axis range defined by boundingRect +- } else if ((seek == Smallest && curr.x() <= p1.x()) || +- (seek == Largest && curr.x() >= p1.x())) { +- p1 = curr; +- p2 = prev; +- } +- } else { +- if (fmin(prev.x(), curr.x()) > boundingRect.x() + boundingRect.width() || +- fmax(prev.x(), curr.x()) < boundingRect.x()) { +- // line is outside X-axis range defined by boundingRect +- } else if ((seek == Smallest && curr.y() <= p1.y()) || +- (seek == Largest && curr.y() >= p1.y())) { +- p1 = curr; +- p2 = prev; +- } +- } +- prev = curr; +- } +- return QLineF(p1, p2); +- } +- +- /** +- * Determine the approximate closest points of two polygons. +- * @param self First QPolygonF. +- * @param other Second QPolygonF. +- * @return QLineF::p1() returns point of \a self; +- * QLineF::p2() returns point of \a other. +- */ +- QLineF closestPoints(const QPolygonF& self, const QPolygonF& other) +- { +- const QRectF& selfRect = self.boundingRect(); +- const QRectF& otherRect = other.boundingRect(); +- Uml::Region::Enum region = findRegion(selfRect, otherRect); +- if (region == Uml::Region::Center) +- return QLineF(); +- if (self.size() < 3 || other.size() < 3) +- return QLineF(); +- QLineF result; +- const int selfLastIndex = self.size() - 1 - (int)self.isClosed(); +- const int otherLastIndex = other.size() - 1 - (int)other.isClosed(); +- QPointF selfPoint(self.at(selfLastIndex)); +- QPointF otherPoint(other.at(otherLastIndex)); +- QLineF selfLine, otherLine; +- int i; +- +- switch (region) { +- +- case Uml::Region::North: +- // Find other's line with largest Y values +- otherLine = findLine(other, Y, Largest, selfRect); +- // Find own line with smallest Y values +- selfLine = findLine(self, Y, Smallest, otherRect); +- // Use the middle value of the X values +- result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), +- middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); +- break; +- +- case Uml::Region::South: +- // Find other's line with smallest Y values +- otherLine = findLine(other, Y, Smallest, selfRect); +- // Find own line with largest Y values +- selfLine = findLine(self, Y, Largest, otherRect); +- // Use the middle value of the X values +- result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), +- middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); +- break; +- +- case Uml::Region::West: +- // Find other's line with largest X values +- otherLine = findLine(other, X, Largest, selfRect); +- // Find own line with smallest X values +- selfLine = findLine(self, X, Smallest, otherRect); +- // Use the middle value of the Y values +- result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), +- otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); +- break; +- +- case Uml::Region::East: +- // Find other's line with smallest X values +- otherLine = findLine(other, X, Smallest, selfRect); +- // Find own line with largest X values +- selfLine = findLine(self, X, Largest, otherRect); +- // Use the middle value of the Y values +- result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), +- otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); +- break; +- +- case Uml::Region::NorthWest: +- // Find other's point with largest X and largest Y value +- for (i = 0; i < otherLastIndex; ++i) { +- QPointF current(other.at(i)); +- if (current.x() + current.y() >= otherPoint.x() + otherPoint.y()) { +- otherPoint = current; +- } +- } +- // Find own point with smallest X and smallest Y value +- for (i = 0; i < selfLastIndex; ++i) { +- QPointF current(self.at(i)); +- if (current.x() + current.y() <= selfPoint.x() + selfPoint.y()) { +- selfPoint = current; +- } +- } +- result.setPoints(selfPoint, otherPoint); +- break; +- +- case Uml::Region::SouthWest: +- // Find other's point with largest X and smallest Y value +- for (i = 0; i < otherLastIndex; ++i) { +- QPointF current(other.at(i)); +- if (current.x() >= otherPoint.x() && current.y() <= otherPoint.y()) { +- otherPoint = current; +- } +- } +- // Find own point with smallest X and largest Y value +- for (i = 0; i < selfLastIndex; ++i) { +- QPointF current(self.at(i)); +- if (current.x() <= selfPoint.x() && current.y() >= selfPoint.y()) { +- selfPoint = current; +- } +- } +- result.setPoints(selfPoint, otherPoint); +- break; +- +- case Uml::Region::NorthEast: +- // Find other's point with smallest X and largest Y value +- for (i = 0; i < otherLastIndex; ++i) { +- QPointF current(other.at(i)); +- if (current.x() <= otherPoint.x() && current.y() >= otherPoint.y()) { +- otherPoint = current; +- } +- } +- // Find own point with largest X and smallest Y value +- for (i = 0; i < selfLastIndex; ++i) { +- QPointF current(self.at(i)); +- if (current.x() >= selfPoint.x() && current.y() <= selfPoint.y()) { +- selfPoint = current; +- } +- } +- result.setPoints(selfPoint, otherPoint); +- break; +- +- case Uml::Region::SouthEast: +- // Find other's point with smallest X and smallest Y value +- for (i = 0; i < otherLastIndex; ++i) { +- QPointF current(other.at(i)); +- if (current.x() + current.y() <= otherPoint.x() + otherPoint.y()) { +- otherPoint = current; +- } +- } +- // Find own point with largest X and largest Y value +- for (i = 0; i < selfLastIndex; ++i) { +- QPointF current(self.at(i)); +- if (current.x() + current.y() >= selfPoint.x() + selfPoint.y()) { +- selfPoint = current; +- } +- } +- result.setPoints(selfPoint, otherPoint); +- break; +- +- default: +- // Error +- break; +- } +- +- return result; +- } +- +-} // namespace Widget_Utils +diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.h umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.h +--- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,66 +0,0 @@ +-/*************************************************************************** +- * 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-kf6 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef WIDGET_UTILS_H +-#define WIDGET_UTILS_H +- +-#include "basictypes.h" +-#include "messagewidgetlist.h" +-#include "umlwidgetlist.h" +- +-#include +-#include +-#include +-#include +-#include +- +-class QGraphicsItem; +-class QGraphicsRectItem; +- +-/** +- * General purpose-kf6 widget utilities. +- * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org +- */ +-namespace Widget_Utils +-{ +- UMLWidget* findWidget(Uml::ID::Type id, +- const UMLWidgetList& widgets, +- const MessageWidgetList* messages = 0); +- +- QGraphicsRectItem* decoratePoint(const QPointF& p, QGraphicsItem* parent = 0); +- +- void drawCrossInEllipse(QPainter *p, const QRectF& ellipse); +- void drawTriangledRect(QPainter *painter, const QRectF& rect, const QSizeF& triSize); +-// void drawArrowHead(QPainter *painter, const QPointF& arrowPos, +-// const QSizeF& arrowSize, Qt::ArrowType arrowType, +-// bool solid-kf6 = false); +-// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, +-// qreal yRadius, Uml::Corners corners); +- +- QString pointToString(const QPointF& point); +- QPointF stringToPoint(const QString& str); +- +- bool loadPixmapFromXMI(QDomElement &qElement, QPixmap &pixmap); +- void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap); +- +- bool loadGradientFromXMI(QDomElement &qElement, QGradient *&gradient); +- void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient); +- +- bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush); +- void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, +- const QBrush& brush); +- +- bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2); +- bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2); +- +- QLineF closestPoints(const QPolygonF& self, const QPolygonF& other); +-} +- +-#endif +diff -Nuar umbrello-kf6-15.08.1.orig/unittests/CMakeLists.txt umbrello-kf6-15.08.1/unittests/CMakeLists.txt +--- umbrello-kf6-15.08.1.orig/unittests/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/unittests/CMakeLists.txt 2015-10-08 11:48:59.553089025 +0300 +@@ -37,7 +37,8 @@ + ${SRC_PATH}/dialogs + ${SRC_PATH}/docgenerators + ${SRC_PATH}/refactoring +- ${SRC_PATH}/widgets ++ ${SRC_PATH}/umlmodel/ ++ ${SRC_PATH}/umlwidgets/ + ${CMAKE_CURRENT_BINARY_DIR} + ) + +diff -Nuar umbrello-kf6-15.08.1.orig/unittests/testbase.cpp umbrello-kf6-15.08.1/unittests/testbase.cpp +--- umbrello-kf6-15.08.1.orig/unittests/testbase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/unittests/testbase.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -39,8 +39,6 @@ + #include + #endif + +-static UMLApp *umlApp = 0; +- + TestBase::TestBase(QObject *parent) + : QObject(parent) + { +@@ -49,12 +47,12 @@ + void TestBase::initTestCase() + { + QWidget *w = new QWidget; +- umlApp = new UMLApp(w); ++ new UMLApp(w); + } + + void TestBase::cleanupTestCase() + { +- delete umlApp; ++ delete UMLApp::app(); + } + + void TestCodeGeneratorBase::initTestCase() +diff -Nuar umbrello-kf6-15.08.1.orig/unittests/TEST_cppwriter.cpp umbrello-kf6-15.08.1/unittests/TEST_cppwriter.cpp +--- umbrello-kf6-15.08.1.orig/unittests/TEST_cppwriter.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-kf6-15.08.1/unittests/TEST_cppwriter.cpp 2015-10-08 11:48:59.553089025 +0300 +@@ -51,9 +51,11 @@ + UMLAttribute* attr; + attr = c->createAttribute("name_"); + attr = c->createAttribute("address_"); ++ c->addAttribute(attr); + UMLOperation* op; + op = c->createOperation("getName"); + op = c->createOperation("getAddress"); ++ c->addOperation(op); + + cpp->writeClass(c); + // does the just created file exist? diff --git a/desktop/kde6/applications/umbrello-kf6/pspec.xml b/desktop/kde6/applications/umbrello-kf6/pspec.xml new file mode 100755 index 0000000000..712943c429 --- /dev/null +++ b/desktop/kde6/applications/umbrello-kf6/pspec.xml @@ -0,0 +1,94 @@ + + + + + + umbrello-kf6 + http://www.kde.org/ + + Mathias Freire + mathiasfreire45@gmail.com + + GPLv2 + app:gui + desktop.kde.sdk + UML modelling tool and code generator + umbrello-kf6 UML Modeller is a Unified Modelling Language diagram editor for KDE. + mirrors://kde/stable/release-service/24.02.0/src/umbrello-24.02.0.tar.xz + + qt6-base-devel + + libxslt-devel + qt6-svg-devel + kio-kf6-devel + kparts-kf6-devel + + kcompletion-kf6-devel + kxmlgui-kf6-devel + kauth-kf6-devel + kconfig-kf6-kf6-devel + ktexteditor-kf6-devel + kcoreaddons-kf6-devel + kdoctools-kf6-devel + docbook-xsl + extra-cmake-modules-kf6 + kwindowsystem-kf6-devel + + + + kitemmodels-kf6-devel + kunitconversion-kf6-devel + llvm + llvm-clang-devel + llvm-mlir + llvm-polly + + + + + + umbrello-kf6 + + qt6-base + + kio-kf6 + ki18n-kf6 + kcrash-kf6 + libgcc + kconfig-kf6-kf6 + kxmlgui-kf6 + libxml2 + qt6-svg + karchive-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + kiconthemes-kf6 + kjobwidgets-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6-kf6 + kwidgetsaddons-kf6 + ktexteditor-kf6 + libxslt + kwindowsystem-kf6 + llvm-mlir + llvm-polly + + + /usr/share + /usr/share/doc + /usr/bin + + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + diff --git a/desktop/kde6/applications/umbrello-kf6/translations.xml b/desktop/kde6/applications/umbrello-kf6/translations.xml new file mode 100755 index 0000000000..c653cbdf80 --- /dev/null +++ b/desktop/kde6/applications/umbrello-kf6/translations.xml @@ -0,0 +1,8 @@ + + + + umbrello-kf6 + UML modelleme aracı ve kod üreticisi. + umbrello-kf6 UML (Unified Modellin Language) modelleme ve diyagram editörüdür. + + diff --git a/pisi-index.xml b/pisi-index.xml index 03f5b5082a..d69ed62599 100644 --- a/pisi-index.xml +++ b/pisi-index.xml @@ -127301,6 +127301,89 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + umbrello-kf6 + http://www.kde.org/ + + Mathias Freire + mathiasfreire45@gmail.com + + GPLv2 + app:gui + desktop.kde.sdk + UML modelling tool and code generator + UML modelleme aracı ve kod üreticisi. + umbrello-kf6 UML Modeller is a Unified Modelling Language diagram editor for KDE. + umbrello-kf6 UML (Unified Modellin Language) modelleme ve diyagram editörüdür. + mirrors://kde/stable/release-service/24.02.0/src/umbrello-24.02.0.tar.xz + + qt6-base-devel + libxslt-devel + qt6-svg-devel + kio-kf6-devel + kparts-kf6-devel + kcompletion-kf6-devel + kxmlgui-kf6-devel + kauth-kf6-devel + kconfig-kf6-kf6-devel + ktexteditor-kf6-devel + kcoreaddons-kf6-devel + kdoctools-kf6-devel + docbook-xsl + extra-cmake-modules-kf6 + kwindowsystem-kf6-devel + kitemmodels-kf6-devel + kunitconversion-kf6-devel + llvm + llvm-clang-devel + llvm-mlir + llvm-polly + + desktop/kde6/applications/umbrello-kf6/pspec.xml + + + umbrello-kf6 + + qt6-base + kio-kf6 + ki18n-kf6 + kcrash-kf6 + libgcc + kconfig-kf6-kf6 + kxmlgui-kf6 + libxml2 + qt6-svg + karchive-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + kiconthemes-kf6 + kjobwidgets-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6-kf6 + kwidgetsaddons-kf6 + ktexteditor-kf6 + libxslt + kwindowsystem-kf6 + llvm-mlir + llvm-polly + + + /usr/share + /usr/share/doc + /usr/bin + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + ksystemlog-kf6 @@ -127504,7 +127587,9 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol mirrors://kde/stable/release-service/24.02.0/src/ktimer-24.02.0.tar.xz qt6-base-devel + qt6-5compat-devel kdoctools-kf6-devel + kstatusnotifieritem-kf6-devel cmake extra-cmake-modules-kf6 ki18n-kf6-devel @@ -127521,6 +127606,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol ktimer-kf6 qt6-base + qt6-5compat kio-kf6 ki18n-kf6 libgcc @@ -127530,6 +127616,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol kconfigwidgets-kf6 knotifications-kf6 kwidgetsaddons-kf6 + kstatusnotifieritem-kf6 /usr/share/doc @@ -127638,6 +127725,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol qt6-base-devel qt6-svg-devel + qt6-5compat-devel kdoctools-kf6-devel knewstuff-kf6-devel extra-cmake-modules-kf6 @@ -127659,6 +127747,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol qt6-base qt6-svg + qt6-5compat ki18n-kf6 knewstuff-kf6 libgcc @@ -127893,6 +127982,92 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + minuet-kf6 + https://minuet-kf6.kde.org + + Alihan Öztürk + alihan@pisilinux.org + + LGPLv2 + app:gui + desktop.kde6.applications + A KDE Software for Music Education + Music education Free Software, thoughtfully designed to push your musical skills to the next level. Enhance your ability to recognize intervals, chords, rhythm, and scales while enjoying all the power of Free Software. + https://download.kde.org/stable/release-service/24.02.0/src/minuet-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-svg-devel + qt6-base-devel + qt6-declarative-devel + ki18n-kf6-devel + kxmlgui-kf6-devel + kio-kf6-devel + kcrash-kf6-devel + kdoctools-kf6-devel + alsa-lib-devel + drumstick-devel + fluidsynth-devel + + desktop/kde6/applications/minuet-kf6/pspec.xml + + + minuet-kf6 + A KDE Software for Music Education + + kio-kf6 + ki18n-kf6 + kcrash-kf6 + libgcc + kconfig-kf6 + kxmlgui-kf6 + alsa-lib + qt6-base + kcompletion-kf6 + kcoreaddons-kf6 + drumstick-libs + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + fluidsynth + qt6-svg + qt6-declarative + + + /usr/bin + /usr/share + /usr/share/appdata + /usr/share/applications + /usr/share/doc + /usr/share/icons + /usr/share/kxmlgui-kf65 + /usr/share/minuet-kf6 + /usr/lib + + + + minuet-kf6-devel + Development files for minuet-kf6 + + qt6-base-devel + minuet-kf6 + + + /usr/include + /usr/lib/cmake + /usr/lib/pkgconfig + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + khelpcenter-kf6 @@ -127978,6 +128153,97 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + rocs-kf6 + https://www.kde.org + + Pisi Linux Admins + admin@pisilinux.org + + LGPLv2 + app:gui + desktop.kde.edu + rocs-kf6 Graph Theory + rocs-kf6 aims to be a Graph Theory IDE for helping professors to show the results of a graph algorithm and also helping students to do the algorithms. rocs-kf6 has a scripting module, done in Qt Script, that interacts with the drawn graph and every change in the graph with the script is reflected on the drawn one.. + mirrors://kde/stable/release-service/24.02.0/src/rocs-24.02.0.tar.xz + + qt6-base-devel + qt6-declarative-devel + qt6-base-devel + extra-cmake-modules-kf6 + kdoctools-kf6-devel + kdeclarative-kf6-devel + ki18n-kf6-devel + gettext-devel + kitemviews-kf6-devel + ktexteditor-kf6-devel + kxmlgui-kf6-devel + kconfig-kf6-devel + karchive-kf6-devel + kcompletion-kf6-devel + kcoreaddons-kf6-devel + kconfigwidgets-kf6-devel + kwidgetsaddons-kf6-devel + cmake + qt6-location-devel + grantlee-qt6-devel + boost-devel + qt6-svg-devel + + desktop/kde6/applications/rocs-kf6/pspec.xml + + + rocs-kf6 + + qt6-base + qt6-declarative + qt6-svg + grantlee-qt6 + kdeclarative-kf6 + ktexteditor-kf6 + kparts-kf6 + libgcc + ki18n-kf6 + kconfig-kf6 + karchive-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + kxmlgui-kf6 + kitemviews-kf6 + + + /usr/bin + /usr/share + /usr/lib + /usr/lib/qt6 + /usr/share/doc + + + + rocs-kf6-devel + Development files for rocs-kf6 + + rocs-kf6 + + + /usr/include + /usr/lib/cmake + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + kcron-kf6 @@ -128180,6 +128446,153 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + libksane-kf6 + https://www.kde.org + + PisiLinux Community + admins@pisilinux.org + + GPLv2 + library + desktop.kde.graphics + SANE library interface for KDE + KDE için SANE kitaplık arayüzü + libksane-kf6 is a SANE library interface for KDE. + libksane-kf6, KDE için bir SANE kitaplık arayüzüdür. + mirrors://kde/stable/release-service/24.02.0/src/libksane-24.02.0.tar.xz + + ki18n-kf6-devel + kwallet-kf6-devel + qt6-base-devel + ktextwidgets-kf6-devel + sane-backends-devel + kwidgetsaddons-kf6-devel + extra-cmake-modules-kf6 + ksanecore-kf6-devel + + desktop/kde6/applications/libksane-kf6/pspec.xml + + + libksane-kf6 + + ki18n-kf6 + kwallet-kf6 + libgcc + qt6-base + ktextwidgets-kf6 + sane-backends + kwidgetsaddons-kf6 + ksanecore-kf6 + + + /usr/lib + /usr/share/icons + /usr/share/locale + + + + libksane-kf6-devel + Development files for libksane-kf6 + libksane-kf6 için geliştirme dosyaları + + libksane-kf6 + ksanecore-kf6-devel + + + /usr/lib/cmake + /usr/include + /usr/lib/pkgconfig + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + + + + step-kf6 + http://kde.org/applications/education/step/ + + Pisi Linux Admins + admin@pisilinux.org + + LGPLv2 + app:gui + desktop.kde.edu + Interactive Physical Simulator + step-kf6 is an interactive physical simulator. It allows you to explore the physical world through simulations. + mirrors://kde/stable/release-service/24.02.0/src/step-24.02.0.tar.xz + + qt6-base-devel + qt6-svg-devel + qt6-declarative-devel + extra-cmake-modules-kf6 + kdoctools-kf6-devel + mesa-devel + kconfig-kf6-devel + knewstuff-kf6-devel + kplotting-kf6-devel + eigen3 + pkgconfig + libqalculate-devel + cln-devel + kitemmodels-kf6-devel + kunitconversion-kf6-devel + qt6-linguist + gsl-devel + + desktop/kde6/applications/step-kf6/pspec.xml + + + step-kf6 + + qt6-base + cln + gsl + kcrash-kf6 + knewstuff-kf6 + kplotting-kf6 + libqalculate + kparts-kf6 + kio-kf6 + libgcc + ki18n-kf6 + kconfig-kf6 + kxmlgui-kf6 + kjobwidgets-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + kiconthemes-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + kservice-kf6 + + + /etc/xdg + /usr/bin + /usr/share + /usr/share/doc + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + kontactinterface-kf6 @@ -128638,6 +129051,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol kwallet-kf6-devel kservice-kf6-devel kcmutils-kf6-devel + kio-kf6-devel karchive-kf6-devel ki18n-kf6-devel kxmlgui-kf6-devel @@ -128645,6 +129059,8 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol kconfigwidgets-kf6-devel kdbusaddons-kf6-devel mesa-devel + kwindowsystem-kf6-devel + kstatusnotifieritem-kf6-devel kitemmodels-kf6-devel kunitconversion-kf6-devel ktextwidgets-kf6-devel @@ -128658,6 +129074,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol qt6-base kcmutils-kf6 + kio-kf6 kauth-kf6 ki18n-kf6 kio-kf6 @@ -128677,6 +129094,8 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol kconfigwidgets-kf6 knotifications-kf6 kwidgetsaddons-kf6 + kwindowsystem-kf6 + kstatusnotifieritem-kf6 /etc/dbus-1/system.d/org.kde.kcontrol.kcmkwallet-kf65.conf @@ -128955,6 +129374,60 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + poxml-kf6 + http://www.kde.org/ + + Mathias Freire + mathiasfreire45@gmail.com + + GPLv2 + app:gui + desktop.kde.sdk + Tools for translating DocBook XML files with Gettex + DocBook XML dosyalarını çevirme araçları. + This is a collection of tools that facilitate translating DocBook XML files using Gettext message files (PO files). + poxml-kf6, DocBook XML dosyalarını (.po) Gettext yarımıyla çevirmeyi sağlayan bir programdır. + https://download.kde.org/stable/release-service/24.02.0/src/poxml-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-base-devel + gettext-devel + kdoctools-kf6-devel + docbook-xsl + + desktop/kde6/applications/poxml-kf6/pspec.xml + + + poxml-kf6 + + libgcc + gettext + qt6-base + + + /usr/bin + /usr/share/doc + /usr/share/man + + + kdesdk + + + kdesdk + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + kdenetwork-filesharing-kf6 @@ -130299,6 +130772,124 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + libkmahjongg-kf6 + https://www.kde.org + + Pisi Linux Admins + admin@pisilinux.org + + LGPLv2 + app:library + desktop.kde.games + Common code, backgrounds and tile sets for games using Mahjongg tiles + Common code, backgrounds and tile sets for games using Mahjongg tiles. + mirrors://kde/stable/release-service/24.02.0/src/libkmahjongg-24.02.0.tar.xz + + qt6-base-devel + qt6-svg-devel + extra-cmake-modules-kf6 + gettext-devel + kdoctools-kf6-devel + ki18n-kf6-devel + kconfig-kf6-devel + kcompletion-kf6-devel + kconfigwidgets-kf6-devel + kwidgetsaddons-kf6-devel + kcoreaddons-kf6-devel + mesa-devel + + desktop/kde6/applications/libkmahjongg-kf6/pspec.xml + + + libkmahjongg-kf6 + + qt6-base + qt6-svg + libgcc + ki18n-kf6 + kconfig-kf6 + kcompletion-kf6 + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + + + /etc/xdg + /usr/bin + /usr/share + /usr/lib + /usr/share/doc + + + + libkmahjongg-kf6-devel + Development files for libkmahjongg-kf6 + + libkmahjongg-kf6 + + + /usr/include + /usr/lib/cmake + /usr/lib/pkgconfig + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + + + + signon-kwallet-extension-kf6 + http://kde.org + + Alihan Öztürk + alihan@pisilinux.org + + LGPLv2 + app + desktop.kde.network + kwallet-kf6 signon extension + kwallet-kf6 signon extension + mirrors://kde/stable/release-service/24.02.0/src/signon-kwallet-extension-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-base-devel + kwallet-kf6-devel + signon-devel + + desktop/kde6/applications/signon-kwallet-extension-kf6/pspec.xml + + + signon-kwallet-extension-kf6 + kwallet-kf6 signon extension + + libgcc + signon + kwallet-kf6 + qt6-base + + + /usr/lib/signon + /usr/share/doc + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + kwave-kf6 @@ -130934,6 +131525,90 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + lokalize-kf6 + http://www.kde.org/ + + Pisi Linux Admins + admin@pisilinux.org + + GPLv2 + app:gui + desktop.kde.sdk + lokalize-kf6 is the localization tool for KDE and other open source software + Uygulama yerelleştirme yardımcısı. + lokalize-kf6 is also a general computer-aided translation system (CAT) with which you can translate OpenDocument files (*.odt). + lokalize-kf6, uygulamalar için kolaylıkla yerelleştirme yapabileceğiniz bir programdır. + mirrors://kde/stable/release-service/24.02.0/src/lokalize-24.02.0.tar.xz + + qt6-base-devel + hunspell-devel + extra-cmake-modules-kf6 + kdoctools-kf6-devel + kio-kf6-devel + enchant-devel + kitemviews-kf6-devel + ki18n-kf6-devel + kross-kf6-devel + kparts-kf6-devel + sonnet-kf6-devel + kconfig-kf6-devel + kxmlgui-kf6-devel + kcompletion-kf6-devel + kcoreaddons-kf6-devel + kdbusaddons-kf6-devel + ktextwidgets-kf6-devel + kconfigwidgets-kf6-devel + knotifications-kf6-devel + kwidgetsaddons-kf6-devel + pkgconfig + qt6-sql-postgresql + qt6-sql-mysql + qt6-sql-sqlite + qt6-sql-odbc + + desktop/kde6/applications/lokalize-kf6/pspec.xml + + + lokalize-kf6 + + qt6-base + kio-kf6 + kitemviews-kf6 + ki18n-kf6 + kross-kf6 + kparts-kf6 + libgcc + sonnet-kf6 + kconfig-kf6 + kxmlgui-kf6 + kcompletion-kf6 + kcoreaddons-kf6 + kdbusaddons-kf6 + ktextwidgets-kf6 + kconfigwidgets-kf6 + knotifications-kf6 + kwidgetsaddons-kf6 + hunspell + + + /etc/xdg + /usr/share + /usr/share/doc + /usr/bin + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + artikulate-kf6 @@ -131483,6 +132158,115 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol + + + marble-kf6 + http://edu.kde.org/applications/all/marble-kf6 + + PisiLinux Community + admins@pisilinux.org + + GPLv2 + app:gui + desktop.kde6.applications + Virtual globe and eorld atlas + Sanal küre ve Dünya atlası + marble-kf6 is a virtual globe and world atlas that you can use to learn more about the Earth. + marble-kf6, sanal küre ve Dünya atlası uygulamasıdır. + marble-kf6 + mirrors://kde/stable/release-service/24.02.0/src/marble-24.02.0.tar.xz + + extra-cmake-modules-kf6 + qt6-base-devel + qt6-designer-devel + qt6-svg-devel + qt6-declarative-devel + qt6-sql-postgresql + qt6-sql-mysql + qt6-sql-odbc + qt6-sql-sqlite + qt6-location-devel + qt6-linguist + qt6-webengine-devel + kdoctools-kf6-devel + qt6-phonon-devel + kio-kf6-devel + quazip-devel + kwallet-kf6-devel + knewstuff-kf6-devel + kparts-kf6-devel + kcoreaddons-kf6-devel + ki18n-kf6-devel + kconfig-kf6-devel + krunner-devel + kservice-kf6-devel + libwlocate-devel + shared-mime-info + qt6-serialport-devel + plasma-desktop-kf6 + + desktop/kde6/applications/marble-kf6/pspec.xml + + + marble-kf6 + + kio-kf6 + zlib + ki18n-kf6 + kcrash-kf6 + kparts-kf6 + libgcc + kconfig-kf6 + krunner + kxmlgui-kf6 + qt6-svg + qt6-base + knewstuff-kf6 + libwlocate + qt6-phonon + kcoreaddons-kf6 + qt6-location + kconfigwidgets-kf6 + kwidgetsaddons-kf6 + qt6-declarative + qt6-serialport + + + /usr/lib + /usr/bin + /usr/share + /usr/share/appdata + /usr/share/applications + /usr/share/config.kcfg + /usr/share/doc + /usr/share/icons + /usr/share/kservice-kf6s5 + /usr/share/kxmlgui-kf65 + /usr/share/marble-kf6 + /etc/xdg + + + + marble-kf6-devel + Development files for marble-kf6 + marble-kf6 için geliştirme dosyaları + + marble-kf6 + + + /usr/include + + + + + 2024-03-03 + 24.02.0 + First release + Mustafa Cinasal + muscnsl@gmail.com + + + kdegraphics-mobipocket-kf6 @@ -131570,6 +132354,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol kio-kf6-devel kcmutils-kf6-devel qt6-base-devel + qt6-5compat-devel kwidgetsaddons-kf6-devel desktop/kde6/applications/libkcddb-kf6/pspec.xml @@ -131584,6 +132369,7 @@ Bu Skype SILK codec ve Xiph.Org 's Celt codec teknolojisi dahil RFC 6716 ol kconfig-kf6 kcmutils-kf6 qt6-base + qt6-5compat kcoreaddons-kf6 musicbrainz5 kconfigwidgets-kf6 @@ -301921,7 +302707,7 @@ It supports email, address books, calendars, tasks, news feeds and much more.desktop.gnome.apps GNOME Maps application Maps is a map application for GNOME. - https://download.gnome.org/sources/gnome-maps/45/gnome-maps-45.4.tar.xz + https://download.gnome.org/sources/gnome-maps/45/gnome-maps-45.5.tar.xz libchamplain-devel meson @@ -301969,6 +302755,13 @@ It supports email, address books, calendars, tasks, news feeds and much more. + + 2024-03-04 + 45.5 + Version bump. + Mustafa Cinasal + muscnsl@gmail.com + 2024-02-10 45.4 @@ -308406,7 +309199,7 @@ It supports email, address books, calendars, tasks, news feeds and much more.desktop.gnome.base The Gcr package contains libraries used for displaying certificates and accessing key stores. The Gcr package contains libraries used for displaying certificates and accessing key stores. It also provides the viewer for crypto files on the GNOME Desktop. - https://download.gnome.org/sources/gcr/4.2/gcr-4.2.0.tar.xz + https://download.gnome.org/sources/gcr/4.2/gcr-4.2.1.tar.xz meson gnupg @@ -308468,7 +309261,7 @@ It supports email, address books, calendars, tasks, news feeds and much more.gtk4-devel p11-kit-devel gobject-introspection-devel - gcr-4 + gcr-4 /usr/include @@ -308488,6 +309281,13 @@ It supports email, address books, calendars, tasks, news feeds and much more. + + 2024-03-04 + 4.2.1 + Version bump. + Mustafa Cinasal + muscnsl@gmail.com + 2024-02-13 4.2.0 diff --git a/pisi-index.xml.sha1sum b/pisi-index.xml.sha1sum index 8a88827437..9366dca054 100644 --- a/pisi-index.xml.sha1sum +++ b/pisi-index.xml.sha1sum @@ -1 +1 @@ -d1f34f3e461b3b8e34dd54544cfb9a80f9a6576e \ No newline at end of file +c52baf6d10ee7b6d0471444b104243f087d4a65c \ No newline at end of file diff --git a/pisi-index.xml.xz b/pisi-index.xml.xz index cc6cf044d8..7ba4e4745d 100644 Binary files a/pisi-index.xml.xz and b/pisi-index.xml.xz differ diff --git a/pisi-index.xml.xz.sha1sum b/pisi-index.xml.xz.sha1sum index 81bc54010e..8bcbe50b19 100644 --- a/pisi-index.xml.xz.sha1sum +++ b/pisi-index.xml.xz.sha1sum @@ -1 +1 @@ -32ed91d760eb4a8473a3ceb41f3af78839646692 \ No newline at end of file +62526c8b212cd322823f54b80665a633f2e3605f \ No newline at end of file