From 7fcdc1c788725f866de71fc9dfd8c4d1cb132b57 Mon Sep 17 00:00:00 2001 From: Orangerot Date: Fri, 24 May 2024 17:42:08 +0200 Subject: Initial commit --- 21-implementierungsheft-kolloquium/.gitignore | 302 ++ 21-implementierungsheft-kolloquium/.gitlab-ci.yml | 37 + 21-implementierungsheft-kolloquium/CHANGELOG.md | 34 + 21-implementierungsheft-kolloquium/Makefile | 19 + 21-implementierungsheft-kolloquium/README.md | 118 + .../assets/.gitignore | 3 + .../assets/.gitingnore | 3 + .../assets/commits-dashboard.png | Bin 0 -> 44171 bytes .../assets/commits-server.png | Bin 0 -> 36705 bytes .../assets/contributors-dashboard.png | Bin 0 -> 193750 bytes .../assets/contributors-server.png | Bin 0 -> 222521 bytes .../assets/diagrams/backendComponentDiagram.puml | 61 + .../diagrams/classdiagram-authentication.puml | 112 + .../diagrams/classdiagram-episode-actions.puml | 84 + .../assets/diagrams/classdiagram-model.puml | 109 + .../diagrams/classdiagram-subscriptions.puml | 75 + .../assets/diagrams/classdiagram-util.puml | 43 + .../assets/diagrams/classdiagram.puml | 68 + .../assets/diagrams/componentdiagram.puml | 53 + .../assets/diagrams/db.puml | 78 + .../assets/diagrams/deployment.puml | 59 + .../diagrams/sequencediagram-forgotAndResetPW.puml | 41 + .../sequencediagram-getEpisodeActions.puml | 38 + ...ncediagram-getEpisodeActionsOfPodcastSince.puml | 32 + .../diagrams/sequencediagram-getSubscriptions.puml | 38 + .../assets/diagrams/sequencediagram-register.puml | 26 + .../sequencediagram-uploadEpisodeActions.puml | 38 + .../sequencediagram-uploadSubscriptions.puml | 32 + .../assets/episode.png | Bin 0 -> 10778 bytes .../assets/gantt-plan.puml | 31 + .../assets/gantt-reality.puml | 39 + 21-implementierungsheft-kolloquium/assets/help.png | Bin 0 -> 14423 bytes .../assets/lastupdate.png | Bin 0 -> 9363 bytes 21-implementierungsheft-kolloquium/assets/logo.svg | 211 + .../assets/navbar.png | Bin 0 -> 8940 bytes .../assets/password-margin.png | Bin 0 -> 8701 bytes .../assets/password.png | Bin 0 -> 8781 bytes .../assets/subscription.png | Bin 0 -> 79929 bytes .../logos/banner_2020_kit.jpg | Bin 0 -> 96829 bytes 21-implementierungsheft-kolloquium/notizen | 40 + .../presentation.tex | 53 + 21-implementierungsheft-kolloquium/sdqbeamer.cls | 975 ++++ .../slides/changes.tex | 84 + .../slides/classdiagram.tex | 36 + .../slides/components.tex | 7 + .../slides/difficulties.tex | 34 + .../slides/einf\303\274hrung.tex" | 40 + .../slides/features.tex | 37 + .../slides/gantt.tex | 11 + .../slides/integrationstrategie.tex | 82 + .../slides/pattern.tex | 12 + .../slides/requirements.tex | 58 + .../slides/statistics.tex | 85 + .../slides/synchronisation.tex | 36 + .../slides/zielsetzung.tex | 39 + 21-implementierungsheft-kolloquium/tikz-uml.sty | 5377 ++++++++++++++++++++ 56 files changed, 8790 insertions(+) create mode 100644 21-implementierungsheft-kolloquium/.gitignore create mode 100644 21-implementierungsheft-kolloquium/.gitlab-ci.yml create mode 100644 21-implementierungsheft-kolloquium/CHANGELOG.md create mode 100644 21-implementierungsheft-kolloquium/Makefile create mode 100644 21-implementierungsheft-kolloquium/README.md create mode 100644 21-implementierungsheft-kolloquium/assets/.gitignore create mode 100644 21-implementierungsheft-kolloquium/assets/.gitingnore create mode 100644 21-implementierungsheft-kolloquium/assets/commits-dashboard.png create mode 100644 21-implementierungsheft-kolloquium/assets/commits-server.png create mode 100644 21-implementierungsheft-kolloquium/assets/contributors-dashboard.png create mode 100644 21-implementierungsheft-kolloquium/assets/contributors-server.png create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/db.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml create mode 100644 21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml create mode 100644 21-implementierungsheft-kolloquium/assets/episode.png create mode 100644 21-implementierungsheft-kolloquium/assets/gantt-plan.puml create mode 100644 21-implementierungsheft-kolloquium/assets/gantt-reality.puml create mode 100644 21-implementierungsheft-kolloquium/assets/help.png create mode 100644 21-implementierungsheft-kolloquium/assets/lastupdate.png create mode 100644 21-implementierungsheft-kolloquium/assets/logo.svg create mode 100644 21-implementierungsheft-kolloquium/assets/navbar.png create mode 100644 21-implementierungsheft-kolloquium/assets/password-margin.png create mode 100644 21-implementierungsheft-kolloquium/assets/password.png create mode 100644 21-implementierungsheft-kolloquium/assets/subscription.png create mode 100644 21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg create mode 100644 21-implementierungsheft-kolloquium/notizen create mode 100644 21-implementierungsheft-kolloquium/presentation.tex create mode 100644 21-implementierungsheft-kolloquium/sdqbeamer.cls create mode 100644 21-implementierungsheft-kolloquium/slides/changes.tex create mode 100644 21-implementierungsheft-kolloquium/slides/classdiagram.tex create mode 100644 21-implementierungsheft-kolloquium/slides/components.tex create mode 100644 21-implementierungsheft-kolloquium/slides/difficulties.tex create mode 100644 "21-implementierungsheft-kolloquium/slides/einf\303\274hrung.tex" create mode 100644 21-implementierungsheft-kolloquium/slides/features.tex create mode 100644 21-implementierungsheft-kolloquium/slides/gantt.tex create mode 100644 21-implementierungsheft-kolloquium/slides/integrationstrategie.tex create mode 100644 21-implementierungsheft-kolloquium/slides/pattern.tex create mode 100644 21-implementierungsheft-kolloquium/slides/requirements.tex create mode 100644 21-implementierungsheft-kolloquium/slides/statistics.tex create mode 100644 21-implementierungsheft-kolloquium/slides/synchronisation.tex create mode 100644 21-implementierungsheft-kolloquium/slides/zielsetzung.tex create mode 100644 21-implementierungsheft-kolloquium/tikz-uml.sty (limited to '21-implementierungsheft-kolloquium') diff --git a/21-implementierungsheft-kolloquium/.gitignore b/21-implementierungsheft-kolloquium/.gitignore new file mode 100644 index 0000000..e20d538 --- /dev/null +++ b/21-implementierungsheft-kolloquium/.gitignore @@ -0,0 +1,302 @@ +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 +.*.lb + +## Intermediate documents: +*.dvi +*.xdv +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +*.eps +*.pdf +# !assets/*.pdf + +## Generated if empty string is given at "Please type another file name for output:" +.pdf + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex(busy) +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Build tool directories for auxiliary files +# latexrun +latex.out/ + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.pre +*.snm +*.vrb + +# changes +*.soc + +# comment +*.cut + +# cprotect +*.cpt + +# elsarticle (documentclass of Elsevier journals) +*.spl + +# endnotes +*.ent + +# fixme +*.lox + +# feynmf/feynmp +*.mf +*.mp +*.t[1-9] +*.t[1-9][0-9] +*.tfm + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs +*.lzo +*.lzs +*.slg +*.slo +*.sls + +# uncomment this for glossaries-extra (will ignore makeindex's style files!) +*.ist + +# gnuplot +*.gnuplot +*.table + +# gnuplottex +*-gnuplottex-* + +# gregoriotex +*.gaux +*.glog +*.gtex + +# htlatex +*.4ct +*.4tc +*.idv +*.lg +*.trc +*.xref + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files +# *.tikz +*-tikzDictionary + +# listings +*.lol + +# luatexja-ruby +*.ltjruby + +# makeidx +*.idx +*.ilg +*.ind + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc[0-9]* +*.slf[0-9]* +*.slt[0-9]* +*.stc[0-9]* + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# newpax +*.newpax + +# nomencl +*.nlg +*.nlo +*.nls + +# pax +*.pax + +# pdfpcnotes +*.pdfpc + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# scrwfile +*.wrt + +# svg +svg-inkscape/ + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# tcolorbox +*.listing + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# titletoc +*.ptc + +# todonotes +*.tdo + +# vhistory +*.hst +*.ver + +# easy-todo +*.lod + +# xcolor +*.xcp + +# xmpincl +*.xmpi + +# xindy +*.xdy + +# xypic precompiled matrices and outlines +*.xyc +*.xyd + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# LyX +*.lyx~ + +# Kile +*.backup + +# gummi +.*.swp + +# KBibTeX +*~[0-9]* + +# TeXnicCenter +*.tps + +# auto folder when using emacs and auctex +./auto/* +*.el + +# expex forward references with \gathertags +*-tags.tex + +# standalone packages +*.sta + +# Makeindex log files +*.lpz + +# xwatermark package +*.xwm + +# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib +# option is specified. Footnotes are the stored in a file with suffix Notes.bib. +# Uncomment the next line to have this generated file ignored. +#*Notes.bib diff --git a/21-implementierungsheft-kolloquium/.gitlab-ci.yml b/21-implementierungsheft-kolloquium/.gitlab-ci.yml new file mode 100644 index 0000000..c4ad5e0 --- /dev/null +++ b/21-implementierungsheft-kolloquium/.gitlab-ci.yml @@ -0,0 +1,37 @@ +plantuml: + stage: .pre + image: + name: eclipse-temurin:17-alpine + entrypoint: [""] + script: + - java -jar plantuml.jar -tpdf assets/diagrams/*.puml + - java -jar plantuml.jar -teps assets/*.puml + artifacts: + paths: + - assets + +tex: + stage: build + image: texlive/texlive + script: + - mkdir public + - make tex + - mv *.pdf public + artifacts: + paths: + - public + dependencies: + - plantuml + +pages: + stage: deploy + script: + - echo Hello, World! + artifacts: + paths: + - public + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + dependencies: + - tex + diff --git a/21-implementierungsheft-kolloquium/CHANGELOG.md b/21-implementierungsheft-kolloquium/CHANGELOG.md new file mode 100644 index 0000000..7671a41 --- /dev/null +++ b/21-implementierungsheft-kolloquium/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog +Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert. +Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`. + +## [2022-05-03 v3.1.3] +- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden +- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab) + +## [2021-08-10 v3.1.2] +- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab) + +## [2020-12-08 v3.1.1] +- FIX: Titelbild (Issue #4 in Gitlab) + +## [2020-12-07 v3.1] +- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt +- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt +- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt +- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen +- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben + +## [2020-11-16 v3.0] +- Seitenformat 16:10 hinzugefügt +- Umstellung auf KIT-Design vom 1. August 2020 + - Anpassung auf neues Farbschema und Maße + - neues Titelbild aus der KIT-Bildwelt +- Neue Optionen: + - durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden + - durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden +- Deutsch (`de`) ist nun die Standard-Option +- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert +- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist +- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar. +- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/Makefile b/21-implementierungsheft-kolloquium/Makefile new file mode 100644 index 0000000..3e1e58a --- /dev/null +++ b/21-implementierungsheft-kolloquium/Makefile @@ -0,0 +1,19 @@ +MAIN = presentation +FLAGS = -pdf + +all: clean compile +compile: diagram tex +clean: clean-diagram clean-tex + +dev: + latexmk $(FLAGS) -pvc $(MAIN) +tex: + latexmk $(FLAGS) $(MAIN) +diagram: + java -jar plantuml.jar -tpdf assets/diagrams/*.puml + java -jar plantuml.jar -teps assets/*.puml +clean-tex: + latexmk -C +clean-diagram: + find assets/diagrams -type f -not -name '*.puml' -delete + diff --git a/21-implementierungsheft-kolloquium/README.md b/21-implementierungsheft-kolloquium/README.md new file mode 100644 index 0000000..6a5e9ea --- /dev/null +++ b/21-implementierungsheft-kolloquium/README.md @@ -0,0 +1,118 @@ +LaTeX-Vorlage für Präsentationen +================================ + +Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020). + +Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer). + +Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php) +mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach + +Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen + +Hinweise, Verbesserungsvorschläge +================================= + +Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen. + +Verwendung +========== + +Optionen der Dokumentklasse `sdqbeamer` +----------------------------------------- +Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden: + +| Seitenverhältnis | Option | +| ---------------- | ------------------- | +| 16:9 | `16:9` (Standard) | +| 16:10 | `16:10` | +| 4:3 | `4:3` | + +Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden. + +| Schriftgröße Fußzeile | Option | +| ----------------------| -------------------- | +| etwas größer (12pt) | `bigfoot` (Standard) | +| KIT-Vorgabe (9pt) | `smallfoot` | + +Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden: + +| Position | Option | Bemerkung | +| ------------------------ | ---------------- | ------------------------------------------ | +| oberhalb der Trennlinie | `navbarinline` | Standard | +| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` | +| Seitenleiste links | `navbarside` | keine Subsection-Punkte | +| keine Navigationsleiste | `navbaroff` | | +| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` | + +Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt. + +| Sprache | | +| -------- |---------------- | +| Deutsch | `de` (Standard) | +| Englisch | `en` | + +Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}` + +Titelbild +--------- + +Das Bild auf der Titelfolie kann mit dem Befehl + +`\titleimage{myimage}` (ohne Dateiendung) + +gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen. + +Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird. + +Logo und Name Abteilung/KIT-Fakultät/Institut +--------------------------------------------- + +Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden: + +`\grouplogo{mylogo}` (ohne Dateiendung) + +Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen. + +Der Gruppenname kann mit folgendem Befehl gesetzt werden: + +`\groupname{Software Design and Quality}` + +Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet. + +Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit + +`\groupnamewidth{80mm}` + +verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`. + +LaTeX allgemein +--------------- +Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX + +Dateistruktur +============ +`presentation.tex` +------------------ +Hauptdatei des LaTeX-Dokuments. + +`presentation.bib` +------------- +Beispieldatei für BibTeX-Referenzen +https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten + +`sdqbeamer.cls` +----------------- +Dokumentklasse für Präsentationen im KIT-Design. + +`logos/` +-------- +In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG. + +`CHANGELOG.md` +-------------- +Dokumentation der Änderungen in den jeweiligen Versionen. + +`README.md` +----------- +Dieser Text. diff --git a/21-implementierungsheft-kolloquium/assets/.gitignore b/21-implementierungsheft-kolloquium/assets/.gitignore new file mode 100644 index 0000000..16252a4 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/.gitignore @@ -0,0 +1,3 @@ +diagrams/* +!diagrams/*.puml + diff --git a/21-implementierungsheft-kolloquium/assets/.gitingnore b/21-implementierungsheft-kolloquium/assets/.gitingnore new file mode 100644 index 0000000..16252a4 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/.gitingnore @@ -0,0 +1,3 @@ +diagrams/* +!diagrams/*.puml + diff --git a/21-implementierungsheft-kolloquium/assets/commits-dashboard.png b/21-implementierungsheft-kolloquium/assets/commits-dashboard.png new file mode 100644 index 0000000..89672d6 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/commits-dashboard.png differ diff --git a/21-implementierungsheft-kolloquium/assets/commits-server.png b/21-implementierungsheft-kolloquium/assets/commits-server.png new file mode 100644 index 0000000..a9d1a5c Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/commits-server.png differ diff --git a/21-implementierungsheft-kolloquium/assets/contributors-dashboard.png b/21-implementierungsheft-kolloquium/assets/contributors-dashboard.png new file mode 100644 index 0000000..3621c31 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/contributors-dashboard.png differ diff --git a/21-implementierungsheft-kolloquium/assets/contributors-server.png b/21-implementierungsheft-kolloquium/assets/contributors-server.png new file mode 100644 index 0000000..500bb43 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/contributors-server.png differ diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml b/21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml new file mode 100644 index 0000000..e382351 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml @@ -0,0 +1,61 @@ +@startuml +' skinparam linetype ortho + +'######################################################################### +'SubscriptionsAPI +component SubscriptionsAPI { + + component SubscriptionService + component SubscriptionController + component SubscriptionDataAccessLayer + + portout "Webserver" as wSub + portin "Database" as dSub + } + +dSub --0)- SubscriptionDataAccessLayer +SubscriptionDataAccessLayer --0)- SubscriptionService +SubscriptionService --0)- SubscriptionController +SubscriptionController --0)- wSub + +'######################################################################### + + +'######################################################################### +'EpisodeActionsAPI + +component EpisodeActionsAPI { + component EpisodeActionService + component EpisodeActionController + component EpisodeActionDataAccessLayer + + portout "Webserver" as wEpisode + portin "Database" as dEpisode +} + +dEpisode --0)- EpisodeActionDataAccessLayer +EpisodeActionController --0)- wEpisode +EpisodeActionDataAccessLayer --0)- EpisodeActionService +EpisodeActionService --0)- EpisodeActionController + +'######################################################################### + + +'######################################################################### +'AuthenticationAPI + +component AuthenticationAPI { + component AuthenticationService + component AuthenticationController + component AuthenticationDataAccessLayer + + portout "Webserver" as wAuth + portin "Database" as dAuth +} + +dAuth --0)- AuthenticationDataAccessLayer +AuthenticationController --0)- wAuth +AuthenticationDataAccessLayer --0)- AuthenticationService +AuthenticationService --0)- AuthenticationController + +@enduml diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml new file mode 100644 index 0000000..a2b3518 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml @@ -0,0 +1,112 @@ +@startuml + +package authenticationAPI <> { + package authenticationDataAccessLayer <> { + ' interface AuthenticationDao { + ' String login(String username) + ' int logout(String username) + ' } + + ' class AuthenticationDataAccessService <<@Respository>> { + ' <> AuthenticationDataAccessService(JpaTemplate jpaTemplate) + ' String login(String username) + ' int logout(String username) + ' } + + interface UserDetailsManager { + void createUser(UserDetails userDetails) + void changePassword(String oldPassword, String newPassword) + void deleteUser(String username) + void updateUser(UserDetails user) + boolean userExists(String username) + } + note left + Aus org.springframework.security.provisioning + - liefert Methoden zum Erstellen neuer User + und zum Aktualisieren bestehender. + end note + + class JdbcUserDetailsManager <<@Repository>> { + <> JdbcUserDetailsManager(DataSource dataSource) + void createUser(UserDetails user) + void changePassword(String oldPassword, String newPassword) + void deleteUser(String username) + void updateUser(UserDetails user) + boolean userExists(String username) + } + note right + User Management Service aus dem Paket + org.springframework.security.provisioning + der CRUD Operationen für User bereitstellt. + Hier sind nur die relevanten Methoden modelliert. + end note + } + + package authenticationService <> { + class AuthenticationService <<@Service>> { + -- + <> AuthenticationService(UserDetailsManager userDetailsManager) + List verifyLogin(String username) + int logout(String username) + int forgotPassword(ForgotPasswordRequest forgotPasswordRequest) + .. via JdbcUserDetailsManager .. + int resetPassword(String username, RequestWithPassword requestWithPassword) + int registerUser(UserDetails user) + int changePassword(String username, ChangePasswordRequest changePasswordRequest) + int deleteUser(String username, RequestWithPassword requestWithPassword) + } + + class JavaMailSenderImpl {} + note left + Aus org.springframework.mail.javamail. + Implementierung des JavaMailSender Interfaces, + welches das MailSender Interface durch Unterstützung + von MIME Nachrichten erweitert. + Das MailSender Interface definiert dabei eine + Strategie zum Versenden einfacher Mails. + Unterstützt sowohl JavaMail MimeMessages und + Spring SimpleMailMessages. + end note + } + + package authenticationController <> { + class AuthenticationController <<@Controller>> { + <> AuthenticationController(AuthenticationService authenticationService) + ResponseEntity> verifyLogin(String username) + ResponseEntity logout(String username) + ResponseEntity forgotPassword(ForgotPasswordRequest forgotPasswordRequest) + ResponseEntity resetPassword(String username, RequestWithPassword requestWithPassword) + ResponseEntity registerUser(UserDetails user) + ResponseEntity changePassword(String username, ChangePasswordRequest changePasswordRequest) + ResponseEntity deleteUser(String username, RequestWithPassword requestWithPassword) + } + + class ChangePasswordRequest { + <> ChangePasswordRequest(String oldPassword, String newPassword) + String getOldPassword() + String getNewPassword() + } + + class ForgotPasswordRequest { + <> ForgotPasswordRequest(String email) + String getEmail() + } + + class RequestWithPassword { + <> ResetPasswordRequest(String password) + String getPassword() + } + } +} + +' User <.. AuthenticationDataAccessService: DB +' User <.. JdbcUserDetailsManager: DB +UserDetailsManager <.. AuthenticationService: <> +' AuthenticationDao <.. AuthenticationService: <> +AuthenticationService --o AuthenticationController +' AuthenticationDao <|. AuthenticationDataAccessService: <> +UserDetailsManager <|. JdbcUserDetailsManager: <> +JavaMailSenderImpl <. AuthenticationService: <> + +@enduml + diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml new file mode 100644 index 0000000..7a4530e --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml @@ -0,0 +1,84 @@ +@startuml + +package episodeActionsAPI <> { + package episodeActionDataAccessLayer <> { + class EpisodeActionDataAccessService <<@Repository>> { + <> EpisodeActionDataAccessService (JpaTemplate jpaTemplate) + long addEpisodeActions(String username, List episodeActionPosts) + List getEpisodeActions(String username) + List getEpisodeActionsOfPodcast(String username, String podcastURL) + List getEpisodeActionsSince(String username, LocalDateTime since) + List getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since) + } + + interface EpisodeActionDao { + long addEpisodeActions(String username, List episodeActionPosts) + List getEpisodeActions(String username) + List getEpisodeActionsOfPodcast(String username, String podcastURL) + List getEpisodeActionsSince(String username, LocalDateTime since) + List getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since) + } + } + + package episodeActionService <> { + class EpisodeActionService <<@Service>> { + <> EpisodeActionService (EpisodeActionDao episodeActionDao) + LocalDateTime addEpisodeActions(String username, List episodeActionPosts) + List getEpisodeActions(String username) + List getEpisodeActionsOfPodcast(String username, String podcastURL) + List getEpisodeActionsSince(String username, LocalDateTime since) + List getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since) + } + } + + package episodeActionController <> { + class EpisodeActionController <<@Controller>>{ + <> EpisodeActionController (EpisodeActionService episodeActionService) + ResponseEntity addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest) + ResponseEntity getEpisodeActions(String username, String deviceID, boolean aggregated) + ResponseEntity getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated) + ResponseEntity getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated) + ResponseEntity getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated) + } + + class EpisodeActionPostResponse { + <> EpisodeActionPostResponse(List> updateURLs) + long getTimestamp() + List> getUpdatedURLs() + } + + class EpisodeActionPost { + <> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position) + String getPodcastURL() + String getEpisodeURL() + int getGUID() + Action getAction() + LocalDateTime getTimestamp() + int getStarted() + int getPosition() + EpisodeAction getEpisodeAction() + } + + class EpisodeActionPostRequest { + <> EpisodeActionPostRequest(List episodeActionPosts) + List getEpisodeActionPosts() + } + + class EpisodeActionGetResponse { + <> EpisodeActionGetResponse(List episodeActionPosts) + List getEpisodeActionPosts() + long getTimestamp() + } + } +} + +EpisodeActionPost -o EpisodeActionGetResponse +EpisodeActionPost -o EpisodeActionPostRequest +' EpisodeAction <.. EpisodeActionDataAccessService: DB +' Episode <.. EpisodeActionDataAccessService: DB +EpisodeActionDao <.. EpisodeActionService: <> +EpisodeActionService --o EpisodeActionController +EpisodeActionDao <|. EpisodeActionDataAccessService: <> + +@enduml + diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml new file mode 100644 index 0000000..72ad49f --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml @@ -0,0 +1,109 @@ +@startuml + +package model <> { + class Subscription { + <> Subscription(String url, String title) + int getID() + String getURL() + long getLastActionTimestamp() + String getTitle() + } + + class SubscriptionAction { + <> SubscriptionAction(int userID, int subscriptionID) + int getID() + int getUserID() + int getSubscriptionID() + long getTimestamp() + boolean getAdded() + } + + class Episode { + <> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total) + int getSubscriptionID() + int getID() + int getGUID() + String getURL() + String getTitle() + int getTotal() + } + + enum Action { + Download + Play + Delete + New + Flattr + String getJsonProperty() + } + + class EpisodeAction { + <> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position) + int getEpisodeID() + Action getAction() + long getTimestamp() + int getStarted() + int getPosition() + void setEpisodeID() + EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL) + } + + interface UserDetails { + String getUsername() + String getPassword() + Collection getAuthorities() + boolean isAccountExpired() + boolean isAccountLocked() + boolean isCredentialsNonExpired() + boolean isEnabled() + } + note left + Aus org.springframework.security.core.userdetails. + Wird für die Schnittstelle UserDetailsManager benötigt. + Stellt wichtige Informationen eines Users bereit. + Diese werden nur indirekt von Spring Security + benutzt, indem sie vorher in Authentication Objekten + gekapselt werden. + end note + + class User { + -- + <> User(String username, String password) + int getID() + String getSessionToken() + boolean getEmailIsValidated() + .. interface methods .. + String getUsername() + String getPassword() + Collection getAuthorities() + boolean isAccountExpired() + boolean isAccountLocked() + boolean isCredentialsNonExpired() + boolean isEnabled() + } + + interface GrantedAuthority { + String getAuthority() + } + note right + Aus org.springframework.security.core. + Wird für die Schnittstelle UserDetails benötigt. + Repräsentiert eine Autorisierung, die einem + Authentication Objekt gewährt wird. + end note + + class Authority { + <> Authority() + String getAuthority() + } +} + +Subscription <. SubscriptionAction: ID +Action <-- EpisodeAction +EpisodeAction .> Episode: ID +UserDetails <|.. User: <> +User -> Authority +GrantedAuthority <|.. Authority: <> + +@enduml + diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml new file mode 100644 index 0000000..432f185 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml @@ -0,0 +1,75 @@ +@startuml + +package subscriptionsAPI <> { + package subscriptionDataAccessLayer <> { + class SubscriptionDataAccessService <<@Repository>> { + <> SubscriptionDataAccessService(JpaTemplate jpaTemplate) + int uploadSubscriptions(String username, List subscriptions) + List getSubscriptions(String username) + List getSubscriptionsSince(String username, LocalDateTime time) + int addSubscriptions(String username, List addedSubscriptions) + int removeSubscriptions(String username, List removedSubscriptions) + List getTitles(String username) + } + + interface SubscriptionDao { + int uploadSubscriptions(String username, List subscriptions) + List getSubscriptions(String username) + List getSubscriptionsSince(String username, LocalDateTime time) + int addSubscriptions(String username, List addedSubscriptions) + int removeSubscriptions(String username, List removedSubscriptions) + List getTitles(String username) + } + } + + package subscriptionService <> { + class SubscriptionService <<@Service>> { + <> SubscriptionService(SubscriptionDao subscriptionDao) + int uploadSubscriptions(String username, List subscriptions) + List getSubscriptions(String username) + List getSubscriptionsSince(String username, LocalDateTime time) + int addSubscriptions(String username, List addedSubscriptions) + int removeSubscriptions(String username, List removedSubscriptions) + List getTitles(String username) + } + } + + package subscriptionController <> { + class SubscriptionController <<@Controller>>{ + ' @Autowired + <> SubscriptionController(SubscriptionService subscriptionService) + ' @GetMapping + ResponseEntity> getSubscriptions(String username, String deviceID, String functionJSONP) + ' @PutMapping + ResponseEntity uploadSubscriptions(String username, String deviceID, List subscriptions) + ' @PostMapping + ResponseEntity applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta) + ' @GetMapping + ResponseEntity getSubscriptionDelta(String username, String deviceID, long since) + ResponseEntity> getTitles(String username, String deviceID) + } + + class SubscriptionTitles { + <> SubscriptionTitles(Subscription subscription, List episodeTitles) + Subscription getSubscription() + List getEpisodesTitles() + } + + class SubscriptionDelta { + <> SubscriptionDelta(List add, List remove) + List getRemove() + LocalDate getTimestamp() + List> getUpdate_urls() + } + } + +} + +' Subscription <.. SubscriptionDataAccessService: DB +' SubscriptionAction <.. SubscriptionDataAccessService: DB +SubscriptionService --o SubscriptionController +SubscriptionDao <.. SubscriptionService: <> +SubscriptionDao <|. SubscriptionDataAccessService: <> + +@enduml + diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml new file mode 100644 index 0000000..03dfc9a --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml @@ -0,0 +1,43 @@ +@startuml + +package util <> { + class RSSParser { + <> RSSParser(String subscriptionURL) + String getSubscriptionTitle() + List getEpisodes() + Episode getEpisodeForURL(String episodeURL) + } + note bottom + Verwendet intern Spring um + HTTP-Anfragen zu erstellen. + end note + + class CleanCronJob { + <> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager) + void cleanInvalidUsers() + } + note bottom + Hintergrundservice, der in periodischen Abständen + Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden + bestätigt haben, wieder aus der Datenbank löscht. + (Auf die Assoziation zu JdbcUserDetailsManager wird + im Sinne der Übersichtlichkeit verzichtet.) + end note + + class ResponseEntity { + <> ResponseEntity(T body, HttpStatusCode status) + T getBody() + HttpStatusCode getStatusCode() + } + note bottom + Aus org.springframework.http. + Erweitert die Klasse HttpEntity, welche + ein HTTP Anfrage- oder Antwort-Objekt + repräsentiert, durch einen HttpStatusCode. + Wird von den Controller-Methoden als + Rückgabewert verwendet. + end note +} + +@enduml + diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml new file mode 100644 index 0000000..f833aa2 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml @@ -0,0 +1,68 @@ +@startuml +' skinparam linetype ortho +' skinparam groupInheritance 2 +allowmixing + +!include classdiagram-authentication.puml +!include classdiagram-episode-actions.puml +!include classdiagram-model.puml +!include classdiagram-subscriptions.puml +!include classdiagram-util.puml + +class SecurityConfigurationBasicAuth { + <> SecurityConfigurationBasicAuth() + PasswordEncoder encoder() + UserDetailsManager userDetailsService() + SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion +} +note top + Erstellt einen Servlet Filter (springSecurityFilterChain) + der für die gesamte Sicherheit zuständig ist (Schutz der URLs, + Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.). +end note + +class PSEApplication { + <> PSEApplication() + void main(String[] args) +} + +database Datenbank +Datenbank <-[hidden]d- subscriptionsAPI +Datenbank <-[hidden]d- episodeActionsAPI +Datenbank <-[hidden]d- authenticationAPI +() SQL as SQLSub +() SQL as SQLAuth +() SQL as SQLEpisode + +Datenbank -- SQLSub +Datenbank -- SQLAuth +Datenbank -- SQLEpisode + +Subscription --o SubscriptionTitles +EpisodeActionPost -o SubscriptionTitles +UserDetailsManager <.. SecurityConfigurationBasicAuth: <> + +SubscriptionController ..o PSEApplication +AuthenticationController ..o PSEApplication +EpisodeActionController ..o PSEApplication +SecurityConfigurationBasicAuth ..o PSEApplication + +PSEApplication --() HTTP + +SQLSub )-- SubscriptionDataAccessService: JPA +' SQLAuth )-- AuthenticationDataAccessService: JPA +SQLAuth )-- JdbcUserDetailsManager: JDBC +SQLEpisode )-- EpisodeActionDataAccessService: JPA + +RSSParser <. SubscriptionDataAccessService: <> +RSSParser <. EpisodeActionDataAccessService: <> +' JdbcUserDetailsManager <-- CleanCronJob + +model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode) +' Datenbank o.. Subscription: ORM +' Datenbank o.. SubscriptionAction: ORM +' Datenbank o.. Episode: ORM +' Datenbank o.. EpisodeAction: ORM +' Datenbank o.. User: ORM + +@enduml diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml b/21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml new file mode 100644 index 0000000..dea4a1d --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml @@ -0,0 +1,53 @@ +@startuml + +[App] as app +[VueRouter] as router +[NavbarComponent] as navbar +[LoginPage] as login_page +[SubscriptionsPage] as abo_page +[EpisodesPage] as episodes_page +[SettingsPage] as settings_page +[ForgotPasswordPage] as forgot_page +[ResetPasswordPage] as reset_page +note top + Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt. + Sendet das alte und neue Passwort und den JWT an die API. +end note +[RegistrationPage] as registration_page + +[SubscriptionComponent] as sub +[EpisodeComponent] as episode +[LastUpdateComponent] as last_update +[PasswordValidatorComponent] as password + +app --> router + +app --> navbar +router --> login_page +router --> forgot_page +router --> reset_page +router --> registration_page +router --> abo_page +router --> episodes_page +router --> settings_page + +navbar -[hidden] router + +episodes_page -[hidden] abo_page +login_page -[hidden] forgot_page +registration_page -[hidden] reset_page +abo_page -[hidden] settings_page +forgot_page -[hidden] episodes_page +' forgot_page -[hidden] settings_page + +abo_page --> sub +episodes_page --> episode + +sub --> last_update +episode --> last_update + +settings_page --> password +reset_page --> password +registration_page --> password + +@enduml diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/db.puml b/21-implementierungsheft-kolloquium/assets/diagrams/db.puml new file mode 100644 index 0000000..bdefaea --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/db.puml @@ -0,0 +1,78 @@ +@startuml +' Type Symbol +' Zero or One |o-- +' Exactly One ||-- +' Zero or Many }o-- +' One or Many }|-- + +skinparam linetype ortho + +entity User { + * int id <> + * String email + * String password + * boolean verified + * long created_at +} + +entity SubscriptionAction { + * int id <> + * int user_id + * long timestamp + * int subscription_id + * boolean added +} + +entity Subscription { + * int id <> + * String url + * long timestamp + * String title +} + +entity Episode { + * int id <> + * int guid <> + * String url + * String title + * int total + * int subscription_id +} +note right + Wenn der Client eine GUID aus dem Feed mitsendet, wird + diese statt der URL verwendet um die Episode zu finden. + So wird die Episode auch noch gefunden, nachdem sich + die URL geändert hat. +end note +note bottom of Episode + Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht, + dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription. + Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf + die aktuelle Zeit. + Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst + nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch + nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben. + Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden. +end note + +entity EpisodeAction { + * int id <> + * int user_id + * int episode_id + * long timestamp + * int action + * int started + * int position +} +note right + Speichere für jede Episode + nur letzte Play-Action. +endnote + +User ||--o{ EpisodeAction +User ||--o{ SubscriptionAction +SubscriptionAction }|--|| Subscription +EpisodeAction }|--|| Episode +Subscription ||-right-|{ Episode + +@enduml diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml b/21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml new file mode 100644 index 0000000..b8d0491 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml @@ -0,0 +1,59 @@ +@startuml + +node "<> \nBackend Server" as backendServer{ + database " <> \n MariaDB Server 10.6" as database { + rectangle rectangle1 [ + <> + User + ] + rectangle rectangle2 [ + <> + SubscriptionAction + ] + rectangle rectangle3 [ + <> + EpisodeAction + ] + rectangle rectangle4 [ + <> + Subscription + ] + rectangle rectangle5 [ + <> + Episode + ] + } + + node "<> \nJava Spring" as javaSpring{ + node " <> \n Tomcat Webserver" + } +} + +node "<> \nFrontend" as frontendServer { + +} + +node "<> \nEndgerät" as terminal { + node "<> \nBrowser" as browser + node "<> \nPodcatcher" as podcatcher +} + +backendServer "1" - "*" podcatcher + +node "<> \nFrontend Server" as frontendServer{ + node "<> \nVue.js" as vuejs { + + } +} + +podcatcher -[hidden] browser + +backendServer - "1" frontendServer + +database "1" -- "1" javaSpring + +browser "*" -- frontendServer + + + +@enduml diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml new file mode 100644 index 0000000..603130c --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml @@ -0,0 +1,41 @@ +@startuml + +skinparam ParticipantPadding 30 + +participant AuthenticationController << (C, #ADD1B2) @Controller >> +-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//) +activate AuthenticationController +participant AuthenticationService << (C, #ADD1B2) @Service >> +AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//) +activate AuthenticationService +participant JavaMailSenderImpl << (C, #ADD1B2) >> +AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link +activate JavaMailSenderImpl +<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password +JavaMailSenderImpl --> AuthenticationService +deactivate JavaMailSenderImpl +AuthenticationService --> AuthenticationController: int indicating status +deactivate AuthenticationService +<-- AuthenticationController: ResponseEntity indicating status \n\n-> ""HTTP status code"" +deactivate AuthenticationController +||60|| +-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//) +activate AuthenticationController +AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//) +activate AuthenticationService +participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >> +AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword) +activate JdbcUserDetailsManager +database Database +JdbcUserDetailsManager -> Database: change password of logged in user +activate Database +Database --> JdbcUserDetailsManager +deactivate Database +JdbcUserDetailsManager --> AuthenticationService: int indicating status +deactivate JdbcUserDetailsManager +AuthenticationService --> AuthenticationController: int indicating status +deactivate AuthenticationService +<-- AuthenticationController: ResponseEntity indicating status \n\n-> ""HTTP status code"" +deactivate AuthenticationController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml new file mode 100644 index 0000000..47497d5 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml @@ -0,0 +1,38 @@ +@startuml + +' title =**Get All Episode Actions** + +participant EpisodeActionController << (C, #ADD1B2) @Controller >> +-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//) +note right + Die Parameter //deviceID// und //aggregated// werden ignoriert, + da nicht zwischen Geräten unterschieden und für jede + Episode sowieso nur die letzte Play-Action gespeichert + wird. Dies gilt für alle GET-Anfragen der Episode Actions API. +end note +activate EpisodeActionController +participant EpisodeActionService << (C, #ADD1B2) @Service >> +EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"") +activate EpisodeActionService +participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >> +EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"") +activate EpisodeActionDataAccessService +EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC)) +database Database +activate EpisodeActionDataAccessService +EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts +activate Database +Database --> EpisodeActionDataAccessService: List selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none) +EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode +Database --> EpisodeActionDataAccessService +deactivate Database +EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List episodeActionPosts +deactivate EpisodeActionDataAccessService +EpisodeActionDataAccessService --> EpisodeActionService: List episodeActionPosts +deactivate EpisodeActionDataAccessService +EpisodeActionService --> EpisodeActionController: List episodeActionPosts +deactivate EpisodeActionService +<-- EpisodeActionController: ResponseEntity response \n\n-> ""HTTP status code"" \n-> ""JSON"" +deactivate EpisodeActionController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml new file mode 100644 index 0000000..d8797d1 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml @@ -0,0 +1,32 @@ +@startuml + +' title =**Get Episode Actions of Podcast Since** + +participant EpisodeActionController << (C, #ADD1B2) @Controller >> +-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//) +note right + Die Parameter //deviceID// und //aggregated// werden ignoriert. + Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**. +end note +activate EpisodeActionController +participant EpisodeActionService << (C, #ADD1B2) @Service >> +EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//) +activate EpisodeActionService +participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >> +EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//) +activate EpisodeActionDataAccessService +database Database +EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//) +activate Database +Database --> EpisodeActionDataAccessService: List selectedEpisodeActions \n-> then remove all older than //since// +EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode +Database --> EpisodeActionDataAccessService +deactivate Database +EpisodeActionDataAccessService --> EpisodeActionService: List episodeActionPosts +deactivate EpisodeActionDataAccessService +EpisodeActionService --> EpisodeActionController: List episodeActionPosts +deactivate EpisodeActionService +<-- EpisodeActionController: ResponseEntity response \n\n-> ""HTTP status code"" \n-> ""JSON"" +deactivate EpisodeActionController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml new file mode 100644 index 0000000..4d8ab90 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml @@ -0,0 +1,38 @@ +@startuml + +' title =**Get All Subscriptions** + +participant SubscriptionController << (C, #ADD1B2) @Controller >> +-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//) +activate SubscriptionController +note right + Die Parameter ""deviceid"" und + //functionJSONP// werden ignoriert, + da nicht zwischen Geräten unterschieden + und JSONP nicht unterstützt wird. +end note +participant SubscriptionService << (C, #ADD1B2) @Service >> +SubscriptionController -> SubscriptionService: getSubscriptions(""username"") +activate SubscriptionService +participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >> +SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"") +activate SubscriptionDataAccessService +SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN) +database Database +activate SubscriptionDataAccessService +SubscriptionDataAccessService -> Database: get all Subscriptions for ""username"" +activate Database +Database --> SubscriptionDataAccessService: List subscriptions +SubscriptionDataAccessService -> Database: get Podcasts from Subscriptions +Database --> SubscriptionDataAccessService: List subscribedPodcasts +deactivate Database +SubscriptionDataAccessService --> SubscriptionDataAccessService: List podcastURLs +deactivate SubscriptionDataAccessService +SubscriptionDataAccessService --> SubscriptionService: List podcastURLs +deactivate SubscriptionDataAccessService +SubscriptionService --> SubscriptionController: List podcastURLs +deactivate SubscriptionService +<-- SubscriptionController: ResponseEntity> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON"" +deactivate SubscriptionController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml new file mode 100644 index 0000000..b7b7aa1 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml @@ -0,0 +1,26 @@ +@startuml + +' title =**Register** + +participant AuthenticationController << (C, #ADD1B2) @Controller >> +-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//) +activate AuthenticationController +participant AuthenticationService << (C, #ADD1B2) @Service >> +AuthenticationController -> AuthenticationService: registerUser(//user//) +activate AuthenticationService +participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >> +AuthenticationService -> JdbcUserDetailsManager: createUser(//user//) +activate JdbcUserDetailsManager +database Database +JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//) +activate Database +Database --> JdbcUserDetailsManager +deactivate Database +JdbcUserDetailsManager --> AuthenticationService: int indicating status +deactivate JdbcUserDetailsManager +AuthenticationService --> AuthenticationController: int indicating status +deactivate AuthenticationService +<-- AuthenticationController: ResponseEntity indicating status \n\n-> ""HTTP status code"" +deactivate AuthenticationController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml new file mode 100644 index 0000000..d3dac57 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml @@ -0,0 +1,38 @@ +@startuml + +' title =**Upload Episode Actions** + +participant EpisodeActionController << (C, #ADD1B2) @Controller >> +-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//) +activate EpisodeActionController +participant EpisodeActionService << (C, #ADD1B2) @Service >> +EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts()) +activate EpisodeActionService +participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >> +EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts) +database Database +activate EpisodeActionDataAccessService +loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction() +opt episodeAction.getAction().equals(Action.PLAY) +EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL +activate Database +Database --> EpisodeActionDataAccessService +EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present +Database --> EpisodeActionDataAccessService: Optional lastEpisodeAction +opt lastEpisodeAction.isPresent() +EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction +else else +EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry +end +Database --> EpisodeActionDataAccessService +deactivate Database +end +end +EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp +deactivate EpisodeActionDataAccessService +EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC) +deactivate EpisodeActionService +<-- EpisodeActionController: ResponseEntity \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON"" +deactivate EpisodeActionController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml new file mode 100644 index 0000000..1edc8cf --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml @@ -0,0 +1,32 @@ +@startuml + +' title =**Upload Subscriptions** + +participant SubscriptionController << (C, #ADD1B2) @Controller >> +-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//) +activate SubscriptionController +participant SubscriptionService << (C, #ADD1B2) @Service >> +SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//) +activate SubscriptionService +participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >> +SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//) +activate SubscriptionDataAccessService +database Database +SubscriptionDataAccessService -> Database: delete all subsciptions of ""username"" +activate Database +Database --> SubscriptionDataAccessService +SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//) +activate SubscriptionDataAccessService +SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username"" +Database --> SubscriptionDataAccessService +deactivate Database +SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status +deactivate SubscriptionDataAccessService +SubscriptionDataAccessService --> SubscriptionService: int indicating status +deactivate SubscriptionDataAccessService +SubscriptionService --> SubscriptionController: int indicating status +deactivate SubscriptionService +<-- SubscriptionController: ResponseEntity with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON"" +deactivate SubscriptionController + +@enduml \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/episode.png b/21-implementierungsheft-kolloquium/assets/episode.png new file mode 100644 index 0000000..c0db4a2 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/episode.png differ diff --git a/21-implementierungsheft-kolloquium/assets/gantt-plan.puml b/21-implementierungsheft-kolloquium/assets/gantt-plan.puml new file mode 100644 index 0000000..0e90aa2 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/gantt-plan.puml @@ -0,0 +1,31 @@ +@startgantt + +printscale daily zoom 5 +project starts on 2023-01-30 + +-- Backend -- +[Controller-Schicht] on {Immanuel} lasts 2 days +[Service-Schicht (Daten durchreichen)] on {Daniel} lasts 2 days +[Authentifizierung] on {Gero} lasts 4 days +[Model-Paket] on {Daniel} lasts 1 days +[Datenbank aufsetzen] on {Immanuel} lasts 4 days +[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 6 days +[DataAccess-Schicht] on {Immanuel} {Julius} lasts 8 days +[Service-Schicht (Geschäftslogik)] on {Daniel} {Immanuel} lasts 8 days +[Util-Paket (CleanCronJob)] on {Julius} lasts 2 days +-- Frontend -- +[Komponenten] on {Gero} {Julius} {Lukas} lasts 15 days +[API-Anbindung] on {Gero} {Lukas} lasts 4 days + +'Backend +[Service-Schicht (Daten durchreichen)] starts at [Controller-Schicht]'s end +[Datenbank aufsetzen] starts at [Model-Paket]'s end +[Authentifizierung] starts at [Controller-Schicht]'s end +[DataAccess-Schicht] starts at [Datenbank aufsetzen]'s end +[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end +[Service-Schicht (Geschäftslogik)] starts at [DataAccess-Schicht]'s end +[Util-Paket (CleanCronJob)] starts at [DataAccess-Schicht]'s end +'Frontend +[API-Anbindung] starts at [DataAccess-Schicht]'s end + +@endgantt \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/gantt-reality.puml b/21-implementierungsheft-kolloquium/assets/gantt-reality.puml new file mode 100644 index 0000000..f726c56 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/gantt-reality.puml @@ -0,0 +1,39 @@ +@startgantt + +printscale daily zoom 5 +project starts on 2023-01-30 + +-- Backend -- +[Controller-Schicht] on {Immanuel} lasts 3 days +[Model-Paket] on {Daniel} lasts 3 days +[Datenbank aufsetzen] on {Immanuel} lasts 6 days +[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 32 days +[DAO-Interfaces] on {Julius} {Immanuel} lasts 6 days +[Authentifizierung] on {Immanuel} lasts 13 days +[Service-Schicht mit Datenzugriff] on {Julius} lasts 14 days +[Util-Paket (CleanCronJob)] on {Daniel} lasts 2 days +[Docker] on {Daniel} lasts 12 days +[EMailService] on {Gero} lasts 1 days +-- Frontend -- +[Komponenten] on {Gero} {Julius} lasts 15 days +[Mehrsprachigkeit] on {Lukas} lasts 5 days +[Router] on {Gero} lasts 1 days +[API-Anbindung] on {Gero} {Lukas} lasts 28 days +[Error-Handling] on {Gero} lasts 5 days + +'Backend +[Datenbank aufsetzen] starts at [Model-Paket]'s end +[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end +[DAO-Interfaces] starts at [Datenbank aufsetzen]'s end +[Authentifizierung] starts at [DAO-Interfaces]'s end +[Service-Schicht mit Datenzugriff] starts at [DAO-Interfaces]'s end +[Util-Paket (CleanCronJob)] starts at [DAO-Interfaces]'s end +[Docker] starts at [Util-Paket (CleanCronJob)]'s end +[EMailService] starts 2023-02-14 +'Frontend +[Mehrsprachigkeit] starts 2023-02-01 +[Router] starts at [Mehrsprachigkeit]'s end +[API-Anbindung] starts at [Router]'s end +[Error-Handling] starts 2023-02-05 + +@endgantt \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/assets/help.png b/21-implementierungsheft-kolloquium/assets/help.png new file mode 100644 index 0000000..39a1b84 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/help.png differ diff --git a/21-implementierungsheft-kolloquium/assets/lastupdate.png b/21-implementierungsheft-kolloquium/assets/lastupdate.png new file mode 100644 index 0000000..e9b7f5c Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/lastupdate.png differ diff --git a/21-implementierungsheft-kolloquium/assets/logo.svg b/21-implementierungsheft-kolloquium/assets/logo.svg new file mode 100644 index 0000000..1609066 --- /dev/null +++ b/21-implementierungsheft-kolloquium/assets/logo.svg @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Podcast Synchronisation made Efficient + + + + diff --git a/21-implementierungsheft-kolloquium/assets/navbar.png b/21-implementierungsheft-kolloquium/assets/navbar.png new file mode 100644 index 0000000..dd9f8e8 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/navbar.png differ diff --git a/21-implementierungsheft-kolloquium/assets/password-margin.png b/21-implementierungsheft-kolloquium/assets/password-margin.png new file mode 100644 index 0000000..d9d4fa3 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/password-margin.png differ diff --git a/21-implementierungsheft-kolloquium/assets/password.png b/21-implementierungsheft-kolloquium/assets/password.png new file mode 100644 index 0000000..68248a0 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/password.png differ diff --git a/21-implementierungsheft-kolloquium/assets/subscription.png b/21-implementierungsheft-kolloquium/assets/subscription.png new file mode 100644 index 0000000..58a84f9 Binary files /dev/null and b/21-implementierungsheft-kolloquium/assets/subscription.png differ diff --git a/21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg b/21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg new file mode 100644 index 0000000..70ae1d0 Binary files /dev/null and b/21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg differ diff --git a/21-implementierungsheft-kolloquium/notizen b/21-implementierungsheft-kolloquium/notizen new file mode 100644 index 0000000..70ac63b --- /dev/null +++ b/21-implementierungsheft-kolloquium/notizen @@ -0,0 +1,40 @@ +Titelseite: +- Begrüßung + +Einführung: +- Podcast: RSS-Feed, Episoden, Audio/Video +- Podcatcher: lokale Verwaltung von Podcasts, API Unterstützung, +Abspielen von Episoden +- Synchronisationsserver (das soll unser Produkt werden): Hörfortschritte, +Abonnements, Discovery (bei AntennaPod z.B. iTunes) + +Zielsetzung: + +Synchronisation (die Art, die wir bei uns anwenden): +- alle Aktionen werden auf den Server und infolge dessen auf alle Podcatcher +übertragen + +Features: +- Synchronisation: Abos, Hörfortschritt +- Weboberfläche: Aboliste, Zuletzt gehört +- Account-Verwaltung: Registrieren, Anmelden, Passwort ändern/zurücksetzen, +Account löschen, Daten importieren/exportieren + +UI-Journey: +- login.html: + - Sprache ändern + - OAuth (kann) + - Registrieren (muss): neues Fenster, E-Mail + 2-mal Passwort (sicher?), + vergeben? -> Fehler / Bestätigungslink per E-Mail (gültig 24h) + - Anmelden (muss): E-Mail + Passwort eingeben, Login merken, + login, Fehlermeldung oder Dashboard + - Passwort vergessen: neues Fenster, E-Mail eingeben, falls Account wird + Link versendet, 24h gültig, nach betätigen PW zweimal eingeben & bestätigen + (Anforderungen) + +- podcasts.html: Abonnements, Eisoden, Hörfortschritte + +- listening.html: Zuletzt gehörte Episoden, Hörfortschritt, Wann gehört + +- settings.html: PW ändern, Gpodder Import, pers. Daten imp./exp., + Account löschen diff --git a/21-implementierungsheft-kolloquium/presentation.tex b/21-implementierungsheft-kolloquium/presentation.tex new file mode 100644 index 0000000..88cb357 --- /dev/null +++ b/21-implementierungsheft-kolloquium/presentation.tex @@ -0,0 +1,53 @@ +%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design +%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020 +%% +%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen + +%% Beispiel-Präsentation +\documentclass[table]{sdqbeamer} + +\usepackage{calc} +\usepackage{multicol} +\usepackage{fontawesome5} +\usepackage{ulem} + +%% Titelbild +\titleimage{banner_2020_kit} + +%% Gruppenlogo +\grouplogo{kitlogo_de_rgb} + +%% Gruppenname und Breite (Standard: 50 mm) +\groupname{Praxis der Softwareentwicklung} +%\groupnamewidth{50mm} + +% Beginn der Präsentation + +\title[Kolloquium Implementierung]{ + PSE\textsuperscript{2} - Podcast Synchronisation made Efficient +} +\subtitle{Kolloquium Implementierung} +\author[Lukas Schmidheissler]{Lukas Schmidheissler} + +\date[28.\,02.\,2023]{28. Februar 2023} + +\begin{document} + +%Titelseite +\KITtitleframe + +%\include{slides/classdiagram} + +\include{slides/integrationstrategie} + +\include{slides/gantt} + +\include{slides/difficulties} + +\include{slides/changes} + +\include{slides/statistics} + +\include{slides/requirements} + +\end{document} diff --git a/21-implementierungsheft-kolloquium/sdqbeamer.cls b/21-implementierungsheft-kolloquium/sdqbeamer.cls new file mode 100644 index 0000000..1b9c2b8 --- /dev/null +++ b/21-implementierungsheft-kolloquium/sdqbeamer.cls @@ -0,0 +1,975 @@ +%% Vorlage für Präsentationen mit LaTeX Beamer im KIT-Design +%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020 +%% +%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen + + +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{sdqbeamer}[2022-05-03 v3.1.3 SDQ Beamer class] + +\RequirePackage[utf8]{inputenc} +\RequirePackage[T1]{fontenc} + +\newif\ifsectionnavigation +\newif\ifnavbarinfoot +\newif\ifnavbarinline +\newif\ifnavbarside +\newif\iffourtothree +\newif\ifsixteentonine +\newif\ifsixteentoten +\newif\ifgerman +\newif\ifsmallfooterfont + +\def\kitslogan#1{\def\@kitslogan{#1}} +\def\kitlogo#1{\def\@kitlogo{#1}} +\def\groupname#1{\def\@groupname{#1}} +\def\groupnamewidth#1{\def\@groupnamewidth{#1}} + +% siehe README.md +\DeclareOption{de}{ + \kitslogan{KIT -- Die Forschungsuniversität in der Helmholtz-Gemeinschaft} + \kitlogo{pse_logo} + \germantrue + \PassOptionsToPackage{autostyle}{csquotes} + } +\DeclareOption{en}{ + \kitslogan{KIT -- The Research University in the Helmholtz Association} + \kitlogo{kitlogo_en_rgb} + \germanfalse + } +\DeclareOption{4:3}{ + \fourtothreetrue + \sixteentoninefalse + \sixteentotenfalse +} +\DeclareOption{16:9}{ + \fourtothreefalse + \sixteentoninetrue + \sixteentotenfalse +} +\DeclareOption{16:10}{ + \fourtothreefalse + \sixteentoninefalse + \sixteentotentrue +} +\DeclareOption{navbarside}{ + \sectionnavigationtrue + \navbarsidetrue + \navbarinlinefalse + \navbarinfootfalse +} +\DeclareOption{navbarinline}{ + \sectionnavigationtrue + \navbarsidefalse + \navbarinlinetrue + \navbarinfootfalse +} +\DeclareOption{navbarinfooter}{ + \sectionnavigationtrue + \navbarsidefalse + \navbarinlinefalse + \navbarinfoottrue +} +\DeclareOption{navbaroff}{ + \sectionnavigationfalse +} +\DeclareOption{navbarkit}{ + \sectionnavigationfalse + \smallfooterfonttrue +} +\DeclareOption{smallfoot}{ + \smallfooterfonttrue +} +\DeclareOption{bigfoot}{ + \smallfooterfontfalse +} + +\ExecuteOptions{de,16:9,navbarinline,bigfoot} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{beamer}} + +\ProcessOptions\relax + +\LoadClass[10pt,utf8]{beamer} + +% Babel-Paket wird nur bei deutscher Sprache benötigt +\ifgerman + \RequirePackage[ngerman]{babel} +\fi +\RequirePackage{csquotes} +\RequirePackage{hyperref} +\RequirePackage[absolute,overlay]{textpos} + +%% --------------- +%% | Typographie | +%% --------------- + +\RequirePackage{microtype} + +\RequirePackage[scaled=.92]{helvet} +\RequirePackage[scaled=.78]{beramono} +\RequirePackage{libertineRoman} + +\setbeamerfont{title}{series=\bfseries,size=\Large} +\setbeamerfont{frametitle}{series=\bfseries,size=\Large} +\setbeamerfont{framesubtitle}{series=\bfseries,size=\normalsize} + +%% ----------------- +%% | Folien-Layout | +%% ----------------- + +% Seitenverhältnis +% +% Die Folien sind auf die Standardhöhe in LaTeX Beamer (9,6 cm) normiert. +% Die Maße der KIT-Gestaltungsrichtlinien (Folienhöhe 14,3 cm) wurden durch +% den Quotienten 1,5 geteilt. + +\RequirePackage{geometry} +\iffourtothree + \geometry{papersize={12.8cm,9.6cm}} +\fi +\ifsixteentoten + \geometry{papersize={15.36cm,9.6cm}} +\fi +\ifsixteentonine + \geometry{papersize={17.07cm,9.6cm}} +\fi + +% Ränder laut Gestaltungsrichtlinen; 3 mm -> 2 mm, 11 mm -> 7,3 mm +\newlength{\kitoutermargin} +\setlength{\kitoutermargin}{2mm} +\newlength{\kitinnermargin} +\setlength{\kitinnermargin}{7.3mm} +\newlength{\kitbottommargin} +\setlength{\kitbottommargin}{\kitinnermargin} + +% Ränder außen +\setbeamersize{text margin left=\kitinnermargin,text margin right=\kitinnermargin} + +% keine Navigationssymbole +\setbeamertemplate{navigation symbols}{} +\setbeamercovered{invisible} +\useinnertheme{rounded} +\beamer@compresstrue % Miniframes (Navigations-Punkte) für Subsections immer in einer Zeile, ohne Umbrüche + +% Folientitel +\setbeamertemplate{frametitle}{ + \ifbeamer@plainframe\else% + % Unterkante Titeltext: 22,5 mm -> 15 mm von Seitenkopf + \begin{textblock*}{\dimexpr\paperwidth-30mm-2\kitinnermargin}[0,1](\kitinnermargin,15mm)% + \usebeamerfont{frametitle}\insertframetitle% + \ifx\insertframesubtitle\@empty\else\\[.1em]\fi + \usebeamerfont{framesubtitle}\insertframesubtitle% + \end{textblock*}% + \begin{textblock*}{20mm}[1,1](\dimexpr\paperwidth-\kitinnermargin\relax,15mm)%j + \includegraphics[width=20mm]{logos/\@kitlogo}% + \end{textblock*}% + \fi +% Rand oben (ergibt Beginn des Textes bei 34 mm -> 22,7 mm) + \vspace {18mm} +} + +%% Fußzeile +\newlength{\kitbottom} + % Navbar in Footer: Schmale Fußzeile +\ifnavbarinfoot + % Bei Navbar in Footer immer kleiner Font in der Fußzeile + \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont} + \setlength{\kitbottom}{4mm} +\else + % Ansonsten kleiner Text nur, wenn "smallfoot" gewählt + \ifsmallfooterfont + \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont} + \else + \setbeamerfont{footer}{size=\scriptsize} + \fi + \setlength{\kitbottom}{\kitbottommargin} +\fi +\setbeamerfont{page number in head/foot}{series=\bfseries} + +\newlength{\kitbottomdepth} +\newlength{\kitbottomheight} +\newlength{\kitfootergroupwidth} + +\setbeamertemplate{footline}{% +\setlength{\kitbottomdepth}{\dimexpr.5\kitbottom-.5em\relax}% +\setlength{\kitbottomheight}{\dimexpr.5\kitbottom+.5em\relax}% + %% die "%" am Ende sind nötig, damit keine Abstände eingefügt werden + % + % Falls kein Gruppenname angegeben, die ganze Breite der Fußzeile für den Titel nutzen. + \ifdefined\@groupname% + \ifx\@groupname\empty% + \setlength{\kitfootergroupwidth}{0mm}% + \else% + % Falls die Breite des Gruppenlogos definiert ist, diese nehmen, sonst 50 mm + \ifdefined\@groupnamewidth% + \setlength{\kitfootergroupwidth}{\@groupnamewidth}% + \else% + \setlength{\kitfootergroupwidth}{50mm}% + \fi% + \fi% + \else + \setlength{\kitfootergroupwidth}{0mm}% + \fi + \usebeamerfont{footer}% + \ifsectionnavigation% + % Option "navbarinline" + \ifnavbarinline% + \begin{beamercolorbox}[wd=\paperwidth, leftskip=2mm, rightskip=2mm]{} + \insertnavigation{\dimexpr\paperwidth-4mm\relax} + \vspace{1mm} + \end{beamercolorbox}% + \fi% + % Option "navbarinfooter" + \ifnavbarinfoot% + % Punkte für Subsections deaktivieren + \setbeamertemplate{mini frames}{}% + \begin{beamercolorbox}[wd=\paperwidth, leftskip=1mm, rightskip=1mm]{}% + \insertsectionnavigationhorizontal{\dimexpr\paperwidth-\kitoutermargin\relax}{}{} + \end{beamercolorbox}% + \fi% + \fi% + \leavevmode% + \begin{beamercolorbox}[wd=13mm, ht=\kitbottomheight, dp=\kitbottomdepth, leftskip=4mm]{} + \usebeamerfont{page number in head/foot}% + \strut\insertframenumber{}/\inserttotalframenumber% + \end{beamercolorbox}% + \begin{beamercolorbox}[wd=20mm, ht=\kitbottomheight, dp=\kitbottomdepth]{} + \usebeamerfont{date in head/foot}% + \strut\insertshortdate% + \end{beamercolorbox}% + % Die Boxen mit dem Titel und dem Gruppennamen sind vertikal zentriert, damit auch zweizeilige Texte schön aussehen + % Daher müssen sie um \kitbottomdepth nach unten verschoben werden + \raisebox{-\kitbottomdepth}{ + % Die Box hat daher auch Höhe \kitbottom und Tiefe 0mm + \begin{beamercolorbox}[wd=\dimexpr\paperwidth-37mm-\kitfootergroupwidth, ht=\kitbottom, dp=0mm]{}% + % Inhalt vertikal zentrieren; Anpassung um 1.5 pt, damit bei einzeiligem Inhalt genau die Baseline der Blöcke mit Seitenzahl und Datum getroffen wird + \vbox to\kitbottom{\vfill\vskip1.5pt% + \beamer@shortauthor\ifx\beamer@shortauthor\empty\else: \fi\beamer@shorttitle% + \vfill}% + \end{beamercolorbox}% + \ifdefined\@groupname% + \begin{beamercolorbox}[wd=\kitfootergroupwidth, ht=\kitbottom, dp=0mm, rightskip=\kitinnermargin]{} + \vbox to\kitbottom{\vfill\vskip1.5pt% + \raggedleft\@groupname% + \vfill}% + \end{beamercolorbox}% + \fi% + }% +} + +%% Option "navbarside" +\ifnavbarside +\useoutertheme[height=0cm,width=3.5cm,left]{sidebar} + +\setbeamerfont{title in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{10pt}{11pt}}} +\setbeamerfont{section in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{9pt}{9.9pt}}} +\setbeamerfont{subsection in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{8pt}{8.8pt}}} + +\setbeamertemplate{sidebar \beamer@sidebarside} + {\vskip1.5cm% + \hskip6.5mm% + \advance\beamer@sidebarwidth by -5mm% + \insertverticalnavigation{\beamer@sidebarwidth}% + }% +\fi + +%% Hintergrund +\usebackgroundtemplate{ + % Trennlinie nicht bei "plain"-Frames + \ifbeamer@plainframe\else\kitseparationline\fi +} + +% Trennlinie +\newcommand{\kitseparationline}{ + \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\paperheight} + \pgfsetstrokecolor{black!15} + \pgfsetlinewidth{.5pt} + \pgfpathmoveto{\pgfpoint{\kitoutermargin}{\kitinnermargin}} + \pgfpathlineto{\pgfpoint{\paperwidth-\kitoutermargin}{\kitinnermargin}} + \pgfusepath{stroke} + \end{pgfpicture}% +} + + +%% -------------- +%% | Titelseite | +%% -------------- + +\def\titleimage#1{\def\@titleimage{#1}} +\def\grouplogo#1{\def\@grouplogo{#1}} + +\newcommand{\KITtitleframe}{ + \begin{frame}[plain] + \titlepage + \end{frame} +} + +\newlength{\kittitleimageheight} +\setbeamertemplate{title page}{ + % From textpos documentation (https://ctan.org/pkg/textpos) + % + % \begin{textblock}{}[,](,) + % The coordinates and are fractions of the width and height of the text + % box, respectively, and state that the box is to be placed so that the reference point + % (,) within the box is to be placed at the point (,) on the page. + + % KIT-Logo + \begin{textblock*}{30mm}(\kitinnermargin,6.7mm) + \includegraphics[width=30mm]{logos/\@kitlogo} + \end{textblock*} + + % Gruppenlogo + \ifdefined\@grouplogo + \ifx\@grouplogo\empty \else + \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm) + \includegraphics[width=20mm,height=20mm,keepaspectratio]{logos/\@grouplogo} + \end{textblock*} + \fi % falls \grouplogo{} aufgerufen wird, kein Gruppenlogo einbinden + \else + \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm) + \colorbox{kit-purple100!20}{\parbox[t][12mm][c]{19mm}{\color{kit-purple100}\scriptsize\centering + \ifgerman + Bitte Logo über \texttt{\textbackslash grouplogo\{\}} festlegen. + \else + Please set a logo using \texttt{\textbackslash grouplogo\{\}}. + \fi + }} + \end{textblock*} + \fi + + % Titel + \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}[0,.5](\kitinnermargin,28mm) + \usebeamerfont*{title}\inserttitle + \end{textblock*} + + % Untertitel + \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,36mm) + \small\textbf{\insertsubtitle} + \end{textblock*} + + % Autor + \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,41mm) + \small\insertauthor~\textbar~\insertdate + \end{textblock*} + + % Titelbild + \setlength{\kittitleimageheight}{40mm} + \begin{textblock*}{\paperwidth}(\kitoutermargin,\dimexpr\paperheight-\kitbottommargin-\kittitleimageheight) + \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\kittitleimageheight} + % Clipping-Pfad um titelbild + \pgfsetstrokecolor{black!15} + \pgfsetlinewidth{1pt} + \pgfsetcornersarced{\pgfpoint{3mm}{3mm}} + \pgfpathmoveto{\pgfpoint{\paperwidth-2\kitoutermargin}{0mm}} + \pgfpathlineto{\pgfpoint{\paperwidth-2\kitoutermargin}{\kittitleimageheight}} + \pgfsetcornersarced{\pgfpointorigin} + \pgfpathlineto{\pgfpoint{0mm}{\kittitleimageheight}} + \pgfsetcornersarced{\pgfpoint{3mm}{3mm}} + \pgfpathlineto{\pgfpointorigin} + \pgfsetcornersarced{\pgfpointorigin} + \pgfpathclose + \pgfusepath{stroke,clip} + \pgfsetstrokecolor{black} + + % Titelbild + \ifdefined\@titleimage + \ifx\@titleimage\empty \else% + \pgftext[at=\pgfpoint{.5\paperwidth}{0mm},center,bottom]{% + \includegraphics[height=40mm]{logos/\@titleimage} + } + \fi % Bei Aufruf von \titleimage{} leeren Rahmen anzeigen. + \else + \pgftext[at=\pgfpoint{.5\paperwidth}{.5\kittitleimageheight},center,base]{% + \colorbox{kit-purple100!20}{\parbox[c][\kittitleimageheight][c]{\paperwidth}{\color{kit-purple100}\centering Bitte Titelbild über \texttt{\textbackslash titleimage\{\}} festlegen. + }}% + } + \fi + + + \end{pgfpicture}% + \end{textblock*} + + + % KIT slogan + \begin{textblock*}{80mm}[0,.5](\kitoutermargin,\dimexpr\paperheight-.5\kitbottommargin) + \fontsize{5.5pt}{5.5pt}\selectfont\@kitslogan + \end{textblock*} + + \begin{textblock*}{30mm}[1,.5](\dimexpr\paperwidth-\kitoutermargin\relax,\dimexpr\paperheight-.5\kitbottommargin) + \fontsize{11pt}{11pt}\selectfont\bfseries\raggedleft% + {\href{https://www.kit.edu}{www.kit.edu}} + \end{textblock*} + +} +%% --------------- +%% | /Titelseite | +%% --------------- + +%% ---------- +%% | Farben | +%% ---------- +%% KIT-Farbschema + +% KIT color green : +\definecolor{kit-green}{RGB}{0, 150, 130} +\definecolor{kit-green100}{RGB}{0, 150, 130} +\definecolor{kit-green90}{rgb}{0.1, 0.6294, 0.5588} +\definecolor{kit-green80}{rgb}{0.2, 0.6706, 0.6078} +\definecolor{kit-green75}{rgb}{0.25, 0.6912, 0.6324} +\definecolor{kit-green70}{rgb}{0.3, 0.7118, 0.6569} +\definecolor{kit-green60}{rgb}{0.4, 0.7529, 0.7059} +\definecolor{kit-green50}{rgb}{0.5, 0.7941, 0.7549} +\definecolor{kit-green40}{rgb}{0.6, 0.8353, 0.8039} +\definecolor{kit-green30}{rgb}{0.7, 0.8765, 0.8529} +\definecolor{kit-green25}{rgb}{0.75, 0.8971, 0.8775} +\definecolor{kit-green20}{rgb}{0.8, 0.9176, 0.902} +\definecolor{kit-green15}{rgb}{0.85, 0.9382, 0.9265} +\definecolor{kit-green10}{rgb}{0.9, 0.9588, 0.951} +\definecolor{kit-green5}{rgb}{0.95, 0.9794, 0.9755} + +% KIT color blue: +\definecolor{kit-blue}{RGB}{70, 100, 170} +\definecolor{kit-blue100}{RGB}{70, 100, 170} +\definecolor{kit-blue90}{rgb}{0.3471, 0.4529, 0.7} +\definecolor{kit-blue80}{rgb}{0.4196, 0.5137, 0.7333} +\definecolor{kit-blue75}{rgb}{0.4559, 0.5441, 0.75} +\definecolor{kit-blue70}{rgb}{0.4922, 0.5745, 0.7667} +\definecolor{kit-blue60}{rgb}{0.5647, 0.6353, 0.8} +\definecolor{kit-blue50}{rgb}{0.6373, 0.6961, 0.8333} +\definecolor{kit-blue40}{rgb}{0.7098, 0.7569, 0.8667} +\definecolor{kit-blue30}{rgb}{0.7824, 0.8176, 0.9} +\definecolor{kit-blue25}{rgb}{0.8186, 0.848, 0.9167} +\definecolor{kit-blue20}{rgb}{0.8549, 0.8784, 0.9333} +\definecolor{kit-blue15}{rgb}{0.8912, 0.9088, 0.95} +\definecolor{kit-blue10}{rgb}{0.9275, 0.9392, 0.9667} +\definecolor{kit-blue5}{rgb}{0.9637, 0.9696, 0.9833} + +% KIT color red : +\definecolor{kit-red}{RGB}{162, 34, 35} +\definecolor{kit-red100}{RGB}{162, 34, 35} +\definecolor{kit-red90}{rgb}{0.6718, 0.22, 0.2235} +\definecolor{kit-red80}{rgb}{0.7082, 0.3067, 0.3098} +\definecolor{kit-red75}{rgb}{0.7265, 0.35, 0.3529} +\definecolor{kit-red70}{rgb}{0.7447, 0.3933, 0.3961} +\definecolor{kit-red60}{rgb}{0.7812, 0.48, 0.4824} +\definecolor{kit-red50}{rgb}{0.8176, 0.5667, 0.5686} +\definecolor{kit-red40}{rgb}{0.8541, 0.6533, 0.6549} +\definecolor{kit-red30}{rgb}{0.8906, 0.74, 0.7412} +\definecolor{kit-red25}{rgb}{0.9088, 0.7833, 0.7843} +\definecolor{kit-red20}{rgb}{0.9271, 0.8267, 0.8275} +\definecolor{kit-red15}{rgb}{0.9453, 0.87, 0.8706} +\definecolor{kit-red10}{rgb}{0.9635, 0.9133, 0.9137} +\definecolor{kit-red5}{rgb}{0.9818, 0.9567, 0.9569} + +% KIT color yellow : +\definecolor{kit-yellow}{RGB}{252, 229, 0} +\definecolor{kit-yellow100}{RGB}{252, 229, 0} +\definecolor{kit-yellow90}{rgb}{0.9894, 0.9082, 0.1} +\definecolor{kit-yellow80}{rgb}{0.9906, 0.9184, 0.2} +\definecolor{kit-yellow75}{rgb}{0.9912, 0.9235, 0.25} +\definecolor{kit-yellow70}{rgb}{0.9918, 0.9286, 0.3} +\definecolor{kit-yellow60}{rgb}{0.9929, 0.9388, 0.4} +\definecolor{kit-yellow50}{rgb}{0.9941, 0.949, 0.5} +\definecolor{kit-yellow40}{rgb}{0.9953, 0.9592, 0.6} +\definecolor{kit-yellow30}{rgb}{0.9965, 0.9694, 0.7} +\definecolor{kit-yellow25}{rgb}{0.9971, 0.9745, 0.75} +\definecolor{kit-yellow20}{rgb}{0.9976, 0.9796, 0.8} +\definecolor{kit-yellow15}{rgb}{0.9982, 0.9847, 0.85} +\definecolor{kit-yellow10}{rgb}{0.9988, 0.9898, 0.9} +\definecolor{kit-yellow5}{rgb}{0.9994, 0.9949, 0.95} + +% KIT color orange : +\definecolor{kit-orange}{RGB}{223, 155, 27} +\definecolor{kit-orange100}{RGB}{223, 155, 27} +\definecolor{kit-orange90}{rgb}{0.8871, 0.6471, 0.1953} +\definecolor{kit-orange80}{rgb}{0.8996, 0.6863, 0.2847} +\definecolor{kit-orange75}{rgb}{0.9059, 0.7059, 0.3294} +\definecolor{kit-orange70}{rgb}{0.9122, 0.7255, 0.3741} +\definecolor{kit-orange60}{rgb}{0.9247, 0.7647, 0.4635} +\definecolor{kit-orange50}{rgb}{0.9373, 0.8039, 0.5529} +\definecolor{kit-orange40}{rgb}{0.9498, 0.8431, 0.6424} +\definecolor{kit-orange30}{rgb}{0.9624, 0.8824, 0.7318} +\definecolor{kit-orange25}{rgb}{0.9686, 0.902, 0.7765} +\definecolor{kit-orange20}{rgb}{0.9749, 0.9216, 0.8212} +\definecolor{kit-orange15}{rgb}{0.9812, 0.9412, 0.8659} +\definecolor{kit-orange10}{rgb}{0.9875, 0.9608, 0.9106} +\definecolor{kit-orange5}{rgb}{0.9937, 0.9804, 0.9553} + +% KIT color lightgreen : +\definecolor{kit-lightgreen}{RGB}{140, 182, 60} +\definecolor{kit-lightgreen100}{RGB}{140, 182, 60} +\definecolor{kit-lightgreen90}{rgb}{0.5941, 0.7424, 0.3118} +\definecolor{kit-lightgreen80}{rgb}{0.6392, 0.771, 0.3882} +\definecolor{kit-lightgreen75}{rgb}{0.6618, 0.7853, 0.4265} +\definecolor{kit-lightgreen70}{rgb}{0.6843, 0.7996, 0.4647} +\definecolor{kit-lightgreen60}{rgb}{0.7294, 0.8282, 0.5412} +\definecolor{kit-lightgreen50}{rgb}{0.7745, 0.8569, 0.6176} +\definecolor{kit-lightgreen40}{rgb}{0.8196, 0.8855, 0.6941} +\definecolor{kit-lightgreen30}{rgb}{0.8647, 0.9141, 0.7706} +\definecolor{kit-lightgreen25}{rgb}{0.8873, 0.9284, 0.8088} +\definecolor{kit-lightgreen20}{rgb}{0.9098, 0.9427, 0.8471} +\definecolor{kit-lightgreen15}{rgb}{0.9324, 0.9571, 0.8853} +\definecolor{kit-lightgreen10}{rgb}{0.9549, 0.9714, 0.9235} +\definecolor{kit-lightgreen5}{rgb}{0.9775, 0.9857, 0.9618} + + +% KIT color purple : +\definecolor{kit-purple}{RGB}{163, 16, 124} +\definecolor{kit-purple100}{RGB}{163, 16, 124} +\definecolor{kit-purple90}{rgb}{0.6753, 0.1565, 0.5376} +\definecolor{kit-purple80}{rgb}{0.7114, 0.2502, 0.589} +\definecolor{kit-purple75}{rgb}{0.7294, 0.2971, 0.6147} +\definecolor{kit-purple70}{rgb}{0.7475, 0.3439, 0.6404} +\definecolor{kit-purple60}{rgb}{0.7835, 0.4376, 0.6918} +\definecolor{kit-purple50}{rgb}{0.8196, 0.5314, 0.7431} +\definecolor{kit-purple40}{rgb}{0.8557, 0.6251, 0.7945} +\definecolor{kit-purple30}{rgb}{0.8918, 0.7188, 0.8459} +\definecolor{kit-purple25}{rgb}{0.9098, 0.7657, 0.8716} +\definecolor{kit-purple20}{rgb}{0.9278, 0.8125, 0.8973} +\definecolor{kit-purple15}{rgb}{0.9459, 0.8594, 0.9229} +\definecolor{kit-purple10}{rgb}{0.9639, 0.9063, 0.9486} +\definecolor{kit-purple5}{rgb}{0.982, 0.9531, 0.9743} + +% KIT color brown : +\definecolor{kit-brown}{RGB}{167, 130, 46} +\definecolor{kit-brown100}{RGB}{167, 130, 46} +\definecolor{kit-brown90}{rgb}{0.6894, 0.5588, 0.2624} +\definecolor{kit-brown80}{rgb}{0.7239, 0.6078, 0.3443} +\definecolor{kit-brown75}{rgb}{0.7412, 0.6324, 0.3853} +\definecolor{kit-brown70}{rgb}{0.7584, 0.6569, 0.4263} +\definecolor{kit-brown60}{rgb}{0.7929, 0.7059, 0.5082} +\definecolor{kit-brown50}{rgb}{0.8275, 0.7549, 0.5902} +\definecolor{kit-brown40}{rgb}{0.862, 0.8039, 0.6722} +\definecolor{kit-brown30}{rgb}{0.8965, 0.8529, 0.7541} +\definecolor{kit-brown25}{rgb}{0.9137, 0.8775, 0.7951} +\definecolor{kit-brown20}{rgb}{0.931, 0.902, 0.8361} +\definecolor{kit-brown15}{rgb}{0.9482, 0.9265, 0.8771} +\definecolor{kit-brown10}{rgb}{0.9655, 0.951, 0.918} +\definecolor{kit-brown5}{rgb}{0.9827, 0.9755, 0.959} + +% KIT color cyan : +\definecolor{kit-cyan}{RGB}{35, 161, 224} +\definecolor{kit-cyan100}{RGB}{35, 161, 224} +\definecolor{kit-cyan90}{rgb}{0.2235, 0.6682, 0.8906} +\definecolor{kit-cyan80}{rgb}{0.3098, 0.7051, 0.9027} +\definecolor{kit-cyan75}{rgb}{0.3529, 0.7235, 0.9088} +\definecolor{kit-cyan70}{rgb}{0.3961, 0.742, 0.9149} +\definecolor{kit-cyan60}{rgb}{0.4824, 0.7788, 0.9271} +\definecolor{kit-cyan50}{rgb}{0.5686, 0.8157, 0.9392} +\definecolor{kit-cyan40}{rgb}{0.6549, 0.8525, 0.9514} +\definecolor{kit-cyan30}{rgb}{0.7412, 0.8894, 0.9635} +\definecolor{kit-cyan25}{rgb}{0.7843, 0.9078, 0.9696} +\definecolor{kit-cyan20}{rgb}{0.8275, 0.9263, 0.9757} +\definecolor{kit-cyan15}{rgb}{0.8706, 0.9447, 0.9818} +\definecolor{kit-cyan10}{rgb}{0.9137, 0.9631, 0.9878} +\definecolor{kit-cyan5}{rgb}{0.9569, 0.9816, 0.9939} + +% KIT color gray : +\definecolor{kit-gray}{RGB}{0, 0, 0} +\definecolor{kit-gray100}{RGB}{0, 0, 0} +\definecolor{kit-gray90}{rgb}{0.1, 0.1, 0.1} +\definecolor{kit-gray80}{rgb}{0.2, 0.2, 0.2} +\definecolor{kit-gray75}{rgb}{0.25, 0.25, 0.25} +\definecolor{kit-gray70}{rgb}{0.3, 0.3, 0.3} +\definecolor{kit-gray60}{rgb}{0.4, 0.4, 0.4} +\definecolor{kit-gray50}{rgb}{0.5, 0.5, 0.5} +\definecolor{kit-gray40}{rgb}{0.6, 0.6, 0.6} +\definecolor{kit-gray30}{rgb}{0.7, 0.7, 0.7} +\definecolor{kit-gray25}{rgb}{0.75, 0.75, 0.75} +\definecolor{kit-gray20}{rgb}{0.8, 0.8, 0.8} +\definecolor{kit-gray15}{rgb}{0.85, 0.85, 0.85} +\definecolor{kit-gray10}{rgb}{0.9, 0.9, 0.9} +\definecolor{kit-gray5}{rgb}{0.95, 0.95, 0.95} + + + +\setbeamercolor*{normal text}{fg=black} +\setbeamercolor*{alerted text}{fg=kit-red100} +\setbeamercolor*{example text}{fg=black} +\setbeamercolor*{structure}{fg=black} + +\setbeamercolor*{palette primary}{fg=black,bg=black!15} +\setbeamercolor*{palette secondary}{fg=black,bg=black!15} +\setbeamercolor*{palette tertiary}{fg=black,bg=black!15} +\setbeamercolor*{palette quaternary}{fg=black,bg=black!15} + +\setbeamercolor*{palette sidebar primary}{fg=black!75} +\setbeamercolor*{palette sidebar secondary}{fg=black!75} +\setbeamercolor*{palette sidebar tertiary}{fg=black!75} +\setbeamercolor*{palette sidebar quaternary}{fg=black!75} + +\setbeamercolor*{item projected}{fg=white,bg=kit-green100} + +\setbeamercolor*{block title}{fg=white,bg=kit-green100} +\setbeamercolor*{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!black} +\setbeamercolor*{block title example}{fg=white,bg=kit-blue100} + +\setbeamercolor*{block body}{fg=black,bg=kit-green15} +\setbeamercolor*{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!10!bg} +\setbeamercolor*{block body example}{fg=black,bg=kit-blue15} + +\setbeamercolor*{separation line}{} +\setbeamercolor*{fine separation line}{} + +\setbeamercolor*{background canvas}{bg=white} + +%% ----------- +%% | /Farben | +%% ----------- + +%% ----------------------------------- +%% | halbgerundete Aufzählungspunkte | +%% ----------------------------------- + +\newcommand{\itemizeColor}{kit-green100} + +% KIT-Aufzählungszeichen +\newcommand{\KITmark}{% + \begin{pgfpicture}{0mm}{0mm}{1ex}{1ex} + {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}} + \pgfpathmoveto{\pgfpoint{0cm}{1ex}} + \pgfpathlineto{\pgfpoint{1ex}{1ex}} + \pgfpathlineto{\pgfpoint{1ex}{0cm}}} + {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}} + \pgfpathmoveto{\pgfpoint{1ex}{0cm}} + \pgfpathlineto{\pgfpointorigin} + \pgfpathlineto{\pgfpoint{0cm}{1ex}}} + \color{\itemizeColor} + \pgfusepath{fill} + \end{pgfpicture}% +} + +% \setbeamertemplate{itemize items}{\raisebox{.2ex}{\KITmark}} +\setbeamertemplate{itemize items}[square] +\setbeamercolor{itemize item}{fg=kit-green100} + +%% ---------------------- +%% | Inhaltsverzeichnis | +%% ---------------------- + +\setbeamertemplate{section in toc}{\normalsize\textbf{\textcolor{kit-blue}{\inserttocsectionnumber.~\inserttocsection}}\par} +\setbeamertemplate{subsection in toc}{\small\hspace{1.2em}\raisebox{.2ex}{\KITmark}\hspace{\labelsep}\inserttocsubsection\par} + +%% ------------------------------ +%% | halbgerundete Beamer-Boxen | +%% ------------------------------ + +\renewcommand\beamerboxesrounded[2][]{% + \global\let\beamer@firstlineitemizeunskip=\relax% + \vbox\bgroup% + \setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false}% + \setkeys{beamerboxes}{#1}% + {% + \usebeamercolor{\bmb@lower}% + \globalcolorstrue% + \colorlet{lower.bg}{bg}% + }% + {% + \usebeamercolor{\bmb@upper}% + \globalcolorstrue% + \colorlet{upper.bg}{bg}% + }% + % + % Typeset head + % + \vskip4bp + \setbox\bmb@box=\hbox{% + \begin{minipage}[b]{\bmb@width}% + \usebeamercolor[fg]{\bmb@upper}% + #2% + \end{minipage}}% + \ifdim\wd\bmb@box=0pt% + \setbox\bmb@box=\hbox{}% + \ht\bmb@box=1.5pt% + \bmb@prevheight=-4.5pt% + \else% + \wd\bmb@box=\bmb@width% + \bmb@temp=\dp\bmb@box% + \ifdim\bmb@temp<1.5pt% + \bmb@temp=1.5pt% + \fi% + \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}% + \dp\bmb@box=0pt% + \bmb@prevheight=\ht\bmb@box% + \fi% + \bmb@temp=\bmb@width% + \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp% + \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp% + \hbox{% + \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box} + \ifdim\wd\bmb@box=0pt% + \color{lower.bg}% + \else% + \color{upper.bg}% + \fi% + \pgfpathqmoveto{-4bp}{-1bp} + % Adaption for "KIT-Design" + \pgfpathlineto{\pgfpoint{-4bp}{3bp}} + %\pgfpathqcurveto{-4bp}{1.2bp}{-2.2bp}{3bp}{0bp}{3bp} + \pgfpathlineto{\pgfpoint{\bmb@temp}{3bp}} + \pgfpathcurveto% + {\pgfpoint{\bmb@dima}{3bp}}% + {\pgfpoint{\bmb@dimb}{1.2bp}}% + {\pgfpoint{\bmb@dimb}{-1bp}}% + \bmb@dima=-\ht\bmb@box% + \advance\bmb@dima by-2pt% + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}} + \pgfusepath{fill} + \end{pgfpicture}% + \copy\bmb@box% + }% + \nointerlineskip% + \vskip-1pt% + \ifdim\wd\bmb@box=0pt% + \else% + \hbox{% + \begin{pgfpicture}{0pt}{0pt}{\bmb@width}{6pt} + \bmb@dima=\bmb@width% + \advance\bmb@dima by8bp% + \pgfpathrectangle{\pgfpoint{-4bp}{-1bp}}{\pgfpoint{\bmb@dima}{8bp}} + \pgfusepath{clip} + {\pgftransformshift{\pgfpoint{-4bp}{0bp}}\pgftext[left,base]{\pgfuseshading{bmb@transition}}}% + \end{pgfpicture}% + }% + \nointerlineskip% + \vskip-0.5pt% + \fi% + \ifbmb@shadow% + \setbox\bmb@boxshadow=\hbox{\pgfuseshading{bmb@shadow}}% + \setbox\bmb@boxshadowball=\hbox{\pgfuseshading{bmb@shadowball}}% + \setbox\bmb@boxshadowballlarge=\hbox{\pgfuseshading{bmb@shadowballlarge}}% + \fi% + \setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}% + \setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}% + \vskip2pt% + \usebeamercolor[fg]{\bmb@lower}% + \colorlet{beamerstructure}{upper.bg}% + \colorlet{structure}{upper.bg}% + %\color{.}% + } + +\def\endbeamerboxesrounded{% + \end{minipage}\egroup% + \wd\bmb@box=\bmb@width% + \bmb@temp=\dp\bmb@box% + \advance\bmb@temp by.5pt% + \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}% + \dp\bmb@box=0pt% + \bmb@temp=\wd\bmb@box% + \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp% + \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp% + \hbox{% + \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp} + \ifbmb@shadow% + {\pgftransformshift{\pgfpoint{4bp}{-3bp}}\pgftext{\copy\bmb@boxshadowball}} + \begin{pgfscope} + {% + \advance\bmb@temp by-1bp% + \pgfpathrectangle{\pgfpoint{\bmb@temp}{-7bp}}{\pgfpoint{9bp}{9bp}}% + \pgfusepath{clip} + }% + {\pgftransformshift{\pgfpoint{\bmb@temp}{1bp}}\pgftext{\box\bmb@boxshadowballlarge}} + \end{pgfscope} + \begin{pgfscope} + \advance\bmb@temp by-4bp% + \pgfpathrectangle{\pgfpoint{4bp}{-7bp}}{\pgfpoint{\bmb@temp}{5bp}} + \pgfusepath{clip} + {\pgftransformshift{\pgfpoint{4bp}{-7bp}}\pgftext[left,base]{\copy\bmb@boxshadow}}% + \end{pgfscope} + \begin{pgfscope} + \advance\bmb@temp by 4bp% + \bmb@dima=\ht\bmb@box% + \advance\bmb@dima by\bmb@prevheight% + \advance\bmb@dima by 4bp% + \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}} + \pgfusepath{clip} + \advance\bmb@dima by-4bp% + {\pgftransformshift{\pgfpoint{\bmb@temp}{\bmb@dima}}\pgftext{\box\bmb@boxshadowball}} + \advance\bmb@dima by-1bp% + \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}} + \pgfusepath{clip} + \advance\bmb@temp by4bp% + {\pgftransformshift{\pgfpoint{\bmb@temp}{-3bp}}% + \pgftransformrotate{90}% + \pgftext[left,base]{\box\bmb@boxshadow}}% + \end{pgfscope} + \fi% + \unhbox\bmb@colorbox% + \pgfpathqmoveto{-4bp}{1bp} + \pgfpathqcurveto{-4bp}{-1.2bp}{-2.2bp}{-3bp}{0bp}{-3bp} + \pgfpathlineto{\pgfpoint{\the\bmb@dimb}{-3bp}} + { + \bmb@dima=\ht\bmb@box% + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}} + \pgfusepath{fill} + } + \ifbmb@shadow% + { + \color{black!50!bg} + \pgfsetlinewidth{0pt} + \pgfpathmoveto{\pgfpoint{\bmb@dimb}{-.5bp}} + \bmb@dima=\ht\bmb@box% + \advance\bmb@dima by\bmb@prevheight% + \advance\bmb@dima by 1bp% + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfusepath{stroke} + \bmb@temp=\bmb@dima + \advance\bmb@dima by 1bp% + \color{black!31!bg} + \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}} + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfusepath{stroke} + \advance\bmb@dima by 1bp% + \advance\bmb@temp by 1bp% + \color{black!19!bg} + \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}} + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfusepath{stroke} + \advance\bmb@dima by 1bp% + \advance\bmb@temp by 1bp% + \color{black!6!bg} + \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}} + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfusepath{stroke} + \advance\bmb@dima by 1.5bp% + \advance\bmb@temp by 1bp% + \color{bg} + \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}} + \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}} + \pgfusepath{stroke} + } + \fi + \end{pgfpicture}% + \box\bmb@box% + }% + \ifbmb@shadow% + \vskip4bp minus 2bp% + \else% + \vskip2bp% + \fi% + \egroup% of \vbox\bgroup +} + + +%% ------------------------------- +%% | /halbgerundete Beamer-Boxen | +%% ------------------------------- + + +%% ---------------------- +%% | Block-Definitionen | +%% ---------------------- + +% Content environment for structuring. Basically a headline followed by text +\newenvironment<>{contentblock}[1]{\begingroup% + \setbeamertemplate{blocks}[default] + \setbeamercolor{block body}{fg=black,bg=}% + \setbeamercolor{block title}{fg=black,bg=}% + \setbeamerfont*{block title}{family=\sffamily,series=\bfseries,size=\large} + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + + +\newenvironment<>{greenblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-green15}% + \setbeamercolor{block title}{fg=white,bg=kit-green100}% + \begin{block}#2{#1}% + }{\end{block} +\endgroup} + +\newenvironment<>{blueblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-blue15}% + \setbeamercolor{block title}{fg=white,bg=kit-blue100}% + \setbeamercolor{itemize item}{fg=kit-blue100} + \begin{block}#2{#1}% + }{\end{block} +\endgroup} + +\newenvironment<>{redblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-red15}% + \setbeamercolor{block title}{fg=white,bg=kit-red100}% + \setbeamercolor{itemize item}{fg=kit-red100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{brownblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-brown15}% + \setbeamercolor{block title}{fg=white,bg=kit-brown100}% + \setbeamercolor{itemize item}{fg=kit-brown100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{purpleblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-purple15}% + \setbeamercolor{block title}{fg=white,bg=kit-purple100}% + \setbeamercolor{itemize item}{fg=kit-purple100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{grayblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-gray15}% + \setbeamercolor{block title}{fg=white,bg=kit-gray70}% + \setbeamercolor{itemize item}{fg=kit-gray70}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{yellowblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-yellow30}% + \setbeamercolor{block title}{fg=black,bg=kit-yellow100}% + \setbeamercolor{itemize item}{fg=kit-yellow100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{lightgreenblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-lightgreen15}% + \setbeamercolor{block title}{fg=white,bg=kit-lightgreen100}% + \setbeamercolor{itemize item}{fg=kit-lightgreen100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{orangeblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-orange15}% + \setbeamercolor{block title}{fg=white,bg=kit-orange100}% + \setbeamercolor{itemize item}{fg=kit-orange100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{cyanblock}[1]{\begingroup% + \setbeamercolor{block body}{fg=black,bg=kit-cyan15}% + \setbeamercolor{block title}{fg=white,bg=kit-cyan100}% + \setbeamercolor{itemize item}{fg=kit-cyan100}% + \begin{block}#2{#1}% + }{\end{block}% +\endgroup} + +\newenvironment<>{maroonblock}[1]{\begingroup% +\setbeamercolor{block body}{fg=black,bg=Maroon!15}% +\setbeamercolor{block title}{fg=white,bg=Maroon}% + \setbeamercolor{itemize item}{fg=Maroon}% +\begin{block}#2{#1}% +}{\end{block}% +\endgroup} +%% ------------------------------ +%% | /Block-Definitionen | +%% ------------------------------ + +%% use this for setting the total page number +\newcommand{\beginbackup}{ + \newcounter{framenumbervorappendix} + \setcounter{framenumbervorappendix}{\value{framenumber}} +} +\newcommand{\backupend}{ + \addtocounter{framenumbervorappendix}{-\value{framenumber}} + \addtocounter{framenumber}{\value{framenumbervorappendix}} +} diff --git a/21-implementierungsheft-kolloquium/slides/changes.tex b/21-implementierungsheft-kolloquium/slides/changes.tex new file mode 100644 index 0000000..692c6ce --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/changes.tex @@ -0,0 +1,84 @@ +\begin{frame}{Änderungen zum Entwurf} + +\vspace{-.4cm} +\begin{orangeblock}{Kompatibilität} + \begin{minipage}{1.7cm} + \centering + \fontsize{23pt}{0pt} + \selectfont + \textcolor{orange} + \faPlug + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{.7\textwidth} + \begin{itemize} + \item Benutzernamen und E-Mail-Adresse speichern + \item Device API + \end{itemize} + \end{minipage} +\end{orangeblock} + +\begin{greenblock}{E-Mail-Verifizierung} + \begin{minipage}{1.7cm} + \centering + \fontsize{23pt}{0pt} + \selectfont + \textcolor{kit-green} + \faUserCheck + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{.7\textwidth} + \begin{itemize} + \item Neuer Endpunkt zur Verifizierung der E-Mail-Adresse + \item Anmelden nur mit bestätigter E-Mail-Adresse + \end{itemize} + \end{minipage} +\end{greenblock} + +\begin{blueblock}{RSS Parser} + \begin{minipage}{1.7cm} + \centering + \fontsize{23pt}{0pt} + \selectfont + \textcolor{kit-blue} + \faRssSquare + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{.7\textwidth} + \begin{itemize} + \item Asynchroner RSS Parser nach \enquote{Fire and Forget} Prinzip + \item Speichern/Löschen über Referenzen in DAO-Schicht + \end{itemize} + \end{minipage} +\end{blueblock} + +\begin{redblock}{Datenzugriffsschicht} + \begin{minipage}{1.7cm} + \centering + \fontsize{23pt}{0pt} + \selectfont + \textcolor{kit-red} + \faDatabase + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{.7\textwidth} + \begin{itemize} + \item \sout{DAO-Implementierungen} (JPA-Repository) + \end{itemize} + \end{minipage} +\end{redblock} + +% +% Original +% +%\begin{itemize} +% \item Kompatibilität mit Podcatchern \begin{itemize} +% \item Speicherung von Benutzernamen und E-Mail-Adressen +% \item Device API +% \end{itemize} +% \item Verifizierung der E-Mail-Adresse +% \item RSSParser +% \item Reduzierte Datenzugriffsschicht +%\end{itemize} + +\end{frame} diff --git a/21-implementierungsheft-kolloquium/slides/classdiagram.tex b/21-implementierungsheft-kolloquium/slides/classdiagram.tex new file mode 100644 index 0000000..3186a53 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/classdiagram.tex @@ -0,0 +1,36 @@ +\begin{frame}[t]{Einführung} + \centering + \includegraphics[width=\textwidth]{assets/diagrams/classdiagram} +\end{frame} + +% sub +% episode +% auth +% model +% util + +\begin{frame}[t]{Subscriptions-API} + \centering + \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-subscriptions} +\end{frame} + +\begin{frame}[t]{EpisodeActions-API} + \centering + \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-episode-actions} +\end{frame} + +\begin{frame}[t]{Authentication-API} + \centering + \includegraphics[width=.75\textwidth]{assets/diagrams/classdiagram-authentication} +\end{frame} + +\begin{frame}[t]{Model-Paket} + \centering + \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-model} +\end{frame} + +\begin{frame}[t]{Util-Paket} + \centering + \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-util} +\end{frame} + diff --git a/21-implementierungsheft-kolloquium/slides/components.tex b/21-implementierungsheft-kolloquium/slides/components.tex new file mode 100644 index 0000000..5a6afe6 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/components.tex @@ -0,0 +1,7 @@ +\begin{frame}[t]{Komponenten Backend} + + \begin{figure}[h] + \includegraphics[width=0.7\textwidth]{assets/diagrams/backendComponentDiagram} + \end{figure} + +\end{frame} \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/slides/difficulties.tex b/21-implementierungsheft-kolloquium/slides/difficulties.tex new file mode 100644 index 0000000..d3e64dd --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/difficulties.tex @@ -0,0 +1,34 @@ +\begin{frame}{Schwierigkeiten} + + \begin{columns}[t] + + \begin{column}{.5\textwidth} + \centering{\fontsize{30pt}{36pt}\selectfont\faDesktop} + \vspace{.2cm} + \begin{blueblock}{Dashboard} + \begin{itemize} + \item CORS Einschränkung + \item Error-Handling + \item Kommunikation zwischen Komponenten + \end{itemize} + \end{blueblock} + \end{column} + + \begin{column}{.5\textwidth} + \centering{\fontsize{30pt}{36pt}\selectfont\faServer} + \vspace{.2cm} + \begin{orangeblock}{Server} + \begin{itemize} + \item Authentifizierung + \item API + \item EpisodeActionService (AntennaPod) + \end{itemize} + \end{orangeblock} + \end{column} + + + \end{columns} + + +\end{frame} + diff --git "a/21-implementierungsheft-kolloquium/slides/einf\303\274hrung.tex" "b/21-implementierungsheft-kolloquium/slides/einf\303\274hrung.tex" new file mode 100644 index 0000000..d818cd3 --- /dev/null +++ "b/21-implementierungsheft-kolloquium/slides/einf\303\274hrung.tex" @@ -0,0 +1,40 @@ +\begin{frame}[t]{Einführung} + + + \begin{columns}[t] + \begin{column}{.3\textwidth} + \centering{\fontsize{30pt}{36pt}\selectfont\faPodcast} + \vspace{.2cm} + \begin{block}{Podcast} + \begin{itemize} + \item RSS-Feed + \item Episoden + \item Audio/Video + \end{itemize} + \end{block} + \end{column} + \begin{column}{.3\textwidth} + \centering{\fontsize{30pt}{36pt}\selectfont\faArrowCircleDown} + \vspace{.2cm} + \begin{block}{Podcatcher} + \begin{itemize} + \item lokale Verwaltung von Podcasts + \item API Unterstützung + \item Abspielen von Episoden + \end{itemize} + \end{block} + \end{column} + \begin{column}{.3\textwidth} + \centering{\fontsize{30pt}{36pt}\selectfont\faSync} + \vspace{.2cm} + \begin{block}{Synchronisationsserver} + \begin{itemize} + \item Hörfortschritte + \item Abonnements + \item Discovery + \end{itemize} + \end{block} + \end{column} + \end{columns} + +\end{frame} \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/slides/features.tex b/21-implementierungsheft-kolloquium/slides/features.tex new file mode 100644 index 0000000..6ec435b --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/features.tex @@ -0,0 +1,37 @@ +\begin{frame}{Features} +\begin{columns}[t] +\begin{column}{.3\textwidth} +\centering{\fontsize{30pt}{36pt}\selectfont\faSync} +\vspace{.2cm} +\begin{block}{Synchronisation} +\begin{itemize} + \item Abos + \item Hörfortschritt +\end{itemize} +\end{block} +\end{column} +\begin{column}{.3\textwidth} +\centering{\fontsize{30pt}{36pt}\selectfont\faGlobe} +\vspace{.2cm} +\begin{block}{Weboberfläche} +\begin{itemize} + \item Aboliste + \item Zuletzt gehört +\end{itemize} +\end{block} +\end{column} +\begin{column}{.3\textwidth} +\centering{\fontsize{30pt}{36pt}\selectfont\faUser} +\vspace{.2cm} +\begin{block}{Account-Verwaltung} +\begin{itemize} + \item Registrieren und Anmelden + \item Passwort ändern und zurücksetzen + \item Account löschen + \item Daten importieren/exportieren +\end{itemize} +\end{block} +\end{column} +\end{columns} +\end{frame} + diff --git a/21-implementierungsheft-kolloquium/slides/gantt.tex b/21-implementierungsheft-kolloquium/slides/gantt.tex new file mode 100644 index 0000000..31ed9b9 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/gantt.tex @@ -0,0 +1,11 @@ +\begin{frame}{Geplanter Zeitplan} + +\includegraphics[width=\textwidth]{assets/gantt-plan.eps} + +\end{frame} +\begin{frame}{Tatsächlicher Zeitplan} + +\includegraphics[width=\textwidth]{assets/gantt-reality.eps} + +\end{frame} + diff --git a/21-implementierungsheft-kolloquium/slides/integrationstrategie.tex b/21-implementierungsheft-kolloquium/slides/integrationstrategie.tex new file mode 100644 index 0000000..0564b5f --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/integrationstrategie.tex @@ -0,0 +1,82 @@ +\begin{frame}{Integrationsstrategie} + +\vspace{-.5cm} +\begin{minipage}[t]{.47\textwidth} + \begin{orangeblock}{Top-Down} + \begin{minipage}{1.6cm} + \centering + \vspace{.15cm} + \fontsize{30pt}{36pt} + \selectfont + \faSortAmountDown + \vspace{.2cm} + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{\textwidth - 1.4cm} + \begin{itemize} + \item Schnelle anschauliche Ergebnisse + \item Integration von Dashboard aus zum Server + \item spätes Zusammenspiel mit Backend + \item Aufwendige/Schwere Tests + \end{itemize} + \end{minipage} + \end{orangeblock} +\end{minipage} +\hfill +\begin{minipage}[t]{.47\textwidth} + \begin{greenblock}{Bottom-Up} + \begin{minipage}{1.6cm} + \centering + \vspace{.2cm} + \fontsize{30pt}{36pt} + \selectfont + {\faSortAmountUp*} + \vspace{.25cm} + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{\textwidth - 1.4cm} + \begin{itemize} + \item Integration von Datenbank aus zum Dashboard + \item viele einfache Tests sind erforderlich + \item spätes Zusammenspiel mit Frontend + \end{itemize} + \end{minipage} + \end{greenblock} +\end{minipage} +\vspace{.3cm} + +\begin{blueblock}{Outside-In} + \begin{minipage}{2cm} + \centering + \vspace{.2cm} + \fontsize{30pt}{36pt} + \selectfont + \faCompressArrows* + \vspace{.3cm} + \end{minipage} + \hspace{-.5cm} + \begin{minipage}{\textwidth - 2cm} + \begin{itemize} + \item Vereinigt Vorteile von Bottom-Up und Top-Down + \item Implementierung von Dashboard und Server gleichzeitig + \item Schnelle Tests + anschauliche Ergebnisse + \item Gut Parallelisierbar auf ganze Team + \end{itemize} + \end{minipage} +\end{blueblock} + +% \begin{greenblock}{Outside-In Prinzip} +% \begin{itemize} +% \item Eine Kombination aus dem Bottom-Up und Top-Down Prinzip +% \item Beginnt gleichzeitig auf höchster und niedrigster Logischer Ebene +% \item Schrittweise Integration aus beiden Richtungen +% \begin{itemize} +% \item Model und Datenbank +% \item Controller und Frontend +% \end{itemize} +% \item Frühzeitiges testen der Endpunkte und Unit Tests +% \item Gut Parallelisierbar auf ganze Team +% \end{itemize} +% \end{greenblock} + +\end{frame} diff --git a/21-implementierungsheft-kolloquium/slides/pattern.tex b/21-implementierungsheft-kolloquium/slides/pattern.tex new file mode 100644 index 0000000..141954b --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/pattern.tex @@ -0,0 +1,12 @@ +\begin{frame}{Entwurfsmuster} + \begin{columns} + \column{.5\textwidth} + \begin{greenblock}{Dependency Injection} + Standard (\texttt{block}) + \end{greenblock} + \column{.5\textwidth} + \begin{blueblock}{Data Access Object (DAO)} + = \texttt{exampleblock} + \end{blueblock} + \end{columns} +\end{frame} \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/slides/requirements.tex b/21-implementierungsheft-kolloquium/slides/requirements.tex new file mode 100644 index 0000000..e660bb9 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/requirements.tex @@ -0,0 +1,58 @@ +\begin{frame}{Muss-Kriterien} +\rowcolors{1}{kit-orange60}{kit-orange30} +\begin{tabular}{ >{\bfseries}l l l} + \rowcolor{kit-orange} + Bezeichner & Zusammenfassung & Implementiert\\\hline + \textlangle RM1 \textrangle & Registrierung, Bestätigung und Anmeldung eines Accounts über das Frontend & Ja\\ + \textlangle RM2 \textrangle & Speichern von Abonnements und Episoden auf dem Server & Ja\\ + \textlangle RM3 \textrangle & Synchronisierung zwischen Podcatchern & Ja\\ + \textlangle RM4 \textrangle & Eine Weboberfläche & Ja\\ + \textlangle RM5 \textrangle & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\ + \textlangle RM6 \textrangle & Abonnementliste in der Weboberfläche & Ja\\ + \textlangle RM7 \textrangle & 50 Anfragen / Sekunde bearbeiten & Zu testen\\ + \textlangle RM8 \textrangle & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\ + \textlangle RM9 \textrangle & Unterstützung der gpodder.net RESTful-API & Ja\\ + \textlangle RM10\textrangle & Das Nutzen einer Datenbank zur Speicherung von Daten & Ja\\ + \textlangle RM11\textrangle & Erweiterte API für Kommunikation zwischen Front- und Backend & Ja +\end{tabular} +\end{frame} + +\begin{frame}{Soll-Kriterien} +\rowcolors{1}{kit-green60}{kit-green30} +\begin{tabular}{ >{\bfseries}l l l} + \rowcolor{kit-green} + Bezeichner & Zusammenfassung & Implementiert\\\hline + \textlangle RS1 \textrangle & Eine Anleitung (Platzhalter) & Ja\\ + \textlangle RS2 \textrangle & Die Möglichkeit einen Account zu löschen & Ja\\ + \textlangle RS3 \textrangle & Spring für das Backend und MariaDB als Datenbank & Ja\\ + \textlangle RS4 \textrangle & Vue.js und Bootstrap für das Frontend & Ja\\ + \textlangle RS5 \textrangle & npm und vite für das Frontend & Ja\\ + \textlangle RS6 \textrangle & Eine Single-Page-Application als Frontend mit dynamischer Aktualisierung & Ja\\ + \textlangle RS7 \textrangle & Ein RSS-Parser um Daten aus einem RSS-Feed zu lesen & Ja\\ + \textlangle RS8 \textrangle & Mindestanforderungen an ein Passwort & Ja\\ + \textlangle RS9 \textrangle & Salting und Hashing für Verschlüsselung der Personenbezogenen Daten & Ja\\ + \textlangle RS10\textrangle & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja +\end{tabular} +\end{frame} + +\begin{frame}{Kann-Kriterien} + +\rowcolors{1}{kit-blue60}{kit-blue30} +\begin{tabular}{ >{\bfseries}l l l } + \rowcolor{kit-blue} + Bezeichner & Zusammenfassung & Implementiert\\\hline + \textlangle RC1 \textrangle & Abonnierten Podcast in Weboberfläche über Link teilen und hinzufügen & Ja\\ + \textlangle RC2 \textrangle & Abonnements in Weboberfläche deabonnieren & Nein\\ + \textlangle RC3 \textrangle & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\ + \textlangle RC4 \textrangle & Umsiedeln von anderen Gpodder-Plattformen & Ja\\ + \textlangle RC5 \textrangle & Kompatible Weboberfläche für beliebige gpodder.net APIs & Entfernt\\ + \textlangle RC6 \textrangle & Responsive designte Weboberfläche & Ja\\ + \textlangle RC7 \textrangle & Administratorkonten mit privilegierten Funktionen & Nein\\ + \textlangle RC8 \textrangle & OAuth 2.0 im Webfrontend & Nein\\ + \textlangle RC9 \textrangle & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\ + \textlangle RC10\textrangle & Mehrsprachige Weboberfläche & Ja\\ + \textlangle RC11\textrangle & Erfüllung der DSGVO & Teils\\ + \textlangle RC12\textrangle & Docker für einfaches Deployment und Sicherheit & Ja +\end{tabular} +\end{frame} + diff --git a/21-implementierungsheft-kolloquium/slides/statistics.tex b/21-implementierungsheft-kolloquium/slides/statistics.tex new file mode 100644 index 0000000..ed9b143 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/statistics.tex @@ -0,0 +1,85 @@ +\begin{frame}{Statistiken} + +\begin{columns}[t] + \begin{column}{.4\textwidth} + \begin{orangeblock}{Dashboard} + \centering + \begin{minipage}{.2\textwidth} + \centering + \vspace{.15cm} + \fontsize{30pt}{36pt} + \selectfont + \faDesktop + \vspace{.2cm} + \end{minipage} + \begin{tabular}{l l} + \textbf{SLOC} & 2020 Zeilen \\ + \textbf{Commits} & 191 \\ + \textbf{Dateien} & 38 + \end{tabular} + \end{orangeblock} + \end{column} + + \begin{column}{.4\textwidth} + \begin{greenblock}{Server} + \centering + \begin{minipage}{.2\textwidth} + \centering + \vspace{.2cm} + \fontsize{30pt}{36pt} + \selectfont + \faServer + \vspace{.25cm} + \end{minipage} + \begin{tabular}{l l} + \textbf{SLOC} & 3812 Zeilen \\ + \textbf{Commits} & 305 \\ + \textbf{Dateien} & 60 + \end{tabular} + \end{greenblock} + \end{column} +\end{columns} +\vspace{.3cm} + +\centering +\begin{minipage}{.9\textwidth} + \begin{blueblock}{Insgesamt} + \centering + \begin{minipage}{.5\textwidth} + \centering + \begin{minipage}{.2\textwidth} + \centering + \vspace{.2cm} + \fontsize{30pt}{36pt} + \selectfont + \faChartLine + \vspace{.3cm} + \end{minipage} + \begin{tabular}{l l} + \textbf{SLOC} & 5832 Zeilen \\ + \textbf{Commits} & 486 \\ + \textbf{Dateien} & 98 + \end{tabular} + + \end{minipage} + \end{blueblock} + \small SLOC und Anzahl der Dateien würden basierend der Inhalte des + Quellordners \texttt{src/} berechnet und beinhalten keine automatisch + generierten Dateien. +\end{minipage} +\end{frame} + +\begin{frame}{Zeitlicher Verlauf der Commits} + \textbf{Dashboard} + \includegraphics[width=\textwidth]{assets/commits-dashboard.png} + \textbf{Server} + \includegraphics[width=\textwidth]{assets/commits-server.png} +\end{frame} + +\begin{frame}{Commit-Verteilung Server} + \includegraphics[width=\textwidth]{assets/contributors-server.png} +\end{frame} + +\begin{frame}{Commit-Verteilung Dashboard} + \includegraphics[width=\textwidth]{assets/contributors-dashboard.png} +\end{frame} diff --git a/21-implementierungsheft-kolloquium/slides/synchronisation.tex b/21-implementierungsheft-kolloquium/slides/synchronisation.tex new file mode 100644 index 0000000..0849279 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/synchronisation.tex @@ -0,0 +1,36 @@ +\begin{frame}{Synchronisation} + + \tikzstyle{line} = [draw, -latex'] + + \begin{figure}[H] + + \begin{tikzpicture} + + \tikzset{focus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, rounded corners, draw}}; + \tikzset{hyperfocus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, draw}}; + + \node[hyperfocus, text width = 2.6cm, fill = green!25](s){Synchronisations-\\\quad \quad Server}; + \node[focus, left = 3cm of s, text width = 3.1cm, orange](p1){\quad \underline{p1:Podcatcher} + \begin{itemize} + \vspace{0.2cm} + \item Abonnements + \item Hörfortschritt + \vspace{0.1cm} + \end{itemize}}; + \node[focus, above = 1.8cm of s, orange](p2){p2}; + \node[focus, right = 2.5cm of s, orange](p3){p3}; + \node[below = 1.7cm of s](p4){\textbf{...}}; + \umlactor[left = 2.7cm of p2, blue!60]{Benutzer}; + + \draw[] (p1) -- (s); + \draw[] (p2) -- (s); + \draw[] (s) -- (p3); + \draw[] (s) -- (p4); + \path [line, thick, blue!60] (Benutzer) -- node [text width=2.5cm, midway, above=0.1cm, align=center] {Podcast abonnieren} (p2); + \path [line, thick, blue!60] (Benutzer) -| node [text width=2.5cm, midway, above=0.1cm, align=center] {Episode anhören} (p1); + + \end{tikzpicture} + + \end{figure} + +\end{frame} \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/slides/zielsetzung.tex b/21-implementierungsheft-kolloquium/slides/zielsetzung.tex new file mode 100644 index 0000000..84e1064 --- /dev/null +++ b/21-implementierungsheft-kolloquium/slides/zielsetzung.tex @@ -0,0 +1,39 @@ +\begin{frame}{Zielsetzung} + +\begin{figure}[H] + +\raggedright + +\begin{tikzpicture} + +\tikzset{focus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, rounded corners=7pt, draw}}; + +\tikzset{hyperfocus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, draw}}; + +\node[hyperfocus] (main) {gPodder}; +\node[focus, right = 2cm of main] (sync) {Synchronisation}; +\node[above = of sync] (share) {Inhalt teilen}; +\node[above = 0.5cm of share] (discover) {Podcasts entdecken}; +\node[text width = 3cm, below = of sync] (create) {Listen erstellen und teilen}; +\node[text width = 3cm, below = 0.5cm of create] (popular) {Publisher:\\ Was ist beliebt?}; + +\node[hyperfocus, right = 3cm of sync, text width = 4cm] (PSE) {\underline{PSE\textsuperscript{2}}\begin{itemize} + \item Schlankes Design + \item Effizient + \item Intuitiv +\end{itemize} +}; + +\draw[] (main) -- (sync); +\draw[] (main) -- (share); +\draw[] (main) |- (discover); +\draw[] (main) -- (create); +\draw[] (main) |- (popular); +\draw[stealth-, thick] (sync.east) -- ($(PSE.north west) + (0, -0.3)$); + + +\end{tikzpicture} + +\end{figure} + +\end{frame} \ No newline at end of file diff --git a/21-implementierungsheft-kolloquium/tikz-uml.sty b/21-implementierungsheft-kolloquium/tikz-uml.sty new file mode 100644 index 0000000..c6e8e0d --- /dev/null +++ b/21-implementierungsheft-kolloquium/tikz-uml.sty @@ -0,0 +1,5377 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Start of tikz-uml.sty +% +% Some macros for UML Diagrams. +% Home page of project : +% Author: Nicolas Kielbasiewicz +% Style from : +% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\NeedsTeXFormat{LaTeX2e}[1995/12/01]% +\ProvidesPackage{tikz-uml}[2011/01/26]% +% +\RequirePackage{etoolbox}% +\RequirePackage{ifthen}% +\RequirePackage{tikz}% +\RequirePackage{xstring}% +\RequirePackage{calc}% +\RequirePackage{pgfopts}% +\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}% +% +\def\tikzumlPackageLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}% +\def\tikzumlStateLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}% +\def\tikzumlFragmentLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}% +\def\tikzumlComponentLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}% +% +\ProcessPgfOptions{/tikzuml/options}% +% +\def\pgfsetlayersArg{background}% +\pgfdeclarelayer{background}% +\newcounter{tikzumlPackageLayers}% +\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}% + \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers% + \stepcounter{tikzumlPackageLayers}% +\repeat% +% +\newcounter{tikzumlFragmentLayers}% +\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}% + \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers% + \stepcounter{tikzumlFragmentLayers}% +\repeat% +% +\newcounter{tikzumlStateLayers}% +\loop \pgfdeclarelayer{state\thetikzumlStateLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}% + \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers% + \stepcounter{tikzumlStateLayers}% +\repeat% +% +\newcounter{tikzumlComponentLayers}% +\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}% + \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers% + \stepcounter{tikzumlComponentLayers}% +\repeat% +% +\pgfdeclarelayer{lifelines}% +\pgfdeclarelayer{activity}% +\pgfdeclarelayer{connections}% +\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}% +\pgfsetlayers{\pgfsetlayersArg}% +% +\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,% + x/.initial=0, y/.initial=0,% + package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,% + class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=yellow!20, fill template/.initial=yellow!2,% + narynode width/.initial=6ex,% + relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,% + note width/.initial=3cm, fill note/.initial=green!20,% + fill system/.initial=white,% + fill usecase/.initial=blue!20,% + actor below/.initial=0.5cm,% + state join width/.initial=3ex,% + state decision width/.initial=3ex,% + state initial width/.initial=5ex,% + state final width/.initial=5.5ex,% + state enter width/.initial=5ex,% + state exit width/.initial=5ex,% + state end width/.initial=5ex,% + state history width/.initial=5ex,% + state deep history width/.initial=5ex,% + state width/.initial=8ex, fill state/.initial=yellow!20,% + object stereo/.initial=object, fill object/.initial=yellow!20,% + call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,% + fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,% + create call dt/.initial=4,% + component width/.initial=8ex, fill component/.initial= yellow!20,% + required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,% + provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,% + port width/.initial=1ex, fill port/.initial= yellow!20,% + fill assembly connector/.initial= white,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}% + }% +}% +% +\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,% + x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,% + package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,% + class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,% + narynode width/.get=\tikzumlNaryNodeDefaultWidth,% + relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,% + note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,% + fill system/.get=\tikzumlSystemDefaultFillColor,% + fill usecase/.get=\tikzumlUseCaseDefaultFillColor,% + actor below/.get=\tikzumlActorDefaultBelow,% + state join width/.get=\tikzumlStateJoinDefaultWidth,% + state decision width/.get=\tikzumlStateDecisionDefaultWidth,% + state initial width/.get=\tikzumlStateInitialDefaultWidth,% + state final width/.get=\tikzumlStateFinalDefaultWidth,% + state enter width/.get=\tikzumlStateEnterDefaultWidth,% + state exit width/.get=\tikzumlStateExitDefaultWidth,% + state end width/.get=\tikzumlStateEndDefaultWidth,% + state history width/.get=\tikzumlStateHistoryDefaultWidth,% + state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,% + state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,% + object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,% + call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,% + fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,% + create call dt/.get=\tikzumlCreateCallDefaultDT,% + component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,% + required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,% + provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,% + port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,% + fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor% +}% +% +% utility : change default colors +\newcommand{\tikzumlset}[1]{% + \pgfkeys{/tikzuml/.cd,#1}% + \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,% + x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,% + package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,% + class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,% + narynode width/.get=\tikzumlNaryNodeWidth,% + relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,% + note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,% + fill system/.get=\tikzumlSystemDefaultFillColor,% + fill usecase/.get=\tikzumlUseCaseDefaultFillColor,% + actor below/.get=\tikzumlActorDefaultBelow,% + state join width/.get=\tikzumlStateJoinDefaultWidth,% + state decision width/.get=\tikzumlStateDecisionDefaultWidth,% + state initial width/.get=\tikzumlStateInitialDefaultWidth,% + state final width/.get=\tikzumlStateFinalDefaultWidth,% + state enter width/.get=\tikzumlStateEnterDefaultWidth,% + state exit width/.get=\tikzumlStateExitDefaultWidth,% + state end width/.get=\tikzumlStateEndDefaultWidth,% + state history width/.get=\tikzumlStateHistoryDefaultWidth,% + state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,% + state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,% + object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,% + call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,% + fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,% + create call dt/.get=\tikzumlCreateCallDT,% + component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,% + required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,% + provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,% + port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,% + fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor% + }% +}% +% +% define a point +% arg : node/coordinates of the point +\newcommand{\umlpoint}[1]{% + \begin{pgfonlayer}{connections}% + \node[tikzuml control nodes style] at (#1) {};% + \end{pgfonlayer}% +}% +% +\newcommand{\tikzumlskipescape}[3][_]{% +\begingroup% + \def\_{#1}\edef\x{\endgroup% + \def\noexpand\csname #3\endcsname{#2}}\x% +}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% class diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},% + attr2/.style args={#1|#2}{arg2=#1, mult2=#2},% + attr/.style args={#1|#2}{arg=#1, mult=#2},% + recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},% + anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},% + recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}% +}% +% +\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% +% +\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]% +\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]% +\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]% +\tikzstyle{tikzuml narynode style}=[diamond]% +\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]% +\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]% +% +\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]% +\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]% +\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]% +\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]% +\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]% +\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]% +\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]% +\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]% +\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]% +\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]% +\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]% +\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]% +% +\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% +% +\newcounter{tikzumlPackageClassNum}% +\newcounter{tikzumlPackageSubPackageNum}% +\newcounter{tikzumlRelationNum}% +\setcounter{tikzumlRelationNum}{1}% +\newcounter{tikzumlNoteNum}% +\setcounter{tikzumlNoteNum}{1}% +% +\newcounter{pos}% +\newcounter{posT}% +\newcounter{posStereo}% +% +\newcounter{tikzumlPackageLevel}% +\setcounter{tikzumlPackageLevel}{0}% +% +\newif\iftikzumlpackageSimpleStyle% +\newif\iftikzumlclassSimpleStyle% +\newif\iftikzumlclassCircleShape% +\newif\iftikzumlpackageWithoutCoords% +\newif\iftikzumlclassWithoutCoords% +\newif\iftikzumlassocclassWithoutCoords% +\newif\iftikzumlnoteWithoutCoords% +% +% define a uml package +% arg : package name +% optional : x, y: coordinates of the package +% type: stereotype of the package +% name: name of the package node +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the package position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newenvironment{umlpackage}[2][]{% + \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},% + name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,% + fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,% + no coords/.is if=tikzumlpackageWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/package/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/package/.cd, #1}% + \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,% + draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,% + text/.get=\tikzumlPackageTextColor% + }% + % + + % + \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{% + \def\tikzumlPackageType{}% + }{% + \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}% + }% + % + \ifnum\thetikzumlPackageLevel>0% + \let\tikzumlPackage@nameold\tikzumlPackage@fitname% + \def\tikzumlPackage@name{#2}% + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% + \let\tikzumlPackage@parentold\tikzumlPackage@parent% + \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}% + \else% + \def\tikzumlPackage@parent{}% + \def\tikzumlPackage@name{#2}% + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% + \fi% + % + \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x% + % + \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{% + \def\tikzumlPackage@nodeName{\tikzumlPackageName}% + }% + % + \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}% + % + \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}% + % + \setcounter{tikzumlPackageClassNum}{0}% + \setcounter{tikzumlPackageSubPackageNum}{0}% + \stepcounter{tikzumlPackageLevel}% + % + \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]% +}{% + \addtocounter{tikzumlPackageLevel}{-1}% + \begin{pgfonlayer}{package\thetikzumlPackageLevel}% + % + % if contains no class, and not simple, one define a fictive node to enable the fit option + \ifnum\c@tikzumlPackageClassNum=0% + \ifnum\c@tikzumlPackageSubPackageNum=0% + \iftikzumlpackageWithoutCoords% + \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};% + \else% + \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};% + \fi% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}% + \fi% + \fi% + % + \ifnum\c@tikzumlPackageLevel>0% + \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}% + \stepcounter{tikzumlPackageSubPackageNum}% + \fi% + % + \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};% + \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};% + \end{pgfonlayer}% + \end{scope}% +}% +% +% shortcut to define an empty package +\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}% +% +% define a uml class +% args : name of the class +% attributes of the class +% operations of the class +% optional : x, y: coordinates of the class +% width: of the class node +% type: type of class (class, interface, typedef, enum) +% tags: tagged values of class +% template: template parameters +% simple: if used, class is empty and drawn with a rectangle +% circle: if used with simple, class is empty and drawn with a circle +% draw, fill, fill template, and text: colors +% style: to manage every default TikZ option +% no coords: to tell that the class position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlclass}[4][]{% + \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,% + tags/.initial={}, style/.style={},% + template/.initial={}, name/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor,% + fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,% + fill/.initial=\tikzumlClassDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,% + simple=false, circle=false, no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/class/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/class/.cd,#1}% + % + \iftikzumlclassSimpleStyle% + \iftikzumlclassCircleShape% + \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}% + \fi% + \fi% + % + \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,% + type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,% + name/.get=\tikzumlClassName,% + draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,% + text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor% + }% + % + \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{% + \def\tikzumlClassType{}% + }{% + \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}% + }% + % + \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{% + \def\tikzumlClassTags{}% + }{% + \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}% + }% + % + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{% + \def\tikzumlClassVPadding{}% + \def\tikzumlClassHPadding{}% + }{% + \def\tikzumlClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlClassName{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{% + \def\tikzumlClassNodeName{\tikzumlClassName}% + }% + % + \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]% + \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]% + % + \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{% + \let\tikzumlClassNameOld\tikzumlClassName% + \def\tikzumlClassName{{\it \tikzumlClassNameOld}}% + }{}% + % + \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}% + \def\tikzumlClassAttributes{#3}% + \def\tikzumlClassOperations{#4}% + % + \iftikzumlclassSimpleStyle% + \iftikzumlclassWithoutCoords% + \iftikzumlclassCircleShape% + \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};% + \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \else% + \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \fi% + \else% + \iftikzumlclassCircleShape% + \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {}; + \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \else% + \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \fi% + \fi% + \else% + \iftikzumlclassWithoutCoords% + \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlClassOperations% + \end{tabular}% + };% + \else% + \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlClassOperations% + \end{tabular}% + };% + \fi% + \fi% + % + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{% + \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};% + }% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}% + }{% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% + }% + \stepcounter{tikzumlComponentSubComponentNum}% + \fi% +}% +% +% shortcuts for interface, enum and typedef environments +\newcommand{\umlabstract}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=abstract,#1]{#2}{#3}{#4}% +}% +\newcommand{\umlinterface}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=interface,#1]{#2}{#3}{#4}% +}% +\newcommand{\umltypedef}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=typedef,#1]{#2}{#3}{#4}% +}% +\newcommand{\umlenum}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=enum,#1]{#2}{#3}{#4} +}% +% +% shortcut to define an empty class +\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}% +\newcommand{\umlsimpleclass}[2][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{simple}}{% + \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlemptyclass[simple, #1]{#2}% +}% +% +\newcommand{\umlsimpleinterface}[2][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{simple}}{% + \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}% + }{% + \ifthenelse{\equal{\keyname}{circle}}{% + \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlsimpleclass[circle, #1]{#2}% +}% +% underline the text for static arg +\newcommand{\umlstatic}[1]{\underline{#1}}% +\newcommand{\umlvirt}[1]{\textit{#1}}% +% +% define node for n-ary association +\newcommand{\umlNarynode}[2][]{% + \def\tikzumlNaryNodeAnchor{.north} + \def\tikzumlNaryNodeLabelPos{above} + \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}}{% + \def\tikzumlNaryNodeAnchor{.north}% + \def\tikzumlNaryNodeLabelPos{above}% + }{% + \ifthenelse{\equal{\keyname}{above left}}{% + \def\tikzumlNaryNodeAnchor{.north west}% + \def\tikzumlNaryNodeLabelPos{above left}% + }{% + \ifthenelse{\equal{\keyname}{left}}{% + \def\tikzumlNaryNodeAnchor{.west}% + \def\tikzumlNaryNodeLabelPos{left}% + }{% + \ifthenelse{\equal{\keyname}{below left}}{% + \def\tikzumlNaryNodeAnchor{.south west}% + \def\tikzumlNaryNodeLabelPos{below left}% + }{% + \ifthenelse{\equal{\keyname}{below}}{% + \def\tikzumlNaryNodeAnchor{.south}% + \def\tikzumlNaryNodeLabelPos{below}% + }{% + \ifthenelse{\equal{\keyname}{below right}}{% + \def\tikzumlNaryNodeAnchor{.south east}% + \def\tikzumlNaryNodeLabelPos{below right}% + }{% + \ifthenelse{\equal{\keyname}{right}}{% + \def\tikzumlNaryNodeAnchor{.east}% + \def\tikzumlNaryNodeLabelPos{right}% + }{% + \ifthenelse{\equal{\keyname}{above right}}{% + \def\tikzumlNaryNodeAnchor{.north east}% + \def\tikzumlNaryNodeLabelPos{above right}% + }{% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + \pgfkeys{/tikzuml/narynode/.cd,#1}% + \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,% + name/.get=\tikzumlNaryNodeName,% + draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,% + text/.get=\tikzumlNaryNodeTextColor% + }% + % + \def\tikzumlNaryName{#2}% + % + \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{% + \edef\tikzumlNaryNodeName{\tikzumlNaryName}% + }{% + \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}% + }% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x% + % + \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]% + \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]% + % + \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}% + % + \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};% + \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +% +\newdimen\tikzumlNestingSymbolSize% +% +% main command to define a relation between two classes +% args : src class +% dest class +% optional : geometry: geometry of the line +% weight: barycentric weight of the middle part when geometry is a 3-line +% arm1, arm2: lengths of first or last part when geometry id a 3-line +% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation +% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation +% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation +% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation +% anchor1, anchor2: src/dest anchors on linked classes +% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive) +% stereo: stereotype of the relation +% pos stereo: position of the stereotype on the relation +% style: style of the relation (association, aggregation, composition, inherit, ...) +% name: rootname used for naming nodes of the relation +% recursive mode: type of recursive arrow (transition for state diagrams, or default) +% recursive direction start/end: when transition relation, start/end directions of the relation arrow +\newcommand{\umlrelation}[3][]{% + \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,% + arm1/.initial=auto, arm2/.initial=auto,% + arg1/.initial={}, arg2/.initial={}, arg/.initial={},% + mult1/.initial={}, mult2/.initial={}, mult/.initial={},% + pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,% + align1/.initial={}, align2/.initial={}, align/.initial={},% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,% + stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,% + style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,% + recursive mode/.initial=default, recursive direction start/.initial=right,% + recursive direction end/.initial=bottom,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}% + \OR\equal{\keyname}{interface}% + \OR\equal{\keyname}{padding}% + \OR\equal{\keyname}{width}% + \OR\equal{\keyname}{first arm}% + \OR\equal{\keyname}{second arm}% + \OR\equal{\keyname}{middle arm}% + \OR\equal{\keyname}{last arm}% + \OR\equal{\keyname}{distance}}{}{% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}% + }% + }% + }% + \pgfkeys{/tikzuml/relation/.cd,#1}% + \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,% + arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,% + arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,% + mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,% + pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,% + align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,% + anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,% + angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,% + stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,% + style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,% + recursive mode/.get=\tikzumlRelationRecursiveMode,% + recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,% + recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd% + }% + % + \def\tikzumlSrcClassName{#2}% + % + % managing \_ in class names for node names + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% + % + \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]% + \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]% + % + \def\tikzumlDestClassName{#3}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% + % + \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]% + \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]% + % + % managing alias keys + \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}% + \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}% + \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}% + \def\posAttrName{}% + \def\posMultiplicity{}% + \def\posAttrNameT{}% + \def\posMultiplicityT{}% + % + \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{% + \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}% + }{% + \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}% + }% + % + \def\attrAlign{}% + \def\multAlign{}% + \def\attrAlignT{}% + \def\multAlignT{}% + % + \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{% + \def\attrAlign{above right}% + \def\multAlign{below right}% + }{% + \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{% + \def\attrAlign{above left}% + \def\multAlign{below left}% + }{}% + }% + % + \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{% + \def\attrAlignT{above right}% + \def\multAlignT{below right}% + }{% + \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{% + \def\attrAlignT{above left}% + \def\multAlignT{below left}% + }{}% + }% + % + % def stereotype + \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{% + \def\stereotype{}% + }{% + \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}% + }% + + % def anchors macros + \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlRelationSrcAnchor{}% + }{% + \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor% + \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlRelationDestAnchor{}% + }{% + \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor% + \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}% + }% + % + \setcounter{pos}{100*\real{\tikzumlRelationPosition}}% + \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}% + \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}% + % + \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}% + % + %\newcounter{tikzumlControlNodesNum}% + %\setcounter{tikzumlControlNodesNum}{0}% + % + \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};% + % + % straight line + \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}% + {% + \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{% + \def\arcNum{1}% + \def\arcNumT{1}% + % + \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{% + \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc% + node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{% + \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}% + \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}% + % + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{% + \def\numArcs{3}% + \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}% + % + \begin{pgfonlayer}{connections}% + \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] % + node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};% + \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};% + }{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};% + \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};% + }% + \end{pgfonlayer}% + }{% + \def\numArcs{4}% + \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}% + \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}% + % + \begin{pgfonlayer}{connections}% + \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] % + node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};% + \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};% + }{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};% + \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};% + }% + \end{pgfonlayer}% + }% + % + \ifnum\numArcs=4% + \ifnum\theposStereo>300% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \else% + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \fi% + \fi% + \fi% + % + \ifthenelse{\thepos=300\OR\thepos=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\thepos=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\thepos>300% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \ifnum\thepos<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \ifnum\thepos>200% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \fi% + \fi% + \fi% + % + \ifthenelse{\theposT=300\OR\theposT=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }% + }% + }% + }{}% + \ifthenelse{\theposT=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\theposT>300% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \ifnum\theposT<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \ifnum\theposT>200% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \fi% + \fi% + \fi% + \else% + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\thepos=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\thepos>200% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \ifnum\thepos<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \fi% + \fi% + % + \ifthenelse{\theposT=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\theposT=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\theposT>200% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \ifnum\theposT<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \fi% + \fi% + \fi% + % + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}% + \fi% + }{% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}% + \fi% + }% + }{}% + }% + }{% + \def\arcNum{1}% + \def\arcNumT{1}% + % + \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};% + \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }% + \fi% + }% + }{% + % first vertical then horizontal line + \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}% + {% + %\setcounter{tikzumlControlNodesNum}{1}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }% + % + \begin{pgfonlayer}{connections}% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }% + \fi% + }{% + % first horizontal then vertical line + \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}% + {% + %\setcounter{tikzumlControlNodesNum}{1}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }% + % + \begin{pgfonlayer}{connections}% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }% + \fi% + }{% + % first vertical, then horizontal, finally vertical line + \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}% + {% + %\setcounter{tikzumlControlNodesNum}{2}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }% + \def\tikzumlMidOneArc{ }% + % + \begin{pgfonlayer}{connections}% + % + \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{% + \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{% + \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + }{% + \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + }{% + \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + \end{pgfonlayer}% + % + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=200\OR\thepos=100}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{}% + % + \ifthenelse{\thepos>200}{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \def\arcNum{3}% + }{% + \ifthenelse{\thepos<100}{% + \def\arcNum{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + }% + }% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifthenelse{\theposT=200\OR\theposT=100}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{}% + % + \ifthenelse{\theposT>200}{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \def\arcNumT{3}% + }{% + \ifthenelse{\theposT<100}{% + \def\arcNumT{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + }% + }% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }% + \fi% + }{% + % first horizontal, then vertical, finally horizontal line + \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}% + {% + %\setcounter{tikzumlControlNodesNum}{2}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }% + \def\tikzumlMidOneArc{}% + % + \begin{pgfonlayer}{connections}% + % + \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{% + \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{% + \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + }{% + \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + }{% + \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + \end{pgfonlayer}% + % + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=200\OR\thepos=100}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{}% + % + \ifthenelse{\thepos>200}{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \def\arcNum{3}% + }{% + \ifthenelse{\thepos<100}{% + \def\arcNum{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + }% + }% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifthenelse{\theposT=200\OR\theposT=100}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{}% + % + \ifthenelse{\theposT>200}{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \def\arcNumT{3}% + }{% + \ifthenelse{\theposT<100}{% + \def\arcNumT{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + }% + }% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }% + \fi% + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{% + \pgfarrowsdeclare{nested}{nested}{...} + { + \tikzumlNestingSymbolSize=0.2pt% + \advance\tikzumlNestingSymbolSize by .5\pgflinewidth% + \pgfsetdash{}{0pt} % do not dash + \pgfsetroundjoin % fix join + \pgfsetroundcap % fix cap + \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}% + \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}% + \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}% + \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}% + \pgfusepathqstroke% + }% + \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;% + }{ + \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;% + } + \end{pgfonlayer}% + % + \stepcounter{tikzumlRelationNum}% +}% +% +% shortcuts of \umlrelation +\newcommand{\umlHVrelation}[3][]{% + \pgfkeys{/tikzuml/HVrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVrelation/.cd, #1}% + \umlrelation[geometry=-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHrelation}[3][]{% + \pgfkeys{/tikzuml/VHrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/VHrelation/.cd, #1}% + \umlrelation[geometry=|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHrelation}[3][]{% + \pgfkeys{/tikzuml/HVHrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVHrelation/.cd, #1}% + \umlrelation[geometry=-|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVrelation}[3][]{% + \pgfkeys{/tikzuml/VHVrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/VHVrelation/.cd, #1}% + \umlrelation[geometry=|-|, #1]{#2}{#3}% +}% +% +% +% shortcuts for relations +\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlHVfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlVHfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlHVHfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlVHVfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +% define a node +\newcommand{\umlnode}[2]{% + \node (#2) at (#1) {};% +}% +% +% main command to define a relation between two classes through a control node +% args : src class +% control node +% dest class +% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation +% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation +% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation +% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation +% anchor1, anchor2: src/dest anchors on linked classes +% stereo: stereotype of the relation +% pos stereo: position of the stereotype on the relation +% style: style of the relation (association, aggregation, composition, inherit, ...) +% name: rootname used for naming nodes of the relation +\newcommand{\umlCNrelation}[4][]{% + \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},% + mult1/.initial={}, mult2/.initial={}, mult/.initial={},% + pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,% + align1/.initial={}, align2/.initial={}, align/.initial={},% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + stereo/.initial={}, pos stereo/.initial=1,% + style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/relation/.cd,#1}% + \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,% + mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,% + pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,% + align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,% + anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,% + stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,% + style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName% + }% + % + % managing \_ in class names for node names + \def\tikzumlSrcClassName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% + % + \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]% + \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]% + % + \def\tikzumlDestClassName{#4}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% + % + \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]% + \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]% + % + % managing alias keys + \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}% + \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}% + \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}% + \def\orientationT{\orientationTO\orientationTT}% + % + \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{% + \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}% + }{% + \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}% + }% + % + \def\attrAlign{}% + \def\multAlign{}% + \def\attrAlignT{}% + \def\multAlignT{}% + % + \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{% + \def\attrAlign{above right}% + \def\multAlign{below right}% + }{% + \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{% + \def\attrAlign{above left}% + \def\multAlign{below left}% + }{}% + }% + % + \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{% + \def\attrAlignT{above right}% + \def\multAlignT{below right}% + }{% + \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{% + \def\attrAlignT{above left}% + \def\multAlignT{below left}% + }{}% + }% + % + % def stereotype + \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{% + \def\stereotype{}% + }{% + \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}% + }% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlCNRelationSrcAnchor{}% + }{% + \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor% + \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlCNRelationDestAnchor{}% + }{% + \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor% + \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}% + }% + % + \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}% + \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}% + \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}% + % + % straight line + %\setcounter{tikzumlControlNodesNum}{1}% + % + \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }% + \def\posAttrName{}% + \def\posMultiplicity{}% + \def\posAttrNameT{}% + \def\posMultiplicityT{}% + % + \begin{pgfonlayer}{connections}% + \node (\tikzumlCNRelationName-2) at (#3) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}% + node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}% + node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}% + node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}% + node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }% + + \begin{pgfonlayer}{connections}% + \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{% + \pgfarrowsdeclare{nested}{nested}{...} + { + \tikzumlNestingSymbolSize=0.2pt% + \advance\tikzumlNestingSymbolSize by .5\pgflinewidth% + \pgfsetdash{}{0pt} % do not dash + \pgfsetroundjoin % fix join + \pgfsetroundcap % fix cap + \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}% + \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}% + \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}% + \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}% + \pgfusepathqstroke% + }% + \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;% + }{ + \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;% + } + \end{pgfonlayer}% + % + \stepcounter{tikzumlRelationNum}% +}% +% +% shortcuts for cnrelations +\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNfriend}[4][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% +% +% define a note +% arg : attached class +% label of the note +% optional : x,y: coordinates of the note +% width: width of the note +% geometry: geometry of the relation between the note and what it is about +% weight: barycentric weight for a 3-line relation +% arm: length of the first arm +% anchor1, anchor2: anchors of the relation +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the note position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,% + geometry/.initial=\tikzumlRelationDefaultGeometry,% + weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + no coords/.is if=tikzumlnoteWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/note/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/note/.cd, #1}% + \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,% + geometry/.get=\tikzumlNoteGeometry,% + weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,% + anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,% + draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,% + text/.get=\tikzumlNoteTextColor% + }% + % + \def\tikzumlClassName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlNoteSrcAnchor{}% + }{% + \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor% + \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlNoteDestAnchor{}% + }{% + \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor% + \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}% + }% + % + \iftikzumlnoteWithoutCoords% + \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};% + \else% + \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};% + \fi% + \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};% + \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};% + \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;% + \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};% + \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);% + % + \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}% + \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};% + % + \ifthenelse{\equal{\tikzumlNoteGeometry}{--}% + \OR\equal{\tikzumlNoteGeometry}{-|}% + \OR\equal{\tikzumlNoteGeometry}{|-}}{% + \edef\tikzumlnotepath{\tikzumlNoteGeometry} + }{% + \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{% + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}% + }{% + \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {}; + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}% + }% + }{% + \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{% + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}% + }{% + \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {}; + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}% + }% + + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);% + \end{pgfonlayer}% + % + \stepcounter{tikzumlNoteNum}% +}% +% +% shortcuts for note with geometry +\newcommand{\umlHVnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=-|, #1]{#2}{#3}% +}% +\newcommand{\umlVHnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=|-, #1]{#2}{#3}% +}% +\newcommand{\umlVHVnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=|-|, #1]{#2}{#3}% +}% +\newcommand{\umlHVHnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=-|-, #1]{#2}{#3}% +}% +% +% define a uml association class (command) +% args : name of the class +% attributes of the class +% operations of the class +% optional : x,y: coordinates of the class +% width: width of the class node +% type: type of of class (class, interface, typedef, enum) +% template: template parameters +% name: name of the class node +% geometry: geometry of the line +% weight: barycentric weight of the middle part when geometry is a 3-line +% arm: length of first part when geometry id a 3-line +% anchor1, anchor2: src/dest anchors on linked classes +% style: style of the association class (association, aggregation, composition, inherit, ...) +% draw, fill, fill template, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the class position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlassocclass}[5][]{% + \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, + width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},% + template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,% + weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor,% + fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,% + fill/.initial=\tikzumlClassDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + no coords/.is if=tikzumlassocclassWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/assocclass/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}% + }% + }% + % + \pgfkeys{/tikzuml/assocclass/.cd,#1}% + \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,% + width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,% + template/.get=\tikzumlAssocClassTemplateParam,% + name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,% + weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,% + anchor1/.get=\tikzumlAssocClassSrcAnchor,% + anchor2/.get=\tikzumlAssocClassDestAnchor,% + draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,% + text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor% + }% + % + \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{% + \def\tikzumlAssocClassType{}% + }{% + \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}% + }% + % + \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{% + \def\tikzumlAssocClassVPadding{}% + \def\tikzumlAssocClassHPadding{}% + }{% + \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlAssocClassName{#2}% + \def\tikzumlAssocClassRelationName{#3}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x% + % + \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{% + \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}% + }% + % + \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]% + \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]% + % + \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{% + \let\tikzumlAssocClassNameOld\tikzumlAssocClassName% + \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}% + }{}% + % + \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}% + \def\tikzumlAssocClassAttributes{#4}% + \def\tikzumlAssocClassOperations{#5}% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlAssocClassSrcAnchor{}% + }{% + \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor% + \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlAssocClassDestAnchor{}% + }{% + \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor% + \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}% + }% + % + \iftikzumlassocclassWithoutCoords% + \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlAssocClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlAssocClassOperations% + \end{tabular}% + };% + \else% + \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlAssocClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlAssocClassOperations% + \end{tabular}% + };% + \fi% + % + \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{% + \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};% + }% + % + \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight} + \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};% + % + \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{% + \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry} + }{% + \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{% + \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}% + }{% + \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {}; + \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{% + \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}% + }{% + \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {}; + \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}% + }% + + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);% + \end{pgfonlayer}% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% use case diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml usecase style}=[ellipse, text centered]% +\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]% +% +\newcounter{tikzumlSystemUseCaseNum}% +\newcounter{tikzumlSystemLevel}% +\newcounter{tikzumlUseCaseNum}% +\newcounter{tikzumlActorNum}% +% +\newif\iftikzumlusecaseWithoutCoords% +\newif\iftikzumlactorWithoutCoords% +% +% define a system +% arg : name +% optional : x, y: coordinates of the system +% draw, fill, text: colors +\newenvironment{umlsystem}[2][]{% + \gdef\tikzumlSystemFit{}% + \def\tikzumlSystemName{#2}% + \setcounter{tikzumlSystemUseCaseNum}{0}% + % + \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}% + }% + }% + % + \pgfkeys{/tikzuml/system/.cd, #1}% + \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,% + draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,% + text/.get=\tikzumlSystemTextColor}% + % + \stepcounter{tikzumlSystemLevel}% + % + \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]% +}{% + \addtocounter{tikzumlSystemLevel}{-1}% + % if contains no usecase, one define a fictive node to enable the fit option + \ifnum\c@tikzumlSystemUseCaseNum=0% + \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};% + \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}% + \fi% + % + \begin{pgfonlayer}{background}% + \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};% + \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};% + \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};% + \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};% + \end{pgfonlayer}% + \end{scope}% + % +}% +% +% define a use case +% arg : label of the use case +% optional : x, y: coordinates of the use case +% name: name of the node +% width: node width +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the use case position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlusecase}[2][]{% + \stepcounter{tikzumlUseCaseNum}% + \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,% + name/.initial=usecase-\thetikzumlUseCaseNum,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + no coords/.is if=tikzumlusecaseWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/usecase/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/usecase/.cd, #1}% + \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,% + name/.get=\tikzumlUseCaseName,% + draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,% + text/.get=\tikzumlUseCaseTextColor% + }% + % + \def\tikzumlUseCaseText{#2}% + % + \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}% + % + \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{% + \iftikzumlusecaseWithoutCoords% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};% + \else% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% + \fi% + }{% + \iftikzumlusecaseWithoutCoords% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};% + \else% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% + \fi% + }% + % + % add to fit + \ifnum\c@tikzumlSystemLevel>0% + \let\tikzumlSystemFitOld\tikzumlSystemFit% + \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}% + \stepcounter{tikzumlSystemUseCaseNum}% + \fi% +}% +% +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\picturedactor}[1]{% + \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/picactor/.cd,#1}% + \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}% + % + \begin{tikzpicture}[#1]% + \coordinate (head) at (0,4ex);% + \coordinate (left-hand) at (-2ex,2ex);% + \coordinate (right-hand) at (2ex,2ex);% + \coordinate (left-foot) at (-2ex,-2ex);% + \coordinate (right-foot) at (2ex,-2ex);% + \coordinate (empty) at (0,-3ex);% + \draw (empty) (0,0) -- (head);% + \draw (left-hand) -- (right-hand);% + \draw (0,0) -- (left-foot) (0,0) -- (right-foot);% + \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};% + \end{tikzpicture}% +}% +% +% define an actor +% arg : var name +% optional : x, y: coordinates of the actor +% scale: scale factor of the actor symbol +% below: distance between the actor symbol and its name below +% draw, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the actor position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlactor}[2][]{% + \stepcounter{tikzumlActorNum}% + \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,% + draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,% + style/.style={},% + no coords/.is if=tikzumlactorWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/actor/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/actor/.cd, #1}% + \pgfkeys{/tikzuml/actor/.cd,% + x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,% + below/.get=\tikzumlActorBelow,% + draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}% + % + \def\tikzumlActorName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x% + % + \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}% + % + \iftikzumlactorWithoutCoords% + \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};% + \else% + \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};% + \fi% + \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};% + % +}% + +% shortcuts for include and extend relation +\newcommand{\umlinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlHVextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlVHextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlHVHextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlVHVextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlCNinclude}[4][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% +\newcommand{\umlCNextend}[4][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% state diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]% +\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]% +% +\newcounter{tikzumlStateJoinNum}% +\newcounter{tikzumlStateDecisionNum}% +\newcounter{tikzumlStateInitialNum}% +\newcounter{tikzumlStateFinalNum}% +\newcounter{tikzumlStateEnterNum}% +\newcounter{tikzumlStateExitNum}% +\newcounter{tikzumlStateEndNum}% +\newcounter{tikzumlStateHistoryNum}% +\newcounter{tikzumlStateDeepHistoryNum}% +\newcounter{tikzumlStateLevel}% +\newcounter{tikzumlStateSubStateNum}% +\newcounter{tikzumlStateText}% +% +\newif\iftikzumlstatejoinWithoutCoords% +\newif\iftikzumlstatedecisionWithoutCoords% +\newif\iftikzumlstateinitialWithoutCoords% +\newif\iftikzumlstatefinalWithoutCoords% +\newif\iftikzumlstateenterWithoutCoords% +\newif\iftikzumlstateexitWithoutCoords% +\newif\iftikzumlstateendWithoutCoords% +\newif\iftikzumlstatehistoryWithoutCoords% +\newif\iftikzumlstatedeephistoryWithoutCoords% +\newif\iftikzumlstateWithoutCoords% +% +% define a uml join state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatejoin}[1][]{% + \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,% + name/.initial=statejoin-\thetikzumlStateJoinNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatejoinWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statejoin/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statejoin/.cd, #1}% + \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,% + name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor% + }% + % + \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}% + % + \iftikzumlstatejoinWithoutCoords% + \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};% + \else% + \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateJoinNum}% +}% +% +% define a uml decision state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatedecision}[1][]{% + \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,% + name/.initial=statedecision-\thetikzumlStateDecisionNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatedecisionWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statedecision/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statedecision/.cd, #1}% + \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,% + name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor% + }% + % + \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}% + % + \iftikzumlstatedecisionWithoutCoords% + \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};% + \else% + \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateDecisionNum}% +}% +% +% define a uml initial state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% entry, do, exit: entry/do/exit action of the state +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateinitial}[1][]{% + \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,% + name/.initial=stateinitial-\thetikzumlStateInitialNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateinitialWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateinitial/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateinitial/.cd, #1}% + \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,% + name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor% + }% + % + \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}% + % + \iftikzumlstateinitialWithoutCoords% + \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};% + \else% + \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateInitialNum}% +}% +% +% define a uml final state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatefinal}[1][]{% + \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,% + name/.initial=statefinal-\thetikzumlStateFinalNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatefinalWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statefinal/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statefinal/.cd, #1}% + \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,% + name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor% + }% + % + \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}% + % + \iftikzumlstatefinalWithoutCoords% + \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};% + \else% + \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateFinalNum}% +}% +% +% define a uml enter state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateenter}[1][]{% + \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,% + name/.initial=stateenter-\thetikzumlStateEnterNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateenterWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateenter/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateenter/.cd, #1}% + \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,% + name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor% + }% + % + \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}% + % + \iftikzumlstateenterWithoutCoords% + \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};% + \else% + \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateEnterNum}% +}% +% +% define a uml exit state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateexit}[1][]{% + \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,% + name/.initial=stateexit-\thetikzumlStateExitNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateexitWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateexit/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateexit/.cd, #1}% + \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,% + name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor% + }% + % + \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}% + % + \iftikzumlstateexitWithoutCoords% + \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};% + \else% + \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};% + \fi% + \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east); + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateExitNum}% +}% +% +% define a uml end state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateend}[1][]{% + \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,% + name/.initial=stateend-\thetikzumlStateEndNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateendWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateend/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateend/.cd, #1}% + \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,% + name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor% + }% + % + \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}% + % + \iftikzumlstateendWithoutCoords% + \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};% + \else% + \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};% + \fi% + \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east); + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateEndNum}% +}% +% +\newcommand{\picturedhistory}[1]{% + \begin{tikzpicture}[#1]% + \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) + (-0.1cm,0) -- (0.1cm,0) + (0.1cm,-0.15cm) -- (0.1cm,0.15cm);% + \end{tikzpicture}% +}% +% +% define a uml history state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatehistory}[1][]{% + \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,% + name/.initial=statehistory-\thetikzumlStateHistoryNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatehistoryWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statehistory/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statehistory/.cd, #1}% + \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,% + name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor% + }% + % + \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}% + % + \iftikzumlstatehistoryWithoutCoords% + \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};% + \else% + \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateHistoryNum}% +}% +% +\newcommand{\pictureddeephistory}[1]{% + \begin{tikzpicture}[#1]% + \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) + (-0.1cm,0) -- (0.1cm,0) + (0.1cm,-0.15cm) -- (0.1cm,0.15cm) + (0.23cm,0.19cm) -- (0.23cm,0.11cm) + (0.20cm,0.17cm) -- (0.26cm,0.13cm) + (0.20cm,0.13cm) -- (0.26cm,0.17cm);% + \end{tikzpicture}% +}% +% +% define a uml deep-history state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatedeephistory}[1][]{% + \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,% + name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatedeephistoryWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statedeephistory/.cd, #1}% + \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,% + name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor% + }% + % + \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}% + % + \iftikzumlstatedeephistoryWithoutCoords% + \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};% + \else% + \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateDeepHistoryNum}% +}% +% +% define a uml state +% args : name of the state +% content of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% entry, do, exit: entry/do/exit action of the state +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newenvironment{umlstate}[2][]{% + \ifnum\thetikzumlStateLevel>0% + \let\tikzumlState@nameold\tikzumlState@fitname% + \let\tikzumlState@parentold\tikzumlState@parent% + \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}% + \else% + \def\tikzumlState@parent{}% + \fi% + % + \stepcounter{tikzumlStateLevel}% + % + \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,% + name/.initial={},% + entry/.initial={}, do/.initial={}, exit/.initial={},% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + no coords/.is if=tikzumlstateWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/state/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/state/.cd, #1}% + \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,% + entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,% + draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,% + text/.get=\tikzumlStateTextColor% + }% + % + \ifthenelse{\equal{\tikzumlStateName}{}}{% + \edef\tikzumlState@name{#2}% + }{% + \edef\tikzumlState@name{\tikzumlStateName}% + }% + % + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x% + % + \let\tikzumlState@nodeNameold\tikzumlState@nodeName% + \def\tikzumlState@caption{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x% + % + \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}% + % + \setcounter{tikzumlStateSubStateNum}{0}% + \setcounter{tikzumlStateText}{0}% + % + \def\tikzumlStateText{tikzumlEmpty}% + \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]% +}{% + % + \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}% + % + \def\tikzumlstaterootinnerysep{0.5ex}% + \def\tikzumlstatebodyinnerysep{2ex}% + % + \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{entry/\tikzumlStateEntry}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{% + \def\tikzumlStateText{entry/\tikzumlStateEntry}% + }{% + \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}% + }% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + \ifthenelse{\equal{\tikzumlStateDo}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{do/\tikzumlStateDo}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{% + \def\tikzumlStateText{do/\tikzumlStateDo}% + }{% + \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}% + }% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + \ifthenelse{\equal{\tikzumlStateExit}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{exit/\tikzumlStateExit}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{% + \def\tikzumlStateText{exit/\tikzumlStateExit}% + }{% + \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}% + }% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + % + \addtocounter{tikzumlStateLevel}{-1}% + \begin{pgfonlayer}{state\thetikzumlStateLevel}% + % + % if contains nothing, one define a fictive node to enable the fit option + \ifnum\c@tikzumlStateSubStateNum=0% + \iftikzumlstateWithoutCoords% + \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};% + \else% + \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};% + \fi% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}% + \fi% + % + \ifnum\c@tikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + % + \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};% + \def\tikzumlState@orig{body}% + \ifnum\c@tikzumlStateText=1% + \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% + \def\tikzumlState@orig{texttmp}% + \fi% + \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};% + \ifnum\c@tikzumlStateText=1% + \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};% + \else% + \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};% + \fi% + \ifnum\c@tikzumlStateText=1% + \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% + \fi% + \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};% + \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);% + \end{pgfonlayer}% + \end{scope}% +}% +% +% shortcut for empty state +\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}% +% +% command to add text in a state, to be used inside umlstate environment +\newcommand{\umlstatetext}[1]{% + \def\tikzumlStateText{#1}% + \setcounter{tikzumlStateText}{1}% +}% +% +% shortcuts for state transitions macros +\newcommand{\umltrans}[3][]{% + \ifthenelse{\equal{#2}{#3}}{% + \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}% + }{% + \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}% + }% +}% +\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% sequence diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]% +\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]% +\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]% +\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]% +\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]% +% +\newcounter{tikzumlObjectNum}% +\newcounter{tikzumlCallLevel}% +\newcounter{tikzumlCallNum}% +\newcounter{tikzumlFragmentLevel}% +\newcounter{tikzumlFragmentLevelNum}% +\newcounter{tikzumlFragmentNum}% +\newcounter{tikzumlFragmentPartNum}% +\newcounter{tikzumlCallStartFragmentNum}% +\newcounter{tikzumlCallEndFragmentNum}% +% +\newif\iftikzumlobjectNoDDots% +\newif\iftikzumlcreatecallNoDDots% +% +% define a sequence diagram +% +\newenvironment{umlseqdiag}{% + \gdef\tikzumlInCreateCall{0}% + \setcounter{tikzumlObjectNum}{0}% + \setcounter{tikzumlCallLevel}{0}% + \setcounter{tikzumlCallNum}{0}% + \setcounter{tikzumlFragmentLevel}{0}% + \setcounter{tikzumlFragmentLevelNum}{0}% + \setcounter{tikzumlFragmentNum}{0}% + \setcounter{tikzumlFragmentPartNum}{0}% + \setcounter{tikzumlCallStartFragmentNum}{0}% + \setcounter{tikzumlCallEndFragmentNum}{0}% + % + \ifx \@umlactor \@empty + \newcommand{\umlactor}[2][]{% + \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% + }{}% + }% + }% + % + \pgfkeys{/tikzuml/actorobj/.cd, ##1}% + \umlobject[stereo=actor, ##1]{##2}% + }% + \else% + \renewcommand{\umlactor}[2][]{% + \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% + }{}% + }% + }% + % + \pgfkeys{/tikzuml/actorobj/.cd, ##1}% + \umlobject[stereo=actor, ##1]{##2}% + }% + \fi% + \begin{scope}[font=\tikzumlDefaultFont]% +}{% + % draw lifelines of each object + \begin{pgfonlayer}{lifelines}% + \foreach \id in \tikzumlIdList {% + \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};% + \draw[dotted] (\id) -- (end-\id);% + }% + \end{pgfonlayer}% + \end{scope}% +}% +% +% define the database symbol +% optional : global tikzpicture styles +\newcommand{\pictureddatabase}[1]{% + \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/database/.cd,#1}% + \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}% + % + \begin{tikzpicture}[#1]% + \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};% + \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};% + \fill (bottom.west) rectangle (top.east);% + \begin{scope}% + \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);% + \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};% + \end{scope}% + \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};% + \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);% + \end{tikzpicture}% +}% +% +% define the entity symbol +% optional : global tikzpicture styles +\newcommand{\picturedentity}[1]{% + \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/entity/.cd,#1}% + \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}% + % + \begin{tikzpicture}[#1]% + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};% + \draw (center.south) node[coordinate, name=bottom] {};% + \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};% + \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};% + \draw (center) -- (bottom);% + \draw (bottom-left) -- (bottom-right);% + \end{tikzpicture}% +}% +% +% define the boundary symbol +% optional : global tikzpicture styles +\newcommand{\picturedboundary}[1]{% + \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/boundary/.cd,#1}% + \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}% + % + \begin{tikzpicture}[#1] + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {}; + \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {}; + \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {}; + \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {}; + \draw (center) -- (left); + \draw (left-top) -- (left-bottom); + \end{tikzpicture} +}% +% +% define the control symbol +% optional : global tikzpicture styles +\newcommand{\picturedcontrol}[1]{% + \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/control/.cd,#1}% + \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}% + % + \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}] + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {}; + \end{tikzpicture} +}% +% +% define a uml object for a sequence diagram +% args : name of the object +% optional : x, y: coordinates of the object +% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject) +% class: class of the object +% scale: scale factor of the object symbol +% draw, fill, text; colors +% no ddots: when used, disable printing of double dots +\newcommand{\umlobject}[2][]{ + \stepcounter{tikzumlObjectNum}% + % + \edef\tikzumlobject@ddot{:}% + \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,% + class/.initial={}, scale/.initial=1,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + no ddots/.is if=tikzumlobjectNoDDots,% + no ddots=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/obj/.cd, #1}% + \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,% + stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,% + scale/.get=\tikzumlObjectScale,% + draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,% + text/.get=\tikzumlObjectTextColor% + }% + % + \iftikzumlobjectNoDDots% + \edef\tikzumlobject@ddot{}% + \fi% + % + \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{% + \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}% + }{}% + % + \def\tikzumlObjectName{#2}% + \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}% + % + \ifnum\thetikzumlObjectNum=1% + \xdef\tikzumlIdList{\tikzumlObjectName}% + \else% + \let\tikzumlIdListOld\tikzumlIdList% + \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}% + \fi% + % + \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]% + % + \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{% + \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]% + }{% + \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{% + \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]% + }{}% + }% + % + \ifnum\tikzumlInCreateCall=1% + \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};% + \else% + \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};% + \fi% + % + \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{% + \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {}; + \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {}; + \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {}; + \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {}; + \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {}; + \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {}; + \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north); + \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east); + \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north); + \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east); + \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east); + }{% + \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{% + \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}}; + }% + }% +}% +% +% shortcuts for objects +\newcommand{\umlbasicobject}[2][]{% + \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{no ddots}}{% + \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}% + }{}% + }% + }% + \pgfkeys{/tikzuml/basicobj/.cd, #1}% + \umlobject[no ddots, #1]{#2}% +}% +% +\newcommand{\umldatabase}[2][]{% + \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/databaseobj/.cd, #1}% + \umlobject[stereo=database, #1]{#2}% +}% +\newcommand{\umlentity}[2][]{% + \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/entityobj/.cd, #1}% + \umlobject[stereo=entity, #1]{#2}% +}% +\newcommand{\umlcontrol}[2][]{% + \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/controlobj/.cd, #1}% + \umlobject[stereo=control, #1]{#2}% +}% +\newcommand{\umlboundary}[2][]{% + \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/boundaryobj/.cd, #1}% + \umlobject[stereo=boundary, #1]{#2}% +}% +\newcommand{\umlmulti}[2][]{% + \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/multiobj/.cd, #1}% + \umlobject[stereo=multi, #1]{#2}% +}% +% +\newcounter{tikzumlSDNodeNum}% +% +% define a hidden node to lengthen lifeline of a object +% args : object node +% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object +% name: name of the sdnode +\newcommand{\umlsdnode}[2][]{% + \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}% + \pgfkeys{/tikzuml/sdnode/.cd, #1}% + \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}% + % + \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{% + \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}% + }{% + \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}% + }% + % + \stepcounter{tikzumlSDNodeNum}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x% + % + \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};% + % + % update last node drawn on sender lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}% +}% +% +\newlength{\tikzumlCall@xa}% +\newlength{\tikzumlCall@xb}% +% +% define a uml operation call for sequence diagrams +% args : call sender +% call receiver +% optional : dt: time delay from precedent event end +% name: name of the call +% op: operation name and input args +% return: return value +% type: type of the call (synchron, asynchron) +% draw, fill, text: colors +% padding: time padding from call start and to call end +\newenvironment{umlcall}[3][]{% + \stepcounter{tikzumlCallNum}% + \def\tikzumlCallWithReturn{tikzumlFalse}% + \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls + \gdef\tikzumlCallBottom{0}% + % + \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},% + op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + padding/.initial=\tikzumlCallDefaultPadding,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with return}}{% + \def\tikzumlCallWithReturn{tikzumlTrue}% + }{% + \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}% + }% + }% + }% + \pgfkeys{/tikzuml/call/.cd, #1}% + \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,% + return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,% + padding/.get=\tikzumlCallPadding,% + draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,% + text/.get=\tikzumlCallTextColor% + }% + % + \edef\tikzumlfillcall{\tikzumlCallFillColor}% + \edef\tikzumldrawcall{\tikzumlCallDrawColor}% + \edef\tikzumltextcall{\tikzumlCallTextColor}% + \edef\tikzumltypecall{\tikzumlCallType}% + % + \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{% + \ifnum\thetikzumlCallNum=1% + \def\tikzumlCallDT{2}% + \def\tikzumlcallSrc{2}% + \else% + \def\tikzumlCallDT{2}% + \def\tikzumlcallSrc{1}% + \fi% + }{% + \def\tikzumlcallSrc{0}% + }% + % + \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName% + \def\tikzumlCallStartNodeName{#2}% + \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName% + \def\tikzumlCallEndNodeName{#3}% + \def\tikzumlcallheight{\tikzumlCallPadding}% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlCallDTold\tikzumlCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}% + \edef\tikzumlCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlCallDTold\tikzumlCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}% + \edef\tikzumlCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + \ifnum\thetikzumlFragmentPartNum>0% + \let\tikzumlCallDTold\tikzumlCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}% + \edef\tikzumlCallDT{\pgfmathresult}% + \fi% + % + % managing parent-child structure + \ifnum\thetikzumlCallLevel>0% + \let\tikzumlCall@nameold\tikzumlCall@name% + \edef\tikzumlCall@name{\tikzumlCallName}% + \let\tikzumlCall@parentold\tikzumlCall@parent% + \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% + \else% + \edef\tikzumlCall@parent{}% + \edef\tikzumlCall@parentold{}% + \edef\tikzumlCall@nameold{} + \edef\tikzumlCall@name{\tikzumlCallName}% + \fi% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x% + % + \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName% + % + \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}% + % + % top node of activity period of call sender + \begin{pgfonlayer}{connections}% + \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}% + \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + % + % update last node drawn on sender lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}% + % + % top node of activity period of call receiver + \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{% + \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};% + }% + % + % update last node drawn on receiver lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}% + \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}% + \end{pgfonlayer}% + % + \stepcounter{tikzumlCallLevel}% +}{% + \addtocounter{tikzumlCallLevel}{-1}% + % + % bottom nodes of activity periods of call sender and receiver + \begin{pgfonlayer}{connections}% + \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum% + % + % this test occurs a bug with latex package preview + \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{% + \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}% + }{% + \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}% + }% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% + }% + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% + \else% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlcallheightold\tikzumlCallPadding% + \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}% + \edef\tikzumlcallheight{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1}% + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlcallheightold\tikzumlCallPadding% + \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}% + \edef\tikzumlcallheight{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1}% + \fi% + % + \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% + }% + % + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% + \fi% + \end{pgfonlayer}% + % + % draw activity periods + \begin{pgfonlayer}{activity}% + \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{% + % draw root activity period only + \ifnum\thetikzumlCallLevel=0% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \else% + % draw root activity from inner call + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + \fi% + }{% + % draw root activity period + \ifnum\thetikzumlCallLevel=0% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \else% + % draw root activity from inner call + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + \fi% + % draw receiver activity period + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);% + }% + \end{pgfonlayer}% + \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{% + \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + % + % update last nodes drawn on sender and receiver lifelines + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}% + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}% + % + % draw call arrows + \begin{pgfonlayer}{connections}% + \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) % + -- ++(0,-0.75*\tikzumlCallPadding ex) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} % + -- (et-\tikzumlCall@nodeName.east);% + % + % draw return arrow and update fit for parent fragment + \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% + \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% + \fi% + % + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) + -- ++(0,-0.75*\tikzumlCallPadding ex) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} % + -- (sb-\tikzumlCall@nodeName.east);% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + % draw call arrows + \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}% + \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}% + % + \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};% + }{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};% + }% + % + % draw return arrow and update fit for parent fragment + \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% + \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% + \fi% + % + \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};% + }{% + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }% + \end{pgfonlayer}% +}% +% +% alias for function self call +\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}% +% +% define a combined fragment +% optional : name: name of fragment +% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref) +% label: label of fragment (ex : condition for opt, iterator for loop, ...) +% inner xsep, inner ysep: padding of the fragment box +% draw, fill, text: colors +\newenvironment{umlfragment}[1][]{% + % define a fragment separator + % optional : label of the fragment part (ex : else for alt) + \providecommand{\umlfpart}[1][]{% + \stepcounter{tikzumlFragmentPartNum}% + % + \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};% + \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};% + \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};% + \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};% + \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum); + \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};% + \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};% + }% + % + \stepcounter{tikzumlFragmentNum}% + % + \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,% + label/.initial=tikzumlEmpty,% + inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/fragment/.cd, #1}% + \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,% + label/.get=\tikzumlFragmentLabel,% + inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,% + draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,% + text/.get=\tikzumlFragmentTextColor% + }% + % + \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{% + \def\tikzumlFragmentLabel{}% + }{% + \let\tikzumlFragmentLabelold\tikzumlFragmentLabel% + \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}% + }% + % + \ifnum\thetikzumlFragmentLevel>0% + \let\tikzumlFragment@parentold\tikzumlFragment@parent% + \let\tikzumlFragment@nameold\tikzumlFragment@name% + \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}% + \else% + \setcounter{tikzumlFragmentPartNum}{0}% + \edef\tikzumlFragment@parent{}% + \edef\tikzumlFragment@parentold{}% + \edef\tikzumlFragment@nameold{}% + \fi% + % + \edef\tikzumlFragment@name{\tikzumlFragmentName}% + \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}% + % + \stepcounter{tikzumlFragmentLevel}% + % + \ifnum\thetikzumlCallLevel>0% + \stepcounter{tikzumlCallStartFragmentNum}% + \fi% + % + \pgfmathparse{6*\tikzumlFragmentYSep}% + \xdef\tikzumlFragment@paddingy{\pgfmathresult}% + \if\c@tikzumlFragmentLevelNum=0% + \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}% + \fi% + % + % time delay adjustment for two consecutive fragments + \ifnum\thetikzumlCallEndFragmentNum>0% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% +}{% + % + \addtocounter{tikzumlFragmentLevel}{-1}% + % + \ifnum\thetikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}% + \fi% + % + % draw working fragment box + \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% + \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};% + \end{pgfonlayer}% + % + % draw type and label + \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] % + at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};% + \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] % + at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};% + % + % draw final fragment box + \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% + \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};% + \end{pgfonlayer}% + % + \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);% + \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};% + \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};% + \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);% + % + \ifnum\thetikzumlCallLevel>0% + \stepcounter{tikzumlCallEndFragmentNum}% + \fi% +}% +% +% define a constructor call +% arg : call sender +% name of constructed object +% optional : x: coordinate of the new object +% stereo: stereotype of the new object +% class: class type of the new object +% dt: time delay from last event +% name: name of the call +% draw, fill, text: colors +% no ddots: when used, disable printing of double dots +\newcommand{\umlcreatecall}[3][]{% + \stepcounter{tikzumlCallNum}% + \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls + \gdef\tikzumlInCreateCall{1}% + \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},% + dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,% + text obj/.initial=\tikzumlDefaultTextColor,% + no ddots/.is if=tikzumlcreatecallNoDDots,% + no ddots=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/createcall/.cd, #1}% + \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,% + class/.get=\tikzumlCreateCallClass,% + dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,% + draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,% + text/.get=\tikzumlCreateCallTextColor,% + draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,% + text obj/.get=\tikzumlCreateCallObjectTextColor% + }% + % + \def\tikzumlCreateCallSrc@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlCreateCallDTold\tikzumlCreateCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}% + \edef\tikzumlCreateCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlCreateCallDTold\tikzumlCreateCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}% + \edef\tikzumlCreateCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + \ifnum\thetikzumlFragmentPartNum>0% + \let\tikzumlCreateCallDTold\tikzumlCreateCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}% + \edef\tikzumlCreateCallDT{\pgfmathresult}% + \fi% + % + % managing parent-child structure + \ifnum\thetikzumlCallLevel>0% + \let\tikzumlCall@nameold\tikzumlCall@name% + \def\tikzumlCall@name{\tikzumlCreateCallName}% + \let\tikzumlCall@parentold\tikzumlCall@parent% + \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% + \else% + \edef\tikzumlCall@parent{}% + \edef\tikzumlCall@parentold{}% + \edef\tikzumlCall@nameold{} + \edef\tikzumlCall@name{\tikzumlCreateCallName}% + \fi% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x% + % + \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% + % + \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}% + % + \iftikzumlcreatecallNoDDots% + \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}% + \else + \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}% + \fi + % + \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% + % + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}% + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}% + % + \begin{pgfonlayer}{connections}% + \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};% + \end{pgfonlayer}% + % + \ifnum\thetikzumlCallLevel=0% + \begin{pgfonlayer}{activity}% + \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);% + \end{pgfonlayer}% + \fi% + % add to fit fragment + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }% + \fi% +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% component diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]% +% +\newcounter{tikzumlComponentLevel}% +\newcounter{tikzumlComponentSubComponentNum}% +\newcounter{tikzumlConnectorNum}% +\setcounter{tikzumlConnectorNum}{1}% +% +\newif\iftikzumlcomponentWithoutCoords% +% +\newcommand{\picturedcomponent}[1]{% + \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/component/picture/.cd,#1}% + \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}% + \begin{tikzpicture}[#1]% + \filldraw (0,0) rectangle (1ex,1.5ex);% + \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);% + \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);% + \end{tikzpicture}% +}% +% +% define a uml component +% args : name of the component +% content of the component +% optional args : x,y coordinates of the component +% width of the component node +\newenvironment{umlcomponent}[2][]{% + \ifnum\thetikzumlComponentLevel>0% + \let\tikzumlComponent@nameold\tikzumlComponent@fitname% + \let\tikzumlComponent@parentold\tikzumlComponent@parent% + \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}% + \else% + \def\tikzumlComponent@parent{}% + \fi% + % + \stepcounter{tikzumlComponentLevel}% + % + \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + no coords/.is if=tikzumlcomponentWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/component/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/component/.cd, #1}% + \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,% + width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,% + draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,% + text/.get=\tikzumlComponentTextColor% + }% + % + \ifthenelse{\equal{\tikzumlComponentName}{}}{% + \edef\tikzumlComponent@name{#2}% + }{% + \edef\tikzumlComponent@name{\tikzumlComponentName}% + }% + % + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x% + % + \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName% + \def\tikzumlComponent@caption{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x% + % + \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}% + % + \setcounter{tikzumlComponentSubComponentNum}{0}% + % + \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]% +}{% + \addtocounter{tikzumlComponentLevel}{-1}% + \begin{pgfonlayer}{component\thetikzumlComponentLevel}% + % + % if contains nothing, one define a fictive node to enable the fit option + \ifnum\c@tikzumlComponentSubComponentNum=0% + \iftikzumlcomponentWithoutCoords% + \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};% + \else% + \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};% + \fi% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}% + \fi% + % + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}% + \stepcounter{tikzumlComponentSubComponentNum}% + \fi% + % + \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};% + \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};% + \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };% + \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};% + \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};% + \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };% + \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);% + \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west); + \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east); + \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south); + \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north); + \end{pgfonlayer}% + \end{scope}% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +% +% shortcut for empty component +\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}% +% +\newcommand{\umlrequiredinterface}[2][]{% + \def\tikzumlInterfaceWithPort{tikzumlFalse}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,% + name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,% + padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlInterfaceWithPort{tikzumlTrue}% + }{}% + }% + }% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,% + distance/.get=\tikzumlRequiredInterfaceDistance,% + name/.get=\tikzumlRequiredInterfaceName,% + width/.get=\tikzumlRequiredInterfaceWidth,% + padding/.get=\tikzumlRequiredInterfacePadding,% + draw/.get=\tikzumlRequiredInterfaceDrawColor,% + fill/.get=\tikzumlRequiredInterfaceFillColor% + }% + % + \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{% + \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}% + \edef\tikzumlRequiredInterface@portname{#2-east-port}% + \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}% + }{% + \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}% + \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}% + \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}% + }% + % + \edef\tikzumlRequiredInterface@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x% + % + \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};% + }{% + \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};% + }% + \begin{scope}% + \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};% + \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);% + \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};% + \end{scope}% + \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}% + % + \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};% + % + % add to fit + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }% + \fi% +}% +% +\newcommand{\umlprovidedinterface}[2][]{% + \def\tikzumlInterfaceWithPort{tikzumlFalse}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,% + name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,% + padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlInterfaceWithPort{tikzumlTrue}% + }{}% + }% + }% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,% + distance/.get=\tikzumlProvidedInterfaceDistance,% + name/.get=\tikzumlProvidedInterfaceName,% + width/.get=\tikzumlProvidedInterfaceWidth,% + padding/.get=\tikzumlProvidedInterfacePadding,% + draw/.get=\tikzumlProvidedInterfaceDrawColor,% + fill/.get=\tikzumlProvidedInterfaceFillColor% + }% + % + \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{% + \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}% + \edef\tikzumlProvidedInterface@portname{#2-west-port}% + \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}% + }{% + \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}% + \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}% + \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}% + }% + % + \edef\tikzumlProvidedInterface@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x% + % + \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};% + }{% + \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};% + }% + \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};% + \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north) + {\tikzumlProvidedInterfaceLabel};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}% + % + \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};% + % + % add to fit + \ifnum\thetikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }% + \fi% +}% +% +\newlength{\tikzuml@AC@xa}% +\newlength{\tikzuml@AC@ya}% +\newlength{\tikzuml@AC@xb}% +\newlength{\tikzuml@AC@yb}% +\newlength{\tikzuml@AC@xi}% +\newlength{\tikzuml@AC@yi}% +\newlength{\tikzuml@AC@xic}% +\newlength{\tikzuml@AC@yic}% +\newlength{\tikzuml@AC@xio}% +\newlength{\tikzuml@AC@yio}% +\newlength{\tikzuml@AC@AB}% +\newlength{\tikzuml@AC@lambda}% +\newlength{\tikzuml@AC@xtrc}% +\newlength{\tikzuml@AC@ytrc}% +\newlength{\tikzuml@AC@xtlc}% +\newlength{\tikzuml@AC@ytlc}% +\newlength{\tikzuml@AC@xblc}% +\newlength{\tikzuml@AC@yblc}% +\newlength{\tikzuml@AC@xbrc}% +\newlength{\tikzuml@AC@ybrc}% +\newlength{\tikzuml@AC@middleArm}% +% +\newcommand{\umlassemblyconnectorsymbol}[2]{% + \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{% + \edef\tikzuml@ACStart@name{#1}% + \edef\tikzuml@ACEnd@name{#2}% + \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x% + % + \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% + \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% + \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% + \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% + \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}% + \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}% + \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}% + \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}% + \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};% + \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};% + \begin{scope}% + \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}% + \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}% + \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);% + \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);% + \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);% + \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);% + \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;% + \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};% + \end{scope}% + \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north) + {\tikzumlAssemblyConnectorLabel};% + }{}% +}% +% +\newcommand{\umlassemblyconnector}[3][]{% + \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}% + \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},% + arm1/.initial={auto}, arm2/.initial={auto},% + name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,% + anchor1/.initial={}, anchor2/.initial={},% + draw/.initial=\tikzumlDefaultDrawColor,% + fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,% + fill port/.initial=\tikzumlPortDefaultFillColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{first arm}}{% + \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{second arm}}{% + \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{middle arm}}{% + \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{last arm}}{% + \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}% + }{% + }% + }% + }% + }% + }% + }% + }% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,% + name/.get=\tikzumlAssemblyConnectorName,% + interface/.get=\tikzumlAssemblyConnectorLabel,% + width/.get=\tikzumlAssemblyConnectorWidth,% + arm1/.get=\tikzumlAssemblyConnectorStartArm,% + arm2/.get=\tikzumlAssemblyConnectorEndArm,% + anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,% + anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,% + draw/.get=\tikzumlAssemblyConnectorDrawColor,% + fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,% + fill port/.get=\tikzumlAssemblyConnectorPortFillColor% + }% + % + \edef\tikzumlAssemblyConnectorStart@name{#2}% + \edef\tikzumlAssemblyConnectorEnd@name{#3}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x% + % + \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% + \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% + \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% + \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + } + \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorEndAnchor{south}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{north}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + } + \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorStartAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{south}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}% + }% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}% + }% + \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa} + \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb} + \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + } + \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}% + }% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}% + }% + \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorStartAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{south}% + } + \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{% + \def\tikzumlAssemblyConnectorEndAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{south}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}% + }% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}% + }% + % + \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% + \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};% + \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};% + }{% + \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% + \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% + }% + % + \addtocounter{tikzumlRelationNum}{-1}% + \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{% + \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}% + \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}% + }{% + \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}% + }% + % + \stepcounter{tikzumlRelationNum}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% + }% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% + }% + }% + }{}% + }% + }% + }% + }% + \stepcounter{tikzumlConnectorNum}% +}% +% +% shortcuts of \umlassemblyconnector +\newcommand{\umlHVassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/HVassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/VHassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlport}[3][]{% + \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,% + width/.initial=\tikzumlPortDefaultWidth,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}% + }% + }% + \pgfkeys{/tikzuml/port/.cd, #1}% + \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,% + draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}% + \edef\tikzumlPort@name{#2}% + \edef\tikzumlPort@anchor{#3}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x% + % + \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};% +}% +% +\newcommand{\umldelegateconnector}[3][]{% + \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}% + \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}% + \pgfkeys{/tikzuml/delegateconnector/.cd, + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/delegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}% +}% +% +% shortcuts of \umldelegateconnector +\newcommand{\umlHVdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/HVdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/VHdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=-|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=|-|, #1]{#2}{#3}% +}% +%%% End of tikz-uml.sty +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file -- cgit v1.2.3