--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysmodellibs/sysmodelgen/core/draw-model.xsl Wed Oct 13 16:21:25 2010 +0100
@@ -0,0 +1,1403 @@
+<?xml version="1.0"?>
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:s="http://www.w3.org/2000/svg" xmlns:exslt="http://exslt.org/common" xmlns:m="http://exslt.org/math" exclude-result-prefixes="s m exslt" >
+<!--Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ All rights reserved.
+ This component and the accompanying materials are made available
+ under the terms of the License "Eclipse Public License v1.0"
+ which accompanies this distribution, and is available
+ at the URL "http://www.eclipse.org/legal/epl-v10.html".
+
+ Initial Contributors:
+ Nokia Corporation - initial contribution.
+ Contributors:
+ Description:
+ Create a stand-alone sysdef from a linked set of fragments
+-->
+ <xsl:key name="color" match="legend/cbox" use="@value"/>
+
+ <xsl:output method="xml" cdata-section-elements="script s:script" indent="yes"/>
+
+<xsl:param name="pkgLabelSize" select="4.23"/> <!-- the height needed at the bottom of a package for the label (mm) -->
+
+<!-- /SystemDefinition/@detail = The level of detail to show in the diagram.
+ The value is the name of the lowest element to show. If @static is set to false, mousing-over an item will show its detailed content.
+ By default this is equivalent to 'component' -->
+
+<!-- ====== Constants ============= -->
+<xsl:param name="groupDx" select="2.1"/> <!-- the horizontal distance between groups (mm) -->
+<xsl:param name="groupDy" select="3.2"/> <!-- the vertical distance between groups (mm) -->
+<xsl:param name="cSize" select="9.3"/> <!-- the width and height of a component (mm) -->
+<xsl:param name="mHeight" select="15.6"/> <!-- the height of a collection (mm) -->
+<xsl:param name="mMinWidth" select="15.6"/> <!-- the minimum width of a collection (mm) -->
+<xsl:param name="lyrFixedWidth" select="$mMinWidth * 6"/><!-- fixed width of a layer (mm)-->
+<xsl:param name="pkgMinWidth" select="$cSize * 3"/><!-- small pkg, use min width of 2 * smallest possible collection -->
+<xsl:param name="subpkgMinWidth" select="$cSize * 3"/> <!-- small nested pkg, use min width of 3 components -->
+<xsl:param name="pkgFixedWidth" select="$mMinWidth * 5"/><!-- fixed width of a pacakge (mm) -->
+<xsl:param name="pkgAuxWidth" select="0"/><!-- Additional width on the right side of each package (mm) -->
+<xsl:param name="subpkgFixedWidth" select="$mMinWidth * 3"/> <!-- fixed width nested pkg (mm) -->
+<xsl:variable name="inlineLabel" select="3 * $cSize"/> <!-- the max width of an inline label. 3 times the width of a collection by default
+ I don't like this. Should compute somehow and make local variable. -->
+<xsl:variable name="detail-block-space" select="6"/>
+<xsl:param name="lyrTitleBox" select="9.3"/> <!-- the width of the layer's title box (mm) -->
+<xsl:variable name="lgrpDx" select="5"/> <!-- the width of a layer group border (mm)-->
+<xsl:variable name="lgrpLabelDx" select="$lyrTitleBox + 5.7"/> <!-- the width of a layer group title (mm) -->
+<xsl:variable name="levelExpandName" select="$cSize"/> <!-- the height of the name when levels are being shown inline (mm) -->
+
+<xsl:param name="Verbose" select="0"/> <!-- Verbosity level of messages. Set to 1 (or higher) to get runtime comments -->
+
+<!-- ====== Computed values ============= -->
+
+
+<xsl:template name="Caller-Debug"><xsl:param name="text"/>
+ <xsl:if test="$Verbose > 4"><xsl:message>
Note: <xsl:value-of select="$text"/></xsl:message></xsl:if>
+</xsl:template>
+<xsl:template name="Caller-Note"><xsl:param name="text"/>
+ <xsl:message>
Note: <xsl:value-of select="$text"/></xsl:message>
+</xsl:template>
+<xsl:template name="Caller-Warning"><xsl:param name="text"/>
+ <xsl:message>
Warning: <xsl:value-of select="$text"/></xsl:message>
+</xsl:template>
+<xsl:template name="Caller-Error"><xsl:param name="text"/>
+ <xsl:message>
Error: <xsl:value-of select="$text"/></xsl:message>
+</xsl:template>
+<xsl:template name="Critical-Error"><xsl:param name="text"/>
+ <xsl:message terminate="yes">
Error: <xsl:value-of select="$text"/></xsl:message>
+</xsl:template>
+
+
+<xsl:template match="/SystemDefinition">
+ <xsl:apply-templates select="." mode="sizing"/>
+</xsl:template>
+
+
+<xsl:template match="node()" mode="sizing"><xsl:copy-of select="."/></xsl:template>
+
+<xsl:template match="systemModel" mode="sizing">
+ <!-- 1st pass to compute the sizes of everything -->
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:apply-templates select="*" mode="sizing"/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="meta" mode="sizing">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:attribute name="width">0</xsl:attribute>
+ <xsl:attribute name="height">0</xsl:attribute>
+ <xsl:copy-of select="node()"/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template name="full-width">
+ <xsl:param name="w0" select="@width"/>
+ <xsl:param name="lscale"/>
+ <!-- call from item which contains the global metas -->
+ <xsl:variable name="logo-w" select="sum(meta[@rel='model-logo']/@width) + $groupDx * count(meta[@rel='model-logo'])"/>
+ <xsl:choose>
+ <xsl:when test="not(meta[@rel='model-legend']) and meta[@rel='model-logo'] and meta[@rel='model-logo']/@width > $w0 ">
+ <!-- no legend, but a logo that's wider than the model, use logo width -->
+ <xsl:value-of select="meta[@rel='model-logo']/@width"/>
+ </xsl:when>
+ <xsl:when test="not(meta[@rel='model-legend']/legend)">
+ <!-- no legend, and if there is a logo it's narrower than the model, use model width -->
+ <xsl:value-of select="$w0"/>
+ </xsl:when>
+ <xsl:when test="meta[@rel='model-legend']/legend/@percent-width and meta[@rel='model-legend']/legend/@percent-width <= 100">
+ <!-- legend takes up less than the full width of the model, so it can be ignored -->
+ <xsl:value-of select="$w0"/>
+ </xsl:when>
+ <xsl:when test="meta[@rel='model-legend']/@width * $lscale + $logo-w > $w0">
+ <!-- if the legend is scaled so that it's wider than the model, then use that width -->
+ <xsl:value-of select="meta[@rel='model-legend']/@width * $lscale + $logo-w"/>
+ </xsl:when>
+ <xsl:otherwise> <!-- legend scaling is smaller than the width, so use model width-->
+ <xsl:value-of select="$w0"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="full-height"><xsl:param name="lscale"/>
+<!--
+ HEIGHT:
+ if there is no scaling, add max(legend height , logo height) to the page height
+ if there is scaling use max(legend height * scale , logo height)
+-->
+ <xsl:call-template name="sum-list">
+ <xsl:with-param name="list">
+ <xsl:value-of select="concat($groupDy,' ')"/>
+ <xsl:choose>
+
+ <xsl:when test="not(meta[@rel='model-legend']/legend) and meta[@rel='model-logo'] ">
+ <!-- no legend, but there's a logo, so add that height -->
+ <xsl:value-of select="meta[@rel='model-logo']/@height"/>
+ </xsl:when>
+ <xsl:when test="not(meta[@rel='model-legend']/legend)">0</xsl:when> <!-- no legend and no logo -->
+ <xsl:when test="meta[@rel='model-legend']/@height * $lscale > sum(meta[@rel='model-logo']/@height)">
+ <!-- legend is taller than the logo, use legend -->
+ <xsl:value-of select="meta[@rel='model-legend']/@height * $lscale"/>
+ </xsl:when>
+ <xsl:otherwise> <!-- legend is not at tall as the logo, use logo -->
+ <xsl:value-of select="meta[@rel='model-logo']/@height"/>
+ </xsl:otherwise>
+ </xsl:choose><xsl:text> </xsl:text>
+ <xsl:if test="meta[@rel='model-footer']">
+ <xsl:value-of select="concat(meta[@rel='model-footer']/@height,' ')"/>
+ </xsl:if>
+
+ <xsl:if test="not(layer)"> <!-- not a full model, just use this one item -->
+ <xsl:value-of select="@height"/>
+ </xsl:if>
+ <!-- padding + extra padding from layer groups for full model-->
+ <xsl:if test="layer">
+ <xsl:value-of select="concat(sum(layer[not(@span) or @span=0]/@height), ' ')"/>
+ <xsl:value-of select="count(layer[not(@span) or @span=0]) * $groupDy + sum(layer[not(@span) or @span=0]/@*[name()='padding-bottom' or name()='padding-top'])"/>
+ </xsl:if>
+ <xsl:text> </xsl:text>
+ </xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="/SystemDefinition" mode="sizing">
+ <!-- not full model, just one item -->
+ <!-- 1st pass to compute the sizes of everything -->
+
+ <xsl:variable name="content">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:attribute name="padding-left">0</xsl:attribute>
+ <xsl:attribute name="padding-right">0</xsl:attribute>
+
+ <xsl:for-each select="exslt:node-set($content)/*">
+ <xsl:attribute name="model-width"><xsl:value-of select="@width"/></xsl:attribute>
+ <xsl:attribute name="model-height"><xsl:value-of select="@height"/></xsl:attribute>
+ <!-- the width without taking the legend into account -->
+ <xsl:variable name="lscale"> <!-- legend scaling -->
+ <xsl:apply-templates select="meta[@rel='model-legend']/legend" mode="scale-factor">
+ <xsl:with-param name="full-width" select="current()/@width + $groupDy"/>
+ </xsl:apply-templates>
+ </xsl:variable>
+
+ <xsl:attribute name="width">
+ <xsl:call-template name="full-width">
+ <xsl:with-param name="w0" select="current()/@width + $groupDy"/>
+ <xsl:with-param name="lscale" select="$lscale"/>
+ </xsl:call-template>
+ </xsl:attribute>
+ <xsl:attribute name="height">
+ <xsl:call-template name="full-height">
+ <xsl:with-param name="lscale" select="$lscale"/>
+ </xsl:call-template>
+ </xsl:attribute>
+ <xsl:copy><xsl:copy-of select="@*"/> <!-- the root item -->
+ <xsl:for-each select="meta[@rel='model-legend']">
+ <!-- copy legend 1st and add scaling -->
+ <xsl:copy>
+ <xsl:copy-of select="@*[name()!='width' and name()!='height']"/>
+ <xsl:attribute name="width"><xsl:value-of select="@width * $lscale"/></xsl:attribute>
+ <xsl:attribute name="height"><xsl:value-of select="@height * $lscale"/></xsl:attribute>
+ <xsl:attribute name="scaled"><xsl:value-of select="$lscale"/></xsl:attribute>
+ <xsl:copy-of select="node()"/>
+ </xsl:copy>
+ </xsl:for-each>
+ <!-- copy everything else -->
+ <xsl:copy-of select="*[not(self::meta and @rel='model-legend')]"/>
+ </xsl:copy>
+ </xsl:for-each>
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="/SystemDefinition[systemModel]" mode="sizing">
+ <!-- 1st pass to compute the sizes of everything -->
+
+ <xsl:variable name="content0">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+
+ <xsl:variable name="heights">
+ <xsl:call-template name="layer-height">
+ <xsl:with-param name="layers">
+ <xsl:for-each select="exslt:node-set($content0)/systemModel/layer">
+ <xsl:copy><xsl:copy-of select="@id|@height|@span"/></xsl:copy>
+ </xsl:for-each>
+ </xsl:with-param>
+ <xsl:with-param name="spans" select="exslt:node-set($content0)/systemModel/layer[@span and @span!=0]"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="content">
+ <xsl:apply-templates select="exslt:node-set($content0)/*" mode="adjust-layer-height">
+ <xsl:with-param name="new-layers" select="exslt:node-set($heights)/layer"/>
+ </xsl:apply-templates>
+ </xsl:variable>
+
+
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:for-each select="exslt:node-set($content)/systemModel">
+ <xsl:variable name="m-width">
+ <xsl:call-template name="max-from-list">
+ <xsl:with-param name="list">
+ <xsl:for-each select="layer[not(@span) or @span=0]">
+ <xsl:value-of select="concat(sum(@width | following-sibling::layer[@span and position() - @span <= 0]/@width) + $groupDx * (count(@width | following-sibling::layer[@span and position() - @span <= 0]/@width) - 1), ' ')"/>
+ </xsl:for-each>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:attribute name="model-width"><xsl:value-of select="$m-width"/></xsl:attribute>
+
+ <xsl:variable name="right-borders">
+ <xsl:call-template name="max-from-list">
+ <xsl:with-param name="list">
+ <xsl:text>0 </xsl:text>
+ <xsl:for-each select="meta[@rel='layer-group']/layer-group">
+ <xsl:apply-templates select="." mode="right-border"/><xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="left-borders">
+ <xsl:call-template name="max-from-list">
+ <xsl:with-param name="list">
+ <xsl:text>0 </xsl:text>
+ <xsl:for-each select="meta[@rel='layer-group']/layer-group">
+ <xsl:apply-templates select="." mode="left-border"/><xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:attribute name="padding-left"><xsl:value-of select="$left-borders + $lyrTitleBox + 3.5 + $groupDy"/></xsl:attribute>
+ <xsl:attribute name="padding-right"><xsl:value-of select="$right-borders + $groupDy"/></xsl:attribute>
+
+ <!-- the width without taking the legend into account -->
+ <xsl:variable name="w0" select="$m-width+ $lyrTitleBox + 3.5 + 2 * $groupDy + $left-borders + $right-borders"/>
+
+ <!--
+ Options for scaling the legend:
+ WIDTH:
+ if the legend has @percent-width, then don't count the legend width in the list
+ if @percent-width < 100 ignore entirely
+ if @percent-width > 100 then width = (full width - logo width) * @percent-width % + logo width
+ @maxscale is set, then clamp scale to that and recalc width if scale > 1
+
+ if there is no legend scaling
+ take into account legend width + logo width +padding
+ -->
+
+ <xsl:variable name="lscale"> <!-- legend scaling -->
+ <xsl:apply-templates select="meta[@rel='model-legend']/legend" mode="scale-factor">
+ <xsl:with-param name="full-width" select="$w0"/>
+ </xsl:apply-templates>
+ </xsl:variable>
+
+<!--
+ HEIGHT:
+ if there is no scaling, add max(legend height , logo height) to the page height
+ if there is scaling use max(legend height * scale , logo height)
+
+-->
+
+ <xsl:attribute name="model-height">
+ <xsl:value-of select="count(layer[not(@span) or @span=0]) * $groupDy + sum(layer[not(@span) or @span=0]/@*[name()='height' or name()='padding-bottom' or name()='padding-top'])"/>
+ </xsl:attribute>
+
+ <xsl:attribute name="width">
+ <xsl:call-template name="full-width">
+ <xsl:with-param name="w0" select="$w0"/>
+ <xsl:with-param name="lscale" select="$lscale"/>
+ </xsl:call-template>
+
+ </xsl:attribute>
+ <xsl:attribute name="height">
+ <xsl:call-template name="full-height">
+ <xsl:with-param name="lscale" select="$lscale"/>
+ </xsl:call-template>
+ </xsl:attribute>
+ <xsl:copy><xsl:copy-of select="@*"/>
+ <xsl:for-each select="meta[@rel='model-legend']">
+ <!-- copy legend 1st and add scaling -->
+ <xsl:copy>
+ <xsl:copy-of select="@*[name()!='width' and name()!='height']"/>
+ <xsl:attribute name="width"><xsl:value-of select="@width * $lscale"/></xsl:attribute>
+ <xsl:attribute name="height"><xsl:value-of select="@height * $lscale"/></xsl:attribute>
+ <xsl:attribute name="scaled"><xsl:value-of select="$lscale"/></xsl:attribute>
+ <xsl:copy-of select="node()"/>
+ </xsl:copy>
+ </xsl:for-each>
+ <!-- copy everything else -->
+ <xsl:copy-of select="*[not(self::meta and @rel='model-legend')]"/>
+ </xsl:copy>
+ </xsl:for-each>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template name="layer-height-step">
+ <xsl:param name="layers"/>
+ <xsl:param name="span"/>
+
+ <xsl:variable name="spanning" select="$span/preceding-sibling::layer[not(@span) and position() <= $span/@span]"/>
+
+ <xsl:variable name="h" select="sum($spanning/@height) + (count($spanning) - 1) * $groupDy"/>
+ <xsl:variable name="even" select="($span/@height - $h) div count($spanning)"/>
+
+ <xsl:for-each select="exslt:node-set($layers)/layer">
+ <xsl:copy><xsl:copy-of select="@id|@span"/>
+ <xsl:choose>
+ <xsl:when test="0"/> <!-- why? was something removed or should something be here?-->
+ <xsl:otherwise> <!-- layers smaller than spanned -->
+ <xsl:choose>
+ <xsl:when test="$spanning[@id=current()/@id] and $span/@height > $h">
+ <!-- layers are smaller than spanned layer -->
+ <xsl:attribute name="height"><xsl:value-of select="@height + $even"/></xsl:attribute>
+ </xsl:when>
+ <xsl:when test="@id=$span/@id and $span/@height < $h">
+ <!-- layers are bigger than spanned layer -->
+ <xsl:attribute name="height"><xsl:value-of select="$h"/></xsl:attribute>
+ </xsl:when>
+ <xsl:otherwise><xsl:copy-of select="@height"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:copy>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="layer-height">
+ <xsl:param name="layers"/>
+ <xsl:param name="spans"/>
+ <xsl:choose>
+ <xsl:when test="not($spans)">
+ <!-- layers are bigger than spanned layer -->
+ <xsl:copy-of select="$layers"/>
+ </xsl:when>
+ <xsl:when test="count($spans)=1">
+ <xsl:call-template name="layer-height-step">
+ <xsl:with-param name="layers" select="$layers"/>
+ <xsl:with-param name="span" select="$spans[1]"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="layer-height">
+ <xsl:with-param name="layers">
+ <xsl:call-template name="layer-height-step">
+ <xsl:with-param name="layers" select="$layers"/>
+ <xsl:with-param name="span" select="$spans[1]"/>
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="spans" select="$spans[position() > 1]"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="legend" mode="scale-factor">
+ <!--
+ Options for scaling the legend:
+ WIDTH:
+ if the legend has @percent-width, then don't count the legend width in the list
+ if @percent-width < 100 ignore entirely
+ if @percent-width > 100 then width = (full width - logo width) * @percent-width % + logo width
+ @maxscale is set, then clamp scale to that and recalc width if scale > 1
+
+ if there is no legend scaling
+ take into account legend width + logo width +padding
+ -->
+
+ <xsl:param name="full-width"/>
+ <!-- the space avialble for the legend -->
+ <xsl:variable name="available-width" select="$full-width - sum(../../meta[@rel='model-logo']/@width) - $groupDx * count(../../meta[@rel='model-logo'])"/>
+
+
+ <!-- the space the legend wants to take up -->
+ <xsl:variable name="want-width">
+ <xsl:choose>
+ <xsl:when test="@percent-width"><xsl:value-of select="0.01* @percent-width * $available-width"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$available-width"/></xsl:otherwise> <!-- assume 100% in relevent cases where % not set -->
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@maxscale and ($want-width > ../@width * @maxscale)"><xsl:value-of select="@maxscale"/></xsl:when> <!-- desired space requires too much scaling, so limit the scale to maxscale -->
+ <xsl:when test="@maxscale or @percent-width"><xsl:value-of select="$want-width div ../@width"/></xsl:when> <!-- scaling = desired size / available size -->
+ <xsl:otherwise>1</xsl:otherwise> <!-- don't scale unless asked to -->
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="node()" mode="adjust-layer-height">
+ <xsl:copy-of select="."/>
+</xsl:template>
+
+<xsl:template match="systemModel" mode="adjust-layer-height"> <xsl:param name="new-layers"/>
+ <xsl:copy><xsl:copy-of select="@*"/>
+ <xsl:apply-templates select="*" mode="adjust-layer-height">
+ <xsl:with-param name="new-layers" select="$new-layers"/>
+ </xsl:apply-templates>
+ </xsl:copy>
+</xsl:template>
+
+
+<xsl:template match="layer" mode="adjust-layer-height"> <xsl:param name="new-layers"/>
+ <xsl:copy><xsl:copy-of select="@*[name()!='height']"/>
+ <xsl:choose>
+ <xsl:when test="$new-layers[@id=current()/@id]/@height">
+ <xsl:copy-of select="$new-layers[@id=current()/@id]/@height"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="@height"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:copy-of select="node()"/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="layer" mode="sizing">
+ <!-- 1st pass to compute the sizes of everything -->
+ <xsl:variable name="content">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+
+ <!-- if there's no content, only show if forced to by placeholder-detail -->
+ <xsl:if test="/SystemDefinition[@placeholder-detail] or exslt:node-set($content)/*[self::package]">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:if test="not(@span) or @span=0 or count(exslt:node-set($content)/package)!=1">
+ <xsl:attribute name="ipad"><xsl:value-of select="2* $groupDy"/></xsl:attribute>
+ </xsl:if>
+ <xsl:attribute name="width">
+ <xsl:value-of select="sum(exslt:node-set($content)/*/@width) + $groupDx * ( count(exslt:node-set($content)/*/@width) - 1 )"/>
+ </xsl:attribute>
+ <xsl:attribute name="height">
+ <xsl:for-each select="exslt:node-set($content)/*">
+ <xsl:sort select="@height" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@height"/></xsl:if>
+ </xsl:for-each>
+ </xsl:attribute>
+ <xsl:call-template name="layer-padding"/>
+ <xsl:copy-of select="$content"/>
+ </xsl:copy>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template name="layer-padding">
+ <xsl:variable name="top" select="count(../meta[@rel='layer-group']/descendant::layer-group[@to=current()/@id])"/>
+ <xsl:variable name="bottom" select="count(../meta[@rel='layer-group']/descendant::layer-group[@from=current()/@id])"/>
+ <xsl:if test="$top!=0">
+ <xsl:attribute name="padding-top">
+ <xsl:value-of select="$top * $lgrpDx"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="$bottom!=0">
+ <xsl:attribute name="padding-bottom">
+ <xsl:value-of select="$bottom * $lgrpDx"/>
+ </xsl:attribute>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template name="spanned-levels-step">
+ <xsl:param name="pkg"/>
+ <xsl:param name="levels"/>
+ <xsl:variable name="named" select="exslt:node-set($levels)/level[@name=$pkg/@level] or not($pkg/@level)"/>
+ <!-- it's this level, or it spans all by not having any level defined, or by being in the span range for level or it's the unnamed error level-->
+ <xsl:variable name="match" select="exslt:node-set($levels)/level[
+ @name=$pkg/@level or
+ not($pkg/@level) or
+ ($pkg/@span and following-sibling::level[position() < $pkg/@span][@name=$pkg/@level or (not(@name) and not($named))]) or
+ (not($named) and not(@name))
+ ]"/>
+
+ <xsl:variable name="h" select="(sum($match/@height) + $groupDy * (count($match) - 1))"/> <!--height of all levels spanned by this -->
+ <xsl:variable name="even" select="($pkg/@height - $groupDy * (count($match) - 1) - sum($match/@min-height)) div count($match)"/>
+
+
+ <xsl:for-each select="exslt:node-set($levels)/level">
+ <xsl:choose>
+ <xsl:when test="$even <= 0">
+ <!-- this is too small to have an impact, ignore this -->
+ <xsl:copy-of select="."/>
+ </xsl:when>
+ <xsl:when test="$match[@name=current()/@name or (not(@name) and not(current()/@name))]">
+ <xsl:choose>
+ <xsl:when test="$h >= $pkg/@height">
+ <xsl:copy-of select="."/> <!-- no change -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy><xsl:copy-of select="@*[name()!='height']"/>
+ <xsl:attribute name="height">
+ <xsl:value-of select="sum(@min-height) + $even"/>
+ </xsl:attribute>
+ <xsl:copy-of select="*"/>
+ </xsl:copy>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="."/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="spanned-levels">
+ <xsl:param name="pkgs"/>
+ <xsl:param name="levels"/>
+ <xsl:choose>
+ <xsl:when test="not($pkgs)">
+ <xsl:copy-of select="$levels"/>
+ </xsl:when>
+ <xsl:when test="count($pkgs) =1">
+ <xsl:call-template name="spanned-levels-step">
+ <xsl:with-param name="pkg" select="$pkgs[1]"/>
+ <xsl:with-param name="levels" select="$levels"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="spanned-levels">
+ <xsl:with-param name="pkgs" select="$pkgs[position() > 1]"/>
+ <xsl:with-param name="levels">
+ <xsl:call-template name="spanned-levels-step">
+ <xsl:with-param name="pkg" select="$pkgs[1]"/>
+ <xsl:with-param name="levels" select="$levels"/>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="layer[@levels]" mode="sizing">
+ <!-- layer has levels and packages, at least some with a level set, so determine height and width of each level -->
+
+ <xsl:variable name="content">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+
+ <!-- if there's no content, only show if forced to by placeholder-detail -->
+ <xsl:if test="/SystemDefinition[@placeholder-detail] or exslt:node-set($content)/*[self::package]">
+
+ <!-- the levels without taking into account spanned pkgs -->
+ <xsl:variable name="levels0">
+ <xsl:call-template name="levels-size">
+ <xsl:with-param name="levels">
+ <xsl:apply-templates select="." mode="levels"/>
+ </xsl:with-param>
+ <xsl:with-param name="items" select="exslt:node-set($content)/package"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <!-- figure out which spanned pkgs actually have an impact. This excludes:
+ * pkgs which span the same levels, but are smaller than another pkg
+ * pkgs which have collections that use the layer's levels (already taken into account)
+ -->
+
+
+ <xsl:variable name="b"> <!--all spanning pkgs with set of levels they cover -->
+ <xsl:for-each select="exslt:node-set($content)/package[((@span and @span!=1) or not(@level)) and not(not(@levels) and meta[@rel='model-levels']/level[@name])]">
+ <!-- all pkgs which span and have levels -->
+ <xsl:variable name="named" select="exslt:node-set($levels0)/level[@name=current()/@level] or not(@level)"/>
+ <xsl:variable name="pkg" select="."/>
+ <!-- it's this level, or it spans all by not having any level defined, or by being in the span range for level or it's the unnamed error level-->
+ <xsl:variable name="match" select="exslt:node-set($levels0)/level[@name=$pkg/@level or not($pkg/@level) or ($pkg/@span and following-sibling::level[position() < $pkg/@span][@name=$pkg/@level or (not(@name) and not($named))]) or (not($named) and not(@name))]"/>
+ <b id="{@id}">
+ <xsl:attribute name="levs">
+ <!-- just a space separated list of level indexs : don't use names, since one name can be blank -->
+ <xsl:for-each select="$match">
+ <xsl:value-of select="count(preceding-sibling::level)+1"/>
+ <xsl:if test="position()!=last()"><xsl:text> </xsl:text></xsl:if>
+ </xsl:for-each>
+ </xsl:attribute>
+ </b>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="impacting"> <!-- just the list of remaining pkgs which have an impact on the levels -->
+ <xsl:for-each select="exslt:node-set($b)/b">
+ <xsl:variable name="pkg" select="exslt:node-set($content)/package[@id=current()/@id]"/> <!-- the actual pkg -->
+ <xsl:variable name="ignore"> <!-- non-empty if this should be ingnored -->
+ <xsl:for-each select="following-sibling::b[@levs=current()/@levs]"> <!-- compare against pkgs with same set of levels-->
+ <!-- ignore if a later pkg is taller or the same size-->
+ <xsl:if test="exslt:node-set($content)/package[@id=current()/@id]/@height >= $pkg/@height">*</xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:if test="$ignore=''"><xsl:copy-of select="."/></xsl:if> <!--only keep the un-ignored -->
+ </xsl:for-each>
+ </xsl:variable>
+
+ <!-- adjust the list of levels to take into account the impacting packages which span levels -->
+ <xsl:variable name="levels">
+ <xsl:call-template name="spanned-levels">
+ <xsl:with-param name="pkgs" select="exslt:node-set($content)/package[@id=exslt:node-set($impacting)/b/@id]"/>
+ <xsl:with-param name="levels" select="$levels0"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="ext-w" select="count(ancestor::SystemDefinition[@levels='expand'])*$levelExpandName"/>
+
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:if test="not(@span) or @span=0 or count(exslt:node-set($content)/package)!=1">
+ <xsl:attribute name="ipad"><xsl:value-of select="2 *$groupDy"/></xsl:attribute>
+ </xsl:if>
+ <xsl:attribute name="width">
+ <xsl:for-each select="exslt:node-set($levels)/level">
+ <xsl:sort select="@width" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@width + $ext-w"/></xsl:if>
+ </xsl:for-each>
+ </xsl:attribute>
+
+ <xsl:attribute name="height">
+ <!-- +1 for padding on top and bottom -->
+ <xsl:value-of select="sum(exslt:node-set($levels)/level/@height) + $groupDy * (count(exslt:node-set($levels)/level/@height) + 1)"/>
+ </xsl:attribute>
+ <xsl:call-template name="layer-padding"/>
+ <meta rel="model-levels">
+ <xsl:copy-of select="$levels"/>
+ </meta>
+ <xsl:copy-of select="$content"/>
+ </xsl:copy>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="layer[ancestor::SystemDefinition[@detail-type='fixed' and @detail='layer']]" mode="sizing" priority="2">
+ <!-- no displayed content and fixed with, so don't even look at the pkgs -->
+ <xsl:variable name="content">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+ <xsl:variable name="levels">
+ <xsl:apply-templates select="." mode="levels"/>
+ </xsl:variable>
+ <xsl:if test="/SystemDefinition[@placeholder-detail] or exslt:node-set($content)/*[self::package]">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:attribute name="width">
+ <xsl:value-of select="$lyrFixedWidth + count(ancestor::SystemDefinition[@levels='expand'])*$levelExpandName"/>
+ </xsl:attribute>
+ <xsl:attribute name="height">
+ <xsl:value-of select="count(exslt:node-set($levels)/level) * $mHeight * 1.5 "/>
+ </xsl:attribute>
+ <xsl:call-template name="layer-padding"/>
+ <meta rel="model-levels">
+ <xsl:copy-of select="$levels"/>
+ </meta>
+ <xsl:copy-of select="$content"/>
+ </xsl:copy>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="layer[not(package/@level)]" mode="sizing" priority="1">
+ <!-- any levels apply to the collections, the pkgs all span full height of the layer => in a row on the same line
+ height = max height of all pkgs + padding
+ width = sum of all pkg widths, plus any internal padding -->
+ <xsl:variable name="content">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+
+ <!-- if there's no content, only show if forced to by placeholder-detail -->
+ <xsl:if test="/SystemDefinition[@placeholder-detail] or exslt:node-set($content)/*[self::package]">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:if test="not(@span) or @span=0 or count(exslt:node-set($content)/package)!=1">
+ <xsl:attribute name="ipad"><xsl:value-of select="2 * $groupDy"/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name="h">
+ <xsl:for-each select="exslt:node-set($content)/*">
+ <xsl:sort select="@height" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@height"/></xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:attribute name="width">
+ <!-- sum of all widths + padding -->
+ <xsl:value-of select="sum(exslt:node-set($content)/*/@width) + $groupDx * (count(exslt:node-set($content)/*) - 1) + count(ancestor::SystemDefinition[@levels='expand'])*$levelExpandName"/>
+ </xsl:attribute>
+ <xsl:attribute name="height">
+ <xsl:choose>
+ <xsl:when test="count(package)=1 and @span and @span!=0">
+ <!-- same height as contents, no room for layer name -->
+ <xsl:value-of select="$h"/>
+ </xsl:when>
+ <xsl:when test="@span and @span!=0">
+ <!-- padding on top, room for name on bottom -->
+ <xsl:value-of select="$h + $groupDy + $pkgLabelSize"/>
+ </xsl:when>
+ <xsl:otherwise> <!-- padding on top and bottom, name outside -->
+ <xsl:value-of select="$h + 2 * $groupDy"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:call-template name="layer-padding"/>
+ <xsl:copy-of select="$content"/>
+ </xsl:copy>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="collection" mode="effective-width"><xsl:param name="levels"/>
+ <!-- called on the last in a set of collections -->
+ <xsl:variable name="id" select="preceding-sibling::package[1]/@id"/>
+ <xsl:variable name="lev">
+ <xsl:call-template name="levels-widths">
+ <xsl:with-param name="levels" select="$levels"/>
+ <xsl:with-param name="items" select=". | preceding-sibling::collection[preceding-sibling::package/@id=$id]"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:for-each select="exslt:node-set($lev)/level">
+ <xsl:sort select="@width" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="concat(@width + $groupDx,' ')"/></xsl:if>
+ </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template match="collection[not(preceding-sibling::package)]" mode="effective-width">
+ <xsl:param name="levels"/> <!-- there is nothing but collections before this -->
+ <xsl:variable name="lev">
+ <xsl:call-template name="levels-widths">
+ <xsl:with-param name="levels" select="$levels"/>
+ <xsl:with-param name="items" select="preceding-sibling::collection | ."/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:for-each select="exslt:node-set($lev)/level">
+ <xsl:sort select="@width" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="concat(@width + $groupDx, ' ')"/></xsl:if>
+ </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template match="package" mode="sizing">
+ <!-- height is explicitly set by levels -->
+
+ <xsl:variable name="content">
+ <xsl:apply-templates mode="sizing"/>
+ </xsl:variable>
+ <!-- if there's no content, only show if forced to by placeholder-detail -->
+ <xsl:if test="/SystemDefinition[@placeholder-detail='package' or @placeholder-detail='component' or @placeholder-detail='collection']
+ or exslt:node-set($content)/*[self::package or self::collection]">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:variable name="levels0">
+ <xsl:apply-templates select="." mode="levels"/>
+ </xsl:variable>
+ <xsl:variable name="levels">
+ <xsl:call-template name="levels-widths">
+ <xsl:with-param name="levels" select="$levels0"/>
+ <xsl:with-param name="items" select="exslt:node-set($content)/collection"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="max-width">
+ <xsl:for-each select="exslt:node-set($levels)/level">
+ <xsl:sort select="@width" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@width"/></xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="min-width">
+ <xsl:for-each select="exslt:node-set($levels)/level">
+ <xsl:sort select="@width" order="ascending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@width"/></xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="h0" select="count(exslt:node-set($levels)/level) * ($mHeight + $groupDy) - $groupDy"/> <!-- height of just levels, no padding -->
+
+ <xsl:variable name="padding" select="number(
+ not(parent::package or
+ count(exslt:node-set($levels)/level) < 2 or
+ (not(@level) and descendant::collection/@level and ../package/@level) )
+ ) * 2 * $groupDy
+ "/>
+
+ <xsl:if test="$padding != 0 ">
+ <xsl:attribute name="ipad"><xsl:value-of select="$padding"/></xsl:attribute>
+ </xsl:if> <!--
+ Perhaps needs this rule for padding too:
+ this has no level, but children have levels and siblings have levels, ie
+ not(@level) and descendant::collection/@level and ../package/@levels
+ -->
+
+ <xsl:variable name="h">
+ <xsl:choose>
+ <xsl:when test="exslt:node-set($content)/package and /SystemDefinition/@detail='package'">
+ <xsl:value-of select="$h0 + $pkgLabelSize + $padding + $detail-block-space"/> <!-- padding plus extra room for larger itle -->
+ </xsl:when>
+ <xsl:when test="exslt:node-set($content)/package">
+ <xsl:value-of select="$h0 + $pkgLabelSize + $padding"/> <!-- padding plus room for title -->
+ </xsl:when>
+ <xsl:when test="/SystemDefinition/@detail='package' and parent::layer">
+ <xsl:value-of select="$h0 + $padding"/> <!-- needs padding -->
+ </xsl:when>
+ <xsl:when test="/SystemDefinition/@detail='package'">
+ <xsl:value-of select="$h0"/> <!-- plenty of room for title (nested pkg) -->
+ </xsl:when>
+ <xsl:when test="parent::SystemDefinition and not( exslt:node-set($levels)/level[1]/@width=0)">
+ <xsl:value-of select="$h0 + $padding + $pkgLabelSize "/> <!-- padding plus room for title -->
+ </xsl:when>
+ <xsl:when test="parent::layer and ($max-width - $min-width > $inlineLabel)">
+ <xsl:value-of select="$h0 + $padding"/> <!-- padding plus room for title -->
+ </xsl:when>
+ <!-- non-nested pkgs here on out don't have room for inline label-->
+ <xsl:when test="parent::layer and count(exslt:node-set($levels)/level) > 1">
+ <xsl:value-of select="$h0 + $padding + $pkgLabelSize"/> <!-- padding plus room for title -->
+ <!--xsl:value-of select="$h0 + 2 * $groupDy"/> <!- title should go inline -->
+ </xsl:when>
+ <xsl:when test="$max-width - $min-width < $inlineLabel">
+ <xsl:value-of select="$h0 + $padding"/> <!-- nested pkg too small to fit label: use normal height, but make wider (below) -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$h0 + $padding"/> <!-- title should go inline (nested pkg) -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="expand-width">
+ <!-- Set expand-width to indicate when the pkg should be expanded to add room for a title iff it's stays at the native height -->
+ <xsl:choose>
+ <xsl:when test="not(exslt:node-set($content)/package or exslt:node-set($content)/collection)">0</xsl:when> <!-- no content, don't expand -->
+ <xsl:when test="exslt:node-set($content)/package">0</xsl:when> <!-- never expand with nested pkgs -->
+ <xsl:when test="/SystemDefinition[@detail-type='fixed' and @detail='package']">0</xsl:when> <!-- fixed detail. -->
+ <xsl:when test="parent::package and ($min-width + $inlineLabel < $subpkgMinWidth)">
+ <xsl:value-of select="$subpkgMinWidth - $max-width"/> <!-- small nested pkg -->
+ </xsl:when>
+ <xsl:when test="parent::package and ($max-width - $min-width < $inlineLabel)">
+ <!-- nested pkg w/o room for label. Expand to fit label -->
+ <xsl:value-of select="$min-width + $inlineLabel - $max-width"/>
+ </xsl:when>
+ <xsl:when test="parent::package and ($max-width < $subpkgMinWidth)">
+ <xsl:value-of select="$subpkgMinWidth - $max-width"/>
+ </xsl:when> <!-- small nested pkg, -->
+ <xsl:when test="not(parent::package) and count(exslt:node-set($levels)/level) = 1 and ../package[@level=current()/@level and not(@span) and contains(normalize-space(@levels),' ')]">
+ <!-- this has one level, but at least one sibling at the same level has more than one, so the height will be expanded. No need to add space for title -->
+ <xsl:choose>
+ <xsl:when test="$max-width < $pkgMinWidth"> <!-- small package -->
+ <xsl:value-of select="$pkgMinWidth - $max-width"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:value-of select="0"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="$max-width < $pkgMinWidth and $inlineLabel + $min-width > $pkgMinWidth and $h < $mHeight*1.5">
+ <!-- small pkg, without enough room for a title. Make wide enough to fit the title -->
+ <xsl:value-of select="$min-width + $inlineLabel - $max-width"/>
+ </xsl:when>
+ <xsl:when test="$max-width < $pkgMinWidth">0</xsl:when>
+ <xsl:when test="parent::package and ($max-width - $min-width < $inlineLabel)">
+ <!-- need to make wider to have room for a title -->
+ <xsl:value-of select="$min-width + $inlineLabel - $max-width"/>
+ </xsl:when>
+ <xsl:when test="$h < $mHeight + $pkgLabelSize">
+ <!-- if not nested and only 1 level tall, make wider instead of taller-->
+ <!-- need to make wider to have room for a title -->
+ <xsl:value-of select="$inlineLabel"/>
+ </xsl:when>
+ <xsl:when test="parent::layer and not(@level) and ../@levels and ($max-width - $min-width < $inlineLabel)">
+ <!-- need to make wider to have room for a title -->
+ <xsl:value-of select="$min-width + $inlineLabel - $max-width"/>
+ </xsl:when>
+ <xsl:otherwise>0</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+
+
+ <xsl:variable name="w">
+ <xsl:choose>
+ <xsl:when test="not(exslt:node-set($content)/package or exslt:node-set($content)/collection) and parent::package">
+ <!-- no content, shown as placeholder. Use nested package-detail width -->
+ <xsl:value-of select="$subpkgFixedWidth"/>
+ </xsl:when>
+ <xsl:when test="not(exslt:node-set($content)/package or exslt:node-set($content)/collection)">
+ <!-- no content, shown as placeholder. Use package-detail width -->
+ <xsl:value-of select="$pkgFixedWidth"/>
+ </xsl:when>
+ <xsl:when test="exslt:node-set($content)/package and exslt:node-set($content)/collection">
+ <!-- sum of all packages, plus space between them + sum of each set of collections in a row w/padding around those-->
+ <xsl:call-template name="sum-list">
+ <xsl:with-param name="list">
+ <xsl:value-of select="concat(sum(exslt:node-set($content)/package/@width) + $groupDx * (count(exslt:node-set($content)/package) - 1),' ')"/>
+ <xsl:apply-templates mode="effective-width" select="exslt:node-set($content)/collection[not(following-sibling::*[self::collection or self::package]) or name(following-sibling::*[self::collection or self::package])='package']">
+ <xsl:with-param name="levels" select="$levels0"/>
+ </xsl:apply-templates>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="/SystemDefinition[@detail-type='fixed' and @detail='package'] and exslt:node-set($content)/package">
+ <!-- pkg detail, so don't take collections into account. Just show at width of nested pkgs + padding -->
+ <xsl:value-of select="sum(exslt:node-set($content)/package/@width) + $groupDx * (count(exslt:node-set($content)/package) - 1)"/>
+ </xsl:when>
+ <xsl:when test="/SystemDefinition[@detail-type='fixed' and @detail='package'] and (parent::layer or parent::systemModel)">
+ <!-- fixed detail. Use package-detail width -->
+ <xsl:value-of select="$pkgFixedWidth"/>
+ </xsl:when>
+ <xsl:when test="/SystemDefinition[@detail-type='fixed' and @detail='package']">
+ <!-- fixed detail. Use nested package-detail width -->
+ <xsl:value-of select="$subpkgFixedWidth"/>
+ </xsl:when>
+ <xsl:when test="parent::package">
+ <!-- small nested pkg, use min width of twice smallest possible collection -->
+ <xsl:value-of select="$max-width"/>
+ </xsl:when>
+ <xsl:when test="exslt:node-set($content)/package and exslt:node-set($content)/collection and not(exslt:node-set($content)/collection[name(following-sibling::*[1])='collection'])">
+ <!-- easy case, all in a line, no two collections next to each other -->
+ <xsl:value-of select="sum(exslt:node-set($content)/*[self::package or self::collection]/@width) + $groupDx * (count(exslt:node-set($content)/*[self::package or self::collection]) - 1)"/>
+ </xsl:when>
+ <xsl:when test="exslt:node-set($content)/package">
+ <!-- sum of all contained packages only-->
+ <xsl:value-of select="sum(exslt:node-set($content)/package/@width) + $groupDx * (count(exslt:node-set($content)/package) - 1)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- use width of widest level -->
+ <xsl:value-of select="$max-width"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <!-- this has to be done in a variable since xalan won't let the node-sets be generated inside an attribute -->
+
+ <xsl:variable name="ext-w" select="count(ancestor::SystemDefinition[@levels='expand'])*$levelExpandName"/>
+ <xsl:attribute name="width">
+ <xsl:choose>
+ <xsl:when test="parent::package and $w + $expand-width < $subpkgMinWidth"> <!-- small nested pkg, use width of 3 components -->
+ <xsl:value-of select="$subpkgMinWidth + $ext-w + pkgAuxWidth"/>
+ </xsl:when>
+ <xsl:when test="$w + $expand-width < $pkgMinWidth"> <!-- small pkg, use width of twice smallest possible collection -->
+ <xsl:value-of select="$pkgMinWidth + $ext-w + $pkgAuxWidth "/>
+ </xsl:when>
+ <xsl:otherwise><xsl:value-of select="$w + $expand-width + $ext-w + $pkgAuxWidth"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:attribute name="height"><xsl:value-of select="$h"/></xsl:attribute>
+
+
+ <meta rel="model-levels"><xsl:copy-of select="$levels"/></meta>
+
+ <xsl:copy-of select="$content"/>
+ </xsl:copy>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="collection" mode="sizing">
+ <xsl:variable name="content">
+ <xsl:apply-templates select="node()" mode="sizing"/>
+ </xsl:variable>
+ <!-- if there's no content, only show if forced to by placeholder-detail -->
+ <xsl:if test="/SystemDefinition[@placeholder-detail='component' or @placeholder-detail='collection']
+ or exslt:node-set($content)/component">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:variable name="w" select="sum(exslt:node-set($content)/component/@width)"/>
+ <xsl:attribute name="width">
+ <xsl:choose>
+ <!-- a collection might be a sibling to a pkg, so it will take up some space at pkag level of detail -->
+ <xsl:when test="$w < $mMinWidth or /SystemDefinition[(@detail='collection' or @detail='package') and @detail-type='fixed']">
+ <xsl:value-of select="$mMinWidth"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:value-of select="$w"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:attribute name="height"><xsl:value-of select="$mHeight"/></xsl:attribute>
+ <xsl:copy-of select="$content"/>
+ </xsl:copy>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="component" mode="sizing">
+ <xsl:copy><xsl:apply-templates mode="copy-attr" select="@*"/>
+ <xsl:attribute name="width"><xsl:value-of select="$cSize"/></xsl:attribute>
+ <xsl:attribute name="height"><xsl:value-of select="$cSize"/></xsl:attribute>
+ <xsl:apply-templates select="node()" mode="sizing"/>
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match="package/package/package" priority="9" mode="sizing"> <!-- ignore 3+ level depth packages -->
+ <xsl:apply-templates mode="sizing"/>
+</xsl:template>
+
+<!-- stuff for dealing with levels -->
+
+<xsl:template match="*" mode="levels" priority="-8"><level/>
+ <!-- Should not be able to get here. Panic -->
+<xsl:message terminate="yes">
+<xsl:value-of select="concat(name(), ' ',@id,': ',@levels)"/> (<xsl:value-of select="*/@level | */*/@level"/>)
+</xsl:message>
+</xsl:template>
+
+
+<xsl:template match="package[not(@levels)] |layer[not(@levels)]" mode="levels" priority="-1">
+ <!-- no levels, so everything must be on same nameless level (barring exceptions below) -->
+ <level/>
+</xsl:template>
+
+
+<xsl:template match="layer[@levels]/package/package" mode="levels" priority="1">
+<!-- a nested package with levels defined in the layer -->
+ <xsl:call-template name="levels-list">
+ <xsl:with-param name="levels" select="normalize-space(../../@levels)"/>
+ </xsl:call-template>
+ <xsl:if test="descendant::collection[not(contains(concat(' ',normalize-space(current()/../../@levels),' '),@level)) or not(@level)]">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">collection without valid level in package <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <level/>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="layer/package/package[@levels]" mode="levels" priority="1">
+<!-- a nested package with levels defined in the layer -->
+ <xsl:call-template name="levels-list">
+ <xsl:with-param name="levels" select="normalize-space(@levels)"/>
+ </xsl:call-template>
+ <xsl:if test="descendant::collection[not(contains(concat(' ',normalize-space(current()/@levels),' '),@level)) or not(@level)]">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">collection without valid level in package <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <level/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="layer/package[@levels]/package" mode="levels" priority="1">
+ <!-- a package with levels and a nested pkg -->
+ <xsl:call-template name="levels-list">
+ <xsl:with-param name="levels" select="normalize-space(../@levels)"/>
+ </xsl:call-template>
+ <xsl:if test="descendant::collection[not(contains(concat(' ',normalize-space(current()/../@levels),' '),@level)) or not(@level)]">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">collection without valid level in package <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <level/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="layer[@levels]/package[not(@levels|@level)]" mode="levels">
+ <!-- pkg with levels defined in the layer, and spans whole set of layer levels-->
+ <xsl:call-template name="levels-list">
+ <xsl:with-param name="levels" select="normalize-space(../@levels)"/>
+ </xsl:call-template>
+ <xsl:if test="descendant::collection[not(contains(concat(' ',normalize-space(current()/../@levels),' '),@level)) or not(@level)]">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">collection without valid level in package <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <level/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="layer[@levels]/package[not(@levels) and @level]" mode="levels">
+ <!-- pkg with levels defined in the layer, but at a range of levels -->
+ <xsl:variable name="span" select="sum(@span) + 1 - count(@span)"/> <!-- easier than having a <choose> -->
+ <xsl:variable name="list">
+ <xsl:call-template name="levels-list">
+ <xsl:with-param name="levels" select="normalize-space(../@levels)"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="match" select="exslt:node-set($list)/level[@name=current()/@level]"/> <!-- the ending level of the span -->
+
+ <xsl:choose>
+ <xsl:when test="not($match)">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">collection without valid level in package <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <xsl:copy-of select="exslt:node-set($list)/level[position() > last() - $span + 1]"/> <!-- want last $span-1 levels from this list -->
+ <level/> <!-- extra unnamed level -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$match | $match/preceding-sibling::level[position() < $span]"/> <!-- previous $span - 1 siblings -->
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="package[not(@levels) and not(descendant::collection/@level)]" mode="levels" priority="1">
+ <!-- no levels on the package, and none used by any collections => just one level in pkg -->
+ <level/>
+</xsl:template>
+
+<xsl:template match="layer/package[@levels]|SystemDefinition/package[@levels]" mode="levels">
+ <!-- a package with levels -->
+ <xsl:call-template name="levels-list"/>
+ <xsl:if test="descendant::collection[not(contains(concat(' ',normalize-space(current()/@levels),' '),@level)) or not(@level)]">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">collection without valid level in package <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <level/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="layer[@levels]" mode="levels">
+ <xsl:call-template name="levels-list"/>
+ <xsl:if test="package[not(contains(concat(' ',normalize-space(current()/@levels),' '),@level)) and @level]">
+ <!--<xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">package without valid level in layer <xsl:value-of select="@id"/></xsl:with-param>
+ </xsl:call-template>-->
+ <level/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="layer[not(@levels) and package/@level]" mode="levels">
+ <xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">layer <xsl:value-of select="@id"/> has no levels, but contains package <xsl:value-of select="package[@level]/@id"/> with defined level</xsl:with-param>
+ </xsl:call-template>
+ <!-- this is an error case, well... more of a warning case. Easy to handle with one fake level -->
+ <level/>
+</xsl:template>
+
+<xsl:template name="levels-list"><xsl:param name="levels" select="normalize-space(@levels)"/>
+ <xsl:choose>
+ <xsl:when test="contains($levels,' ')">
+ <level name="{substring-before($levels,' ')}"/>
+ <xsl:call-template name="levels-list">
+ <xsl:with-param name="levels" select="substring-after($levels,' ')"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise><level name="{$levels}"/></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- widths of the collections in the levels that are in $item -->
+<xsl:template name="levels-widths"><xsl:param name="levels"/><xsl:param name="items" select="collection"/>
+ <xsl:for-each select="exslt:node-set($levels)/*">
+ <xsl:copy><xsl:copy-of select="@*"/>
+ <xsl:attribute name="width">
+ <xsl:variable name="match" select="$items[@level=current()/@name or (not(@level) and not(current()/@name)) ]"/>
+ <xsl:choose>
+ <xsl:when test="$match">
+ <xsl:variable name="w" select="sum($match/@width)"/>
+ <xsl:value-of select="$w + (count($match) - 1) * $groupDx"/>
+ </xsl:when>
+ <xsl:otherwise>0</xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ </xsl:copy>
+ </xsl:for-each>
+</xsl:template>
+
+<!-- add 2d sizes for each level contained in $item -->
+<xsl:template name="levels-size"><xsl:param name="levels"/><xsl:param name="items" select="package"/>
+ <xsl:apply-templates select="$items[1]" mode="levels-size">
+ <xsl:with-param name="levels" select="$levels"/>
+ </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template mode="levels-size-step" match="package">
+ <xsl:param name="levels"/> <!-- the set of levels -->
+ <xsl:variable name="pkg" select="."/>
+ <xsl:variable name="named" select="$levels[@name=current()/@level] or not(@level)"/>
+ <!-- it's this level, or it spans all by not having any level defined, or by being in the span range for level or it's the unnamed error level-->
+ <xsl:variable name="match" select="$levels[@name=$pkg/@level or not($pkg/@level) or ($pkg/@span and following-sibling::level[position() < $pkg/@span][@name=$pkg/@level or (not(@name) and not($named))]) or (not($named) and not(@name))]"/>
+
+
+ <xsl:variable name="max-width"> <!-- the width of the widest level this spans (ie the x-pos of this pkg) -->
+ <xsl:for-each select="$match[@width]">
+ <xsl:sort select="@width" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@width"/></xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+
+
+
+ <xsl:variable name="h" select="(sum($match/@height) + $groupDy * (count($match/@height) - 1))"/> <!--height of all levels spanned by this, may be negative if no match -->
+
+ <xsl:for-each select="$levels">
+ <xsl:copy><xsl:copy-of select="@*[name()!='width' and name()!='height' and name()!='min-height']"/>
+ <xsl:choose>
+ <xsl:when test="not($match[@name=current()/@name or (not(@name) and not(current()/@name))])">
+ <!-- the package does not impact this level, just copy existing attributes -->
+ <xsl:copy-of select="@width|@height|@min-height"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="width">
+ <!-- current level is added to by this pkg -->
+ <xsl:choose>
+ <xsl:when test="$max-width='' or $max-width=0">
+ <!-- at the current level, but not adding to anything-->
+ <xsl:value-of select="$pkg/@width"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- at the current level, but adding after something -->
+ <xsl:value-of select="$pkg/@width + $groupDx + $max-width"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:choose>
+ <xsl:when test="count($match)=1 and (not(@height) or (@height < $pkg/@height))">
+ <!-- pkg too tall, make just this single level bigger -->
+ <xsl:copy-of select="$pkg/@height"/>
+ <xsl:attribute name="min-height"><xsl:value-of select="$pkg/@height"/></xsl:attribute> <!-- level cannot be smaller than this -->
+ </xsl:when>
+ <xsl:when test="count($match)=1">
+ <!-- level is bigger then the pkg, so keep height as is -->
+ <xsl:copy-of select="@height|@min-height"/>
+ </xsl:when>
+ <xsl:when test="not($pkg/@levels) and $pkg/meta[@rel='model-levels']/level[@name=current()/@name or (not(@name) and not(current()/@name))]">
+ <!-- there is a collection at this level, so note that height -->
+ <xsl:choose>
+ <xsl:when test="not(@height) or @height < $mHeight">
+ <xsl:attribute name="height"><xsl:value-of select="$mHeight"/></xsl:attribute>
+ <xsl:attribute name="min-height"><xsl:value-of select="$mHeight"/></xsl:attribute>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="@height|@min-height"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise><xsl:copy-of select="@height|@min-height"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:copy-of select="*"/>
+ <xsl:if test="@name=$pkg/@level or (not($named) and not(@name)) or not($pkg/@level) and not(following-sibling::level)">
+ <xsl:variable name="base">
+ <xsl:for-each select="$match[@width]">
+ <xsl:sort select="@width" order="descending" data-type="number"/>
+ <xsl:if test="position()=1"><xsl:value-of select="@width"/></xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="x">
+ <xsl:choose>
+ <xsl:when test="$base=''">
+ <xsl:value-of select="$groupDx *count(@width)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$base + $groupDx *count(@width)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <step ref="{$pkg/@id}" x="{$x}"/>
+ </xsl:if>
+ </xsl:copy>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template mode="levels-size" match="package"><xsl:param name="levels"/>
+ <xsl:apply-templates select="following-sibling::package[1]" mode="levels-size">
+ <xsl:with-param name="levels">
+ <xsl:apply-templates mode="levels-size-step" select="current()">
+ <xsl:with-param name="levels" select="exslt:node-set($levels)/*"/>
+ </xsl:apply-templates>
+ </xsl:with-param>
+ </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template mode="levels-size" match="package[not(following-sibling::package)]"><xsl:param name="levels"/>
+ <xsl:apply-templates mode="levels-size-step" select=".">
+ <xsl:with-param name="levels" select="exslt:node-set($levels)/*"/>
+ </xsl:apply-templates>
+</xsl:template>
+
+
+<!-- /levels -->
+
+<!-- fix attributes -->
+<xsl:template mode="copy-attr" match="@*"><xsl:copy-of select="."/></xsl:template>
+
+<xsl:template mode="copy-attr" match="collection/@level" priority="2">
+ <xsl:choose><!-- remove invalid level attribute -->
+ <!-- easier to read and write as two entries rather than one long one -->
+ <xsl:when test="ancestor::package[@levels] and contains(concat(' ',normalize-space(ancestor::package/@levels),' '),concat(' ',.,' '))">
+ <xsl:copy-of select="."/>
+ </xsl:when>
+ <xsl:when test="not(ancestor::package[@levels]) and ancestor::layer[@levels] and contains(concat(' ',normalize-space(ancestor::layer/@levels),' '),concat(' ',.,' '))">
+ <xsl:copy-of select="."/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="Caller-Warning"><xsl:with-param name="text">collection <xsl:value-of select="../@id"/> with invalid level "<xsl:value-of select="."/>"</xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template mode="copy-attr" match="layer/package/@level" priority="2">
+ <xsl:choose><!--set to empty invalid level attribute -->
+ <!-- easier to read and write as two entries rather than one long one -->
+ <xsl:when test="not(../../@levels)">
+ <xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">package <xsl:value-of select="../@id"/> cannot have level "<xsl:value-of select="."/>" if none defined in layer <xsl:value-of select="../@id"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="contains(concat(' ',normalize-space(../../@levels),' '),concat(' ',.,' '))">
+ <xsl:copy-of select="."/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="Caller-Warning">
+ <xsl:with-param name="text">package <xsl:value-of select="../@id"/> with invalid level "<xsl:value-of select="."/>"</xsl:with-param>
+ </xsl:call-template>
+ <xsl:attribute name="level">*</xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template mode="copy-attr" match="layer/@span[.=0]" priority="2"/> <!-- default value, easier to remove -->
+
+<xsl:template mode="copy-attr" match="package/@span[.=1]" priority="2"/> <!-- default value, easier to remove -->
+
+
+<!-- remove empty items, unless specifically told to include -->
+
+<xsl:template match="component[not(unit) and @filtered and not(/SystemDefinition/@placeholder-detail='component')]" mode="sizing" priority="3"/>
+<xsl:template match="collection[not(component) and @filtered and not(/SystemDefinition[@placeholder-detail='component' or @placeholder-detail='collection'])]" mode="sizing"/>
+<xsl:template match="package[not(collection or package) and @filtered and not(/SystemDefinition[@placeholder-detail!='layer'])]" mode="sizing"/>
+<xsl:template match="layer[not(package) and @filtered and not(/SystemDefinition[@placeholder-detail='layer'])]" mode="sizing"/>
+
+
+
+
+<xsl:template match="layer-group" mode="right-border">
+ <xsl:variable name="d"><xsl:apply-templates select="." mode="depth"/></xsl:variable>
+ <xsl:value-of select="$d * $lgrpDx"/>
+</xsl:template>
+
+<xsl:template match="layer-group" mode="depth">
+ <xsl:variable name="d">
+ <xsl:call-template name="max-from-list">
+ <xsl:with-param name="list">
+ <xsl:text>0 </xsl:text>
+ <xsl:for-each select="layer-group">
+ <xsl:apply-templates select="." mode="depth"/><xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="$d + 1"/>
+</xsl:template>
+
+
+<xsl:template match="layer-group" mode="left-border">
+ <xsl:variable name="child-border">
+ <xsl:call-template name="max-from-list">
+ <xsl:with-param name="list">
+ <xsl:text>0 </xsl:text>
+ <xsl:for-each select="layer-group">
+ <xsl:apply-templates select="." mode="left-border"/><xsl:text> </xsl:text>
+ </xsl:for-each>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@label"><xsl:value-of select="$child-border + $lgrpLabelDx"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$child-border + 0.75 * $lgrpDx"/></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!-- ====== legend ============= -->
+
+<xsl:include href="legend-module.xsl"/>
+<!-- end legend -->
+
+
+<!-- ============ utilities ============ -->
+
+<xsl:template name="sum-list"><xsl:param name="list"/> <!-- space-separated and terminated -->
+ <xsl:variable name="cur" select="substring-before($list,' ')"/>
+ <xsl:variable name="next" select="substring-after($list,' ')"/>
+ <xsl:variable name="add"><xsl:choose>
+ <xsl:when test="$next=''">0</xsl:when>
+ <xsl:otherwise><xsl:call-template name="sum-list">
+ <xsl:with-param name="list" select="$next"/>
+ </xsl:call-template></xsl:otherwise>
+ </xsl:choose></xsl:variable>
+ <xsl:value-of select="$cur + $add"/>
+</xsl:template>
+
+
+<xsl:template name="max-from-list"><xsl:param name="list"/>
+ <xsl:variable name="cur" select="substring-before($list,' ')"/>
+ <xsl:variable name="next" select="substring-after($list,' ')"/>
+ <xsl:variable name="max"><xsl:choose>
+ <xsl:when test="$next=''">0</xsl:when>
+ <xsl:otherwise><xsl:call-template name="max-from-list">
+ <xsl:with-param name="list" select="$next"/>
+ </xsl:call-template></xsl:otherwise>
+ </xsl:choose></xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$cur > $max"><xsl:value-of select="$cur"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$max"/></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+</xsl:stylesheet>
\ No newline at end of file