From 8a3daa78d96de6be6f2a5617d8996a631997b28f Mon Sep 17 00:00:00 2001 From: simon <simon> Date: Tue, 20 Jul 2010 19:53:39 +0000 Subject: [PATCH] Some new work on Postgres, but not yet working and maybe a false start; apart from that, stuff brought over from Cygnets, getting file upload working on Monorail. --- ADL.csproj | 61 - ADL.sln | 44 - TestApp/TestApp.csproj | 124 - TestApp/Web.config | 125 - TestApp/testapp.adl.xml | 181 +- schemas/adl-1.4.dtd | 1229 ++++---- test.build | 165 - transforms/adl2canonical.xslt | 12 +- transforms/adl2controllerclasses.xslt | 2777 +++++++++-------- transforms/adl2documentation.xslt | 4 +- transforms/adl2entityclasses.xslt | 18 +- transforms/adl2hibernate.xslt | 8 +- transforms/adl2mssql.xslt | 1686 +++++----- transforms/adl2psql.xslt | 202 +- transforms/adl2views.xslt | 4125 +++++++++++++------------ transforms/base-type-include.xslt | 150 +- transforms/csharp-type-include.xslt | 199 +- transforms/i18n-en-GB-include.xslt | 10 +- transforms/permissions-include.xslt | 10 +- 19 files changed, 5376 insertions(+), 5754 deletions(-) delete mode 100755 ADL.csproj delete mode 100755 ADL.sln delete mode 100755 TestApp/TestApp.csproj delete mode 100755 TestApp/Web.config delete mode 100755 test.build diff --git a/ADL.csproj b/ADL.csproj deleted file mode 100755 index 9cc4ee5..0000000 --- a/ADL.csproj +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.21022</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{15DF3516-FE95-4BB0-9353-2E1E624303B8}</ProjectGuid> - <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>ADL</RootNamespace> - <AssemblyName>ADL</AssemblyName> - <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> - <FileAlignment>512</FileAlignment> - <StartupObject> - </StartupObject> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>false</Optimize> - <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> - <Optimize>true</Optimize> - <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> - <!-- To modify your build process, add your task inside one of the targets below and uncomment it. - Other similar extension points exist, see Microsoft.Common.targets. - <Target Name="BeforeBuild"> - </Target> - <Target Name="AfterBuild"> - </Target> - --> - <ItemGroup> - <Content Include="transforms\adl2canonical.xslt" /> - <Content Include="transforms\adl2controllerclasses.xslt" /> - <Content Include="transforms\adl2documentation.xslt" /> - <Content Include="transforms\adl2entityclasses.xslt" /> - <Content Include="transforms\adl2hibernate.xslt" /> - <Content Include="transforms\adl2mssql.xslt" /> - <Content Include="transforms\adl2psql.xslt" /> - <Content Include="transforms\adl2views.xslt" /> - <Content Include="transforms\base-type-include.xslt" /> - <Content Include="transforms\csharp-type-include.xslt" /> - <Content Include="transforms\i18n-en-GB-include.xslt" /> - <Content Include="transforms\localise-transform.xslt" /> - </ItemGroup> - <ItemGroup> - <None Include="schemas\adl-1.1.dtd" /> - <None Include="test.build" /> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/ADL.sln b/ADL.sln deleted file mode 100755 index a829b97..0000000 --- a/ADL.sln +++ /dev/null @@ -1,44 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ADL", "ADL.csproj", "{15DF3516-FE95-4BB0-9353-2E1E624303B8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CygnetToolkit", "..\CygnetToolkit\CygnetToolkit.csproj", "{77FB7DE5-1F33-4DDC-8A2E-79EF4728705E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp\TestApp.csproj", "{45578889-14A2-4A53-8391-0596369CCBA5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{D705F7CA-EB87-48EF-8F18-7D1AD90660BA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{83B41EED-23C8-4DEF-B113-46A426346E45}" - ProjectSection(SolutionItems) = preProject - ADL.vsmdi = ADL.vsmdi - LocalTestRun.testrunconfig = LocalTestRun.testrunconfig - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {15DF3516-FE95-4BB0-9353-2E1E624303B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {15DF3516-FE95-4BB0-9353-2E1E624303B8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {15DF3516-FE95-4BB0-9353-2E1E624303B8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {15DF3516-FE95-4BB0-9353-2E1E624303B8}.Release|Any CPU.Build.0 = Release|Any CPU - {77FB7DE5-1F33-4DDC-8A2E-79EF4728705E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77FB7DE5-1F33-4DDC-8A2E-79EF4728705E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77FB7DE5-1F33-4DDC-8A2E-79EF4728705E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77FB7DE5-1F33-4DDC-8A2E-79EF4728705E}.Release|Any CPU.Build.0 = Release|Any CPU - {45578889-14A2-4A53-8391-0596369CCBA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {45578889-14A2-4A53-8391-0596369CCBA5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {45578889-14A2-4A53-8391-0596369CCBA5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {45578889-14A2-4A53-8391-0596369CCBA5}.Release|Any CPU.Build.0 = Release|Any CPU - {D705F7CA-EB87-48EF-8F18-7D1AD90660BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D705F7CA-EB87-48EF-8F18-7D1AD90660BA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D705F7CA-EB87-48EF-8F18-7D1AD90660BA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D705F7CA-EB87-48EF-8F18-7D1AD90660BA}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj deleted file mode 100755 index 7883618..0000000 --- a/TestApp/TestApp.csproj +++ /dev/null @@ -1,124 +0,0 @@ -<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.21022</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{45578889-14A2-4A53-8391-0596369CCBA5}</ProjectGuid> - <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> - <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>TestApp</RootNamespace> - <AssemblyName>TestApp</AssemblyName> - <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>false</Optimize> - <OutputPath>bin\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> - <Optimize>true</Optimize> - <OutputPath>bin\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <ItemGroup> - <Reference Include="Castle.Core, Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL" /> - <Reference Include="Castle.MonoRail.Framework, Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL" /> - <Reference Include="Castle.MonoRail.Framework.Views.NVelocity, Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL" /> - <Reference Include="Iesi.Collections, Version=1.0.0.3, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>L:\Castle\1.0.3RC3\Iesi.Collections.dll</HintPath> - </Reference> - <Reference Include="NHibernate, Version=1.2.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL" /> - <Reference Include="System" /> - <Reference Include="System.Data" /> - <Reference Include="System.Core"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Data.DataSetExtensions"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Web.Extensions"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Xml.Linq"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Drawing" /> - <Reference Include="System.Web" /> - <Reference Include="System.Xml" /> - <Reference Include="System.Configuration" /> - <Reference Include="System.Web.Services" /> - <Reference Include="System.EnterpriseServices" /> - <Reference Include="System.Web.Mobile" /> - </ItemGroup> - <ItemGroup> - <Content Include="Default.aspx" /> - <Content Include="testapp.adl.xml" /> - <Content Include="Web.config" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Auto\address.auto.cs" /> - <Compile Include="Auto\person.auto.cs" /> - <Compile Include="Default.aspx.cs"> - <DependentUpon>Default.aspx</DependentUpon> - </Compile> - <Compile Include="Default.aspx.designer.cs"> - <DependentUpon>Default.aspx</DependentUpon> - </Compile> - <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Web\Controllers\Auto\AbstractadltestappController.auto.cs" /> - <Compile Include="Web\Controllers\Auto\addressController.auto.cs" /> - <Compile Include="Web\Controllers\Auto\personController.auto.cs" /> - </ItemGroup> - <ItemGroup> - <None Include="Web\Views\Auto\test\address\edit.auto.vm" /> - <None Include="Web\Views\Auto\test\address\list.auto.vm" /> - <None Include="Web\Views\Auto\test\address\maybedelete.auto.vm" /> - <None Include="Web\Views\Auto\test\person\edit.auto.vm" /> - <None Include="Web\Views\Auto\test\person\maybedelete.auto.vm" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\..\CygnetToolkit\CygnetToolkit.csproj"> - <Project>{77FB7DE5-1F33-4DDC-8A2E-79EF4728705E}</Project> - <Name>CygnetToolkit</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <Folder Include="App_Data\" /> - <Folder Include="Web\bin\" /> - </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" /> - <!-- To modify your build process, add your task inside one of the targets below and uncomment it. - Other similar extension points exist, see Microsoft.Common.targets. - <Target Name="BeforeBuild"> - </Target> - <Target Name="AfterBuild"> - </Target> - --> - <ProjectExtensions> - <VisualStudio> - <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}"> - <WebProjectProperties> - <UseIIS>False</UseIIS> - <AutoAssignPort>True</AutoAssignPort> - <DevelopmentServerPort>3627</DevelopmentServerPort> - <DevelopmentServerVPath>/</DevelopmentServerVPath> - <IISUrl> - </IISUrl> - <NTLMAuthentication>False</NTLMAuthentication> - <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> - </WebProjectProperties> - </FlavorProperties> - </VisualStudio> - </ProjectExtensions> -</Project> \ No newline at end of file diff --git a/TestApp/Web.config b/TestApp/Web.config deleted file mode 100755 index fcaa9dc..0000000 --- a/TestApp/Web.config +++ /dev/null @@ -1,125 +0,0 @@ -<?xml version="1.0"?> - -<configuration> - - - <configSections> - <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> - <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> - <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> - <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> - <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" /> - <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> - <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> - <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> - </sectionGroup> - </sectionGroup> - </sectionGroup> - </configSections> - - - <appSettings/> - <connectionStrings/> - - <system.web> - <!-- - Set compilation debug="true" to insert debugging - symbols into the compiled page. Because this - affects performance, set this value to true only - during development. - --> - <compilation debug="false"> - - <assemblies> - <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> - <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> - <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> - </assemblies> - - </compilation> - <!-- - The <authentication> section enables configuration - of the security authentication mode used by - ASP.NET to identify an incoming user. - --> - <authentication mode="Windows" /> - <!-- - The <customErrors> section enables configuration - of what to do if/when an unhandled error occurs - during the execution of a request. Specifically, - it enables developers to configure html error pages - to be displayed in place of a error stack trace. - - <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm"> - <error statusCode="403" redirect="NoAccess.htm" /> - <error statusCode="404" redirect="FileNotFound.htm" /> - </customErrors> - --> - - <pages> - <controls> - <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - </controls> - </pages> - - <httpHandlers> - <remove verb="*" path="*.asmx"/> - <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/> - </httpHandlers> - <httpModules> - <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - </httpModules> - - </system.web> - - <system.codedom> - <compilers> - <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" - type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <providerOption name="CompilerVersion" value="v3.5"/> - <providerOption name="WarnAsError" value="false"/> - </compiler> - </compilers> - </system.codedom> - - <!-- - The system.webServer section is required for running ASP.NET AJAX under Internet - Information Services 7.0. It is not necessary for previous version of IIS. - --> - <system.webServer> - <validation validateIntegratedModeConfiguration="false"/> - <modules> - <remove name="ScriptModule" /> - <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - </modules> - <handlers> - <remove name="WebServiceHandlerFactory-Integrated"/> - <remove name="ScriptHandlerFactory" /> - <remove name="ScriptHandlerFactoryAppServices" /> - <remove name="ScriptResource" /> - <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" - type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" - type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> - <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> - </handlers> - </system.webServer> - - <runtime> - <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> - <dependentAssembly> - <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/> - <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/> - <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> - </dependentAssembly> - </assemblyBinding> - </runtime> - -</configuration> diff --git a/TestApp/testapp.adl.xml b/TestApp/testapp.adl.xml index d05b3ec..136379f 100755 --- a/TestApp/testapp.adl.xml +++ b/TestApp/testapp.adl.xml @@ -1,115 +1,82 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- DOCTYPE application PUBLIC "-//CYGNETS//DTD ADL 0.1//EN" "http://www.cygnets.co.uk/schemas/adl-0.1.1.dtd" --> -<!-- DOCTYPE application SYSTEM "file:/C:/Projects/ADL/schemas/adl-0.dtd" --> - -<!-- +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE application PUBLIC "-//JOURNEYMAN//DTD ADL 1.4//EN" + "http://bowyer.journeyman.cc/adl/stable/adl/schemas/adl-1.4.dtd"> +<!-- Application Description Language framework testapp.adl.xml the object of this file is to exercise as many aspects of ADL as possible; - it isn't expected to describe an application which does anything useful + in the first instance, this is an attempt to recreate PRES in ADL - Copyright (c) 2008 Cygnet Solutions Ltd - - $Author: sb $ - $Revision: 1.2 $ - $Date: 2008-07-01 16:08:17 $ ---> - -<application name="ADLTestApp" xmlns="http://cygnets.co.uk/schemas/adl-1.2"> - <content> - <head> - - </head> - <top> - - </top> - <foot> - - </foot> - </content> - <typedef name="postcode" type="string" size="10" - pattern="^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$"> - <documentation> - a postcode follows arcane rules; this specification from - http://regexlib.com/REDetails.aspx?regexp_id=260. + $Author: simon $ + $Revision: 1.3 $ + $Date: 2010-07-20 19:53:40 $ + --> +<application name="pres" xmlns="http://bowyer.journeyman.cc/adl/stable/"> + <specification abbr="regexplib" name="RegexpLib.com" url="http://regexlib.com/"/> + <content> + <head/> + <top/> + <foot/> + </content> + <typedef name="postcode" + pattern="^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$" + size="10" type="string"> + <documentation> + <reference abbr="regexplib" section="REDetails.aspx?regexp_id=260"/> + a postcode follows arcane rules. </documentation> - </typedef> - <typedef name="age" type="integer" minimum="0" maximum="120"> - <documentation> + </typedef> + <typedef maximum="120" minimum="0" name="age" type="integer"> + <documentation> We don't believe people who claim to be over 120. </documentation> - </typedef> - <group name="public"/> - <group name="admin" parent="public"/> - <entity name="Person"> - <property name="LastName" type="string" required="true" size="100" distinct="user"> - <prompt locale="en-UK" prompt="Surname"/> - </property> - <property name="ForeNames" type="string" required="true" size="100" distinct="user"> - <prompt locale="en-UK" prompt="Fore names"/> - </property> - <property name="Partner" type="entity" entity="Person"/> - <property name="Gender" type="string" size="1" required="true"> - <option value="M"> - <prompt locale="en-GB" prompt="Male"/> - </option> - <option value="F"> - <prompt locale="en-GB" prompt="Female"/> - </option> - </property> - <property name="age" type="defined" typedef="age"/> - <property name="Address" type="entity" entity="Address" distinct="user"/> - <property name="Friends" type="link" entity="Person"/> - <form name="edit" properties="listed"> - <fieldgroup name="Personal Data"> - <documentation> - Basic data about the person - </documentation> - <field property="ForeNames"> - <prompt locale="en-GB" prompt="Fore names"/> - </field> - <field property="LastName"> - <prompt locale="en-GB" prompt="Surname"/> - <help locale="en-GB"> - Family name of this person, conventionally their last name - </help> - </field> - <field property="Partner"/> - <field property="Gender"/> - <field property="Address"/> - </fieldgroup> - <fieldgroup name="Community"> - <field property="Friends"/> - </fieldgroup> - </form> - </entity> - <entity name="Address"> - <key> - <property name="Number" type="string" size="8" distinct="all"> - <prompt locale="en-GB" prompt="House number"/> - <help locale="en-GB"> - House or building number - </help> - </property> - <property name="Postcode" type="defined" typedef="postcode" required="false" distinct="all"> - <prompt locale="en-UK" prompt="Post code"/> - </property> - </key> - <property name="Address1" type="string" required="true" size="255"> - <prompt locale="en-UK" prompt="Address"/> - </property> - <property name="Address2" type="string" required="false" size="255"> - <prompt locale="en-UK" prompt="Line 2"/> - </property> - <property name="Address3" type="string" required="false" size="255"> - <prompt locale="en-UK" prompt="Line 3"/> - </property> - <property name="City" type="string" required="false" size="255"> - <prompt locale="en-UK" prompt="Post town"/> - </property> - <property name="County" type="string" required="false" size="255" /> - <form name="edit" properties="all"/> - <list name="list" properties="user-distinct"/> - </entity> -</application> \ No newline at end of file + </typedef> + <typedef name="email" + pattern="^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$" size="128"> + <documentation> + <reference abbr="regexplib" section="REDetails.aspx?regexp_id=26"/> + </documentation> + </typedef> + <group name="public"/> + <group name="admin" parent="public"/> + <entity name="Actor"> + <documentation> + A real (administrative) user of this system with a first-class, database layer login, + as opposed to a Subscriber with a second-class, application layer login. + </documentation> + <property name="Name" size="64" type="string"/> + <property name="EMail" type="defined" typedef="email"/> + <property name="Approved" type="boolean"/> + </entity> + <entity name="Article"> + <property name="Created" type="date"/> + <property name="Embargo" type="date"/> + <property entity="Category" name="Category" type="entity"/> + <property name="Title" size="128" type="string"/> + <property entity="Actor" name="Author" type="entity"/> + <property name="Location" type="entity" entity="Location"/> + </entity> + <entity name="Author"> + <property name="CanonicalName" size="128" type="string"/> + <property entity="NomDePlume" name="NomsDePlume" type="list"/> + <property name="Disambiguation" size="256" type="string"> + <documentation> + If the canonical name is a common one, or there are known to be two or more authors + with the same canonical name, some brief text about the author to disambiguate. + </documentation> + </property> + </entity> + <entity name="Book"> + <property entity="Article" name="Article" type="entity"/> + <property name="AuthorAsEntered" size="128" type="string"> + <documentation>The name of the author as entered by the original user, prior to being resolved against known authors</documentation> + </property> + <property entity="Author" name="Authors" type="link"/> + <property name="Title" size="128" type="string"/> + </entity> + <entity name="NomDePlume"> + <property name="Name" size="128" type="string"/> + <property entity="Author" name="Author" type="entity"/> + </entity> +</application> diff --git a/schemas/adl-1.4.dtd b/schemas/adl-1.4.dtd index a52cfbf..d8286e3 100755 --- a/schemas/adl-1.4.dtd +++ b/schemas/adl-1.4.dtd @@ -1,614 +1,615 @@ - <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> - <!-- --> - <!-- adl-1.4.dtd --> - <!-- --> - <!-- Purpose: --> - <!-- Document Type Description for Application Description --> - <!-- Language. Normative for now; will be replaced by a schema. ` --> - <!-- --> - <!-- Author: Simon Brooke <stillyet@journeyman.cc> --> - <!-- Created: 24th January 2006 --> - <!-- Copyright: (c) 2007 Cygnet Solutions --> - <!-- --> - <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> - - <!-- - $Revision: 1.4 $ - --> - -<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> -<!-- Before we start: import XHTML for use in documentation sections --> -<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> -<!-- doesn't work yet --> -<!-- ENTITY % XHTML PUBLIC - "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -%XHTML; --> - -<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> -<!-- Before we start: some useful definitions --> -<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> - -<!-- some basic character entities inherited from HTML. Actually we probably ought to -import all the HTML4 character entity files, and possibly the HTML4 Strict DTD (so -that we can allow HTML block level entities within content elements --> -<!ENTITY nbsp " "> -<!ENTITY pound "£"> -<!ENTITY copy "©"> - - -<!-- boolean means true or false --> -<!ENTITY % Boolean "(true|false)" > - -<!-- - Locale is a string comprising an ISO 639 language code followed by a space - followed by an ISO 3166 country code, or else the string 'default'. See: - <URL:http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt> - <URL:http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html> ---> -<!ENTITY % Locale "CDATA" > - -<!-- - permissions a group may have on an entity, list, page, form or field - permissions are deemed to increase as you go right. A group cannot - have greater permission on a field than on the form it is in, or - greater permission on form than the entity it belongs to - - none: none - read: select - insert: insert - noedit: select, insert - edit: select, insert, update - all: select, insert, update, delete ---> -<!ENTITY % Permissions "none|read|insert|noedit|edit|all" > - - -<!-- - actions which should be cascaded to dependent objects. All these values except - 'manual' are taken from Hibernate and should be passed through the adl2hibernate - mapping transparently. Relevent only for properties with type='entity', type='link' - and type='list' - - all : cascade delete, save and update - all-delete-orphan : see hibernate documentation; relates to transient objects only - delete : cascade delete actions, but not save and update - manual : cascading will be handled in manually managed code, code to - handle cascading should not be generated - save-update : cascade save and update actions, but not delete. ---> -<!ENTITY % CascadeActions "all|all-delete-orphan|delete|manual|save-update"> - -<!-- - data types which can be used in a typedef to provide validation - - e.g. a string can be used with a regexp or a scalar can be used with - min and max values - string: varchar java.sql.Types.VARCHAR - integer: int java.sql.Types.INTEGER - real: double java.sql.Types.DOUBLE - money: money java.sql.Types.INTEGER - date: date java.sql.Types.DATE - time: time java.sql.Types.TIME - timestamp: timestamp java.sql.Types.TIMESTAMP - uploadable: varchar java.sql.Types.VARCHAR - image: varchar java.sql.Types.VARCHAR - - uploadable is as string but points to an uploaded file; image is as - uploadable but points to an uploadable graphical image file ---> -<!ENTITY % DefinableDataTypes "string|integer|real|money|date|time|timestamp|uploadable" > - -<!-- - data types which are fairly straightforward translations of JDBC data types - boolean: boolean or java.sql.Types.BIT - char(1) java.sql.Types.CHAR - text: text or java.sql.Types.LONGVARCHAR - memo java.sql.Types.CLOB ---> -<!ENTITY % SimpleDataTypes "%DefinableDataTypes;|boolean|text" > - -<!-- - data types which are more complex than SimpleDataTypes... - entity : a foreign key link to another entity (i.e. the 'many' end of a - one-to-many link); - list : a list of some other entity that links to me (i.e. the 'one' end of - a one-to-many link); - link : a many to many link (via a link table); - defined : a type defined by a typedef. ---> -<!ENTITY % ComplexDataTypes "entity|link|list|defined" > - -<!-- - data types which require special handling - which don't simply map onto - common SQL data types - geopos : a latitude/longitude pair (experimental and not yet implemented) - image : a raster image file, in jpeg|gif|png format (experimental, not yet implemented) - message : an internationalised message, having different translations for different locales ---> -<!ENTITY % SpecialDataTypes "geopos|image|message" > - -<!-- all data types --> -<!ENTITY % AllDataTypes "%ComplexDataTypes;|%SimpleDataTypes;|%SpecialDataTypes;" > - -<!-- content, for things like pages (i.e. forms, lists, pages) --> -<!ENTITY % Content "head|top|foot" > - -<!ENTITY % FieldStuff "field|fieldgroup|auxlist|verb"> - -<!ENTITY % PageContent "%Content;|%FieldStuff;" > - -<!ENTITY % PageStuff "%PageContent;|permission|pragma" > - -<!-- Properties for pages: - name: obviously, the name (URL stub) of the page - properties: the properties of the entity the page describes to be shown - as fields on the page - all: obviously, all properties (except the abstract primary key, if - present) - user-distinct: all properties which are user-distinct (NOTE: Not yet implemented) - listed: only those properties for which fields are explicitly listed ---> -<!ENTITY % PageAttrs - "name CDATA #REQUIRED - properties (all|user-distinct|listed) #REQUIRED" > - -<!-- Actions for generators (mainly for keyfields - see entity 'generator', below - assigned: In manually-maintained code, you contract to assign a value - to this property before it is persisted. - guid: The system will supply a unique GUid value to this field - before it is persisted. - mannual: You contract to supply a generatos class in manually maintained - code. - native: The database will supply a unique value to this field when it - is persisted; the value will be an integer. RECOMMENDED! ---> -<!ENTITY % GeneratorActions "assigned|guid|manual|native"> - -<!-- sequences for orderings of lists - see entity 'order' - canonical: Whatever the normal canonical ordering for this datatype is - - typically alpha-numeric, except for dates, etc. - reverse-canonical: The reverse of the above - - possibly there should be some further values but I have no idea what these are ---> -<!ENTITY % Sequences "canonical|reverse-canonical"> - -<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> -<!-- Elements --> -<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> - -<!-- - the application that the document describes: required top level element - - name: the name of this application - version: the version number of this application - revision: the revision of the ADL document - currency: the base monetary currency, in the form of an ISO 4217 three-letter code - xmlns: XML namespace, in case required ---> -<!ELEMENT application ( specification*, documentation?, content?, typedef*, group*, entity*)> -<!ATTLIST application - name CDATA #REQUIRED - version CDATA #IMPLIED - revision CDATA #IMPLIED - currency CDATA #IMPLIED - xmlns CDATA #IMPLIED> - -<!-- - the definition of a defined type. At this stage a defined type is either - a string in which case it must have size and pattern, or - a scalar in which case it must have minimum and/or maximum - pattern must be a regular expression as interpreted by org.apache.regexp.RE - minimum and maximum must be of appropriate format for the datatype specified. - Validation may be done client-side and/or server-side at application layer - and/or server side at database layer. - - name: the name of this typedef - type: the simple type on which this defined type is based; must be - present unless in-implementation children are supplied - size: the data size of this defined type - pattern: a regular expression which values for this type must match - minimum: the minimum value for this type (if base type is scalar) - maximum: the maximum value for this type (if base type is scalar) - --> -<!ELEMENT typedef (documentation?, in-implementation*, help*) > - -<!ATTLIST typedef - name CDATA #REQUIRED - type (%DefinableDataTypes;) #IMPLIED - size CDATA #IMPLIED - pattern CDATA #IMPLIED - minimum CDATA #IMPLIED - maximum CDATA #IMPLIED> - -<!-- - information about how to translate a type into types known to different target - languages. TODO: Once again I'm not wholly comfortable with the name; I'm not - really comfortable that this belongs in ADL at all. - - target: the target language - value: the type to use in that target language - kind: OK, I confess I don't understand this, but Andrew needs it... ---> -<!ELEMENT in-implementation (documentation?)> - -<!ATTLIST in-implementation - target CDATA #REQUIRED - value CDATA #REQUIRED - kind CDATA #IMPLIED> - -<!-- - a group of people with similar permissions to one another - - name: the name of this group - parent: the name of a group of which this group is subset - --> -<!ELEMENT group (documentation?)> - -<!ATTLIST group - name CDATA #REQUIRED - parent CDATA #IMPLIED> - - - -<!-- - an entity which has properties and relationships; maps onto a database - table or a Java serialisable class - or, of course, various other things - - name: obviously, the name of this entity - natural-key: if present, the name of a property of this entity which forms - a natural primary key [NOTE: Only partly implemented. NOTE: much of - the present implementation assumes all primary keys will be - integers. This needs to be fixed!] DEPRECATED: remove; replace with the - 'key' element, below. - table: the name of the table in which this entity is stored. Defaults to same - as name of entity. Strongly recommend this is not used unless it needs - to be different from the name of the entity - foreign: this entity is part of some other system; no code will be generated - for it, although code which links to it will be generated ---> -<!ELEMENT entity ( documentation?, prompt*, content?, key?, - property*, permission*, (form | page | list)*)> -<!ATTLIST entity - name CDATA #REQUIRED - natural-key CDATA #IMPLIED - table CDATA #IMPLIED - foreign %Boolean; #IMPLIED> - -<!-- - contains documentation on the element which immediately contains it. TODO: - should HTML markup within a documentation element be allowed? If so, are - there restrictions? ---> -<!ELEMENT documentation ( #PCDATA|reference)*> -<!ATTLIST documentation - xmlns CDATA #IMPLIED> - - -<!-- an explicit primary key, possibly compound --> -<!ELEMENT key (property*)> - - -<!-- - a property (field) of an entity (table) - - name: the name of this property. - type: the type of this property. - default: the default value of this property. There will probably be - magic values of this! - typedef: name of the typedef to use, it type = 'defined'. - distinct: distinct='system' required that every value in the system - will be distinct (i.e. natural primary key); - distinct='user' implies that the value may be used by users - in distinguishing entities even if values are not formally - unique; - distinct='all' implies that the values are formally unique - /and/ are user friendly (NOTE: not implemented). - entity: if type='entity', the name of the entity this property is - a foreign key link to. - if type='list', the name of the entity that has a foreign - key link to this entity - farkey: if type='list', the name of farside key in the listed - entity; if type='entity' and the farside field to join to - is not the farside primary key, then the name of that - farside field - required: whether this propery is required (i.e. 'not null'). - immutable: if true, once a value has been set it cannot be changed. - size: fieldwidth of the property if specified. - concrete: if set to 'false', this property is not stored in the - database but must be computed (manually written code must - be provided to support this) - cascade: what action(s) on the parent entity should be cascaded to - entitie(s) linked on this property. Valid only if type='entity', - type='link' or type='list'. - column: name of the column in a SQL database table in which this property - is stored. TODO: Think about this. - unsaved-value: - of a property whose persistent value is set on first being - committed to persistent store, the value which it holds before - it has been committed ---> -<!ELEMENT property ( documentation?, generator?, (permission|option|prompt|help|ifmissing)*)> - -<!ATTLIST property - name CDATA #REQUIRED - type (%AllDataTypes;) #REQUIRED - default CDATA #IMPLIED - typedef CDATA #IMPLIED - distinct (none|all|user|system) #IMPLIED - entity CDATA #IMPLIED - farkey CDATA #IMPLIED - required %Boolean; #IMPLIED - immutable %Boolean; #IMPLIED - size CDATA #IMPLIED - column CDATA #IMPLIED - concrete %Boolean; #IMPLIED - cascade (%CascadeActions;) #IMPLIED> - - -<!-- - marks a property which is auto-generated by some part of the system. - This is based on the Hibernate construct, except that the Hibernate - implementation folds both its internal generators and custom generators - onto the same attribute. This separates them onto two attributes so we - can police values for Hibernate's 'builtin' generators. - - action: one of the supported Hibernate builtin generators, or - 'manual'. 'native' is strongly recommended in most instances - class: if action is 'manual', the name of a manually maintained - class conforming to the Hibernate IdentifierGenerator - interface, or its equivalent in other languages ---> -<!ELEMENT generator (documentation?, param*)> -<!ATTLIST generator - action (%GeneratorActions;) #REQUIRED - class CDATA #IMPLIED> - -<!-- - A parameter passed to the generator. Again, based on the Hibernate - implementation. TODO: #PCDATA is wrong as the content model, as embedded - markup is definitely not allowed! - - name: the name of this parameter - - TODO: This needs to be renamed or removed because it conflicts with the - XHTML element of the same name. In fact it could be simply removed since - our usage is compatible with the XHTML usage, but it might be less - ambiguous to rename it. ---> -<!ELEMENT param (#PCDATA)> -<!ATTLIST param - name CDATA #REQUIRED> - - - -<!-- - one of an explicit list of optional values a property may have - NOTE: whether options get encoded at application layer or at database layer - is UNDEFINED; either behaviour is correct. If at database layer it's also - UNDEFINED whether they're encoded as a single reference data table or as - separate reference data tables for each property. - - value: the value of this option - - TODO: This needs to be renamed or removed because it conflicts with the - XHTML element of the same name. In fact it could be simply removed since - our usage is compatible with the XHTML usage, but it might be less - ambiguous to rename it. ---> -<!ELEMENT option (documentation?, prompt*)> -<!-- if the value is different from the prompt the user sees, specify it --> -<!ATTLIST option - value CDATA #IMPLIED> - - -<!-- - permissions policy on an entity, a page, form, list or field - - group: the group to which permission is granted - permission: the permission which is granted to that group ---> -<!ELEMENT permission (documentation?)> -<!ATTLIST permission - group CDATA #REQUIRED - permission (%Permissions;) #REQUIRED> - - -<!-- - pragmatic advice to generators of lists and forms, in the form of - name/value pairs which may contain anything. Over time some pragmas - will become 'well known', but the whole point of having a pragma - architecture is that it is extensible. ---> -<!ELEMENT pragma (documentation?)> -<!ATTLIST pragma - name CDATA #REQUIRED - value CDATA #REQUIRED> - -<!-- - a prompt for a property or field; used as the prompt text for a widget - which edits it. Typically there will be only one of these per property - per locale; if there are more than one all those matching the locale may - be concatenated, or just one may be used. - - prompt: the prompt to use - locale: the locale in which to prefer this prompt ---> -<!ELEMENT prompt (documentation?)> -<!ATTLIST prompt - prompt CDATA #REQUIRED - locale %Locale; #REQUIRED > - -<!-- - helptext about a property of an entity, or a field of a page, form or - list, or a typedef. Typically there will be only one of these per property - per locale; if there are more than one all those matching the locale may - be concatenated, or just one may be used. - - locale: the locale in which to prefer this prompt ---> -<!ELEMENT help (#PCDATA)> -<!ATTLIST help - locale %Locale; #REQUIRED - xmlns CDATA #IMPLIED > - -<!-- - helpful text to be shown if a property value is missing, typically when - a form is submitted. Typically there will be only one of these per property - per locale; if there are more than one all those matching the locale may - be concatenated, or just one may be used. Later there may be more sophisticated - behaviour here. ---> -<!ELEMENT ifmissing (#PCDATA)> -<!ATTLIST ifmissing - locale %Locale; #REQUIRED - xmlns CDATA #IMPLIED> - -<!-- a form through which an entity may be added or edited - - TODO: This needs to be renamed because it conflicts with the - XHTML element of the same name. ---> -<!ELEMENT form (documentation?, ( %PageStuff;)*)> -<!ATTLIST form %PageAttrs;> - - -<!-- a page on which an entity may be displayed --> -<!ELEMENT page (documentation?, ( %PageStuff;)*)> -<!ATTLIST page %PageAttrs;> - -<!ELEMENT order (documentation?)> -<!ATTLIST order - property CDATA #REQUIRED - sequence (%Sequences;) #IMPLIED> - -<!-- - a list on which entities of a given type are listed - - onselect: name of form/page/list to go to when - a selection is made from the list ---> -<!ELEMENT list (documentation?, ( %PageStuff;|order)*)> -<!ATTLIST list %PageAttrs; - onselect CDATA #IMPLIED > - - -<!-- - a subsidiary list, on which entities related to primary - entities in the enclosing page or list are listed - - property: the property of the enclosing entity that this - list displays (obviously, must be of type='list') - onselect: the form or page of the listed entity to call - when an item from the list is selected - canadd: true if the user should be able to add records - to this list - --> -<!ELEMENT auxlist (documentation?, (prompt|%FieldStuff;)*)> -<!ATTLIST auxlist %PageAttrs; - property CDATA #REQUIRED - onselect CDATA #IMPLIED - canadd %Boolean; #IMPLIED> - -<!-- - a group of fields and other controls within a form or list, which the - renderer might render as a single pane in a tabbed display, for example. - --> -<!ELEMENT fieldgroup (documentation?, (prompt|permission|%FieldStuff;)*)> -<!ATTLIST fieldgroup - name CDATA #REQUIRED> - - -<!-- a field in a form or page - - property: the property which this field displays/edits - --> -<!ELEMENT field (documentation?, (prompt|help|permission)*) > -<!ATTLIST field - property CDATA #REQUIRED > - -<!-- a verb is something that may be done through a form. Probably the verbs 'store' - and 'delete' are implied, but maybe they need to be explicitly declared. The 'verb' - attribute of the verb is what gets returned to the controller --> -<!ELEMENT verb (documentation?, (prompt|help|permission)*) > -<!ATTLIST verb - verb CDATA #REQUIRED - dangerous %Boolean; #REQUIRED> - - -<!-- a container for global content --> -<!ELEMENT content (%Content;)*> - - -<!-- - content to place in the head of the generated document; this is #PCDATA - because it will almost certainly belong to a different namespace - (usually HTML) - - TODO: This needs to be renamed or removed because it conflicts with the - XHTML element of the same name. In fact it could be simply removed since - our usage is compatible with the XHTML usage, but it might be less - ambiguous to rename it. ---> -<!ELEMENT head (#PCDATA) > -<!ATTLIST head - xmlns CDATA #IMPLIED> - - -<!-- - content to place in the top of the body of the generated document; - this is %Flow; which is any HTML block or inline level element. ---> -<!ELEMENT top (#PCDATA) > -<!ATTLIST top - xmlns CDATA #IMPLIED> - -<!-- - content to place at the foot of the body of the generated document; - this is %Flow; which is any HTML block or inline level element. ---> -<!ELEMENT foot (#PCDATA) > -<!ATTLIST foot - xmlns CDATA #IMPLIED> - -<!-- - The 'specification' and 'reference' elements are for documentation only, - and do not contribute to the engineering of the application described. - - A specification element is intended chiefly to declare the reference - documents which may be used in documentation elements later in the - document. - - url: The URL from which the document referenced can be retrieved - name: The full name (title) given to this document - abbr: A convenient abbreviated name ---> -<!ELEMENT specification (documentation?, reference*)> -<!ATTLIST specification - url CDATA #IMPLIED - name CDATA #REQUIRED - abbr CDATA #REQUIRED> - -<!-- - The 'specification' and 'reference' elements are for documentation only, - and do not contribute to the engineering of the application described. - - A reference element is a reference to a specifying document. - - abbr: The abbreviated name of the specification to which this - reference refers - section: The 'anchor part' (part following a hash character) which, - when appended to the URL, will locate the exact section - referenced. - entity: A reference to another entity within this ADL document - property: A reference to another property within this ADL document; - if entity is also specified then of that entity, else of - the ancestor entity if any - --> -<!ELEMENT reference (documentation?)> -<!ATTLIST reference - abbr CDATA #IMPLIED - section CDATA #IMPLIED - entity CDATA #IMPLIED - property CDATA #IMPLIED> - + <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + <!-- --> + <!-- adl-1.4.dtd --> + <!-- --> + <!-- Purpose: --> + <!-- Document Type Description for Application Description --> + <!-- Language. Normative for now; will be replaced by a schema. ` --> + <!-- --> + <!-- Author: Simon Brooke <simon@cygnets.co.uk> --> + <!-- Created: 24th January 2006 --> + <!-- Copyright: (c) 2007 Cygnet Solutions --> + <!-- --> + <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + + <!-- + $Revision: 1.5 $ + --> + +<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> +<!-- Before we start: import XHTML for use in documentation sections --> +<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + +<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> +<!-- Before we start: some useful definitions --> +<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + +<!-- some basic character entities inherited from HTML. Actually we probably ought to +import all the HTML4 character entity files, and possibly the HTML4 Strict DTD (so +that we can allow HTML block level entities within content elements --> +<!ENTITY nbsp " "> +<!ENTITY pound "£"> +<!ENTITY copy "©"> + + +<!-- boolean means true or false --> +<!ENTITY % Boolean "(true|false)" > + +<!-- + Locale is a string comprising an ISO 639 language code followed by a space + followed by an ISO 3166 country code, or else the string 'default'. See: + <URL:http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt> + <URL:http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html> +--> +<!ENTITY % Locale "CDATA" > + +<!-- + permissions a group may have on an entity, list, page, form or field + permissions are deemed to increase as you go right. A group cannot + have greater permission on a field than on the form it is in, or + greater permission on form than the entity it belongs to + + none: none + read: select + insert: insert + noedit: select, insert + edit: select, insert, update + all: select, insert, update, delete +--> +<!ENTITY % Permissions "none|read|insert|noedit|edit|all" > + + +<!-- + actions which should be cascaded to dependent objects. All these values except + 'manual' are taken from Hibernate and should be passed through the adl2hibernate + mapping transparently. Relevent only for properties with type='entity', type='link' + and type='list' + + all : cascade delete, save and update + all-delete-orphan : see hibernate documentation; relates to transient objects only + delete : cascade delete actions, but not save and update + manual : cascading will be handled in manually managed code, code to + handle cascading should not be generated + save-update : cascade save and update actions, but not delete. +--> +<!ENTITY % CascadeActions "all|all-delete-orphan|delete|manual|save-update"> + +<!-- + data types which can be used in a typedef to provide validation - + e.g. a string can be used with a regexp or a scalar can be used with + min and max values + string: varchar java.sql.Types.VARCHAR + integer: int java.sql.Types.INTEGER + real: double java.sql.Types.DOUBLE + money: money java.sql.Types.INTEGER + date: date java.sql.Types.DATE + time: time java.sql.Types.TIME + timestamp: timestamp java.sql.Types.TIMESTAMP + uploadable: varchar java.sql.Types.VARCHAR + image: varchar java.sql.Types.VARCHAR + + uploadable is as string but points to an uploaded file; image is as + uploadable but points to an uploadable graphical image file +--> +<!ENTITY % DefinableDataTypes "string|integer|real|money|date|time|timestamp|uploadable" > + +<!-- + data types which are fairly straightforward translations of JDBC data types + boolean: boolean or java.sql.Types.BIT + char(1) java.sql.Types.CHAR + text: text or java.sql.Types.LONGVARCHAR + memo java.sql.Types.CLOB +--> +<!ENTITY % SimpleDataTypes "%DefinableDataTypes;|boolean|text" > + +<!-- + data types which are more complex than SimpleDataTypes... + entity : a foreign key link to another entity (i.e. the 'many' end of a + one-to-many link); + list : a list of some other entity that links to me (i.e. the 'one' end of + a one-to-many link); + link : a many to many link (via a link table); + defined : a type defined by a typedef. +--> +<!ENTITY % ComplexDataTypes "entity|link|list|defined" > + +<!-- + data types which require special handling - which don't simply map onto + common SQL data types + geopos : a latitude/longitude pair (experimental and not yet implemented) + image : a raster image file, in jpeg|gif|png format (experimental, not yet implemented) + message : an internationalised message, having different translations for different locales +--> +<!ENTITY % SpecialDataTypes "geopos|image|message" > + +<!-- all data types --> +<!ENTITY % AllDataTypes "%ComplexDataTypes;|%SimpleDataTypes;|%SpecialDataTypes;" > + +<!-- content, for things like pages (i.e. forms, lists, pages) --> +<!ENTITY % Content "head|top|foot" > + +<!ENTITY % FieldStuff "field|fieldgroup|auxlist|verb"> + +<!ENTITY % PageContent "%Content;|%FieldStuff;" > + +<!ENTITY % PageStuff "%PageContent;|permission|pragma" > + +<!-- Properties for pages: + name: obviously, the name (URL stub) of the page + properties: the properties of the entity the page describes to be shown + as fields on the page + all: obviously, all properties (except the abstract primary key, if + present) + user-distinct: all properties which are user-distinct (NOTE: Not yet implemented) + listed: only those properties for which fields are explicitly listed +--> +<!ENTITY % PageAttrs + "name CDATA #REQUIRED + properties (all|user-distinct|listed) #REQUIRED" > + +<!-- Actions for generators (mainly for keyfields - see entity 'generator', below + assigned: In manually-maintained code, you contract to assign a value + to this property before it is persisted. + guid: The system will supply a unique GUid value to this field + before it is persisted. + mannual: You contract to supply a generatos class in manually maintained + code. + native: The database will supply a unique value to this field when it + is persisted; the value will be an integer. RECOMMENDED! +--> +<!ENTITY % GeneratorActions "assigned|guid|manual|native"> + +<!-- sequences for orderings of lists - see entity 'order' + canonical: Whatever the normal canonical ordering for this datatype is - + typically alpha-numeric, except for dates, etc. + reverse-canonical: The reverse of the above + + possibly there should be some further values but I have no idea what these are +--> +<!ENTITY % Sequences "canonical|reverse-canonical"> + +<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> +<!-- Elements --> +<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + +<!-- + the application that the document describes: required top level element + + name: the name of this application + version: the version number of this application + revision: the revision of the ADL document + currency: the base monetary currency, in the form of an ISO 4217 three-letter code + xmlns: XML namespace, in case required +--> +<!ELEMENT application ( specification*, documentation?, content?, typedef*, group*, entity*)> +<!ATTLIST application + name CDATA #REQUIRED + version CDATA #IMPLIED + revision CDATA #IMPLIED + currency CDATA #IMPLIED + xmlns CDATA #IMPLIED> + +<!-- + the definition of a defined type. At this stage a defined type is either + a string in which case it must have size and pattern, or + a scalar in which case it must have minimum and/or maximum + pattern must be a regular expression as interpreted by org.apache.regexp.RE + minimum and maximum must be of appropriate format for the datatype specified. + Validation may be done client-side and/or server-side at application layer + and/or server side at database layer. + + name: the name of this typedef + type: the simple type on which this defined type is based; must be + present unless in-implementation children are supplied + size: the data size of this defined type + pattern: a regular expression which values for this type must match + minimum: the minimum value for this type (if base type is scalar) + maximum: the maximum value for this type (if base type is scalar) + --> +<!ELEMENT typedef (documentation?, in-implementation*, help*) > + +<!ATTLIST typedef + name CDATA #REQUIRED + type (%DefinableDataTypes;) #IMPLIED + size CDATA #IMPLIED + pattern CDATA #IMPLIED + minimum CDATA #IMPLIED + maximum CDATA #IMPLIED> + +<!-- + information about how to translate a type into types known to different target + languages. TODO: Once again I'm not wholly comfortable with the name; I'm not + really comfortable that this belongs in ADL at all. + + target: the target language + value: the type to use in that target language + kind: OK, I confess I don't understand this, but Andrew needs it... +--> +<!ELEMENT in-implementation (documentation?)> + +<!ATTLIST in-implementation + target CDATA #REQUIRED + value CDATA #REQUIRED + kind CDATA #IMPLIED> + +<!-- + a group of people with similar permissions to one another + + name: the name of this group + parent: the name of a group of which this group is subset + --> +<!ELEMENT group (documentation?)> + +<!ATTLIST group + name CDATA #REQUIRED + parent CDATA #IMPLIED> + + + +<!-- + an entity which has properties and relationships; maps onto a database + table or a Java serialisable class - or, of course, various other things + + name: obviously, the name of this entity + natural-key: if present, the name of a property of this entity which forms + a natural primary key [NOTE: Only partly implemented. NOTE: much of + the present implementation assumes all primary keys will be + integers. This needs to be fixed!] DEPRECATED: remove; replace with the + 'key' element, below. + table: the name of the table in which this entity is stored. Defaults to same + as name of entity. Strongly recommend this is not used unless it needs + to be different from the name of the entity + foreign: this entity is part of some other system; no code will be generated + for it, although code which links to it will be generated +--> +<!ELEMENT entity ( documentation?, prompt*, content?, key?, + property*, permission*, (form | page | list)*)> +<!ATTLIST entity + name CDATA #REQUIRED + natural-key CDATA #IMPLIED + table CDATA #IMPLIED + foreign %Boolean; #IMPLIED> + +<!-- + contains documentation on the element which immediately contains it. TODO: + should HTML markup within a documentation element be allowed? If so, are + there restrictions? +--> +<!ELEMENT documentation ( #PCDATA|reference)*> +<!ATTLIST documentation + xmlns CDATA #IMPLIED> + + +<!-- an explicit primary key, possibly compound --> +<!ELEMENT key (property*)> + + +<!-- + a property (field) of an entity (table) + + name: the name of this property. + type: the type of this property. + default: the default value of this property. There will probably be + magic values of this! + typedef: name of the typedef to use, it type = 'defined'. + distinct: distinct='system' required that every value in the system + will be distinct (i.e. natural primary key); + distinct='user' implies that the value may be used by users + in distinguishing entities even if values are not formally + unique; + distinct='all' implies that the values are formally unique + /and/ are user friendly (NOTE: not implemented). + entity: if type='entity', the name of the entity this property is + a foreign key link to. + if type='list', the name of the entity that has a foreign + key link to this entity + farkey: if type='list', the name of farside key in the listed + entity; if type='entity' and the farside field to join to + is not the farside primary key, then the name of that + farside field + required: whether this propery is required (i.e. 'not null'). + immutable: if true, once a value has been set it cannot be changed. + size: fieldwidth of the property if specified. + concrete: if set to 'false', this property is not stored in the + database but must be computed (manually written code must + be provided to support this) + cascade: what action(s) on the parent entity should be cascaded to + entitie(s) linked on this property. Valid only if type='entity', + type='link' or type='list'. + column: name of the column in a SQL database table in which this property + is stored. TODO: Think about this. + unsaved-value: + of a property whose persistent value is set on first being + committed to persistent store, the value which it holds before + it has been committed +--> +<!ELEMENT property ( documentation?, generator?, (permission|option|prompt|help|ifmissing)*)> + +<!ATTLIST property + name CDATA #REQUIRED + type (%AllDataTypes;) #REQUIRED + default CDATA #IMPLIED + typedef CDATA #IMPLIED + distinct (none|all|user|system) #IMPLIED + entity CDATA #IMPLIED + farkey CDATA #IMPLIED + required %Boolean; #IMPLIED + immutable %Boolean; #IMPLIED + size CDATA #IMPLIED + column CDATA #IMPLIED + concrete %Boolean; #IMPLIED + cascade (%CascadeActions;) #IMPLIED> + + +<!-- + marks a property which is auto-generated by some part of the system. + This is based on the Hibernate construct, except that the Hibernate + implementation folds both its internal generators and custom generators + onto the same attribute. This separates them onto two attributes so we + can police values for Hibernate's 'builtin' generators. + + action: one of the supported Hibernate builtin generators, or + 'manual'. 'native' is strongly recommended in most instances + class: if action is 'manual', the name of a manually maintained + class conforming to the Hibernate IdentifierGenerator + interface, or its equivalent in other languages +--> +<!ELEMENT generator (documentation?, param*)> +<!ATTLIST generator + action (%GeneratorActions;) #REQUIRED + class CDATA #IMPLIED> + +<!-- + A parameter passed to the generator. Again, based on the Hibernate + implementation. TODO: #PCDATA is wrong as the content model, as embedded + markup is definitely not allowed! + + name: the name of this parameter + + TODO: This needs to be renamed or removed because it conflicts with the + XHTML element of the same name. In fact it could be simply removed since + our usage is compatible with the XHTML usage, but it might be less + ambiguous to rename it. +--> +<!ELEMENT param (#PCDATA)> +<!ATTLIST param + name CDATA #REQUIRED> + + + +<!-- + one of an explicit list of optional values a property may have + NOTE: whether options get encoded at application layer or at database layer + is UNDEFINED; either behaviour is correct. If at database layer it's also + UNDEFINED whether they're encoded as a single reference data table or as + separate reference data tables for each property. + + value: the value of this option + + TODO: This needs to be renamed or removed because it conflicts with the + XHTML element of the same name. In fact it could be simply removed since + our usage is compatible with the XHTML usage, but it might be less + ambiguous to rename it. +--> +<!ELEMENT option (documentation?, prompt*)> +<!-- if the value is different from the prompt the user sees, specify it --> +<!ATTLIST option + value CDATA #IMPLIED> + + +<!-- + permissions policy on an entity, a page, form, list or field + + group: the group to which permission is granted + permission: the permission which is granted to that group +--> +<!ELEMENT permission (documentation?)> +<!ATTLIST permission + group CDATA #REQUIRED + permission (%Permissions;) #REQUIRED> + + +<!-- + pragmatic advice to generators of lists and forms, in the form of + name/value pairs which may contain anything. Over time some pragmas + will become 'well known', but the whole point of having a pragma + architecture is that it is extensible. +--> +<!ELEMENT pragma (documentation?)> +<!ATTLIST pragma + name CDATA #REQUIRED + value CDATA #REQUIRED> + +<!-- + a prompt for a property or field; used as the prompt text for a widget + which edits it. Typically there will be only one of these per property + per locale; if there are more than one all those matching the locale may + be concatenated, or just one may be used. + + prompt: the prompt to use + locale: the locale in which to prefer this prompt +--> +<!ELEMENT prompt (documentation?)> +<!ATTLIST prompt + prompt CDATA #REQUIRED + locale %Locale; #REQUIRED > + +<!-- + helptext about a property of an entity, or a field of a page, form or + list, or a typedef. Typically there will be only one of these per property + per locale; if there are more than one all those matching the locale may + be concatenated, or just one may be used. + + locale: the locale in which to prefer this prompt +--> +<!ELEMENT help (#PCDATA)> +<!ATTLIST help + locale %Locale; #REQUIRED + xmlns CDATA #IMPLIED > + +<!-- + helpful text to be shown if a property value is missing, typically when + a form is submitted. Typically there will be only one of these per property + per locale; if there are more than one all those matching the locale may + be concatenated, or just one may be used. Later there may be more sophisticated + behaviour here. +--> +<!ELEMENT ifmissing (#PCDATA)> +<!ATTLIST ifmissing + locale %Locale; #REQUIRED + xmlns CDATA #IMPLIED> + +<!-- a form through which an entity may be added or edited + + TODO: This needs to be renamed because it conflicts with the + XHTML element of the same name. +--> +<!ELEMENT form (documentation?, ( %PageStuff;)*)> +<!ATTLIST form %PageAttrs;> + + +<!-- a page on which an entity may be displayed --> +<!ELEMENT page (documentation?, ( %PageStuff;)*)> +<!ATTLIST page %PageAttrs;> + +<!-- an ordering or records in a list + property: the property on which to order + sequence: the sequence in which to order +--> +<!ELEMENT order (documentation?)> +<!ATTLIST order + property CDATA #REQUIRED + sequence (%Sequences;) #IMPLIED> + +<!-- + a list on which entities of a given type are listed + + onselect: name of form/page/list to go to when + a selection is made from the list +--> +<!ELEMENT list (documentation?, ( %PageStuff;|order)*)> +<!ATTLIST list %PageAttrs; + onselect CDATA #IMPLIED > + + +<!-- + a subsidiary list, on which entities related to primary + entities in the enclosing page or list are listed + + property: the property of the enclosing entity that this + list displays (obviously, must be of type='list') + onselect: the form or page of the listed entity to call + when an item from the list is selected + canadd: true if the user should be able to add records + to this list + --> +<!ELEMENT auxlist (documentation?, (prompt|%FieldStuff;)*)> +<!ATTLIST auxlist %PageAttrs; + property CDATA #REQUIRED + onselect CDATA #IMPLIED + canadd %Boolean; #IMPLIED> + +<!-- + a group of fields and other controls within a form or list, which the + renderer might render as a single pane in a tabbed display, for example. + --> +<!ELEMENT fieldgroup (documentation?, (prompt|permission|%FieldStuff;)*)> +<!ATTLIST fieldgroup + name CDATA #REQUIRED> + + +<!-- a field in a form or page + + property: the property which this field displays/edits + --> +<!ELEMENT field (documentation?, (prompt|help|permission)*) > +<!ATTLIST field + property CDATA #REQUIRED > + +<!-- a verb is something that may be done through a form. Probably the verbs 'store' + and 'delete' are implied, but maybe they need to be explicitly declared. The 'verb' + attribute of the verb is what gets returned to the controller --> +<!ELEMENT verb (documentation?, (prompt|help|permission)*) > +<!ATTLIST verb + verb CDATA #REQUIRED + dangerous %Boolean; #REQUIRED> + + +<!-- a container for global content --> +<!ELEMENT content (%Content;)*> + + +<!-- + content to place in the head of the generated document; this is #PCDATA + because it will almost certainly belong to a different namespace + (usually HTML) + + TODO: This needs to be renamed or removed because it conflicts with the + XHTML element of the same name. In fact it could be simply removed since + our usage is compatible with the XHTML usage, but it might be less + ambiguous to rename it. +--> +<!ELEMENT head (#PCDATA) > +<!ATTLIST head + xmlns CDATA #IMPLIED> + + +<!-- + content to place in the top of the body of the generated document; + this is %Flow; which is any HTML block or inline level element. +--> +<!ELEMENT top (#PCDATA) > +<!ATTLIST top + xmlns CDATA #IMPLIED> + +<!-- + content to place at the foot of the body of the generated document; + this is %Flow; which is any HTML block or inline level element. +--> +<!ELEMENT foot (#PCDATA) > +<!ATTLIST foot + xmlns CDATA #IMPLIED> + +<!-- + The 'specification' and 'reference' elements are for documentation only, + and do not contribute to the engineering of the application described. + + A specification element is intended chiefly to declare the reference + documents which may be used in documentation elements later in the + document. + + url: The URL from which the document referenced can be retrieved + name: The full name (title) given to this document + abbr: A convenient abbreviated name +--> +<!ELEMENT specification (documentation?, reference*)> +<!ATTLIST specification + url CDATA #IMPLIED + name CDATA #REQUIRED + abbr CDATA #REQUIRED + > + +<!-- + The 'specification' and 'reference' elements are for documentation only, + and do not contribute to the engineering of the application described. + + A reference element is a reference to a specifying document. + + abbr: The abbreviated name of the specification to which this + reference refers + section: The 'anchor part' (part following a hash character) which, + when appended to the URL, will locate the exact section + referenced. + entity: A reference to another entity within this ADL document + property: A reference to another property within this ADL document; + if entity is also specified then of that entity, else of + the ancestor entity if any + --> +<!ELEMENT reference (documentation?)> +<!ATTLIST reference + abbr CDATA #IMPLIED + section CDATA #IMPLIED + entity CDATA #IMPLIED + property CDATA #IMPLIED + > + diff --git a/test.build b/test.build deleted file mode 100755 index 4611d9a..0000000 --- a/test.build +++ /dev/null @@ -1,165 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<project name="ADL-Test-App" default="build" - xmlns="http://nant.sf.net/release/0.85-rc4/nant.xsd" - xmlns:nant="http://nant.sf.net/release/0.85-rc4/nant.xsd" - > - <property name="build.revision" value="$Revision: 1.5 $"/> - - <property name="adl" value="."/> - <property name="adl-transforms" value="${adl}/transforms"/> - <property name="testapp" value="testapp"/> - <property name="rootns" value="Cygnet.ADL.TestApp"/> - <property name="entityns" value="${rootns}.Entities"/> - <property name="controllerns" value="${rootns}.Controllers"/> - - <property name="controllers" value="testapp/Web/Controllers"/> - <property name="views" value="testapp/Web/Views" /> - - <property name="formcontroller" value="testapp/Web/Controllers/Form"/> - <property name="formview" value="testapp/Web/Views/Form"/> - <property name="bindir" value="testapp/Web/bin"/> - <property name="tmpdir" value="tmp"/> - - <property name="adl-src" value="${testapp}/testapp.adl.xml" /> - <property name="canonical" value="${tmpdir}/testapp.adl.xml" /> - <property name="area-name" value="test"/> - <property name="nant-tasks" value="${tmpdir}/NantTasks.dll"/> - <property name="nant-contrib-dll" value="C:\Program Files\nantcontrib-0.85\bin\NAnt.Contrib.Tasks.dll"/> - - - <target name="fetchtasks" depends="prepare" - description="fetches our NantTaks library from the well known place where it resides"> - <get src="http://libs.cygnets.co.uk/NantTasks.dll" dest="${nant-tasks}"/> - </target> - - <target name="canonicalise" description="generates adl for testapp entities"> - <!-- adl2canonical.xslt --> - <style verbose="true" style="${adl-transforms}/adl2canonical.xslt" - in="${adl-src}" - out="${canonical}"> - <parameters> - <parameter name="abstract-key-name-convention" value="Name_Id"/> - </parameters> - </style> - </target> - - <target name="analyse"> - <loadtasks assembly="${nant-contrib-dll}" /> - <fxcop directOutputToConsole="true" projectFile="${testapp}/TestApp.fxcop"> - </fxcop> - </target> - - <target name="hbm" description="generates adl for testapp database NHibernate mapping" - depends="canonicalise"> - <style verbose="true" style="${adl-transforms}/adl2hibernate.xslt" - in="${canonical}" - out="${tmpdir}/testapp.hbm.xml"> - <parameters> - <parameter name="namespace" value="${entityns}"/> - <parameter name="assembly" value="${rootns}"/> - </parameters> - </style> - </target> - - <target name="sql" description="Generates testapp database initialisation script" - depends="canonicalise"> - <style verbose="true" style="${adl-transforms}/adl2mssql.xslt" - in="${canonical}" - out="${testapp}/testapp.auto.sql"> - <parameters> - <parameter name="abstract-key-name-convention" value="Name_Id"/> - <parameter name="database" value="ADL_TestApp"/> - </parameters> - </style> - </target> - - <target name="entities" description="creates C# classes for entities in the database" - depends="fetchtasks canonicalise"> - <loadtasks assembly="${nant-tasks}" /> - - <style verbose="true" style="${adl-transforms}/adl2entityclass.xslt" - in="${canonical}" - out="${tmpdir}/classes.auto.cs"> - <parameters> - <parameter name="locale" value="en-UK"/> - <parameter name="controllerns" value="${controllerns}"/> - <parameter name="entityns" value="${entityns}"/> - </parameters> - </style> - <exec program="c:\Program Files\astyle\bin\astyle.exe" - basedir="." - commandline="--style=java --indent=tab=4 --indent-namespaces ${tmpdir}/classes.auto.cs"/> - <split-regex in="${tmpdir}/classes.auto.cs" - destdir="${testapp}/Auto" - pattern="cut here: next file '([a-zA-Z0-9_.]*)'"/> - </target> - - <target name="views" description="creates Velocity templates" - depends="fetchtasks canonicalise"> - <loadtasks assembly="${nant-tasks}" /> - - <style verbose="true" style="${adl-transforms}/adl2views.xslt" - in="${canonical}" - out="${tmpdir}/views.auto.vm"> - <parameters> - <parameter name="layout-name" value="default"/> - <parameter name="locale" value="en-UK"/> - <parameter name="controllerns" value="${controllerns}"/> - <parameter name="entityns" value="${entityns}"/> - <parameter name="generate-site-navigation" value="false"/> - <parameter name="permissions-group" value="partsbookeditors"/> - <parameter name="area-name" value="${area-name}"/> - <parameter name="show-messages" value="true"/> - </parameters> - </style> - <split-regex in="${tmpdir}/views.auto.vm" - destdir="${views}/Auto/${area-name}" pattern="cut here: next file '([a-zA-Z0-9_./]*)'"/> - </target> - - <target name="controllers" description="creates C# controller classes" depends="fetchtasks canonicalise"> - <loadtasks assembly="${nant-tasks}" /> - <style verbose="true" style="${adl-transforms}/adl2controllerclasses.xslt" - in="${canonical}" - out="${tmpdir}/controllers.auto.cs"> - - <parameters> - <parameter name="locale" value="en-UK"/> - <parameter name="controllerns" value="${controllerns}"/> - <parameter name="entityns" value="${entityns}"/> - <parameter name="layout-name" value="default"/> - <parameter name="rescue-name" value="generalerror"/> - <parameter name="area-name" value="${area-name}"/> - </parameters> - </style> - <exec program="c:\Program Files\astyle\bin\astyle.exe" - basedir="." - commandline="--style=java --indent=tab=4 --indent-namespaces ${tmpdir}/controllers.auto.cs"/> - <split-regex in="${tmpdir}/controllers.auto.cs" - destdir="${controllers}/Auto" pattern="cut here: next file '([a-zA-Z0-9_.]*)'"/> - </target> - - - <target name="prepare" description="prepare directories used during the build"> - <mkdir dir="${bindir}" failonerror="false"/> - <mkdir dir="${tmpdir}" failonerror="false"/> - </target> - - <target name="clean" description="removes all products of the build process except the xml-ised database schema"> - <delete> - <fileset> - <include name="**/*.auto.*"/> - </fileset> - </delete> - <delete failonerror="false" dir="${bindir}"/> - <delete failonerror="false" dir="${tmpdir}"/> - </target> - - <target name="build" depends="prepare entities controllers views sql hbm" - description="compiles Visual Studio solution using msbuild"> - <exec program="msbuild.exe" - basedir="c:\windows\microsoft.net\framework\v3.5\" - commandline="ADL.sln"/> - </target> - <target name="deploy" depends="clean build"/> - -</project> \ No newline at end of file diff --git a/transforms/adl2canonical.xslt b/transforms/adl2canonical.xslt index d7482e0..1f381be 100755 --- a/transforms/adl2canonical.xslt +++ b/transforms/adl2canonical.xslt @@ -19,14 +19,14 @@ every entity, form, page, list or field, the canonical form should explicitly state the permission, even if it is 'none'. - $Author: sb $ - $Revision: 1.9 $ - $Date: 2010-01-12 17:20:17 $ + $Author: simon $ + $Revision: 1.10 $ + $Date: 2010-07-20 19:53:40 $ --> <xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns="http://bowyer.journeyman.cc/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="adl"> @@ -74,7 +74,7 @@ * THIS FILE IS AUTOMATICALLY GENERATED AND SHOULD NOT * BE MANUALLY EDITED. * - * Generated using adl2canonical.xslt <xsl:value-of select="substring('$Revision: 1.9 $', 12)"/> + * Generated using adl2canonical.xslt <xsl:value-of select="substring('$Revision: 1.10 $', 12)"/> * *************************************************************************** </xsl:comment> diff --git a/transforms/adl2controllerclasses.xslt b/transforms/adl2controllerclasses.xslt index c2fdf30..59a3550 100755 --- a/transforms/adl2controllerclasses.xslt +++ b/transforms/adl2controllerclasses.xslt @@ -1,1374 +1,1405 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - Application Description Language framework - adl2controllerclasses.xsl - - (c) 2007 Cygnet Solutions Ltd - - Transform ADL into (partial) controller classes - - $Author: sb $ - $Revision: 1.45 $ - $Date: 2010-06-01 17:29:02 $ - --> - -<!-- WARNING WARNING WARNING: Do NOT reformat this file! - Whitespace (or lack of it) is significant! --> -<xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns:exsl="urn:schemas-microsoft-com:xslt" - extension-element-prefixes="exsl"> - - <xsl:include href="csharp-type-include.xslt"/> - <xsl:include href="permissions-include.xslt"/> - - <xsl:output encoding="UTF-8" method="text"/> - - <!-- The locale for which these controllers are generated - TODO: Controllers should NOT be locale specific. Instead, the - controller should render views and generate messages based on the - client's locale. However, there may still need to be a concept of a - 'default locale', for when we don't have messages which suit the - client's locale --> - <xsl:param name="locale" select="en-UK"/> - - <!-- bug 1896 : boilerplate text in views should be tailored to the locale of - the expected user. Unfortunately I haven't yet worked out how to do - conditional includes in XSLT, so this is a step on the way to a solution, - not a solution in itself. --> - <xsl:include href="i18n-en-GB-include.xslt"/> - - <!-- The C# namespace within which I shall generate controllers --> - <xsl:param name="controllerns" select="Unset"/> - <!-- The C# namespace used by the entities for this project --> - <xsl:param name="entityns" select="Unset"/> - <!-- Whether to authenticate at application or at database layer. - If not 'Application', then 'Database'. --> - <xsl:param name="authentication-layer" select="'Application'"/> - - <!-- the name and version of the product being built --> - <xsl:param name="product-version" select="'Application Description Language Framework'"/> - - <!-- bug 1800 : the name of the Velocity layout to use --> - <xsl:param name="layout-name" select="adl-default-layout"/> - <!-- bug 1800 : the name of the Velocity rescue view to use --> - <xsl:param name="rescue-name"/> - <!-- bug 1800 : the name of the area (i.e. URL path part) to use --> - <xsl:param name="area-name"/> - <!-- bug 2883 : number of entries to show per list page (does not affect auxiliary lists) --> - <xsl:param name="records-per-page" select="15"/> - - <xsl:template match="adl:application"> - /* ---- [ cut here: next file '<xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/>.auto.cs'] ---------------- */ - //------------------------------------------------------------------ - // - // <xsl:value-of select="$product-version"/> - // <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller.auto.cs')"/> - // - // (c) 2007 Cygnet Solutions Ltd - // - // Automatically generated abstract super class for controllers for the - // <xsl:value-of select="/adl:application/@name"/> application; generated using - // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.45 $', 10)"/> - // - // <xsl:value-of select="/adl:application/@revision"/> - // - // This file is automatically generated; DO NOT EDIT IT. - // - //------------------------------------------------------------------ - - /// <summary> - /// \mainpage <xsl:value-of select="concat( @name, ' ', @version)"/> - /// <xsl:value-of select="normalize-space(adl:documentation)"/> - /// - /// \package <xsl:value-of select="$controllerns"/> - /// MVC Controller classes for <xsl:value-of select='/adl:application/@name'/> - /// </summary> - namespace <xsl:value-of select="$controllerns"/> { - using System; - using System.Data; - using System.Collections.Generic; - using System.Data.SqlClient; - using NHibernate; - using NHibernate.Expression; - using Cygnet.DBAuth; - using Cygnet.Web.Controllers; - using Cygnet.Web.Helpers; - using Castle.MonoRail.Framework; - using <xsl:value-of select="$entityns"/>; - - /// <summary> - /// Automatically generated abstract super class for controllers for the - /// <xsl:value-of select="/adl:application/@name"/> application - /// - /// DO NOT EDIT THIS FILE! - /// </summary> - [ <!-- in the longer term, all the helpers which a given - project needs which not every project needs should be listed here, - with appropriate 'xsl:if' wrappers. --> - Helper(typeof(FormatterHelper), "t"), - Helper(typeof(SecurityHelper), "SecurityHelper") - ] - public abstract partial class <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> : BaseController { - - <xsl:choose> - <xsl:when test="$authentication-layer = 'Application'"/> - <xsl:when test="$authentication-layer = 'Database'"> - /* authentication layer is requested to be 'database', but in fact database-layer - authentication does not work well with NHibernate so this is being ignored. */ - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="yes"> - ADL: ERROR: invalid value (<xsl:value-of select="$authentication-layer"/>) provided for authentication-layer - </xsl:message> - </xsl:otherwise> - </xsl:choose> - - <xsl:for-each select="//adl:entity"> - /// <summary> - /// Return a list of all instances of <xsl:value-of select="@name"/> for use in menus, etc; - /// </summary> - protected IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> <xsl:value-of select="concat( 'FetchAll', @name)"/>( ) { - IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> result = new List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); - - <xsl:variable name="readgroups"> - <xsl:call-template name="entity-read-groups"> - <xsl:with-param name="entity" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:if test="$authentication-layer = 'Database'"> - if ( - <xsl:for-each select="exsl:node-set( $readgroups)/*"> - InGroup( "<xsl:value-of select="./@name"/>")<xsl:if test="position() != last()">||</xsl:if> - </xsl:for-each> - ){ - </xsl:if> - result = GetDBSession().CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) - <xsl:for-each select="descendant::adl:property[@distinct='user']"> - .AddOrder( <xsl:value-of select="concat('new Order( "', @name, '", true)')"/>) - </xsl:for-each> - .SetCacheable( true) - .SetCacheRegion( "<xsl:value-of select="/adl:application/@name"/>") - .List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); - <xsl:if test="$authentication-layer != 'Application'"> - } - </xsl:if> - return result; - } - - </xsl:for-each> - } - } - <xsl:apply-templates select="adl:entity"/> - </xsl:template> - - - <!-- Don't bother generating anything for foreign entities --> - <xsl:template match="adl:entity[@foreign='true']"/> - - <xsl:template match="adl:entity"> - /* - * Not generating controller for entity <xsl:value-of select="@name"/>, - * as it has no forms, pages or lists. - */ - </xsl:template> - <xsl:template match="adl:entity[adl:form|adl:page|adl:list]"> - - /* ---- [ cut here: next file '<xsl:value-of select="@name"/>Controller.auto.cs'] ---------------- */ - - //------------------------------------------------------------------ - // - // <xsl:value-of select="$product-version"/> - // <xsl:value-of select="@name"/>Controller.auto.cs - // - // (c) 2007 Cygnet Solutions Ltd - // - // Controller for auto-generated forms for editing <xsl:value-of select="@name"/>s - // Automatically generated from application description using - // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.45 $', 10)"/> - // - // This file is automatically generated; DO NOT EDIT IT. - // - //------------------------------------------------------------------ - - namespace <xsl:value-of select="$controllerns"/> { - using System; - using System.Data; - using System.Collections.Generic; - using System.Configuration; - using System.Web; - using System.Web.Security; - using System.Web.UI; - using System.Web.UI.WebControls; - using System.Web.UI.WebControls.WebParts; - using System.Web.UI.HtmlControls; - using Castle.MonoRail.Framework.Helpers; - using Cygnet.Entities; - using Cygnet.Exceptions; - using Cygnet.Web.Helpers; - using Cygnet.Web.Controllers; - using Cygnet.Web.SmartControls; - using Cygnet.Utility; - using NHibernate; - using NHibernate.Expression; - using Castle.MonoRail.Framework; - using Iesi.Collections.Generic; - using <xsl:value-of select="$entityns"/>; - - /// <summary> - /// Automatically generated partial controller class following 'thin controller' - /// strategy, for entity <xsl:value-of select="@name"/>. Note that part of this - /// class may be defined in a separate file called - /// <xsl:value-of select="@name"/>Controller.manual.cs, q.v. - /// </summary> - /// - /// <remarks> - /// <list type='bullet'> - /// <listheader><description>See also auto-generated Velocity view macros</description></listheader><xsl:for-each select='adl:form|adl:page|adl:list'> - /// <item> - /// <term><xsl:value-of select="concat(@name, '.auto.vm')"/></term> - /// <description><xsl:apply-templates select='adl:documentation'/></description> - /// </item></xsl:for-each> - /// </list> - /// - /// DO NOT EDIT THIS FILE! - /// </remarks> - [ - <xsl:if test="$layout-name"> - Layout("<xsl:value-of select="$layout-name"/>"), - </xsl:if> - <xsl:if test="$rescue-name"> - Rescue("<xsl:value-of select="$rescue-name"/>"), - </xsl:if> - ControllerDetails("<xsl:value-of select="@name"/>", Area = "<xsl:value-of select="$area-name"/>"), - Helper(typeof(StylesHelper), "StylesHelper"), - Helper(typeof(<xsl:value-of select="concat( @name, 'FieldHelper')"/>), "<xsl:value-of select="concat( @name, 'FieldHelper')"/>") - ] - public partial class <xsl:value-of select="concat( @name, 'Controller')"/> : <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> { - - protected class <xsl:value-of select="concat( @name, 'FieldHelper')"/> : SmartFormHelper { - public <xsl:value-of select="concat( @name, 'FieldHelper')"/>() { - <xsl:for-each select="descendant::adl:property[@type='entity']"> - <xsl:variable name="entityname" select="@entity"/> - <xsl:variable name="entity" select="//adl:entity[@name=$entityname]"/> - <xsl:choose> - <xsl:when test="$entity/@foreign='true'"> - /* Entity <xsl:value-of select="$entityname"/> is foreign..? */ - <xsl:variable name="foreignkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> - <xsl:variable name="userident"> - <xsl:choose> - <xsl:when test="$entity//adl:property[@distinct='user' or @distinct='all']"> - <xsl:value-of select="$entity//adl:property[@distinct='user' or @distinct='all'][position()=1]/@name"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$foreignkey"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", - new TypeMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "<xsl:value-of select="$foreignkey"/>","<xsl:value-of select="$userident"/>")); - </xsl:when> - <xsl:otherwise> - Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - <xsl:for-each select="descendant::adl:property[@type='list']"> - <xsl:variable name="entityname" select="@entity"/> - Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityShuffleControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); - </xsl:for-each> - - } - } - - <xsl:if test="adl:property[@type='message']"> - /// <summary> - /// Temporary hack to sort a problem with uninitialised messages - /// </summary> - public void fixupMessages() { - ISession hibernator = GetDBSession(); - ICollection<<xsl:value-of select="concat($entityns, '.', @name)"/>> instances = - hibernator.CreateCriteria( typeof( <xsl:value-of select="concat($entityns, '.', @name)"/>)) - .List<<xsl:value-of select="concat($entityns, '.', @name)"/>>(); - - foreach ( <xsl:value-of select="concat($entityns, '.', @name)"/> instance in instances) { - <xsl:for-each select="adl:property[@type='message']"> - <xsl:variable name="slot" select="concat( 'instance.', @name)"/> - if ( <xsl:value-of select="$slot"/> == null || <xsl:value-of select="concat( $slot, '.MessageId')"/> == 0 ){ - <xsl:value-of select="$slot"/> = new Message(); - - <xsl:value-of select="$slot"/>.BeforeUpdateHook( hibernator); - hibernator.SaveOrUpdate( <xsl:value-of select="$slot"/>); - <xsl:value-of select="$slot"/>.AfterUpdateHook( hibernator); - } - </xsl:for-each> - instance.BeforeUpdateHook( hibernator); - hibernator.SaveOrUpdate( instance); - instance.AfterUpdateHook( hibernator); - } - hibernator.Flush(); - <xsl:if test="adl:list[@name='list']"> - list(); - </xsl:if> - } - </xsl:if> - - <xsl:if test="adl:form"> - <!-- unless there's at least one form, we won't generate a 'store' method --> - /// <summary> - /// Store the record represented by the parameters passed in an HTTP service - /// Without Id -> it's new, I create a new persistent object; - /// With Id -> it's existing, I update the existing persistent object. - /// NOTE: Should only be called from a handler for method 'POST', never 'GET'. - /// </summary> - private void Store() - { - ISession hibernator = GetDBSession(); - List<string> messages = new List<string>(); - PropertyBag["messages"] = messages; - /* A 'newborn' instance can be updated even if the current user doesn't have - * update permissions, seeing that we use an update operation to set the - * field values and save the entity. */ - Boolean isnewborn = false; - - /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ - <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; - - try { - <xsl:if test="adl:property[@distinct='system' or @distinct='all']"> - /* a criteria object to use in distinctness checks */ - ICriteria matchCriteria = null; - </xsl:if> - - record = FetchRecord( hibernator); - - <xsl:apply-templates select="adl:property"/> - - if ( HasNoErrors()) { - if ( record == null) { - /* it seems to be new, create persistent object - if the user is permitted to */ - AssertUserCanCreate(); - - try { - if ( AllKeys()) { - record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(<xsl:for-each select="adl:key/adl:property"> - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$basetype='integer'"> - Int32.Parse( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]) - </xsl:when> - <xsl:when test="$basetype='entity'"> - <!-- Maybe TODO: this doesn't work recursively - if an entity has a key which is an entity - and the key of that entity is an entity, you're on your own, mate! --> - <xsl:variable name="keyentity" select="@entity"/> - <xsl:variable name="keyenttype"> - <xsl:call-template name="primary-key-csharp-type"> - <xsl:with-param name="entity" select="//adl:entity[@name=$keyentity]"/> - </xsl:call-template> - </xsl:variable> - hibernator.CreateCriteria( typeof( <xsl:value-of select="concat( $entityns, '.', $keyentity)"/>)) - <xsl:call-template name="add-hibernate-expression-eq"> - <xsl:with-param name="property" select="//adl:entity[@name=$keyentity]/adl:key/adl:property[position()=1]"/> - <xsl:with-param name="value"> - Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] - </xsl:with-param> - </xsl:call-template> - .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $keyentity)"/>>() - </xsl:when> - <xsl:otherwise> - Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] - </xsl:otherwise> - </xsl:choose> - <xsl:choose> - <xsl:when test="position() = last()"/> - <xsl:otherwise>, </xsl:otherwise> - </xsl:choose> - </xsl:for-each>); - } - else - { - record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); - } - } - catch ( FormatException) { - /* failed to parse a number - not wholly unexpected, since it's most likely - * that an empty string was passed in */ - record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); - } - catch ( NullReferenceException) { - /* again, probably more normal than otherwise */ - record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); - } - messages.Add( "New <xsl:value-of select="@name"/> record created"); - isnewborn = true; - } - - if ( record != null) { - /* a transaction to ensure our database operations are atomic */ - ITransaction tx = null; - - - if ( ! isnewborn) { - /* isnewborn cannot be true unless we've already checked user can create - * so no need to do it again here */ - AssertUserCanUpdate(); - } - - try { - /* begin our atomic transaction */ - tx = hibernator.BeginTransaction(); - /* list of entities modified in this transaction */ - List<Entity> modified = new List<Entity>(); - - /* actually update the record */ - BindObjectInstance( record, ParamStore.Form, "instance"); - modified.Add( record); - - <xsl:if test="descendant::adl:property[@type='message']"> - /* there is at least one slot whose value is an internationalised message; - * if these have yet to be initialised they must be handled specially */ - Locale locale = GetBestLocaleForUser(); - <xsl:for-each select="descendant::adl:property[@type='message']"> - if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])){ - /* there's an uninitialised message for this slot */ - Message mess = record.<xsl:value-of select="@name"/>; - if ( mess == null) { - mess = new Message(); - } - mess.BeforeUpdateHook( hibernator); - hibernator.SaveOrUpdate( mess); - mess.AfterUpdateHook( hibernator); - - Translation trans = mess.GetTranslationObject( locale, hibernator); - if ( trans == null) { - trans = new Translation( mess, locale); - } - trans.MessageText = Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]; - record.<xsl:value-of select="@name"/> = mess; - trans.BeforeUpdateHook( hibernator); - hibernator.SaveOrUpdate( trans); - trans.AfterUpdateHook( hibernator); - } - </xsl:for-each> - </xsl:if> - <xsl:for-each select="descendant::adl:property[@type='entity']"> - /* for properties of type 'entity', it should not be necessary to do anything - * special - BindObjectInstance /should/ do it all. Unfortunately it sometimes - * doesn't, and I haven't yet characterised why not. */ - <xsl:variable name="entityname" select="@entity"/> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$entityname]"> - if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]) && - ! EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>.NULLMARKER.Equals ( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) - { - record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="value"> - Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] - </xsl:with-param> - </xsl:call-template>; - - modified.Add( record.<xsl:value-of select="@name"/>); - } - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="yes"> - ADL: ERROR: Could not fix up value of <xsl:value-of select="@name "/>, because no - entity was found called <xsl:value-of select="$entityname"/> - </xsl:message> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - - <xsl:for-each select="descendant::adl:property[@type='link']"> - <xsl:variable name="nearentityname" select="ancestor::adl:entity/@name"/> - <xsl:variable name="farentityname" select="@entity"/> - <xsl:variable name="entity" select="//adl:entity[@name=$farentityname]"/> - <xsl:variable name="farkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> - <xsl:variable name="farkeybasetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="deletegroups"> - <xsl:call-template name="entity-delete-groups"> - <xsl:with-param name="entity" select="$entity"/> - </xsl:call-template> - </xsl:variable> - /* For a link, collect changes to link table and process them */ - <xsl:if test="$authentication-layer = 'Database'"> - if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*">InGroup( "<xsl:value-of select="./@name"/>") ||</xsl:for-each> false) { - /* however, we cannot do anything unless we have delete permissions on the table, so - * should not try. */ - </xsl:if> - LinkChanges<<xsl:value-of select="concat( $entityns, '.', @entity)"/>> changes = - LinkTableUpdater<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>.Changes( <xsl:value-of select="concat( 'record.', @name)"/>, Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"), - hibernator); - - foreach ( var item in changes.ToRemove) { - modified.Add(item); - <xsl:value-of select="concat( 'record.', @name)"/>.Remove(item); - <xsl:for-each select="$entity//adl:property[@type='link' and @entity=$nearentityname]"> - <xsl:value-of select="concat( 'item.', @name)"/>.Remove( record); - <xsl:if test="position() != 1"> - /* WARNING WARNING WARNING! Could not uniquely determine the far side property; - * redesign your application or manually maintain this code! */ - <xsl:message terminate="no"> - WARNING: Could not uniquely determine far end of link represented by property <xsl:value-of select="@name"/> of <xsl:value-of select="$nearentityname"/> - </xsl:message> - </xsl:if> - </xsl:for-each> - } - foreach ( var item in changes.ToAdd) { - modified.Add(item); - <xsl:value-of select="concat( 'record.', @name)"/>.Add(item); - <xsl:for-each select="$entity//adl:property[@type='link' and @entity=$nearentityname]"> - <xsl:value-of select="concat( 'item.', @name)"/>.Add( record); - <xsl:if test="position() != 1"> - /* WARNING WARNING WARNING! Could not uniquely determine the far side property; - * redesign your application or manually maintain this code! */ - <xsl:message terminate="no"> - WARNING: Could not uniquely determine far end of link represented by property <xsl:value-of select="@name"/> of <xsl:value-of select="$nearentityname"/> - </xsl:message> - </xsl:if> - </xsl:for-each> - } - - <xsl:if test="$authentication-layer = 'Database'"> - } /* if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> - InGroup( "<xsl:value-of select="./@name"/>") || - </xsl:for-each> false) */ - </xsl:if> - </xsl:for-each> - - <xsl:for-each select="descendant::adl:property[@type='list']"> - <xsl:variable name="farentityname" select="@entity"/> - <xsl:variable name="entity" select="//adl:entity[@name=$farentityname]"/> - <xsl:variable name="farkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> - <xsl:variable name="farkeybasetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="foreignkey"> - <xsl:choose> - <xsl:when test="@farkey"> - <xsl:value-of select="@farkey"/> - </xsl:when> - <xsl:otherwise> - <!-- If I haven't been told what the far side foreign key is, assume it has the - name of my entity --> - <xsl:value-of select="ancestor::adl:entity/@name"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="deletegroups"> - <xsl:call-template name="entity-delete-groups"> - <xsl:with-param name="entity" select="$entity"/> - </xsl:call-template> - </xsl:variable> - /* with a list we cannot just smash the old values! Instead we need to check - * each one and exclude it if no longer required; */ - <xsl:if test="$authentication-layer = 'Database'"> - if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> - InGroup( "<xsl:value-of select="./@name"/>") || - </xsl:for-each> false) { - /* but once again only if we can delete and create entities at the far end. */ - </xsl:if> - if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) - { - string[] <xsl:value-of select="concat(@name, 'Values')"/> = Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"); - - /* updating <xsl:value-of select="@name"/> child records; first remove any not on the submitted list */ - foreach ( <xsl:value-of select="@entity"/> item in record.<xsl:value-of select="@name"/>) - { - String itemId = item.KeyString; - bool found = false; - - foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) - { - if ( index.Equals( itemId)) - { - found = true; - break; - } - } /* foreach ( string index... */ - - if ( ! found) - { - record.<xsl:value-of select="@name"/>.Remove( item); - modified.Add( item); - break; - } - } /* foreach ( <xsl:value-of select="@entity"/> item ... */ - - /* then add any on the included list which are not already members */ - foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) - { - <xsl:value-of select="concat( $entityns, '.', @entity)"/> item = - hibernator.CreateCriteria(typeof(<xsl:value-of select="@entity"/>)) - <xsl:call-template name="add-hibernate-expression-eq"> - <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> - <xsl:with-param name="value" select="'index'"/> - </xsl:call-template> - .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>(); - - if ( ! record.<xsl:value-of select="@name"/>.Contains( item)) - { - /* check whether it's already a child of another <xsl:value-of select="ancestor::adl:entity/@name"/> - * and, if it is, remove it */ - <xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/> oldparent = - <xsl:value-of select="concat( 'item.', $foreignkey)"/>; - if ( oldparent != null) { - oldparent.<xsl:value-of select="@name"/>.Remove( item); - - modified.Add( oldparent); - } - - /* then add it to my <xsl:value-of select="@name"/> */ - record.<xsl:value-of select="@name"/>.Add( item); - <xsl:value-of select="concat( 'item.', $foreignkey)"/> = record; - modified.Add( item); - } - } /* foreach ( string index... */ - } /* if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) */ - <xsl:if test="$authentication-layer = 'Database'"> - } /* if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*">InGroup( "<xsl:value-of select="./@name"/>") ||</xsl:for-each> false) */ - </xsl:if> - - </xsl:for-each> - - /* write the modified records to the database */ - foreach ( Entity item in modified) { - item.BeforeUpdateHook( hibernator); - hibernator.SaveOrUpdate(item); - item.AfterUpdateHook( hibernator); - } - /* and if no exceptions, commit */ - tx.Commit(); - - messages.Add( "<xsl:call-template name="i18n-record-saved"/>"); - } /* try actually commit */ - catch ( Exception any) { - messages.Add( "<xsl:call-template name="i18n-record-not-saved"/>"); - AddError( any); - try { - tx.Rollback(); - } catch ( ObjectDisposedException ode) { - AddError( ode); - } - } /* catch ( Exception any) */ - } /* if ( record != null) */ - else { - throw new ApplicationException( String.Format( "<xsl:call-template name="i18n-record-not-found"> - <xsl:with-param name="entity-name" select="@name"/> - </xsl:call-template>")); - } - } /* if ( HasNoErrors()) */ - } /* try */ - catch ( DataSuitabilityException dse) - { - AddError( dse); - } - catch ( ApplicationException axe) - { - AddError( axe.Message); - } - - if ( ! HasNoErrors()) - { - /* the session may be polluted; create a new session */ - CloseDBSession(); - hibernator = GetDBSession(); - - record = FetchRecord( hibernator); - } /* if ( ! HasNoErrors()) */ - <xsl:value-of select="concat( 'this.',adl:form[position()=1]/@name)"/>( record); - } - - <!-- unless there's at least one form, we won't generate a 'delete' method --> - /// <summary> - /// Actually delete the selected record - /// </summary> - [AccessibleThrough(Verb.Post)] - public void Delete() - { - AssertUserCanDelete(); - ISession hibernator = GetDBSession(); - <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; - - if ( "true".Equals( Params["reallydelete"])) - { - record = FetchRecord( hibernator); - - if ( record != null) - { - try { - record.BeforeDeleteHook( hibernator); - hibernator.Delete( record); - hibernator.Flush(); - } catch ( DomainKnowledgeViolationException dkve) { - AddError( dkve); - } - } - else - { - throw new ApplicationException( "No such record?"); - } - } - if ( HasNoErrors()) { - <xsl:choose> - <xsl:when test="adl:list"> - Redirect( "<xsl:value-of select="concat(adl:list[position()=1]/@name, '.rails')"/>"); - </xsl:when> - <xsl:otherwise> - Redirect( FormsAuthentication.DefaultUrl); - </xsl:otherwise> - </xsl:choose> - } else { - PropertyBag[ "instance"] = record; - RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm"); - } - } - </xsl:if> - <xsl:apply-templates select="adl:form"/> - <xsl:apply-templates select="adl:list"/> - - /// <summary> - /// Check whether values for all my keys are available in the form fields - /// </summary> - protected bool AllKeys() { - /* whether we have valid values for all the key fields */ - bool result = true; - - <xsl:for-each select="adl:key/adl:property"> - if ( String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { - result = false; - } else if ( "<xsl:value-of select="concat('$instance.', @name)"/>".Equals( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { - /* nasty artefact of NVelocity forms - default 'null value' is dollar followed by fieldname */ - result = false; - } - </xsl:for-each> - - return result; - } - - /// <summary> - /// Fetch the record represented by the values in the current Form - /// </summary> - protected <xsl:value-of select="concat($entityns, '.', @name)"/> FetchRecord(ISession hibernator) { - /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ - <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; - - if ( AllKeys()){ - /* it's (probably) existing, retrieve it */ - record = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) - <xsl:for-each select="adl:key/adl:property"> - <xsl:call-template name="add-hibernate-expression-eq"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="value">Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]</xsl:with-param> - </xsl:call-template> - </xsl:for-each> - .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); - } - - return record; - } - } - } - /* ---- [ cut here: next file 'junk'] ------------------------- */ - </xsl:template> - - <xsl:template match="adl:property"> - <xsl:if test="@required='true'"> - if ( - <xsl:if test="@immutable='true'"> - (record == null || <xsl:value-of select="concat( 'record.', @name)"/> == null) && - </xsl:if> - String.IsNullOrEmpty( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>" ])) - { - AddError( <xsl:choose> - <xsl:when test="adl:ifmissing[@locale=$locale]"> - <xsl:apply-templates select="adl:ifmissing[@locale=$locale]"/> - </xsl:when> - <xsl:otherwise> - "<xsl:call-template name="i18n-value-required"> - <xsl:with-param name="property-name" select="@name"/> - </xsl:call-template>" - </xsl:otherwise> - </xsl:choose>); - } - </xsl:if> - <xsl:if test="@distinct='system' or @distinct='all'"> - <xsl:call-template name="check-property-value-distinct"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:if> - </xsl:template> - - <xsl:template match="adl:ifmissing"> - "<xsl:value-of select="normalize-space(.)"/>" - </xsl:template> - - <xsl:template match="adl:form"> - /// <summary> - /// Handle the submission of the form named <xsl:value-of select="@name"/> - /// </summary> - [AccessibleThrough(Verb.Post)] - public void <xsl:value-of select="concat( @name, 'SubmitHandler')"/>( ) { - string command = Form[ "command"]; - - if ( command == null) { - throw new Exception( "<xsl:call-template name="i18n-command-not-found"/>"); - } - else - <xsl:for-each select=".//adl:verb"> - if ( command.Equals( "<xsl:value-of select="@verb"/>")) - { - /* NOTE: You must write an implementation of this verb in a - * manually maintained partial class file for this class */ - <xsl:value-of select="@verb"/>(); - } - else - </xsl:for-each> - if ( command.Equals( "delete")) - { - ISession hibernator = GetDBSession(); - - <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = FetchRecord( hibernator); - - TypedPropertyBag = new { - instance = record }; - - RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm"); - } - else if ( command.Equals( "store")) - { - Store(); - } - else - { - throw new Exception( String.Format("<xsl:call-template name="i18n-command-not-found"> - <xsl:with-param name="command" select="'{0}'"/> - </xsl:call-template>", command)); - } - } - - /// <summary> - /// Show the form named <xsl:value-of select="@name"/>, with no existing record - /// </summary> - [AccessibleThrough(Verb.Get)] - public void <xsl:value-of select="@name"/>( ) - { - AssertUserCanRead(); - <xsl:value-of select="concat( 'PrototypeFor', ancestor::adl:entity/@name)"/> record = - new <xsl:value-of select="concat( 'PrototypeFor', ancestor::adl:entity/@name)"/>(); - - ISession hibernator = GetDBSession(); - - TypedPropertyBag = new { - <xsl:call-template name="formmenus"> - <xsl:with-param name="form" select="."/> - </xsl:call-template> - instance = record }; - - RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); - } - - <xsl:variable name="form" select="."/> - <xsl:for-each select="ancestor::adl:entity/adl:property[ @type='entity']"> - /// <summary> - /// Show the form named <xsl:value-of select="$form/@name"/>, for a new record, but with the - /// value for <xsl:value-of select="@name"/> already predetermined - /// </summary> - [AccessibleThrough(Verb.Get)] - public void <xsl:value-of select="concat($form/@name, 'With', @name)"/>( string <xsl:value-of select="@name"/>) - { - AssertUserCanRead(); - ISession hibernator = GetDBSession(); - <xsl:value-of select="ancestor::adl:entity/@name"/> record = new <xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>(); - - record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="value" select="@name"/> - </xsl:call-template>; - - <xsl:value-of select="concat( 'this.', $form/@name)"/>( record); - } - </xsl:for-each> - - /// <summary> - /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record. As - /// the primary key of the record is itself an entity, we need to first fetch that entity - /// </summary> - <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> - <xsl:choose> - <xsl:when test="@type='entity'"> - /// <param name="<xsl:value-of select="@name"/>">the key value of the key value of the record to show</param> - </xsl:when> - <xsl:otherwise> - /// <param name="<xsl:value-of select="@name"/>">the key value of the record to show</param> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - [AccessibleThrough(Verb.Get)] - public void <xsl:value-of select="@name"/>( <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> - <!-- all args are passed as string because that's what hibernate-expression-eq expects --> - string <xsl:value-of select="concat( ' ', @name)"/> - <xsl:if test="not( position() = last())">,</xsl:if> - </xsl:for-each>) { - ISession hibernator = GetDBSession(); - <xsl:value-of select="concat( 'this.', @name)"/>( - hibernator.CreateCriteria( typeof(<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>)) - <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> - <xsl:call-template name="add-hibernate-expression-eq"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="value" select="@name"/> - </xsl:call-template> - </xsl:for-each> - .UniqueResult<<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>>()); - } - - /// <summary> - /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record - /// </summary> - /// <param name="record">the record to show</param> - protected void <xsl:value-of select="@name"/>( <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record) - { - ISession hibernator = GetDBSession(); - - TypedPropertyBag = new { - <xsl:call-template name="formmenus"> - <xsl:with-param name="form" select="."/> - </xsl:call-template> - instance = record }; - - RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); - } - </xsl:template> - - <xsl:template match="adl:list"> - /// <summary> - /// list all instances of this entity to allow the user to select one - /// this method invokes the named view. - /// </summary> - public void <xsl:value-of select="@name"/>() - { - AssertUserCanRead(); - - string view = "<xsl:value-of select="@name"/>"; - ISession hibernator = GetDBSession(); - ICriteria search = - hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>)); - Boolean withSearchCriteria = false; - - <xsl:for-each select="adl:field"> - <xsl:variable name="fieldprop" select="@property"/> - <xsl:variable name="property" select="ancestor::adl:entity//adl:property[@name=$fieldprop]"/> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - /* <xsl:value-of select="@property"/> */ - <xsl:choose> - <xsl:when test="$base-type='boolean'"/> - <xsl:when test="$base-type='link'"/> - <xsl:when test="$base-type='list'"/> - <xsl:otherwise> - if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', $property/@name)"/>"])) { - search<xsl:call-template name="add-hibernate-expression-like"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="value"> - Params["<xsl:value-of select="concat( 'search_', $property/@name)"/>"] - </xsl:with-param> - </xsl:call-template>; - PropertyBag["<xsl:value-of select="concat( 'search_', $property/@name)"/>"] = Params[ "<xsl:value-of select="concat( 'search_', $property/@name)"/>"]; - withSearchCriteria = true; - } - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - - <xsl:choose> - <xsl:when test="adl:order"> - /* explicit ordering */ - <xsl:apply-templates select="adl:order"/> - </xsl:when> - <xsl:otherwise> - /* no explicit ordering */ - <xsl:for-each select="ancestor::adl:entity//adl:property[@distinct='user' or @distinct='all']"> - search.AddOrder(<xsl:value-of select="concat( ' new Order( "', @name, '", true)')"/>); - </xsl:for-each> - </xsl:otherwise> - </xsl:choose> - - IList<<xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>> instances = search.List<<xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>>(); - - /* if no instances, set showRecords to one else we get a division by zero error */ - int showRecords = instances.Count > 0? instances.Count: 1; - - if ( ! withSearchCriteria) { - showRecords = <xsl:value-of select="$records-per-page"/>; - } - - PropertyBag["instances"] = - PaginationHelper.CreatePagination( this, instances, showRecords); - - RenderViewWithFailover(view + ".vm", view + ".auto.vm"); - } - - </xsl:template> - - <xsl:template match="adl:order"> - search.AddOrder( new Order( "<xsl:value-of select="@property"/>", - <xsl:choose> - <xsl:when test="@sequence='reverse-canonical'">false</xsl:when> - <xsl:otherwise>true</xsl:otherwise> - </xsl:choose>)); - </xsl:template> - - <xsl:template match="adl:documentation"> - /* <xsl:apply-templates/> */ - </xsl:template> - - - <xsl:template match="adl:key"> - <!-- the key shouldn't be matched directly - at least, not in this implementation --> - </xsl:template> - - <!-- for properties with @distinct='all' or @distinct='system', - check that values are indeed distinct --> - <xsl:template name="check-property-value-distinct"> - <xsl:param name="property"/> - - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$property/ancestor::adl:key and not( $property/ancestor::adl:entity/adl:key[position()=2])"> - <!-- if I'm the property of a key field and it is the only key field of my entity then - it is pointless trying to establish my distinctness --> - </xsl:when> - <xsl:when test="$property/@distinct = 'system' or $property/@distinct='all'"> - /* <xsl:value-of select="$property/@name"/> should be distinct: check that it is */ - matchCriteria = - hibernator.CreateCriteria(typeof(<xsl:value-of select="$property/ancestor::adl:entity/@name"/>)); - - matchCriteria<xsl:call-template name="add-hibernate-expression-eq"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="value"> - Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] - </xsl:with-param> - </xsl:call-template>; - - if ( record != null) { - /* i.e. we do have values for each of our key fields... */ - <xsl:for-each select="$property/ancestor::adl:entity/adl:key/adl:property[position()=1]"> - <xsl:variable name="keybasetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - matchCriteria.Add(Expression.Not(<xsl:call-template name="hibernate-expression-eq"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="value"> - Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] - </xsl:with-param> - </xsl:call-template>)); - </xsl:for-each> - } - - if ( matchCriteria.List<<xsl:value-of select="$property/ancestor::adl:entity/@name"/>>().Count > 0) - { - AddError( - String.Format("There is already a {0} with the {1} '{2}'", - "<xsl:value-of select="$property/ancestor::adl:entity/@name"/>", "<xsl:value-of select="$property/@name"/>", Form["<xsl:value-of select="concat('instance.', $property/@name)"/>"])); - } - </xsl:when> - </xsl:choose> - </xsl:template> - - - <!-- produce all menus for a given form: harder, but more efficient --> - <xsl:template name="formmenus"> - <!-- an entity assumed to be of type adl:form --> - <xsl:param name="form"/> - <xsl:choose> - <xsl:when test="$form/@properties = 'all'"> - <xsl:call-template name="entitymenus"> - <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - /* form menus */ - <xsl:for-each select="$form//adl:field"> - <xsl:variable name="propname" select="@property"/> - <xsl:choose> - <xsl:when test="parent::adl:auxlist"/> - <xsl:when test="$form/ancestor::adl:entity//adl:property[@name=$propname and @type='entity']"> - /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity//adl:property[@name=$propname]/@entity"/> to populate the select for <xsl:value-of select="$propname"/> */ - <xsl:call-template name="menu"> - <xsl:with-param name="property" select="$form/ancestor::adl:entity//adl:property[@name=$propname]"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$form/ancestor::adl:entity//adl:property[@name=$propname and @type='link']"> - /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity//adl:property[@name=$propname]/@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="$propname"/> */ - <xsl:call-template name="menu"> - <xsl:with-param name="property" select="$form/ancestor::adl:entity//adl:property[@name=$propname]"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$form/ancestor::adl:entity//adl:property[@name=$propname and @type='list']"> - /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity//adl:property[@name=$propname]/@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ - <xsl:call-template name="menu"> - <xsl:with-param name="property" select="$form/ancestor::adl:entity//adl:property[@name=$propname]"/> - </xsl:call-template> - </xsl:when> - </xsl:choose> - </xsl:for-each> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - - <!-- produce all menus for a given entity: easier, but less efficient --> - <xsl:template name="entitymenus"> - <xsl:param name="entity"/> - /* there's no way I can find of producing a set of just those entities - * we'll need menus for. So we set up variables for all the menus we might - * need, and then only instantiate those we do need. */ - <xsl:for-each select="$entity/adl:property[@type='entity']"> - <!-- $entity/adl:property because it is possible to have type='entity' in the key --> - <xsl:call-template name="menu"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:for-each> - <xsl:for-each select="$entity/adl:property[@type='link']"> - <!-- $entity/adl:property because it is not possible to have type='link' in the key --> - /* produce a list of <xsl:value-of select="@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="@name"/> */ - <xsl:call-template name="menu"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:for-each> - <xsl:for-each select="$entity/adl:property[@type='list']"> - /* produce a list of <xsl:value-of select="@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ - <xsl:call-template name="menu"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:for-each> - - </xsl:template> - - <xsl:template name="menu"> - <xsl:param name="property"/> - <xsl:variable name="entity" select="//adl:entity[@name=$property/@entity]"/> - <xsl:value-of select="concat('all_', $property/@name)"/> = - <xsl:value-of select="concat( 'FetchAll', $entity/@name)"/>( ), - </xsl:template> - - <xsl:template name="primary-key-csharp-type"> - <xsl:param name="entity"/> - <xsl:if test="not( $entity)"> - <xsl:message terminate="yes"> - ADL: ERROR: No entity passed to template primary-key-csharp-type - </xsl:message> - </xsl:if> - <xsl:if test="not($entity/adl:key/adl:property)"> - <xsl:message terminate="no"> - ADL: WARNING: entity '<xsl:value-of select="$entity/@name"/>' has no primary key. - You will have to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> - </xsl:message> - </xsl:if> - <xsl:call-template name="csharp-type"> - <xsl:with-param name="property" select="$entity/adl:key/adl:property[ position() = 1]"/> - <xsl:with-param name="entityns" select="$entityns"/> - </xsl:call-template> - </xsl:template> - - <xsl:template name="primary-key-name"> - <!-- return the name of the primary key of the entity with this name --> - <xsl:param name="entity"/> - <xsl:if test="not($entity/adl:key)"> - <xsl:message terminate="yes"> - ADL: ERROR: No key for entity: <xsl:value-of select="$entity/@name"/> - </xsl:message> - </xsl:if> - <xsl:choose> - <xsl:when test="$entity/adl:key/adl:property[position()=2]"> - <xsl:message terminate="no"> - ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has a composite primary key. - You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> - </xsl:message> - <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> - </xsl:when> - <xsl:when test="$entity/adl:key/adl:property"> - <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="no"> - ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has no primary key. - You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> - </xsl:message> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- it's often convenient to wrap an expression in an Add() --> - <xsl:template name="add-hibernate-expression-eq"> - <xsl:param name="property"/> - <xsl:param name="value"/> - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - .Add(<xsl:call-template name="hibernate-expression-eq"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="value" select="$value"/> - </xsl:call-template>) - </xsl:template> - - <!-- it's often convenient to wrap an expression in an Add() --> - <xsl:template name="add-hibernate-expression-like"> - <xsl:param name="property"/> - <xsl:param name="value"/> - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - .Add(<xsl:call-template name="hibernate-expression-like"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="value" select="$value"/> - </xsl:call-template>) - </xsl:template> - - <!-- generate a hibernate equality expression based on this property, - comparing it to this value --> - <xsl:template name="hibernate-expression-eq"> - <!-- an entity of type property --> - <xsl:param name="property"/> - <!-- an expression which, at run time, will evaluate to a string --> - <xsl:param name="value"/> - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - Expression.Eq("<xsl:value-of select="$property/@name"/>", <xsl:choose> - <xsl:when test="$basetype = 'string'"> - <xsl:value-of select="$value"/> - </xsl:when> - <xsl:when test="$basetype = 'integer'"> - Int32.Parse( <xsl:value-of select="$value"/>) - </xsl:when> - <xsl:when test="$basetype = 'money'"> - Decimal.Parse( <xsl:value-of select="$value"/>) - </xsl:when> - <xsl:when test="$basetype = 'date'"> - DateTime.Parse( <xsl:value-of select="$value"/>) - </xsl:when> - <xsl:when test="$basetype='entity'"> - <xsl:call-template name="fetch-property-instance"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="value" select="$value"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="yes"> - ADL: Error: properties of type <xsl:value-of select="$basetype"/> cannot yet be used - in equality tests - </xsl:message> - </xsl:otherwise> - </xsl:choose>) - </xsl:template> - - <!-- generate a hibernate like expression based on this property, - comparing it to this value --> - <xsl:template name="hibernate-expression-like"> - <xsl:param name="property"/> - <xsl:param name="value"/> - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$basetype='string' or $basetype='text'"> - Expression.Like( "<xsl:value-of select="$property/@name"/>", "%"+<xsl:value-of select="$value"/>+"%") - </xsl:when> - <xsl:when test="$basetype='real'"> - /* match to four significant places */ - Expression.Between( "<xsl:value-of select="$property/@name"/>", - Double.Parse( <xsl:value-of select="$value"/>) * 1.0001, - Double.Parse( <xsl:value-of select="$value"/>) * 0.9999) - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="hibernate-expression-eq"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="value" select="$value"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- argument: a property - returns 'true' if that property is of a type which makes it searchable, - else 'false'. See also how search fields are generated in adl2views.xsl --> - <xsl:template name="is-searchable"> - <xsl:param name="property"/> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$base-type='string'">true</xsl:when> - <xsl:when test="$base-type='integer'">true</xsl:when> - <xsl:when test="$base-type='real'">true</xsl:when> - <xsl:when test="$base-type='money'">true</xsl:when> - <xsl:when test="$base-type='text'">true</xsl:when> - <xsl:when test="$base-type='entity'">true</xsl:when> - <xsl:otherwise>false</xsl:otherwise> - </xsl:choose> - - </xsl:template> - - <xsl:template name="fetch-property-instance"> - <!-- the property for which the instance is sought; it is assumed that - the property passed has type 'entity' --> - <xsl:param name="property"/> - <!-- the name of the value in the returned values from which the instance - must be resolved --> - <xsl:param name="value"/> - <xsl:variable name="basetype"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:if test="not( $basetype='entity')"> - <xsl:message terminate="yes"> - ADL: ERROR: property passed to fetch-property-instance whose type is not 'entity' - </xsl:message> - </xsl:if> - hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>)) - <xsl:for-each select="//adl:entity[@name=$property/@entity]/adl:key/adl:property"> - <xsl:call-template name="add-hibernate-expression-eq"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="value" select="$value"/> - </xsl:call-template> - </xsl:for-each> - .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>>() - </xsl:template> - +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Application Description Language framework + adl2controllerclasses.xsl + + (c) 2007 Cygnet Solutions Ltd + + Transform ADL into (partial) controller classes + + $Author: simon $ + $Revision: 1.46 $ + $Date: 2010-07-20 19:53:40 $ + --> + +<!-- WARNING WARNING WARNING: Do NOT reformat this file! + Whitespace (or lack of it) is significant! --> +<xsl:stylesheet version="1.0" + xmlns="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:exsl="urn:schemas-microsoft-com:xslt" + extension-element-prefixes="exsl"> + + <xsl:include href="csharp-type-include.xslt"/> + <xsl:include href="permissions-include.xslt"/> + + <xsl:output encoding="UTF-8" method="text"/> + + <!-- The locale for which these controllers are generated + TODO: Controllers should NOT be locale specific. Instead, the + controller should render views and generate messages based on the + client's locale. However, there may still need to be a concept of a + 'default locale', for when we don't have messages which suit the + client's locale --> + <xsl:param name="locale" select="en-UK"/> + + <!-- bug 1896 : boilerplate text in views should be tailored to the locale of + the expected user. Unfortunately I haven't yet worked out how to do + conditional includes in XSLT, so this is a step on the way to a solution, + not a solution in itself. --> + <xsl:include href="i18n-en-GB-include.xslt"/> + + <!-- The C# namespace within which I shall generate controllers --> + <xsl:param name="controllerns" select="Unset"/> + <!-- The C# namespace used by the entities for this project --> + <xsl:param name="entityns" select="Unset"/> + <!-- Whether to authenticate at application or at database layer. + If not 'Application', then 'Database'. --> + <xsl:param name="authentication-layer" select="'Application'"/> + + <!-- the name and version of the product being built --> + <xsl:param name="product-version" select="'Application Description Language Framework'"/> + + <!-- bug 1800 : the name of the Velocity layout to use --> + <xsl:param name="layout-name" select="adl-default-layout"/> + <!-- bug 1800 : the name of the Velocity rescue view to use --> + <xsl:param name="rescue-name"/> + <!-- bug 1800 : the name of the area (i.e. URL path part) to use --> + <xsl:param name="area-name"/> + <!-- bug 2883 : number of entries to show per list page (does not affect auxiliary lists) --> + <xsl:param name="records-per-page" select="15"/> + + <xsl:template match="adl:application"> + /* ---- [ cut here: next file '<xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/>.auto.cs'] ---------------- */ + //------------------------------------------------------------------ + // + // <xsl:value-of select="$product-version"/> + // <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller.auto.cs')"/> + // + // (c) 2007 Cygnet Solutions Ltd + // + // Automatically generated abstract super class for controllers for the + // <xsl:value-of select="/adl:application/@name"/> application; generated using + // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.46 $', 10)"/> + // + // <xsl:value-of select="/adl:application/@revision"/> + // + // This file is automatically generated; DO NOT EDIT IT. + // + //------------------------------------------------------------------ + + /// <summary> + /// \mainpage <xsl:value-of select="concat( @name, ' ', @version)"/> + /// <xsl:value-of select="normalize-space(adl:documentation)"/> + /// + /// \package <xsl:value-of select="$controllerns"/> + /// MVC Controller classes for <xsl:value-of select='/adl:application/@name'/> + /// </summary> + namespace <xsl:value-of select="$controllerns"/> { + using System; + using System.Data; + using System.Collections.Generic; + using System.Data.SqlClient; + using NHibernate; + using NHibernate.Expression; + using Cygnet.DBAuth; + using Cygnet.Web.Controllers; + using Cygnet.Web.Helpers; + using Castle.MonoRail.Framework; + using <xsl:value-of select="$entityns"/>; + + /// <summary> + /// Automatically generated abstract super class for controllers for the + /// <xsl:value-of select="/adl:application/@name"/> application + /// + /// DO NOT EDIT THIS FILE! + /// </summary> + [ <!-- in the longer term, all the helpers which a given + project needs which not every project needs should be listed here, + with appropriate 'xsl:if' wrappers. --> + Helper(typeof(FormatterHelper), "t"), + Helper(typeof(SecurityHelper), "SecurityHelper") + ] + public abstract partial class <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> : BaseController { + + <xsl:choose> + <xsl:when test="$authentication-layer = 'Application'"/> + <xsl:when test="$authentication-layer = 'Database'"> + /* authentication layer is requested to be 'database', but in fact database-layer + authentication does not work well with NHibernate so this is being ignored. */ + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + ADL: ERROR: invalid value (<xsl:value-of select="$authentication-layer"/>) provided for authentication-layer + </xsl:message> + </xsl:otherwise> + </xsl:choose> + + <xsl:for-each select="//adl:entity"> + /// <summary> + /// Return a list of all instances of <xsl:value-of select="@name"/> for use in menus, etc; + /// </summary> + protected IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> <xsl:value-of select="concat( 'FetchAll', @name)"/>( ) { + IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> result = new List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); + + <xsl:variable name="readgroups"> + <xsl:call-template name="entity-read-groups"> + <xsl:with-param name="entity" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:if test="$authentication-layer = 'Database'"> + if ( + <xsl:for-each select="exsl:node-set( $readgroups)/*"> + InGroup( "<xsl:value-of select="./@name"/>")<xsl:if test="position() != last()">||</xsl:if> + </xsl:for-each> + ){ + </xsl:if> + result = GetDBSession().CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) + <xsl:for-each select="descendant::adl:property[@distinct='user']"> + .AddOrder( <xsl:value-of select="concat('new Order( "', @name, '", true)')"/>) + </xsl:for-each> + .SetCacheable( true) + .SetCacheRegion( "<xsl:value-of select="/adl:application/@name"/>") + .List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); + <xsl:if test="$authentication-layer != 'Application'"> + } + </xsl:if> + return result; + } + + </xsl:for-each> + } + } + <xsl:apply-templates select="adl:entity"/> + </xsl:template> + + + <!-- Don't bother generating anything for foreign entities --> + <xsl:template match="adl:entity[@foreign='true']"/> + + <xsl:template match="adl:entity"> + /* + * Not generating controller for entity <xsl:value-of select="@name"/>, + * as it has no forms, pages or lists. + */ + </xsl:template> + <xsl:template match="adl:entity[adl:form|adl:page|adl:list]"> + + /* ---- [ cut here: next file '<xsl:value-of select="@name"/>Controller.auto.cs'] ---------------- */ + + //------------------------------------------------------------------ + // + // <xsl:value-of select="$product-version"/> + // <xsl:value-of select="@name"/>Controller.auto.cs + // + // (c) 2007 Cygnet Solutions Ltd + // + // Controller for auto-generated forms for editing <xsl:value-of select="@name"/>s + // Automatically generated from application description using + // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.46 $', 10)"/> + // + // This file is automatically generated; DO NOT EDIT IT. + // + //------------------------------------------------------------------ + + namespace <xsl:value-of select="$controllerns"/> { + using System; + using System.Data; + using System.Collections.Generic; + using System.Configuration; + using System.Web; + using System.Web.Security; + using System.Web.UI; + using System.Web.UI.WebControls; + using System.Web.UI.WebControls.WebParts; + using System.Web.UI.HtmlControls; + using Castle.MonoRail.Framework.Helpers; + using Cygnet.Entities; + using Cygnet.Exceptions; + using Cygnet.Web.Helpers; + using Cygnet.Web.Controllers; + using Cygnet.Web.SmartControls; + using Cygnet.Utility; + using NHibernate; + using NHibernate.Expression; + using Castle.MonoRail.Framework; + using Iesi.Collections.Generic; + using <xsl:value-of select="$entityns"/>; + + /// <summary> + /// Automatically generated partial controller class following 'thin controller' + /// strategy, for entity <xsl:value-of select="@name"/>. Note that part of this + /// class may be defined in a separate file called + /// <xsl:value-of select="@name"/>Controller.manual.cs, q.v. + /// </summary> + /// + /// <remarks> + /// <list type='bullet'> + /// <listheader><description>See also auto-generated Velocity view macros</description></listheader><xsl:for-each select='adl:form|adl:page|adl:list'> + /// <item> + /// <term><xsl:value-of select="concat(@name, '.auto.vm')"/></term> + /// <description><xsl:apply-templates select='adl:documentation'/></description> + /// </item></xsl:for-each> + /// </list> + /// + /// DO NOT EDIT THIS FILE! + /// </remarks> + [ + <xsl:if test="$layout-name"> + Layout("<xsl:value-of select="$layout-name"/>"), + </xsl:if> + <xsl:if test="$rescue-name"> + Rescue("<xsl:value-of select="$rescue-name"/>"), + </xsl:if> + ControllerDetails("<xsl:value-of select="@name"/>", Area = "<xsl:value-of select="$area-name"/>"), + Helper(typeof(StylesHelper), "StylesHelper"), + Helper(typeof(<xsl:value-of select="concat( @name, 'FieldHelper')"/>), "<xsl:value-of select="concat( @name, 'FieldHelper')"/>") + ] + public partial class <xsl:value-of select="concat( @name, 'Controller')"/> : <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> { + + protected class <xsl:value-of select="concat( @name, 'FieldHelper')"/> : SmartFormHelper { + public <xsl:value-of select="concat( @name, 'FieldHelper')"/>() { + <xsl:for-each select="descendant::adl:property[@type='entity']"> + <xsl:variable name="entityname" select="@entity"/> + <xsl:variable name="entity" select="//adl:entity[@name=$entityname]"/> + <xsl:choose> + <xsl:when test="$entity/@foreign='true'"> + /* Entity <xsl:value-of select="$entityname"/> is foreign..? */ + <xsl:variable name="foreignkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> + <xsl:variable name="userident"> + <xsl:choose> + <xsl:when test="$entity//adl:property[@distinct='user' or @distinct='all']"> + <xsl:value-of select="$entity//adl:property[@distinct='user' or @distinct='all'][position()=1]/@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$foreignkey"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", + new TypeMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "<xsl:value-of select="$foreignkey"/>","<xsl:value-of select="$userident"/>")); + </xsl:when> + <xsl:otherwise> + Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <xsl:for-each select="descendant::adl:property[@type='list']"> + <xsl:variable name="entityname" select="@entity"/> + Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityShuffleControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); + </xsl:for-each> + + } + } + + <xsl:if test="adl:property[@type='message']"> + /// <summary> + /// Temporary hack to sort a problem with uninitialised messages + /// </summary> + public void fixupMessages() { + ISession hibernator = GetDBSession(); + ICollection<<xsl:value-of select="concat($entityns, '.', @name)"/>> instances = + hibernator.CreateCriteria( typeof( <xsl:value-of select="concat($entityns, '.', @name)"/>)) + .List<<xsl:value-of select="concat($entityns, '.', @name)"/>>(); + + foreach ( <xsl:value-of select="concat($entityns, '.', @name)"/> instance in instances) { + <xsl:for-each select="adl:property[@type='message']"> + <xsl:variable name="slot" select="concat( 'instance.', @name)"/> + if ( <xsl:value-of select="$slot"/> == null || <xsl:value-of select="concat( $slot, '.MessageId')"/> == 0 ){ + <xsl:value-of select="$slot"/> = new Message(); + + <xsl:value-of select="$slot"/>.BeforeUpdateHook( hibernator); + hibernator.SaveOrUpdate( <xsl:value-of select="$slot"/>); + <xsl:value-of select="$slot"/>.AfterUpdateHook( hibernator); + } + </xsl:for-each> + instance.BeforeUpdateHook( hibernator); + hibernator.SaveOrUpdate( instance); + instance.AfterUpdateHook( hibernator); + } + hibernator.Flush(); + <xsl:if test="adl:list[@name='list']"> + list(); + </xsl:if> + } + </xsl:if> + + <xsl:if test="adl:form"> + <!-- unless there's at least one form, we won't generate a 'store' method --> + /// <summary> + /// Store the record represented by the parameters passed in an HTTP service + /// Without Id -> it's new, I create a new persistent object; + /// With Id -> it's existing, I update the existing persistent object. + /// NOTE: Should only be called from a handler for method 'POST', never 'GET'. + /// </summary> + private void Store() + { + ISession hibernator = GetDBSession(); + List<string> messages = new List<string>(); + PropertyBag["messages"] = messages; + /* A 'newborn' instance can be updated even if the current user doesn't have + * update permissions, seeing that we use an update operation to set the + * field values and save the entity. */ + Boolean isnewborn = false; + + /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ + <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; + + try { + <xsl:if test="adl:property[@distinct='system' or @distinct='all']"> + /* a criteria object to use in distinctness checks */ + ICriteria matchCriteria = null; + </xsl:if> + + record = FetchRecord( hibernator); + + <xsl:apply-templates select="adl:property" mode="presenceAndValidity"/> + + if ( HasNoErrors()) { + if ( record == null) { + /* it seems to be new, create persistent object - if the user is permitted to */ + AssertUserCanCreate(); + + try { + if ( AllKeys()) { + record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(<xsl:for-each select="adl:key/adl:property"> + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$basetype='integer'"> + Int32.Parse( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]) + </xsl:when> + <xsl:when test="$basetype='entity'"> + <!-- Maybe TODO: this doesn't work recursively - if an entity has a key which is an entity + and the key of that entity is an entity, you're on your own, mate! --> + <xsl:variable name="keyentity" select="@entity"/> + <xsl:variable name="keyenttype"> + <xsl:call-template name="primary-key-csharp-type"> + <xsl:with-param name="entity" select="//adl:entity[@name=$keyentity]"/> + </xsl:call-template> + </xsl:variable> + hibernator.CreateCriteria( typeof( <xsl:value-of select="concat( $entityns, '.', $keyentity)"/>)) + <xsl:call-template name="add-hibernate-expression-eq"> + <xsl:with-param name="property" select="//adl:entity[@name=$keyentity]/adl:key/adl:property[position()=1]"/> + <xsl:with-param name="value"> + Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] + </xsl:with-param> + </xsl:call-template> + .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $keyentity)"/>>() + </xsl:when> + <xsl:otherwise> + Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] + </xsl:otherwise> + </xsl:choose> + <xsl:choose> + <xsl:when test="position() = last()"/> + <xsl:otherwise>, </xsl:otherwise> + </xsl:choose> + </xsl:for-each>); + } + else + { + record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); + } + } + catch ( FormatException) { + /* failed to parse a number - not wholly unexpected, since it's most likely + * that an empty string was passed in */ + record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); + } + catch ( NullReferenceException) { + /* again, probably more normal than otherwise */ + record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); + } + messages.Add( "New <xsl:value-of select="@name"/> record created"); + isnewborn = true; + } + + if ( record != null) { + /* a transaction to ensure our database operations are atomic */ + ITransaction tx = null; + + + if ( ! isnewborn) { + /* isnewborn cannot be true unless we've already checked user can create + * so no need to do it again here */ + AssertUserCanUpdate(); + } + + try { + /* begin our atomic transaction */ + tx = hibernator.BeginTransaction(); + /* list of entities modified in this transaction */ + List<Entity> modified = new List<Entity>(); + + /* actually update the record */ + BindObjectInstance( record, ParamStore.Form, "instance"); + modified.Add( record); + + <xsl:if test="descendant::adl:property[@type='message']"> + /* there is at least one slot whose value is an internationalised message; + * if these have yet to be initialised they must be handled specially */ + Locale locale = GetBestLocaleForUser(); + <xsl:for-each select="descendant::adl:property[@type='message']"> + if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])){ + /* there's an uninitialised message for this slot */ + Message mess = record.<xsl:value-of select="@name"/>; + if ( mess == null) { + mess = new Message(); + } + mess.BeforeUpdateHook( hibernator); + hibernator.SaveOrUpdate( mess); + mess.AfterUpdateHook( hibernator); + + Translation trans = mess.GetTranslationObject( locale, hibernator); + if ( trans == null) { + trans = new Translation( mess, locale); + } + trans.MessageText = Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]; + record.<xsl:value-of select="@name"/> = mess; + trans.BeforeUpdateHook( hibernator); + hibernator.SaveOrUpdate( trans); + trans.AfterUpdateHook( hibernator); + } + </xsl:for-each> + </xsl:if> + + <!-- special binding for types which don't bind straightforwardly in BindObjectInstance--> + <xsl:apply-templates select="descendant::adl:property" mode="bind"/> + + /* write the modified records to the database */ + foreach ( Entity item in modified) { + item.BeforeUpdateHook( hibernator); + hibernator.SaveOrUpdate(item); + item.AfterUpdateHook( hibernator); + } + /* and if no exceptions, commit */ + tx.Commit(); + + messages.Add( "<xsl:call-template name="i18n-record-saved"/>"); + } /* try actually commit */ + catch ( Exception any) { + messages.Add( "<xsl:call-template name="i18n-record-not-saved"/>"); + AddError( any); + try { + tx.Rollback(); + } catch ( ObjectDisposedException ode) { + AddError( ode); + } + } /* catch ( Exception any) */ + } /* if ( record != null) */ + else { + throw new ApplicationException( String.Format( "<xsl:call-template name="i18n-record-not-found"> + <xsl:with-param name="entity-name" select="@name"/> + </xsl:call-template>")); + } + } /* if ( HasNoErrors()) */ + } /* try */ + catch ( DataSuitabilityException dse) + { + AddError( dse); + } + catch ( ApplicationException axe) + { + AddError( axe.Message); + } + + if ( ! HasNoErrors()) + { + /* the session may be polluted; create a new session */ + CloseDBSession(); + hibernator = GetDBSession(); + + record = FetchRecord( hibernator); + } /* if ( ! HasNoErrors()) */ + <xsl:value-of select="concat( 'this.',adl:form[position()=1]/@name)"/>( record); + } + + <!-- unless there's at least one form, we won't generate a 'delete' method --> + /// <summary> + /// Actually delete the selected record + /// </summary> + [AccessibleThrough(Verb.Post)] + public void Delete() + { + AssertUserCanDelete(); + ISession hibernator = GetDBSession(); + <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; + + if ( "true".Equals( Params["reallydelete"])) + { + record = FetchRecord( hibernator); + + if ( record != null) + { + try { + record.BeforeDeleteHook( hibernator); + hibernator.Delete( record); + hibernator.Flush(); + } catch ( DomainKnowledgeViolationException dkve) { + AddError( dkve); + } + } + else + { + throw new ApplicationException( "No such record?"); + } + } + if ( HasNoErrors()) { + <xsl:choose> + <xsl:when test="adl:list"> + Redirect( "<xsl:value-of select="concat(adl:list[position()=1]/@name, '.rails')"/>"); + </xsl:when> + <xsl:otherwise> + Redirect( FormsAuthentication.DefaultUrl); + </xsl:otherwise> + </xsl:choose> + } else { + PropertyBag[ "instance"] = record; + RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm"); + } + } + </xsl:if> + <xsl:apply-templates select="adl:form"/> + <xsl:apply-templates select="adl:list"/> + + /// <summary> + /// Check whether values for all my keys are available in the form fields + /// </summary> + protected bool AllKeys() { + /* whether we have valid values for all the key fields */ + bool result = true; + + <xsl:for-each select="adl:key/adl:property"> + if ( String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { + result = false; + } else if ( "<xsl:value-of select="concat('$instance.', @name)"/>".Equals( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { + /* nasty artefact of NVelocity forms - default 'null value' is dollar followed by fieldname */ + result = false; + } + </xsl:for-each> + + return result; + } + + /// <summary> + /// Fetch the record represented by the values in the current Form + /// </summary> + protected <xsl:value-of select="concat($entityns, '.', @name)"/> FetchRecord(ISession hibernator) { + /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ + <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; + + if ( AllKeys()){ + /* it's (probably) existing, retrieve it */ + record = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) + <xsl:for-each select="adl:key/adl:property"> + <xsl:call-template name="add-hibernate-expression-eq"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="value">Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]</xsl:with-param> + </xsl:call-template> + </xsl:for-each> + .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); + } + + return record; + } + } + } + /* ---- [ cut here: next file 'junk'] ------------------------- */ + </xsl:template> + + <xsl:template match="adl:property" mode="presenceAndValidity"> + <xsl:if test="@required='true'"> + if ( + <xsl:if test="@immutable='true'"> + (record == null || <xsl:value-of select="concat( 'record.', @name)"/> == null) && + </xsl:if> + String.IsNullOrEmpty( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>" ])) + { + AddError( <xsl:choose> + <xsl:when test="adl:ifmissing[@locale=$locale]"> + <xsl:apply-templates select="adl:ifmissing[@locale=$locale]"/> + </xsl:when> + <xsl:otherwise> + "<xsl:call-template name="i18n-value-required"> + <xsl:with-param name="property-name" select="@name"/> + </xsl:call-template>" + </xsl:otherwise> + </xsl:choose>); + } + </xsl:if> + <xsl:if test="@distinct='system' or @distinct='all'"> + <xsl:call-template name="check-property-value-distinct"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:if> + </xsl:template> + + <!-- upload and bind an image file to the instance --> + <xsl:template match="adl:property[@type='image']" mode="bind"> + record.<xsl:value-of select="@name"/> = + this.MaybeUploadImage("<xsl:value-of select="concat( 'instance.', @name)"/>"); + </xsl:template> + + <!-- upload and bind a file to the instance --> + <xsl:template match="adl:property[@type='uploadable']" mode="bind"> + record.<xsl:value-of select="@name"/> = + this.MaybeUploadFile("<xsl:value-of select="concat( 'instance.', @name)"/>"); + </xsl:template> + + <!-- locate and bind the specified instance of this entity --> + <xsl:template match="adl:property[@type='entity']" mode="bind"> + /* for properties of type 'entity', it should not be necessary to do anything + * special - BindObjectInstance /should/ do it all. Unfortunately it sometimes + * doesn't, and I haven't yet characterised why not. */ + <xsl:variable name="entityname" select="@entity"/> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$entityname]"> + if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]) && + ! EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>.NULLMARKER.Equals ( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) + { + record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="value"> + Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] + </xsl:with-param> + </xsl:call-template>; + + modified.Add( record.<xsl:value-of select="@name"/>); + } + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + ADL: ERROR: Could not fix up value of <xsl:value-of select="@name "/>, because no + entity was found called <xsl:value-of select="$entityname"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- locate and bind the specified linked instances --> + <xsl:template match="adl:property[@type='link']" mode="bind"> + <xsl:variable name="nearentityname" select="ancestor::adl:entity/@name"/> + <xsl:variable name="farentityname" select="@entity"/> + <xsl:variable name="entity" select="//adl:entity[@name=$farentityname]"/> + <xsl:variable name="farkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> + <xsl:variable name="farkeybasetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="deletegroups"> + <xsl:call-template name="entity-delete-groups"> + <xsl:with-param name="entity" select="$entity"/> + </xsl:call-template> + </xsl:variable> + /* For a link, collect changes to link table and process them */ + <xsl:if test="$authentication-layer = 'Database'"> + if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> + InGroup( "<xsl:value-of select="./@name"/>") || + </xsl:for-each> false) { + /* however, we cannot do anything unless we have delete permissions on the table, so + * should not try. */ + </xsl:if> + LinkChanges<<xsl:value-of select="concat( $entityns, '.', @entity)"/>> changes = + LinkTableUpdater<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>.Changes( <xsl:value-of select="concat( 'record.', @name)"/>, Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"), + hibernator); + + foreach ( var item in changes.ToRemove) { + modified.Add(item); + <xsl:value-of select="concat( 'record.', @name)"/>.Remove(item); + <xsl:for-each select="$entity//adl:property[@type='link' and @entity=$nearentityname]"> + <xsl:value-of select="concat( 'item.', @name)"/>.Remove( record); + <xsl:if test="position() != 1"> + /* WARNING WARNING WARNING! Could not uniquely determine the far side property; + * redesign your application or manually maintain this code! */ + <xsl:message terminate="no"> + WARNING: Could not uniquely determine far end of link represented by property <xsl:value-of select="@name"/> of <xsl:value-of select="$nearentityname"/> + </xsl:message> + </xsl:if> + </xsl:for-each> + } + foreach ( var item in changes.ToAdd) { + modified.Add(item); + <xsl:value-of select="concat( 'record.', @name)"/>.Add(item); + <xsl:for-each select="$entity//adl:property[@type='link' and @entity=$nearentityname]"> + <xsl:value-of select="concat( 'item.', @name)"/>.Add( record); + <xsl:if test="position() != 1"> + /* WARNING WARNING WARNING! Could not uniquely determine the far side property; + * redesign your application or manually maintain this code! */ + <xsl:message terminate="no"> + WARNING: Could not uniquely determine far end of link represented by property <xsl:value-of select="@name"/> of <xsl:value-of select="$nearentityname"/> + </xsl:message> + </xsl:if> + </xsl:for-each> + } + + <xsl:if test="$authentication-layer = 'Database'"> + } /* if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> InGroup( "<xsl:value-of select="./@name"/>") ||</xsl:for-each> false) */ + </xsl:if> + </xsl:template> + + <!-- locate and bind the specified child instances --> + <xsl:template match="adl:property[@type='list']" mode="bind"> + <xsl:variable name="farentityname" select="@entity"/> + <xsl:variable name="entity" select="//adl:entity[@name=$farentityname]"/> + <xsl:variable name="farkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> + <xsl:variable name="farkeybasetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="foreignkey"> + <xsl:choose> + <xsl:when test="@farkey"> + <xsl:value-of select="@farkey"/> + </xsl:when> + <xsl:otherwise> + <!-- If I haven't been told what the far side foreign key is, assume it has the + name of my entity --> + <xsl:value-of select="ancestor::adl:entity/@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="deletegroups"> + <xsl:call-template name="entity-delete-groups"> + <xsl:with-param name="entity" select="$entity"/> + </xsl:call-template> + </xsl:variable> + /* with a list we cannot just smash the old values! Instead we need to check + * each one and exclude it if no longer required; */ + <xsl:if test="$authentication-layer = 'Database'"> + if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> + InGroup( "<xsl:value-of select="./@name"/>") || + </xsl:for-each> false) { + /* but once again only if we can delete and create entities at the far end. */ + </xsl:if> + if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) + { + string[] <xsl:value-of select="concat(@name, 'Values')"/> = Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"); + + /* updating <xsl:value-of select="@name"/> child records; first remove any not on the submitted list */ + foreach ( <xsl:value-of select="@entity"/> item in record.<xsl:value-of select="@name"/>) + { + String itemId = item.KeyString; + bool found = false; + + foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) + { + if ( index.Equals( itemId)) + { + found = true; + break; + } + } /* foreach ( string index... */ + + if ( ! found) + { + record.<xsl:value-of select="@name"/>.Remove( item); + modified.Add( item); + break; + } + } /* foreach ( <xsl:value-of select="@entity"/> item ... */ + + /* then add any on the included list which are not already members */ + foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) + { + <xsl:value-of select="concat( $entityns, '.', @entity)"/> item = + hibernator.CreateCriteria(typeof(<xsl:value-of select="@entity"/>)) + <xsl:call-template name="add-hibernate-expression-eq"> + <xsl:with-param name="property" select="//adl:entity[@name=$farentityname]/adl:key/adl:property[position()=1]"/> + <xsl:with-param name="value" select="'index'"/> + </xsl:call-template> + .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>(); + + if ( ! record.<xsl:value-of select="@name"/>.Contains( item)) + { + /* check whether it's already a child of another <xsl:value-of select="ancestor::adl:entity/@name"/> + * and, if it is, remove it */ + <xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/> oldparent = + <xsl:value-of select="concat( 'item.', $foreignkey)"/>; + if ( oldparent != null) { + oldparent.<xsl:value-of select="@name"/>.Remove( item); + + modified.Add( oldparent); + } + + /* then add it to my <xsl:value-of select="@name"/> */ + record.<xsl:value-of select="@name"/>.Add( item); + <xsl:value-of select="concat( 'item.', $foreignkey)"/> = record; + modified.Add( item); + } + } /* foreach ( string index... */ + } /* if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) */ + <xsl:if test="$authentication-layer = 'Database'"> + } /* if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> + InGroup( "<xsl:value-of select="./@name"/>") || + </xsl:for-each> false) */ + </xsl:if> + </xsl:template> + + <!-- other properties don't need any special binding --> + <xsl:template match="adl:property" mode="bind"/> + + <xsl:template match="adl:ifmissing"> + "<xsl:value-of select="normalize-space(.)"/>" + </xsl:template> + + <xsl:template match="adl:form"> + /// <summary> + /// Handle the submission of the form named <xsl:value-of select="@name"/> + /// </summary> + [AccessibleThrough(Verb.Post)] + public void <xsl:value-of select="concat( @name, 'SubmitHandler')"/>( ) { + string command = Form[ "command"]; + + if ( command == null) { + throw new Exception( "<xsl:call-template name="i18n-command-not-found"/>"); + } + else + <xsl:for-each select=".//adl:verb"> + if ( command.Equals( "<xsl:value-of select="@verb"/>")) + { + /* NOTE: You must write an implementation of this verb in a + * manually maintained partial class file for this class */ + <xsl:value-of select="@verb"/>(); + } + else + </xsl:for-each> + if ( command.Equals( "delete")) + { + ISession hibernator = GetDBSession(); + + <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = FetchRecord( hibernator); + + TypedPropertyBag = new { + instance = record }; + + RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm"); + } + else if ( command.Equals( "store")) + { + Store(); + } + else + { + throw new Exception( String.Format("<xsl:call-template name="i18n-command-not-found"> + <xsl:with-param name="command" select="'{0}'"/> + </xsl:call-template>", command)); + } + } + + /// <summary> + /// Show the form named <xsl:value-of select="@name"/>, with no existing record + /// </summary> + [AccessibleThrough(Verb.Get)] + public void <xsl:value-of select="@name"/>( ) + { + AssertUserCanRead(); + <xsl:value-of select="concat( 'PrototypeFor', ancestor::adl:entity/@name)"/> record = + new <xsl:value-of select="concat( 'PrototypeFor', ancestor::adl:entity/@name)"/>(); + + ISession hibernator = GetDBSession(); + + TypedPropertyBag = new { + <xsl:call-template name="formmenus"> + <xsl:with-param name="form" select="."/> + </xsl:call-template> + instance = record }; + + RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); + } + + <xsl:variable name="form" select="."/> + <xsl:for-each select="ancestor::adl:entity/adl:property[ @type='entity']"> + /// <summary> + /// Show the form named <xsl:value-of select="$form/@name"/>, for a new record, but with the + /// value for <xsl:value-of select="@name"/> already predetermined + /// </summary> + [AccessibleThrough(Verb.Get)] + public void <xsl:value-of select="concat($form/@name, 'With', @name)"/>( string <xsl:value-of select="@name"/>) + { + AssertUserCanRead(); + ISession hibernator = GetDBSession(); + <xsl:value-of select="ancestor::adl:entity/@name"/> record = new <xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>(); + + record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="value" select="@name"/> + </xsl:call-template>; + + <xsl:value-of select="concat( 'this.', $form/@name)"/>( record); + } + </xsl:for-each> + + /// <summary> + /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record. As + /// the primary key of the record is itself an entity, we need to first fetch that entity + /// </summary> + <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> + <xsl:choose> + <xsl:when test="@type='entity'"> + /// <param name="<xsl:value-of select="@name"/>">the key value of the key value of the record to show</param> + </xsl:when> + <xsl:otherwise> + /// <param name="<xsl:value-of select="@name"/>">the key value of the record to show</param> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + [AccessibleThrough(Verb.Get)] + public void <xsl:value-of select="@name"/>( <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> + <!-- all args are passed as string because that's what hibernate-expression-eq expects --> + string <xsl:value-of select="concat( ' ', @name)"/> + <xsl:if test="not( position() = last())">,</xsl:if> + </xsl:for-each>) { + ISession hibernator = GetDBSession(); + <xsl:value-of select="concat( 'this.', @name)"/>( + hibernator.CreateCriteria( typeof(<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>)) + <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> + <xsl:call-template name="add-hibernate-expression-eq"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="value" select="@name"/> + </xsl:call-template> + </xsl:for-each> + .UniqueResult<<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>>()); + } + + /// <summary> + /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record + /// </summary> + /// <param name="record">the record to show</param> + protected void <xsl:value-of select="@name"/>( <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record) + { + ISession hibernator = GetDBSession(); + + TypedPropertyBag = new { + <xsl:call-template name="formmenus"> + <xsl:with-param name="form" select="."/> + </xsl:call-template> + instance = record }; + + RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); + } + </xsl:template> + + <xsl:template match="adl:list"> + /// <summary> + /// list all instances of this entity to allow the user to select one + /// this method invokes the named view. + /// </summary> + public void <xsl:value-of select="@name"/>() + { + AssertUserCanRead(); + + string view = "<xsl:value-of select="@name"/>"; + ISession hibernator = GetDBSession(); + ICriteria search = + hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>)); + Boolean withSearchCriteria = false; + + <xsl:for-each select="adl:field"> + <xsl:variable name="fieldprop" select="@property"/> + <xsl:variable name="property" select="ancestor::adl:entity//adl:property[@name=$fieldprop]"/> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + /* <xsl:value-of select="@property"/> */ + <xsl:choose> + <xsl:when test="$base-type='boolean'"/> + <xsl:when test="$base-type='link'"/> + <xsl:when test="$base-type='list'"/> + <xsl:otherwise> + if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', $property/@name)"/>"])) { + search<xsl:call-template name="add-hibernate-expression-like"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="value"> + Params["<xsl:value-of select="concat( 'search_', $property/@name)"/>"] + </xsl:with-param> + </xsl:call-template>; + PropertyBag["<xsl:value-of select="concat( 'search_', $property/@name)"/>"] = Params[ "<xsl:value-of select="concat( 'search_', $property/@name)"/>"]; + withSearchCriteria = true; + } + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + + <xsl:choose> + <xsl:when test="adl:order"> + /* explicit ordering */ + <xsl:apply-templates select="adl:order"/> + </xsl:when> + <xsl:otherwise> + /* no explicit ordering */ + <xsl:for-each select="ancestor::adl:entity//adl:property[@distinct='user' or @distinct='all']"> + search.AddOrder(<xsl:value-of select="concat( ' new Order( "', @name, '", true)')"/>); + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + + IList<<xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>> instances = search.List<<xsl:value-of select="concat( $entityns, '.', ancestor::adl:entity/@name)"/>>(); + + /* if no instances, set showRecords to one else we get a division by zero error */ + int showRecords = instances.Count > 0? instances.Count: 1; + + if ( ! withSearchCriteria) { + showRecords = <xsl:value-of select="$records-per-page"/>; + } + + PropertyBag["instances"] = + PaginationHelper.CreatePagination( this, instances, showRecords); + + RenderViewWithFailover(view + ".vm", view + ".auto.vm"); + } + + </xsl:template> + + <xsl:template match="adl:order"> + search.AddOrder( new Order( "<xsl:value-of select="@property"/>", + <xsl:choose> + <xsl:when test="@sequence='reverse-canonical'">false</xsl:when> + <xsl:otherwise>true</xsl:otherwise> + </xsl:choose>)); + </xsl:template> + + <xsl:template match="adl:documentation"> + /* <xsl:apply-templates/> */ + </xsl:template> + + + <xsl:template match="adl:key"> + <!-- the key shouldn't be matched directly - at least, not in this implementation --> + </xsl:template> + + <!-- for properties with @distinct='all' or @distinct='system', + check that values are indeed distinct --> + <xsl:template name="check-property-value-distinct"> + <xsl:param name="property"/> + + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$property/ancestor::adl:key and not( $property/ancestor::adl:entity/adl:key[position()=2])"> + <!-- if I'm the property of a key field and it is the only key field of my entity then + it is pointless trying to establish my distinctness --> + </xsl:when> + <xsl:when test="$property/@distinct = 'system' or $property/@distinct='all'"> + /* <xsl:value-of select="$property/@name"/> should be distinct: check that it is */ + matchCriteria = + hibernator.CreateCriteria(typeof(<xsl:value-of select="$property/ancestor::adl:entity/@name"/>)); + + matchCriteria<xsl:call-template name="add-hibernate-expression-eq"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="value"> + Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] + </xsl:with-param> + </xsl:call-template>; + + if ( record != null) { + /* i.e. we do have values for each of our key fields... */ + <xsl:for-each select="$property/ancestor::adl:entity/adl:key/adl:property[position()=1]"> + <xsl:variable name="keybasetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + matchCriteria.Add(Expression.Not(<xsl:call-template name="hibernate-expression-eq"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="value"> + Form["<xsl:value-of select="concat( 'instance.', @name)"/>"] + </xsl:with-param> + </xsl:call-template>)); + </xsl:for-each> + } + + if ( matchCriteria.List<<xsl:value-of select="$property/ancestor::adl:entity/@name"/>>().Count > 0) + { + AddError( + String.Format("There is already a {0} with the {1} '{2}'", + "<xsl:value-of select="$property/ancestor::adl:entity/@name"/>", "<xsl:value-of select="$property/@name"/>", Form["<xsl:value-of select="concat('instance.', $property/@name)"/>"])); + } + </xsl:when> + </xsl:choose> + </xsl:template> + + + <!-- produce all menus for a given form: harder, but more efficient --> + <xsl:template name="formmenus"> + <!-- an entity assumed to be of type adl:form --> + <xsl:param name="form"/> + <xsl:choose> + <xsl:when test="$form/@properties = 'all'"> + <xsl:call-template name="entitymenus"> + <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + /* form menus */ + <xsl:for-each select="$form//adl:field"> + <xsl:variable name="propname" select="@property"/> + <xsl:choose> + <xsl:when test="parent::adl:auxlist"/> + <xsl:when test="$form/ancestor::adl:entity//adl:property[@name=$propname and @type='entity']"> + /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity//adl:property[@name=$propname]/@entity"/> to populate the select for <xsl:value-of select="$propname"/> */ + <xsl:call-template name="menu"> + <xsl:with-param name="property" select="$form/ancestor::adl:entity//adl:property[@name=$propname]"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$form/ancestor::adl:entity//adl:property[@name=$propname and @type='link']"> + /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity//adl:property[@name=$propname]/@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="$propname"/> */ + <xsl:call-template name="menu"> + <xsl:with-param name="property" select="$form/ancestor::adl:entity//adl:property[@name=$propname]"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$form/ancestor::adl:entity//adl:property[@name=$propname and @type='list']"> + /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity//adl:property[@name=$propname]/@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ + <xsl:call-template name="menu"> + <xsl:with-param name="property" select="$form/ancestor::adl:entity//adl:property[@name=$propname]"/> + </xsl:call-template> + </xsl:when> + </xsl:choose> + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- produce all menus for a given entity: easier, but less efficient --> + <xsl:template name="entitymenus"> + <xsl:param name="entity"/> + /* there's no way I can find of producing a set of just those entities + * we'll need menus for. So we set up variables for all the menus we might + * need, and then only instantiate those we do need. */ + <xsl:for-each select="$entity/adl:property[@type='entity']"> + <!-- $entity/adl:property because it is possible to have type='entity' in the key --> + <xsl:call-template name="menu"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:for-each> + <xsl:for-each select="$entity/adl:property[@type='link']"> + <!-- $entity/adl:property because it is not possible to have type='link' in the key --> + /* produce a list of <xsl:value-of select="@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="@name"/> */ + <xsl:call-template name="menu"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:for-each> + <xsl:for-each select="$entity/adl:property[@type='list']"> + /* produce a list of <xsl:value-of select="@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ + <xsl:call-template name="menu"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:for-each> + + </xsl:template> + + <xsl:template name="menu"> + <xsl:param name="property"/> + <xsl:variable name="entity" select="//adl:entity[@name=$property/@entity]"/> + <xsl:value-of select="concat('all_', $property/@name)"/> = + <xsl:value-of select="concat( 'FetchAll', $entity/@name)"/>( ), + </xsl:template> + + <xsl:template name="primary-key-csharp-type"> + <xsl:param name="entity"/> + <xsl:if test="not( $entity)"> + <xsl:message terminate="yes"> + ADL: ERROR: No entity passed to template primary-key-csharp-type + </xsl:message> + </xsl:if> + <xsl:if test="not($entity/adl:key/adl:property)"> + <xsl:message terminate="no"> + ADL: WARNING: entity '<xsl:value-of select="$entity/@name"/>' has no primary key. + You will have to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> + </xsl:message> + </xsl:if> + <xsl:call-template name="csharp-type"> + <xsl:with-param name="property" select="$entity/adl:key/adl:property[ position() = 1]"/> + <xsl:with-param name="entityns" select="$entityns"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="primary-key-name"> + <!-- return the name of the primary key of the entity with this name --> + <xsl:param name="entity"/> + <xsl:if test="not($entity/adl:key)"> + <xsl:message terminate="yes"> + ADL: ERROR: No key for entity: <xsl:value-of select="$entity/@name"/> + </xsl:message> + </xsl:if> + <xsl:choose> + <xsl:when test="$entity/adl:key/adl:property[position()=2]"> + <xsl:message terminate="no"> + ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has a composite primary key. + You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> + </xsl:message> + <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> + </xsl:when> + <xsl:when test="$entity/adl:key/adl:property"> + <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="no"> + ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has no primary key. + You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- it's often convenient to wrap an expression in an Add() --> + <xsl:template name="add-hibernate-expression-eq"> + <xsl:param name="property"/> + <xsl:param name="value"/> + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + .Add(<xsl:call-template name="hibernate-expression-eq"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="value" select="$value"/> + </xsl:call-template>) + </xsl:template> + + <!-- it's often convenient to wrap an expression in an Add() --> + <xsl:template name="add-hibernate-expression-like"> + <xsl:param name="property"/> + <xsl:param name="value"/> + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + .Add(<xsl:call-template name="hibernate-expression-like"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="value" select="$value"/> + </xsl:call-template>) + </xsl:template> + + <!-- generate a hibernate equality expression based on this property, + comparing it to this value --> + <xsl:template name="hibernate-expression-eq"> + <!-- an entity of type property --> + <xsl:param name="property"/> + <!-- an expression which, at run time, will evaluate to a string --> + <xsl:param name="value"/> + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + Expression.Eq("<xsl:value-of select="$property/@name"/>", <xsl:choose> + <xsl:when test="$basetype = 'string'"> + <xsl:value-of select="$value"/> + </xsl:when> + <xsl:when test="$basetype = 'image'"> + <!-- image and uplodable are essentially just comparisons of file names --> + <xsl:value-of select="$value"/> + </xsl:when> + <xsl:when test="$basetype = 'uploadable'"> + <!-- image and uplodable are essentially just comparisons of file names --> + <xsl:value-of select="$value"/> + </xsl:when> + <xsl:when test="$basetype = 'integer'"> + Int32.Parse( <xsl:value-of select="$value"/>) + </xsl:when> + <xsl:when test="$basetype = 'money'"> + Decimal.Parse( <xsl:value-of select="$value"/>) + </xsl:when> + <xsl:when test="$basetype = 'date'"> + DateTime.Parse( <xsl:value-of select="$value"/>) + </xsl:when> + <xsl:when test="$basetype='entity'"> + <xsl:call-template name="fetch-property-instance"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="value" select="$value"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + ADL: Error: properties of type <xsl:value-of select="$basetype"/> cannot yet be used + in equality tests + </xsl:message> + </xsl:otherwise> + </xsl:choose>) + </xsl:template> + + <!-- generate a hibernate like expression based on this property, + comparing it to this value --> + <xsl:template name="hibernate-expression-like"> + <xsl:param name="property"/> + <xsl:param name="value"/> + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$basetype='string' or $basetype='text'"> + Expression.Like( "<xsl:value-of select="$property/@name"/>", "%"+<xsl:value-of select="$value"/>+"%") + </xsl:when> + <xsl:when test="$basetype='real'"> + /* match to four significant places */ + Expression.Between( "<xsl:value-of select="$property/@name"/>", + Double.Parse( <xsl:value-of select="$value"/>) * 1.0001, + Double.Parse( <xsl:value-of select="$value"/>) * 0.9999) + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="hibernate-expression-eq"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="value" select="$value"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- argument: a property + returns 'true' if that property is of a type which makes it searchable, + else 'false'. See also how search fields are generated in adl2views.xsl --> + <xsl:template name="is-searchable"> + <xsl:param name="property"/> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$base-type='string'">true</xsl:when> + <xsl:when test="$base-type='integer'">true</xsl:when> + <xsl:when test="$base-type='real'">true</xsl:when> + <xsl:when test="$base-type='money'">true</xsl:when> + <xsl:when test="$base-type='text'">true</xsl:when> + <xsl:when test="$base-type='entity'">true</xsl:when> + <xsl:otherwise>false</xsl:otherwise> + </xsl:choose> + + </xsl:template> + + <xsl:template name="fetch-property-instance"> + <!-- the property for which the instance is sought; it is assumed that + the property passed has type 'entity' --> + <xsl:param name="property"/> + <!-- the name of the value in the returned values from which the instance + must be resolved --> + <xsl:param name="value"/> + <xsl:variable name="basetype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:if test="not( $basetype='entity')"> + <xsl:message terminate="yes"> + ADL: ERROR: property passed to fetch-property-instance whose type is not 'entity' + </xsl:message> + </xsl:if> + hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>)) + <xsl:for-each select="//adl:entity[@name=$property/@entity]/adl:key/adl:property"> + <xsl:call-template name="add-hibernate-expression-eq"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="value" select="$value"/> + </xsl:call-template> + </xsl:for-each> + .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>>() + </xsl:template> + </xsl:stylesheet> \ No newline at end of file diff --git a/transforms/adl2documentation.xslt b/transforms/adl2documentation.xslt index 454e113..1ae21b9 100755 --- a/transforms/adl2documentation.xslt +++ b/transforms/adl2documentation.xslt @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns="http://bowyer.journeyman.cc/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output encoding="UTF-8" method="xml" indent="yes" /> diff --git a/transforms/adl2entityclasses.xslt b/transforms/adl2entityclasses.xslt index ee022e4..b0f629f 100755 --- a/transforms/adl2entityclasses.xslt +++ b/transforms/adl2entityclasses.xslt @@ -7,17 +7,17 @@ Transform ADL into C# entity classes - $Author: sb $ - $Revision: 1.28 $ - $Date: 2010-06-01 17:29:02 $ + $Author: simon $ + $Revision: 1.29 $ + $Date: 2010-07-20 19:53:40 $ --> <!-- WARNING WARNING WARNING: Do NOT reformat this file! Whitespace (or lack of it) is significant! --> <xsl:stylesheet version="1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:xsl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:exsl="http://exslt.org/common" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:msxsl="urn:schemas-microsoft-com:xslt"> <xsl:include href="csharp-type-include.xslt"/> @@ -70,7 +70,7 @@ // (c)2007 Cygnet Solutions Ltd // // Automatically generated from application description using - // adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.28 $', 10)"/> + // adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.29 $', 10)"/> // // <xsl:value-of select="/adl:application/@revision"/> // @@ -97,7 +97,7 @@ /// </summary> /// <remarks> /// Automatically generated from description of group <xsl:value-of select="@name"/> - /// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.28 $', 10)"/>. + /// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.29 $', 10)"/>. /// /// DO NOT EDIT THIS FILE! /// </remarks> @@ -123,7 +123,7 @@ // (c)2007 Cygnet Solutions Ltd // // Automatically generated from application description using - // adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.28 $', 10)"/> + // adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.29 $', 10)"/> // // <xsl:value-of select="/adl:application/@revision"/> // @@ -159,7 +159,7 @@ /// </summary> /// <remarks> /// Automatically generated from description of entity <xsl:value-of select="@name"/> - /// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.28 $', 10)"/>. + /// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.29 $', 10)"/>. /// Note that manually maintained parts of this class may be defined in /// a separate file called <xsl:value-of select="@name"/>.manual.cs, q.v. /// diff --git a/transforms/adl2hibernate.xslt b/transforms/adl2hibernate.xslt index 8bd0c0c..821d347 100755 --- a/transforms/adl2hibernate.xslt +++ b/transforms/adl2hibernate.xslt @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns="urn:nhibernate-mapping-2.2" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Application Description Framework @@ -11,8 +11,8 @@ Transform ADL to Hibernate - $Author: sb $ - $Revision: 1.10 $ + $Author: simon $ + $Revision: 1.11 $ --> <xsl:param name="namespace"/> @@ -138,7 +138,7 @@ * * <xsl:value-of select="@revision"/> * - * Generated using adl2hibernate.xslt revision <xsl:value-of select="substring('$Revision: 1.10 $', 12)"/> + * Generated using adl2hibernate.xslt revision <xsl:value-of select="substring('$Revision: 1.11 $', 12)"/> * *************************************************************************** </xsl:comment> diff --git a/transforms/adl2mssql.xslt b/transforms/adl2mssql.xslt index 80d3257..b6fc0c4 100755 --- a/transforms/adl2mssql.xslt +++ b/transforms/adl2mssql.xslt @@ -1,834 +1,852 @@ -<?xml version="1.0"?> -<xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <!-- - Application Description Language framework - adl2mssql.xsl - - (c) 2007 Cygnet Solutions Ltd - - Convert ADL to MS-SQL - - $Author: sb $ - $Revision: 1.20 $ - --> - - <xsl:output indent="no" encoding="UTF-8" method="text"/> - <xsl:include href="base-type-include.xslt"/> - - <!-- - The convention to use for naming auto-generated abstract primary keys. Known values are - Id - the autogenerated primary key, if any, is called just 'Id' - Name - the autogenerated primary key has the same name as the entity - NameId - the name of the auto generated primary key is the name of the entity followed by 'Id' - Name_Id - the name of the auto generated primary key is the name of the entity followed by '_Id' - --> - <xsl:param name="abstract-key-name-convention" select="Id"/> - - <!-- the convention to use for fieldnames in link tables: - Name - the name of the foreign key is the same as the name of the table linked to - NameId - the name of the foreign key is the same as the name of the table linked to, followed by 'Id' - Name_Id - the name of the foreign key is the same as the name of the table linked to, followed by '_Id' - Name_Link - the name of the foreign key is the same as the name of the table linked to, followed by '_Link' - --> - <xsl:param name="linktable-field-name-convention" select="Name"/> - - <xsl:param name="database"/> - <!-- the name and version of the product being built --> - <xsl:param name="product-version" select="'Application Description Language Framework'"/> - - <!-- define upper and lower case letters to enable case conversion --> - <xsl:variable name="ucase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable> - <xsl:variable name="lcase">abcdefghijklmnopqrstuvwxyz</xsl:variable> - <!-- define SQL keywords to police these out of field names --> - <xsl:variable name="sqlkeywords-multiline"> - ADD EXCEPT PERCENT - ALL EXEC PLAN - ALTER EXECUTE PRECISION - AND EXISTS PRIMARY - ANY EXIT PRINT - AS FETCH PROC - ASC FILE PROCEDURE - AUTHORIZATION FILLFACTOR PUBLIC - BACKUP FOR RAISERROR - BEGIN FOREIGN READ - BETWEEN FREETEXT READTEXT - BREAK FREETEXTTABLE RECONFIGURE - BROWSE FROM REFERENCES - BULK FULL REPLICATION - BY FUNCTION RESTORE - CASCADE GOTO RESTRICT - CASE GRANT RETURN - CHECK GROUP REVOKE - CHECKPOINT HAVING RIGHT - CLOSE HOLDLOCK ROLLBACK - CLUSTERED IDENTITY ROWCOUNT - COALESCE IDENTITY_INSERT ROWGUIDCOL - COLLATE IDENTITYCOL RULE - COLUMN IF SAVE - COMMIT IN SCHEMA - COMPUTE INDEX SELECT - CONSTRAINT INNER SESSION_USER - CONTAINS INSERT SET - CONTAINSTABLE INTERSECT SETUSER - CONTINUE INTO SHUTDOWN - CONVERT IS SOME - CREATE JOIN STATISTICS - CROSS KEY SYSTEM_USER - CURRENT KILL TABLE - CURRENT_DATE LEFT TEXTSIZE - CURRENT_TIME LIKE THEN - CURRENT_TIMESTAMP LINENO TO - CURRENT_USER LOAD TOP - CURSOR NATIONAL TRAN - DATABASE NOCHECK TRANSACTION - DBCC NONCLUSTERED TRIGGER - DEALLOCATE NOT TRUNCATE - DECLARE NULL TSEQUAL - DEFAULT NULLIF UNION - DELETE OF UNIQUE - DENY OFF UPDATE - DESC OFFSETS UPDATETEXT - DISK ON USE - DISTINCT OPEN USER - DISTRIBUTED OPENDATASOURCE VALUES - DOUBLE OPENQUERY VARYING - DROP OPENROWSET VIEW - DUMMY OPENXML WAITFOR - DUMP OPTION WHEN - ELSE OR WHERE - END ORDER WHILE - ERRLVL OUTER WITH - ESCAPE OVER WRITETEXT - </xsl:variable> - <xsl:variable name="sqlkeywords" select="concat(' ', normalize-space($sqlkeywords-multiline), ' ')"/> - - - <xsl:template match="adl:application"> - ------------------------------------------------------------------------------------------------- - -- - -- <xsl:value-of select="$product-version"/> - -- - -- Database for application <xsl:value-of select="@name"/> version <xsl:value-of select="@version"/> - -- Generated for MS-SQL 2000+ using adl2mssql.xslt <xsl:value-of select="substring('$Revision: 1.20 $', 12)"/> - -- THIS FILE IS AUTOMATICALLY GENERATED: DO NOT EDIT IT. - -- - -- <xsl:value-of select="@revision"/> - -- - -- Code generator (c) 2007 Cygnet Solutions Ltd - -- - ------------------------------------------------------------------------------------------------- - - <xsl:if test="string-length( $database) > 0"> - use "<xsl:value-of select="$database"/>"; - </xsl:if> - - ------------------------------------------------------------------------------------------------- - -- authentication roles - ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="adl:group"/> - - ------------------------------------------------------------------------------------------------- - -- magic view for role membership, used in establishing security credentials - ------------------------------------------------------------------------------------------------- - CREATE VIEW RoleMembership AS - SELECT dbuser.name as "dbuser", - dbrole.name as "dbrole" - FROM sysusers AS dbuser, sysmembers, sysusers AS dbrole - WHERE dbuser.uid = sysmembers.memberuid - AND dbrole.uid = sysmembers.groupuid - GO - - GRANT SELECT on RoleMembership to public - GO - - ------------------------------------------------------------------------------------------------- - -- primary tables, views and permissions - ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="adl:entity" mode="table"/> - - ------------------------------------------------------------------------------------------------- - -- link tables - ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="adl:entity" mode="links"/> - - ------------------------------------------------------------------------------------------------- - -- primary referential integrity constraints - ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="adl:entity" mode="refinteg"/> - - ------------------------------------------------------------------------------------------------- - -- end of file - ------------------------------------------------------------------------------------------------- - </xsl:template> - - <xsl:template match="adl:documentation"> - /* <xsl:apply-templates/> */ - </xsl:template> - - <xsl:template match="adl:group"> - ------------------------------------------------------------------------------------------------- - -- security group <xsl:value-of select="@name"/> - ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="adl:documentation"/> - execute sp_addrole @rolename = '<xsl:value-of select="@name"/>' - GO - </xsl:template> - - <!-- return the table name for the entity with this entity name --> - <xsl:template name="tablename"> - <xsl:param name="entityname"/> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$entityname]/@table"> - <xsl:value-of select="//adl:entity[@name=$entityname]/@table"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$entityname"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- generate a foreign key referential integrity check --> - <xsl:template name="foreignkey"> - <xsl:param name="nearside"/> - <xsl:param name="farside"/> - <xsl:param name="linkfield"/> - <xsl:param name="ondelete" select="'NO ACTION'"/> - - <xsl:variable name="neartable"> - <xsl:call-template name="tablename"> - <xsl:with-param name="entityname" select="$nearside"/> - </xsl:call-template> - </xsl:variable> - - <xsl:variable name="fartable"> - <xsl:call-template name="tablename"> - <xsl:with-param name="entityname" select="$farside"/> - </xsl:call-template> - </xsl:variable> - - <!-- set up referential integrity constraints for primary tables --> - ALTER TABLE "<xsl:value-of select="$neartable"/>" - ADD FOREIGN KEY ( "<xsl:value-of select="$linkfield"/>") - REFERENCES "<xsl:value-of select="$fartable"/>" ON DELETE <xsl:value-of select="$ondelete"/> - - GO - </xsl:template> - - <!-- generate referential integrity constraints --> - <!-- there's a sort-of problem with this - if we have properties at both - ends of a link (which we often do) we currently generate two identical - constraints. This doesn't seem to cause any major problems but must hurt - efficiency. It would be better if we fixed this. --> - <xsl:template match="adl:entity" mode="refinteg"> - <xsl:variable name="nearside" select="@name"/> - <xsl:for-each select="descendant::adl:property[@type='entity']"> - <xsl:variable name="farside" select="@entity"/> - <xsl:variable name="keyfield"> - <xsl:call-template name="property-column-name"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$farside]//adl:property[@farkey=$keyfield and @entity=$nearside]"> - <!-- there's a 'list' property pointing the other way; let it do the heavy hauling --> - <!-- list with farkey --> - </xsl:when> - <xsl:when test="//adl:entity[@name=$farside]//adl:property[@entity=$nearside and not( @farkey)]"> - <!-- there's a 'list' property pointing the other way; let it do the heavy hauling --> - <!-- list with no farkey --> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="foreignkey"> - <xsl:with-param name="nearside" select="$nearside"/> - <xsl:with-param name="farside" select="$farside"/> - <xsl:with-param name="linkfield" select="$keyfield"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - <xsl:for-each select="descendant::adl:property[@type='list']"> - <xsl:variable name="ns2" select="@entity"/> - <xsl:variable name="linkfield"> - <xsl:call-template name="property-column-name"> - <xsl:with-param name="property" - select="//adl:entity[@name=$ns2]//adl:property[@entity=$nearside]"/> - </xsl:call-template> - </xsl:variable> - <xsl:if test="string-length( $linkfield) = 0"> - <xsl:message terminate="yes"> - ADL: ERROR: Failed to infer link field name whilst processing list property <xsl:value-of select="@name"/> of <xsl:value-of select="ancestor::adl:entity/@name"/> - Entity is '<xsl:value-of select="$ns2"/>', nearside is '<xsl:value-of select="$nearside"/>' - </xsl:message> - </xsl:if> - <xsl:call-template name="foreignkey"> - <xsl:with-param name="nearside" select="@entity"/> - <xsl:with-param name="farside" select="../@name"/> - <xsl:with-param name="linkfield" select="$linkfield"/> - <xsl:with-param name="ondelete"> - <xsl:choose> - <xsl:when test="@cascade='all'">CASCADE</xsl:when> - <xsl:when test="@cascade='all-delete-orphan'">CASCADE</xsl:when> - <xsl:when test="@cascade='delete'">CASCADE</xsl:when> - <xsl:otherwise>NO ACTION</xsl:otherwise> - </xsl:choose> - </xsl:with-param> - </xsl:call-template> - </xsl:for-each> - </xsl:template> - - - <!-- don't generate foreign tables - although we will generate ref integ constraints for them --> - <xsl:template match="adl:entity[@foreign='true']" mode="table"/> - - <xsl:template match="adl:entity" mode="table"> - <!-- the name of the entity we're generating --> - <xsl:variable name="entityname" select="@name"/> - <!-- the name of the table to generate --> - <xsl:variable name="table"> - <xsl:call-template name="tablename"> - <xsl:with-param name="entityname" select="@name"/> - </xsl:call-template> - </xsl:variable> - <!-- the entity we are generating --> - <xsl:variable name="generating-entity" select="."/> - - ------------------------------------------------------------------------------------------------- - -- primary table <xsl:value-of select="$table"/> - ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="adl:documentation"/> - CREATE TABLE "<xsl:value-of select="$table"/>" - ( - <xsl:for-each select="descendant::adl:property[not( @type='link' or @type = 'list' or @concrete='false')]"> - <xsl:apply-templates select="."/> - <xsl:if test="position() != last()">,</xsl:if> - </xsl:for-each> - <xsl:for-each select="//adl:property[@type='list' and @entity = $entityname]"> - <xsl:variable name="referringprop" select="."/> - <xsl:choose> - <xsl:when test="$generating-entity//adl:property[ @type='entity' and @entity=$referringprop/ancestor::adl:entity/@name]"> - <!-- if the entity for which I'm currently generating already has a specified property - which links to this foreign entity, I don't have to dummy one up --> - </xsl:when> - <xsl:otherwise> - <!-- dummy up the 'many' end of a one-to-many link --> - , "<xsl:value-of select="ancestor::adl:entity/@name"/>"<xsl:text> </xsl:text><xsl:call-template name="sql-type"> - <xsl:with-param name="property" select="ancestor::adl:entity/adl:key/adl:property[position() = 1]"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - <xsl:apply-templates select="adl:key"/> - ) - GO - - ---- permissions ------------------------------------------------------------------------------ - <xsl:for-each select="adl:permission"> - <xsl:call-template name="permission"> - <xsl:with-param name="entity" select="ancestor::adl:entity"/> - </xsl:call-template> - </xsl:for-each> - - </xsl:template> - - <xsl:template match="adl:key"> - <xsl:if test="adl:property[not( @concrete='false')]"> - , - PRIMARY KEY( <xsl:for-each select="adl:property[not( @concrete='false')]">"<xsl:call-template name="property-column-name"> - <xsl:with-param name="property" select="."/> - </xsl:call-template>"<xsl:if test="position() != last()">, </xsl:if></xsl:for-each>) - </xsl:if> - </xsl:template> - - <xsl:template name="distinctfield"> - <xsl:param name="table"/> - <xsl:param name="alias"/> - <!-- - print the names of the distinguishing fields in this table, - concatenating into a single string. - --> - <xsl:for-each select="/application/entity[@name=$table]"> - <xsl:for-each select="property[@distinct='user' or @distinct='all']"> - <xsl:choose> - <xsl:when test="@type='entity'"> - <xsl:call-template name="distinctfield"> - <xsl:with-param name="table" select="@entity"/> - <xsl:with-param name="alias" select="concat( $alias, '_', @name)"></xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - "<xsl:value-of select="$alias"/>"."<xsl:value-of - select="@name"/>"<xsl:if test="position() != last()"> + ' ' + </xsl:if> - </xsl:otherwise> - </xsl:choose> - - </xsl:for-each> - </xsl:for-each> - </xsl:template> - - <!-- fix up linking tables. Donoe after all primary tables have been created, - because otherwise some links may fail --> - <xsl:template match="adl:entity" mode="links"> - <xsl:variable name="entityname" select="@name"/> - <xsl:for-each select="adl:property[@type='link']"> - <xsl:call-template name="linktable"> - <xsl:with-param name="nearside" select="$entityname"/> - </xsl:call-template> - </xsl:for-each> - </xsl:template> - - <xsl:template name="permission"> - <xsl:param name="entity"/> - <!-- decode the permissions for a table --> - <xsl:variable name="table"> - <xsl:call-template name="tablename"> - <xsl:with-param name="entityname" select="$entity/@name"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="@permission='read'"> - GRANT SELECT ON "<xsl:value-of - select="$table"/>" TO "<xsl:value-of select="@group"/>" - </xsl:when> - <xsl:when test="@permission='insert'"> - GRANT INSERT ON "<xsl:value-of - select="$table"/>" TO "<xsl:value-of select="@group"/>" - </xsl:when> - <xsl:when test="@permission='noedit'"> - GRANT SELECT, INSERT ON "<xsl:value-of - select="$table"/>" TO "<xsl:value-of select="@group"/>" - </xsl:when> - <xsl:when test="@permission='edit'"> - GRANT SELECT, INSERT, UPDATE ON "<xsl:value-of - select="$table"/>" TO "<xsl:value-of select="@group"/>" - </xsl:when> - <xsl:when test="@permission='all'"> - GRANT SELECT, INSERT, UPDATE, DELETE ON "<xsl:value-of - select="$table"/>" TO "<xsl:value-of select="@group"/>" - </xsl:when> - <xsl:otherwise> - REVOKE ALL ON "<xsl:value-of - select="$table"/>" FROM "<xsl:value-of select="@group"/>" - </xsl:otherwise> - </xsl:choose> - <xsl:text> - GO - - </xsl:text> - </xsl:template> - - <!-- expects to be called in the context of an entity; probably should make this explicit. - TODO: this is a mess; refactor. --> - <xsl:template name="linktable"> - <xsl:param name="nearside"/> - <!-- This is tricky. For any many-to-many relationship between two - entities, we only want to create one link table, even if (as should be) - a property of type 'link' has been declared at both ends --> - <xsl:variable name="farside"> - <xsl:choose> - <xsl:when test="@entity = $nearside"> - <xsl:value-of select="concat( @entity, '_1')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="@entity"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="comparison"> - <xsl:call-template name="stringcompare"> - <xsl:with-param name="node1" select="$nearside"/> - <xsl:with-param name="node2" select="@entity"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="farentityname" select="@entity"/> - <xsl:variable name="farentity" select="//adl:entity[@name=$farentityname]"/> - <xsl:variable name="linksuffix"> - <xsl:choose> - <xsl:when test="$linktable-field-name-convention = 'Name'"/> - <xsl:when test="$linktable-field-name-convention = 'NameId'"> - <xsl:value-of select="'Id'"/> - </xsl:when> - <xsl:when test="$linktable-field-name-convention = 'Name_Id'"> - <xsl:value-of select="'_Id'"/> - </xsl:when> - <xsl:when test="$linktable-field-name-convention = 'NameLink'"> - <xsl:value-of select="'Link'"/> - </xsl:when> - <xsl:when test="$linktable-field-name-convention = 'Name_Link'"> - <xsl:value-of select="'_Link'"/> - </xsl:when> - </xsl:choose> - </xsl:variable> - - <xsl:variable name="myresponsibility"> - <xsl:choose> - <!-- if we could use the compare( string, string) function this would be a lot simpler, but - unfortunately that's in XSL 2.0, and neither NAnt nor Visual Studio can manage that --> - <!-- if the link is back to me, then obviously I'm responsible --> - <xsl:when test="$comparison = 0">true</xsl:when> - <!-- generally, the entity whose name is later in the default collating sequence - shall not be responsible. --> - <xsl:when test="$comparison = -1">true</xsl:when> - <!-- However if the one that is earlier doesn't have a 'link' - property for this join, however, then later end will have to do it --> - <xsl:when test="$comparison = 1"> - <xsl:choose> - <!-- the far side is doing it... --> - <xsl:when test="$farentity/adl:property[@type='link' and @entity=$nearside]">false</xsl:when> - <xsl:otherwise>true</xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise>false</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <!-- Problems with responsibility for generating link tables: --> - -- Problems with responsibility for generating link tables: - -- @entity = <xsl:value-of select="@entity"/> - -- $nearside = <xsl:value-of select="$nearside"/> - -- $farside = <xsl:value-of select="$farside"/> - -- farlink = <xsl:value-of select="$farentity/adl:property[@type='link' and @entity=$nearside]/@name"/> - -- comparison = '<xsl:value-of select="$comparison"/>' - -- my responsibility = <xsl:value-of select="$myresponsibility"/> - <xsl:variable name="linktablename"> - <xsl:choose> - <xsl:when test="$comparison =-1"> - <xsl:value-of select="concat( 'LN_', $nearside, '_', @entity)"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat( 'LN_', @entity, '_', $nearside)"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="$myresponsibility='true'"> - <!-- create a linking table --> - - ------------------------------------------------------------------------------------------------- - -- link table joining <xsl:value-of select="$nearside"/> with <xsl:value-of select="@entity"/> - ------------------------------------------------------------------------------------------------- - CREATE TABLE "<xsl:value-of select="$linktablename"/>" - ( - "<xsl:value-of select="concat( $nearside, $linksuffix)"/>" <xsl:call-template name="sql-type"> - <xsl:with-param name="property" select="//adl:entity[@name=$nearside]/adl:key/adl:property[position()=1]"/> - </xsl:call-template> NOT NULL, - "<xsl:value-of select="concat( $farside, $linksuffix)"/>" <xsl:call-template name="sql-type"> - <xsl:with-param name="property" select="$farentity/adl:key/adl:property[position()=1]"/> - </xsl:call-template> NOT NULL - ) - - GO - <xsl:text> - - </xsl:text> - ---- permissions ------------------------------------------------------------------------------ - <!-- only two levels of permission really matter for a link table. If you can read both of the - parent tables, then you can read the link table. If you can edit either of the parent tables, - then you need full CRUD permissions on the link table. Otherwise, you get nothing. --> - <xsl:for-each select="//adl:group"> - <xsl:variable name="groupname" select="@name"/> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='all']"> - GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" - </xsl:when> - <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='edit']"> - GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" - </xsl:when> - <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='all']"> - GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" - </xsl:when> - <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='edit']"> - GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" - </xsl:when> - <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='none']"> - REVOKE ALL ON "<xsl:value-of select="$linktablename"/>" FROM "<xsl:value-of select="$groupname"/>" - </xsl:when> - <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='none']"> - REVOKE ALL ON "<xsl:value-of select="$linktablename"/>" FROM "<xsl:value-of select="$groupname"/>" - </xsl:when> - <xsl:otherwise> - GRANT SELECT ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> - </xsl:otherwise> - </xsl:choose> - GO - </xsl:for-each> - - ---- referential integrity -------------------------------------------------------------------- - - <xsl:variable name="neartable"> - <xsl:call-template name="tablename"> - <xsl:with-param name="entityname" select="$nearside"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="fartable"> - <xsl:call-template name="tablename"> - <xsl:with-param name="entityname" select="$farentityname"/> - </xsl:call-template> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$nearside=@entity"> - <xsl:call-template name="foreignkey"> - <xsl:with-param name="nearside" select="$linktablename"/> - <xsl:with-param name="farside" select="$neartable"/> - <xsl:with-param name="linkfield" select="concat( $nearside, $linksuffix)"/> - <xsl:with-param name="ondelete" select="'NO ACTION'"/> - </xsl:call-template> - <xsl:call-template name="foreignkey"> - <xsl:with-param name="nearside" select="$linktablename"/> - <xsl:with-param name="farside" select="$fartable"/> - <xsl:with-param name="linkfield" select="concat( $farside, $linksuffix)"/> - <xsl:with-param name="ondelete" select="'CASCADE'"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="foreignkey"> - <xsl:with-param name="nearside" select="$linktablename"/> - <xsl:with-param name="farside" select="$neartable"/> - <xsl:with-param name="linkfield" select="concat( $nearside, $linksuffix)"/> - <xsl:with-param name="ondelete" select="'CASCADE'"/> - </xsl:call-template> - <xsl:call-template name="foreignkey"> - <xsl:with-param name="nearside" select="$linktablename"/> - <xsl:with-param name="farside" select="$fartable"/> - <xsl:with-param name="linkfield" select="concat( @entity, $linksuffix)"/> - <xsl:with-param name="ondelete" select="'CASCADE'"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - -- Suppressing generation of <xsl:value-of select="$linktablename"/>, as it is not my responsibility - </xsl:otherwise> - </xsl:choose> - <xsl:if test="myresponsibility='true'"> - </xsl:if> - </xsl:template> - - <xsl:template match="adl:property[@type='list']"> - -- Suppressing output of property <xsl:value-of select="@name"/>, - -- as it is the 'one' end of a one-to-many relationship - </xsl:template> - - <xsl:template match="adl:generator[@action='native']"> - IDENTITY( 1, 1) - </xsl:template> - <xsl:template match="adl:generator"/> - - <!-- the grand unified property handler, using the sql-type template to - generate the correct types for each field --> - <xsl:template match="adl:property"> - <xsl:variable name="column"> - <xsl:call-template name="property-column-name"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="type"> - <xsl:call-template name="sql-type"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="generator"> - <xsl:apply-templates select="adl:generator"/> - </xsl:variable> - "<xsl:value-of select="$column"/>" <xsl:value-of - select="concat( normalize-space( $type), ' ', normalize-space( $generator))"/><xsl:if - test="@required='true'"> NOT NULL</xsl:if><xsl:if - test="string(@default)"> DEFAULT <xsl:choose> - <xsl:when test="$base-type = 'integer' or $base-type = 'real' or $base-type = 'money'"> - <xsl:value-of select="@default"/> - </xsl:when> - <xsl:when test="$base-type = 'boolean'"> - <xsl:choose> - <xsl:when test="@default='true'">1</xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise>'<xsl:value-of select="@default"/>'</xsl:otherwise> - </xsl:choose> - </xsl:if> - - </xsl:template> - - <!-- properties of type 'entity' are supposed to be being handled by the - grand unified property handler. Unfortunately it gets them wrong and I'm not - sure why. So temporarily this special case template fixes the problem. TODO: - work out what's wrong with the grand unified version --> - <xsl:template match="adl:property[@type='entity']"> - <xsl:variable name="column"> - <xsl:call-template name="property-column-name"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="type"> - <xsl:call-template name="sql-type"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </xsl:variable> - "<xsl:value-of select="$column"/>" <xsl:value-of select="$type"/><xsl:if - test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if> - </xsl:template> - - - <!-- consistent, repeatable way of getting the column name for a given property --> - <xsl:template name="property-column-name"> - <!-- a property element --> - <xsl:param name="property"/> - <xsl:variable name="unescaped"> - <xsl:choose> - <xsl:when test="$property/@column"> - <xsl:value-of select="$property/@column"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$property/@name"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="contains( $sqlkeywords, concat(' ', translate( $unescaped, $lcase, $ucase),' '))"> - <!-- - names which are keywords need to be escaped /either/ with square - brackets /or/ with quotes, but currently we're using quotes for all names - so don't need square brackets. - xsl:value-of select="concat( '[', $unescaped, ']')"/ --> - <xsl:value-of select="$unescaped"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$unescaped"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template name="primary-key-name"> - <xsl:param name="entityname"/> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$entityname]/@natural-key"> - <xsl:value-of select="//adl:entity[@name=$entityname]/@natural-key"/> - </xsl:when> - <xsl:when test="//adl:entity[@name=$entityname]/key"> - <xsl:choose> - <xsl:when test="count(//adl:entity[@name=$entityname]/adl:key/adl:property) > 1"> - <xsl:message terminate="no"> - ADL: WARNING: entity '<xsl:value-of select="$entityname"/>' has a compound primary key; - adl2mssql is not yet clever enough to generate appropriate code - </xsl:message> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]"/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="$abstract-key-name-convention='Name'"> - <xsl:value-of select="@name"/> - </xsl:when> - <xsl:when test="$abstract-key-name-convention = 'NameId'"> - <xsl:value-of select="concat( $entityname, 'Id')"/> - </xsl:when> - <xsl:when test="$abstract-key-name-convention = 'Name_Id'"> - <xsl:value-of select="concat( $entityname, '_Id')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="'Id'"/> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- return the SQL type of the property which is passed as a parameter --> - <xsl:template name="sql-type"> - <xsl:param name="property"/> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="base-size"> - <xsl:call-template name="base-size"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$base-type = 'entity'"> - <xsl:variable name="entity" select="$property/@entity"/> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$entity]"> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$entity]/adl:key/adl:property"> - <xsl:call-template name="sql-type"> - <xsl:with-param name="property" - select="//adl:entity[@name=$entity]/adl:key/adl:property[position()=1]"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="yes"> - ADL: ERROR: property '<xsl:value-of select="$property/@name"/>' refers to - entity '<xsl:value-of select="$property/@entity"/>', but this entity has no key. - </xsl:message> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="yes"> - ADL: ERROR: property '<xsl:value-of select="$property/@name"/>' refers to - entity '<xsl:value-of select="$property/@entity"/>', but no such entity exists. - </xsl:message> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="$base-type = 'date'">DATETIME</xsl:when> - <xsl:when test="$base-type = 'time'">DATETIME</xsl:when> - <!-- TODO: if the type was 'defined' then the size should probably come from the typedef --> - <xsl:when test="$base-type = 'string'">VARCHAR( <xsl:value-of select="$base-size"/>)</xsl:when> - <xsl:when test="$base-type = 'text'">TEXT</xsl:when> - <xsl:when test="$base-type = 'boolean'">BIT</xsl:when> - <xsl:when test="$base-type = 'timestamp'">DATETIME</xsl:when> - <xsl:when test="$base-type = 'integer'">INT</xsl:when> - <xsl:when test="$base-type = 'real'">DOUBLE PRECISION</xsl:when> - <xsl:when test="$base-type = 'money'">DECIMAL( 16, 2)</xsl:when> - <xsl:otherwise>[sql:unknown? [<xsl:value-of select="$base-type"/>]]</xsl:otherwise> - </xsl:choose> - - </xsl:template> - - - <!-- horrible, horrible hackery. Compare two strings and return - * 0 if they are identical, - * -1 if the first is earlier in the default collating sequence, - * 1 if the first is later. - In XSL 2.0 this could be done using the compare(string, string) function. --> - <xsl:template name="stringcompare"> - <xsl:param name="node1"/> - <xsl:param name="node2"/> - <xsl:choose> - <xsl:when test="string($node1)=string($node2)"> - <xsl:text>0</xsl:text> - </xsl:when> - <xsl:otherwise> - <xsl:for-each select="$node1 | $node2"> - <xsl:sort select="."/> - <xsl:if test="position()=1"> - <xsl:choose> - <xsl:when test="string(.) = string($node1)"> - <xsl:text>-1</xsl:text> - </xsl:when> - <xsl:otherwise> - <xsl:text>1</xsl:text> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:for-each> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - -</xsl:stylesheet> +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" + xmlns="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <!-- + Application Description Language framework + adl2mssql.xsl + + (c) 2007 Cygnet Solutions Ltd + + Convert ADL to MS-SQL + + $Author: simon $ + $Revision: 1.21 $ + --> + + <xsl:output indent="no" encoding="UTF-8" method="text"/> + <xsl:include href="base-type-include.xslt"/> + + <!-- + The convention to use for naming auto-generated abstract primary keys. Known values are + Id - the autogenerated primary key, if any, is called just 'Id' + Name - the autogenerated primary key has the same name as the entity + NameId - the name of the auto generated primary key is the name of the entity followed by 'Id' + Name_Id - the name of the auto generated primary key is the name of the entity followed by '_Id' + --> + <xsl:param name="abstract-key-name-convention" select="Id"/> + + <!-- the convention to use for fieldnames in link tables: + Name - the name of the foreign key is the same as the name of the table linked to + NameId - the name of the foreign key is the same as the name of the table linked to, followed by 'Id' + Name_Id - the name of the foreign key is the same as the name of the table linked to, followed by '_Id' + Name_Link - the name of the foreign key is the same as the name of the table linked to, followed by '_Link' + --> + <xsl:param name="linktable-field-name-convention" select="Name"/> + + <xsl:param name="database"/> + <!-- the name and version of the product being built --> + <xsl:param name="product-version" select="'Application Description Language Framework'"/> + + <!-- define upper and lower case letters to enable case conversion --> + <xsl:variable name="ucase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable> + <xsl:variable name="lcase">abcdefghijklmnopqrstuvwxyz</xsl:variable> + <!-- define SQL keywords to police these out of field names --> + <xsl:variable name="sqlkeywords-multiline"> + ADD EXCEPT PERCENT + ALL EXEC PLAN + ALTER EXECUTE PRECISION + AND EXISTS PRIMARY + ANY EXIT PRINT + AS FETCH PROC + ASC FILE PROCEDURE + AUTHORIZATION FILLFACTOR PUBLIC + BACKUP FOR RAISERROR + BEGIN FOREIGN READ + BETWEEN FREETEXT READTEXT + BREAK FREETEXTTABLE RECONFIGURE + BROWSE FROM REFERENCES + BULK FULL REPLICATION + BY FUNCTION RESTORE + CASCADE GOTO RESTRICT + CASE GRANT RETURN + CHECK GROUP REVOKE + CHECKPOINT HAVING RIGHT + CLOSE HOLDLOCK ROLLBACK + CLUSTERED IDENTITY ROWCOUNT + COALESCE IDENTITY_INSERT ROWGUIDCOL + COLLATE IDENTITYCOL RULE + COLUMN IF SAVE + COMMIT IN SCHEMA + COMPUTE INDEX SELECT + CONSTRAINT INNER SESSION_USER + CONTAINS INSERT SET + CONTAINSTABLE INTERSECT SETUSER + CONTINUE INTO SHUTDOWN + CONVERT IS SOME + CREATE JOIN STATISTICS + CROSS KEY SYSTEM_USER + CURRENT KILL TABLE + CURRENT_DATE LEFT TEXTSIZE + CURRENT_TIME LIKE THEN + CURRENT_TIMESTAMP LINENO TO + CURRENT_USER LOAD TOP + CURSOR NATIONAL TRAN + DATABASE NOCHECK TRANSACTION + DBCC NONCLUSTERED TRIGGER + DEALLOCATE NOT TRUNCATE + DECLARE NULL TSEQUAL + DEFAULT NULLIF UNION + DELETE OF UNIQUE + DENY OFF UPDATE + DESC OFFSETS UPDATETEXT + DISK ON USE + DISTINCT OPEN USER + DISTRIBUTED OPENDATASOURCE VALUES + DOUBLE OPENQUERY VARYING + DROP OPENROWSET VIEW + DUMMY OPENXML WAITFOR + DUMP OPTION WHEN + ELSE OR WHERE + END ORDER WHILE + ERRLVL OUTER WITH + ESCAPE OVER WRITETEXT + </xsl:variable> + <xsl:variable name="sqlkeywords" select="concat(' ', normalize-space($sqlkeywords-multiline), ' ')"/> + + + <xsl:template match="adl:application"> + ------------------------------------------------------------------------------------------------- + -- + -- <xsl:value-of select="$product-version"/> + -- + -- Database for application <xsl:value-of select="@name"/> version <xsl:value-of select="@version"/> + -- Generated for MS-SQL 2000+ using adl2mssql.xslt <xsl:value-of select="substring('$Revision: 1.21 $', 12)"/> + -- THIS FILE IS AUTOMATICALLY GENERATED: DO NOT EDIT IT. + -- + -- <xsl:value-of select="@revision"/> + -- + -- Code generator (c) 2007 Cygnet Solutions Ltd + -- + ------------------------------------------------------------------------------------------------- + + <xsl:if test="string-length( $database) > 0"> + use "<xsl:value-of select="$database"/>"; + </xsl:if> + + ------------------------------------------------------------------------------------------------- + -- authentication roles + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:group"/> + + ------------------------------------------------------------------------------------------------- + -- magic view for role membership, used in establishing security credentials + ------------------------------------------------------------------------------------------------- + CREATE VIEW RoleMembership AS + SELECT dbuser.name as "dbuser", + dbrole.name as "dbrole" + FROM sysusers AS dbuser, sysmembers, sysusers AS dbrole + WHERE dbuser.uid = sysmembers.memberuid + AND dbrole.uid = sysmembers.groupuid + GO + + GRANT SELECT on RoleMembership to public + GO + + ------------------------------------------------------------------------------------------------- + -- primary tables, views and permissions + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:entity" mode="table"/> + + ------------------------------------------------------------------------------------------------- + -- link tables + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:entity" mode="links"/> + + ------------------------------------------------------------------------------------------------- + -- primary referential integrity constraints + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:entity" mode="refinteg"/> + + ------------------------------------------------------------------------------------------------- + -- end of file + ------------------------------------------------------------------------------------------------- + </xsl:template> + + <xsl:template match="adl:documentation"> + /* <xsl:apply-templates/> */ + </xsl:template> + + <xsl:template match="adl:group"> + ------------------------------------------------------------------------------------------------- + -- security group <xsl:value-of select="@name"/> + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:documentation"/> + execute sp_addrole @rolename = '<xsl:value-of select="@name"/>' + GO + </xsl:template> + + <!-- return the table name for the entity with this entity name --> + <xsl:template name="tablename"> + <xsl:param name="entityname"/> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$entityname]/@table"> + <xsl:value-of select="//adl:entity[@name=$entityname]/@table"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$entityname"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- generate a foreign key referential integrity check --> + <xsl:template name="foreignkey"> + <xsl:param name="nearside"/> + <xsl:param name="farside"/> + <xsl:param name="linkfield"/> + <xsl:param name="ondelete" select="'NO ACTION'"/> + + <xsl:variable name="neartable"> + <xsl:call-template name="tablename"> + <xsl:with-param name="entityname" select="$nearside"/> + </xsl:call-template> + </xsl:variable> + + <xsl:variable name="fartable"> + <xsl:call-template name="tablename"> + <xsl:with-param name="entityname" select="$farside"/> + </xsl:call-template> + </xsl:variable> + + <!-- set up referential integrity constraints for primary tables --> + ALTER TABLE "<xsl:value-of select="$neartable"/>" + ADD FOREIGN KEY ( "<xsl:value-of select="$linkfield"/>") + REFERENCES "<xsl:value-of select="$fartable"/>" ON DELETE <xsl:value-of select="$ondelete"/> + + GO + </xsl:template> + + <!-- generate referential integrity constraints --> + <!-- there's a sort-of problem with this - if we have properties at both + ends of a link (which we often do) we currently generate two identical + constraints. This doesn't seem to cause any major problems but must hurt + efficiency. It would be better if we fixed this. --> + <xsl:template match="adl:entity" mode="refinteg"> + <xsl:variable name="nearside" select="@name"/> + <xsl:for-each select="descendant::adl:property[@type='entity']"> + <xsl:variable name="farside" select="@entity"/> + <xsl:variable name="keyfield"> + <xsl:call-template name="property-column-name"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$farside]//adl:property[@farkey=$keyfield and @entity=$nearside]"> + <!-- there's a 'list' property pointing the other way; let it do the heavy hauling --> + <!-- list with farkey --> + </xsl:when> + <xsl:when test="//adl:entity[@name=$farside]//adl:property[@entity=$nearside and not( @farkey)]"> + <!-- there's a 'list' property pointing the other way; let it do the heavy hauling --> + <!-- list with no farkey --> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="foreignkey"> + <xsl:with-param name="nearside" select="$nearside"/> + <xsl:with-param name="farside" select="$farside"/> + <xsl:with-param name="linkfield" select="$keyfield"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <xsl:for-each select="descendant::adl:property[@type='list']"> + <xsl:variable name="ns2" select="@entity"/> + <xsl:variable name="linkfield"> + <xsl:call-template name="property-column-name"> + <xsl:with-param name="property" + select="//adl:entity[@name=$ns2]//adl:property[@entity=$nearside]"/> + </xsl:call-template> + </xsl:variable> + <xsl:if test="string-length( $linkfield) = 0"> + <xsl:message terminate="yes"> + ADL: ERROR: Failed to infer link field name whilst processing list property <xsl:value-of select="@name"/> of <xsl:value-of select="ancestor::adl:entity/@name"/> + Entity is '<xsl:value-of select="$ns2"/>', nearside is '<xsl:value-of select="$nearside"/>' + </xsl:message> + </xsl:if> + <xsl:call-template name="foreignkey"> + <xsl:with-param name="nearside" select="@entity"/> + <xsl:with-param name="farside" select="../@name"/> + <xsl:with-param name="linkfield" select="$linkfield"/> + <xsl:with-param name="ondelete"> + <xsl:choose> + <xsl:when test="@cascade='all'">CASCADE</xsl:when> + <xsl:when test="@cascade='all-delete-orphan'">CASCADE</xsl:when> + <xsl:when test="@cascade='delete'">CASCADE</xsl:when> + <xsl:otherwise>NO ACTION</xsl:otherwise> + </xsl:choose> + </xsl:with-param> + </xsl:call-template> + </xsl:for-each> + </xsl:template> + + + <!-- don't generate foreign tables - although we will generate ref integ constraints for them --> + <xsl:template match="adl:entity[@foreign='true']" mode="table"/> + + <xsl:template match="adl:entity" mode="table"> + <!-- the name of the entity we're generating --> + <xsl:variable name="entityname" select="@name"/> + <!-- the name of the table to generate --> + <xsl:variable name="table"> + <xsl:call-template name="tablename"> + <xsl:with-param name="entityname" select="@name"/> + </xsl:call-template> + </xsl:variable> + <!-- the entity we are generating --> + <xsl:variable name="generating-entity" select="."/> + + ------------------------------------------------------------------------------------------------- + -- primary table <xsl:value-of select="$table"/> + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:documentation"/> + CREATE TABLE "<xsl:value-of select="$table"/>" + ( + <xsl:for-each select="descendant::adl:property[not( @type='link' or @type = 'list' or @concrete='false')]"> + <xsl:apply-templates select="."/> + <xsl:if test="position() != last()">,</xsl:if> + </xsl:for-each> + <xsl:for-each select="//adl:property[@type='list' and @entity = $entityname]"> + <xsl:variable name="referringprop" select="."/> + <xsl:choose> + <xsl:when test="$generating-entity//adl:property[ @type='entity' and @entity=$referringprop/ancestor::adl:entity/@name]"> + <!-- if the entity for which I'm currently generating already has a specified property + which links to this foreign entity, I don't have to dummy one up --> + </xsl:when> + <xsl:otherwise> + <!-- dummy up the 'many' end of a one-to-many link --> + , "<xsl:value-of select="ancestor::adl:entity/@name"/>"<xsl:text> </xsl:text><xsl:call-template name="sql-type"> + <xsl:with-param name="property" select="ancestor::adl:entity/adl:key/adl:property[position() = 1]"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <xsl:apply-templates select="adl:key"/> + ) + GO + + ---- permissions ------------------------------------------------------------------------------ + <xsl:for-each select="adl:permission"> + <xsl:call-template name="permission"> + <xsl:with-param name="entity" select="ancestor::adl:entity"/> + </xsl:call-template> + </xsl:for-each> + + </xsl:template> + + <xsl:template match="adl:key"> + <xsl:if test="adl:property[not( @concrete='false')]"> + , + PRIMARY KEY( <xsl:for-each select="adl:property[not( @concrete='false')]">"<xsl:call-template name="property-column-name"> + <xsl:with-param name="property" select="."/> + </xsl:call-template>"<xsl:if test="position() != last()">, </xsl:if></xsl:for-each>) + </xsl:if> + </xsl:template> + + <xsl:template name="distinctfield"> + <xsl:param name="table"/> + <xsl:param name="alias"/> + <!-- + print the names of the distinguishing fields in this table, + concatenating into a single string. + --> + <xsl:for-each select="/application/entity[@name=$table]"> + <xsl:for-each select="property[@distinct='user' or @distinct='all']"> + <xsl:choose> + <xsl:when test="@type='entity'"> + <xsl:call-template name="distinctfield"> + <xsl:with-param name="table" select="@entity"/> + <xsl:with-param name="alias" select="concat( $alias, '_', @name)"></xsl:with-param> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + "<xsl:value-of select="$alias"/>"."<xsl:value-of + select="@name"/>"<xsl:if test="position() != last()"> + ' ' + </xsl:if> + </xsl:otherwise> + </xsl:choose> + + </xsl:for-each> + </xsl:for-each> + </xsl:template> + + <!-- fix up linking tables. Donoe after all primary tables have been created, + because otherwise some links may fail --> + <xsl:template match="adl:entity" mode="links"> + <xsl:variable name="entityname" select="@name"/> + <xsl:for-each select="adl:property[@type='link']"> + <xsl:call-template name="linktable"> + <xsl:with-param name="nearside" select="$entityname"/> + </xsl:call-template> + </xsl:for-each> + </xsl:template> + + <xsl:template name="permission"> + <xsl:param name="entity"/> + <!-- decode the permissions for a table --> + <xsl:variable name="table"> + <xsl:call-template name="tablename"> + <xsl:with-param name="entityname" select="$entity/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="@permission='read'"> + GRANT SELECT ON "<xsl:value-of + select="$table"/>" TO "<xsl:value-of select="@group"/>" + </xsl:when> + <xsl:when test="@permission='insert'"> + GRANT INSERT ON "<xsl:value-of + select="$table"/>" TO "<xsl:value-of select="@group"/>" + </xsl:when> + <xsl:when test="@permission='noedit'"> + GRANT SELECT, INSERT ON "<xsl:value-of + select="$table"/>" TO "<xsl:value-of select="@group"/>" + </xsl:when> + <xsl:when test="@permission='edit'"> + GRANT SELECT, INSERT, UPDATE ON "<xsl:value-of + select="$table"/>" TO "<xsl:value-of select="@group"/>" + </xsl:when> + <xsl:when test="@permission='all'"> + GRANT SELECT, INSERT, UPDATE, DELETE ON "<xsl:value-of + select="$table"/>" TO "<xsl:value-of select="@group"/>" + </xsl:when> + <xsl:otherwise> + REVOKE ALL ON "<xsl:value-of + select="$table"/>" FROM "<xsl:value-of select="@group"/>" + </xsl:otherwise> + </xsl:choose> + <xsl:text> + GO + + </xsl:text> + </xsl:template> + + <!-- expects to be called in the context of an entity; probably should make this explicit. + TODO: this is a mess; refactor. --> + <xsl:template name="linktable"> + <xsl:param name="nearside"/> + <!-- This is tricky. For any many-to-many relationship between two + entities, we only want to create one link table, even if (as should be) + a property of type 'link' has been declared at both ends --> + <xsl:variable name="farside"> + <xsl:choose> + <xsl:when test="@entity = $nearside"> + <xsl:value-of select="concat( @entity, '_1')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@entity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="comparison"> + <xsl:call-template name="stringcompare"> + <xsl:with-param name="node1" select="$nearside"/> + <xsl:with-param name="node2" select="@entity"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="farentityname" select="@entity"/> + <xsl:variable name="farentity" select="//adl:entity[@name=$farentityname]"/> + <xsl:variable name="linksuffix"> + <xsl:choose> + <xsl:when test="$linktable-field-name-convention = 'Name'"/> + <xsl:when test="$linktable-field-name-convention = 'NameId'"> + <xsl:value-of select="'Id'"/> + </xsl:when> + <xsl:when test="$linktable-field-name-convention = 'Name_Id'"> + <xsl:value-of select="'_Id'"/> + </xsl:when> + <xsl:when test="$linktable-field-name-convention = 'NameLink'"> + <xsl:value-of select="'Link'"/> + </xsl:when> + <xsl:when test="$linktable-field-name-convention = 'Name_Link'"> + <xsl:value-of select="'_Link'"/> + </xsl:when> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="myresponsibility"> + <xsl:choose> + <!-- if we could use the compare( string, string) function this would be a lot simpler, but + unfortunately that's in XSL 2.0, and neither NAnt nor Visual Studio can manage that --> + <!-- if the link is back to me, then obviously I'm responsible --> + <xsl:when test="$comparison = 0">true</xsl:when> + <!-- generally, the entity whose name is later in the default collating sequence + shall not be responsible. --> + <xsl:when test="$comparison = -1">true</xsl:when> + <!-- However if the one that is earlier doesn't have a 'link' + property for this join, however, then later end will have to do it --> + <xsl:when test="$comparison = 1"> + <xsl:choose> + <!-- the far side is doing it... --> + <xsl:when test="$farentity/adl:property[@type='link' and @entity=$nearside]">false</xsl:when> + <xsl:otherwise>true</xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise>false</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <!-- Problems with responsibility for generating link tables: --> + -- Problems with responsibility for generating link tables: + -- @entity = <xsl:value-of select="@entity"/> + -- $nearside = <xsl:value-of select="$nearside"/> + -- $farside = <xsl:value-of select="$farside"/> + -- farlink = <xsl:value-of select="$farentity/adl:property[@type='link' and @entity=$nearside]/@name"/> + -- comparison = '<xsl:value-of select="$comparison"/>' + -- my responsibility = <xsl:value-of select="$myresponsibility"/> + <xsl:variable name="linktablename"> + <xsl:choose> + <xsl:when test="$comparison =-1"> + <xsl:value-of select="concat( 'LN_', $nearside, '_', @entity)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat( 'LN_', @entity, '_', $nearside)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="$myresponsibility='true'"> + <!-- create a linking table --> + + ------------------------------------------------------------------------------------------------- + -- link table joining <xsl:value-of select="$nearside"/> with <xsl:value-of select="@entity"/> + ------------------------------------------------------------------------------------------------- + CREATE TABLE "<xsl:value-of select="$linktablename"/>" + ( + "<xsl:value-of select="concat( $nearside, $linksuffix)"/>" <xsl:call-template name="sql-type"> + <xsl:with-param name="property" select="//adl:entity[@name=$nearside]/adl:key/adl:property[position()=1]"/> + </xsl:call-template> NOT NULL, + "<xsl:value-of select="concat( $farside, $linksuffix)"/>" <xsl:call-template name="sql-type"> + <xsl:with-param name="property" select="$farentity/adl:key/adl:property[position()=1]"/> + </xsl:call-template> NOT NULL + ) + + GO + <xsl:text> + + </xsl:text> + ---- permissions ------------------------------------------------------------------------------ + <!-- only two levels of permission really matter for a link table. If you can read both of the + parent tables, then you can read the link table. If you can edit either of the parent tables, + then you need full CRUD permissions on the link table. Otherwise, you get nothing. --> + <xsl:for-each select="//adl:group"> + <xsl:variable name="groupname" select="@name"/> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='all']"> + GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" + </xsl:when> + <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='edit']"> + GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" + </xsl:when> + <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='all']"> + GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" + </xsl:when> + <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='edit']"> + GRANT SELECT,INSERT,UPDATE,DELETE ON "<xsl:value-of select="$linktablename"/>" TO "<xsl:value-of select="$groupname"/>" + </xsl:when> + <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='none']"> + REVOKE ALL ON "<xsl:value-of select="$linktablename"/>" FROM "<xsl:value-of select="$groupname"/>" + </xsl:when> + <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='none']"> + REVOKE ALL ON "<xsl:value-of select="$linktablename"/>" FROM "<xsl:value-of select="$groupname"/>" + </xsl:when> + <xsl:otherwise> + GRANT SELECT ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> + </xsl:otherwise> + </xsl:choose> + GO + </xsl:for-each> + + ---- referential integrity -------------------------------------------------------------------- + + <xsl:variable name="neartable"> + <xsl:call-template name="tablename"> + <xsl:with-param name="entityname" select="$nearside"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="fartable"> + <xsl:call-template name="tablename"> + <xsl:with-param name="entityname" select="$farentityname"/> + </xsl:call-template> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$nearside=@entity"> + <xsl:call-template name="foreignkey"> + <xsl:with-param name="nearside" select="$linktablename"/> + <xsl:with-param name="farside" select="$neartable"/> + <xsl:with-param name="linkfield" select="concat( $nearside, $linksuffix)"/> + <xsl:with-param name="ondelete" select="'NO ACTION'"/> + </xsl:call-template> + <xsl:call-template name="foreignkey"> + <xsl:with-param name="nearside" select="$linktablename"/> + <xsl:with-param name="farside" select="$fartable"/> + <xsl:with-param name="linkfield" select="concat( $farside, $linksuffix)"/> + <xsl:with-param name="ondelete" select="'CASCADE'"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="foreignkey"> + <xsl:with-param name="nearside" select="$linktablename"/> + <xsl:with-param name="farside" select="$neartable"/> + <xsl:with-param name="linkfield" select="concat( $nearside, $linksuffix)"/> + <xsl:with-param name="ondelete" select="'CASCADE'"/> + </xsl:call-template> + <xsl:call-template name="foreignkey"> + <xsl:with-param name="nearside" select="$linktablename"/> + <xsl:with-param name="farside" select="$fartable"/> + <xsl:with-param name="linkfield" select="concat( @entity, $linksuffix)"/> + <xsl:with-param name="ondelete" select="'CASCADE'"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + -- Suppressing generation of <xsl:value-of select="$linktablename"/>, as it is not my responsibility + </xsl:otherwise> + </xsl:choose> + <xsl:if test="myresponsibility='true'"> + </xsl:if> + </xsl:template> + + <xsl:template match="adl:property[@type='list']"> + -- Suppressing output of property <xsl:value-of select="@name"/>, + -- as it is the 'one' end of a one-to-many relationship + </xsl:template> + + <xsl:template match="adl:generator[@action='native']"> + IDENTITY( 1, 1) + </xsl:template> + <xsl:template match="adl:generator"/> + + <!-- the grand unified property handler, using the sql-type template to + generate the correct types for each field --> + <xsl:template match="adl:property"> + <xsl:variable name="column"> + <xsl:call-template name="property-column-name"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="type"> + <xsl:call-template name="sql-type"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="generator"> + <xsl:apply-templates select="adl:generator"/> + </xsl:variable> + "<xsl:value-of select="$column"/>" <xsl:value-of + select="concat( normalize-space( $type), ' ', normalize-space( $generator))"/><xsl:if + test="@required='true'"> NOT NULL</xsl:if><xsl:if + test="string(@default)"> DEFAULT <xsl:choose> + <xsl:when test="$base-type = 'integer' or $base-type = 'real' or $base-type = 'money'"> + <xsl:value-of select="@default"/> + </xsl:when> + <xsl:when test="$base-type = 'boolean'"> + <xsl:choose> + <xsl:when test="@default='true'">1</xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise>'<xsl:value-of select="@default"/>'</xsl:otherwise> + </xsl:choose> + </xsl:if> + + </xsl:template> + + <!-- properties of type 'entity' are supposed to be being handled by the + grand unified property handler. Unfortunately it gets them wrong and I'm not + sure why. So temporarily this special case template fixes the problem. TODO: + work out what's wrong with the grand unified version --> + <xsl:template match="adl:property[@type='entity']"> + <xsl:variable name="column"> + <xsl:call-template name="property-column-name"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="type"> + <xsl:call-template name="sql-type"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="entity" select="@entity"/> + <xsl:variable name="defaulttype"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" + select="ancestor::adl:application/adl:entity[@name = $entity]/adl:key/adl:property[position() = 1]"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="default"> + <xsl:choose> + <xsl:when test="$defaulttype = 'string'"> + '<xsl:value-of select="@default"/>' + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@default"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + "<xsl:value-of select="$column"/>" <xsl:value-of select="$type"/><xsl:if + test="string(@default)"> DEFAULT <xsl:value-of select="normalize-space($default)"/></xsl:if><xsl:if + test="@required='true'"> NOT NULL</xsl:if> + </xsl:template> + + + <!-- consistent, repeatable way of getting the column name for a given property --> + <xsl:template name="property-column-name"> + <!-- a property element --> + <xsl:param name="property"/> + <xsl:variable name="unescaped"> + <xsl:choose> + <xsl:when test="$property/@column"> + <xsl:value-of select="$property/@column"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$property/@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="contains( $sqlkeywords, concat(' ', translate( $unescaped, $lcase, $ucase),' '))"> + <!-- + names which are keywords need to be escaped /either/ with square + brackets /or/ with quotes, but currently we're using quotes for all names + so don't need square brackets. + xsl:value-of select="concat( '[', $unescaped, ']')"/ --> + <xsl:value-of select="$unescaped"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$unescaped"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="primary-key-name"> + <xsl:param name="entityname"/> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$entityname]/@natural-key"> + <xsl:value-of select="//adl:entity[@name=$entityname]/@natural-key"/> + </xsl:when> + <xsl:when test="//adl:entity[@name=$entityname]/key"> + <xsl:choose> + <xsl:when test="count(//adl:entity[@name=$entityname]/adl:key/adl:property) > 1"> + <xsl:message terminate="no"> + ADL: WARNING: entity '<xsl:value-of select="$entityname"/>' has a compound primary key; + adl2mssql is not yet clever enough to generate appropriate code + </xsl:message> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="$abstract-key-name-convention='Name'"> + <xsl:value-of select="@name"/> + </xsl:when> + <xsl:when test="$abstract-key-name-convention = 'NameId'"> + <xsl:value-of select="concat( $entityname, 'Id')"/> + </xsl:when> + <xsl:when test="$abstract-key-name-convention = 'Name_Id'"> + <xsl:value-of select="concat( $entityname, '_Id')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="'Id'"/> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- return the SQL type of the property which is passed as a parameter --> + <xsl:template name="sql-type"> + <xsl:param name="property"/> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="base-size"> + <xsl:call-template name="base-size"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$base-type = 'entity'"> + <xsl:variable name="entity" select="$property/@entity"/> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$entity]"> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$entity]/adl:key/adl:property"> + <xsl:call-template name="sql-type"> + <xsl:with-param name="property" + select="//adl:entity[@name=$entity]/adl:key/adl:property[position()=1]"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + ADL: ERROR: property '<xsl:value-of select="$property/@name"/>' refers to + entity '<xsl:value-of select="$property/@entity"/>', but this entity has no key. + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + ADL: ERROR: property '<xsl:value-of select="$property/@name"/>' refers to + entity '<xsl:value-of select="$property/@entity"/>', but no such entity exists. + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="$base-type = 'date'">DATETIME</xsl:when> + <xsl:when test="$base-type = 'time'">DATETIME</xsl:when> + <!-- TODO: if the type was 'defined' then the size should probably come from the typedef --> + <xsl:when test="$base-type = 'string'">VARCHAR( <xsl:value-of select="$base-size"/>)</xsl:when> + <xsl:when test="$base-type = 'image'">VARCHAR( <xsl:value-of select="$base-size"/>)</xsl:when> + <xsl:when test="$base-type = 'text'">TEXT</xsl:when> + <xsl:when test="$base-type = 'boolean'">BIT</xsl:when> + <xsl:when test="$base-type = 'timestamp'">DATETIME</xsl:when> + <xsl:when test="$base-type = 'integer'">INT</xsl:when> + <xsl:when test="$base-type = 'real'">DOUBLE PRECISION</xsl:when> + <xsl:when test="$base-type = 'money'">DECIMAL( 16, 2)</xsl:when> + <xsl:otherwise>[sql:unknown? [<xsl:value-of select="$base-type"/>]]</xsl:otherwise> + </xsl:choose> + + </xsl:template> + + + <!-- horrible, horrible hackery. Compare two strings and return + * 0 if they are identical, + * -1 if the first is earlier in the default collating sequence, + * 1 if the first is later. + In XSL 2.0 this could be done using the compare(string, string) function. --> + <xsl:template name="stringcompare"> + <xsl:param name="node1"/> + <xsl:param name="node2"/> + <xsl:choose> + <xsl:when test="string($node1)=string($node2)"> + <xsl:text>0</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:for-each select="$node1 | $node2"> + <xsl:sort select="."/> + <xsl:if test="position()=1"> + <xsl:choose> + <xsl:when test="string(.) = string($node1)"> + <xsl:text>-1</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>1</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> diff --git a/transforms/adl2psql.xslt b/transforms/adl2psql.xslt index 7044b31..7850ad9 100755 --- a/transforms/adl2psql.xslt +++ b/transforms/adl2psql.xslt @@ -1,5 +1,8 @@ <?xml version="1.0"?> -<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:stylesheet version="1.0" + xmlns="http://bowyer.journeyman.cc/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> <!-- --> <!-- adl2psql.xsl --> @@ -18,7 +21,7 @@ <!-- JACQUARD 2 APPLICATION DESCRIPTION LANGUAGE FRAMEWORK - $Revision: 1.2 $ + $Revision: 1.3 $ NOTES: @@ -35,41 +38,137 @@ two removes (i.e. the 'distinguish' mechanism in ADL --> - <xsl:output indent="no" encoding="UTF-8" method="text"/> - - <xsl:template match="application"> + <xsl:include href="base-type-include.xslt"/> + + <!-- + The convention to use for naming auto-generated abstract primary keys. Known values are + Id - the autogenerated primary key, if any, is called just 'Id' + Name - the autogenerated primary key has the same name as the entity + NameId - the name of the auto generated primary key is the name of the entity followed by 'Id' + Name_Id - the name of the auto generated primary key is the name of the entity followed by '_Id' + --> + <xsl:param name="abstract-key-name-convention" select="Id"/> + + <!-- the convention to use for fieldnames in link tables: + Name - the name of the foreign key is the same as the name of the table linked to + NameId - the name of the foreign key is the same as the name of the table linked to, followed by 'Id' + Name_Id - the name of the foreign key is the same as the name of the table linked to, followed by '_Id' + Name_Link - the name of the foreign key is the same as the name of the table linked to, followed by '_Link' + --> + <xsl:param name="linktable-field-name-convention" select="Name"/> + + <xsl:param name="database"/> + <!-- the name and version of the product being built --> + <xsl:param name="product-version" select="'Application Description Language Framework'"/> + + <!-- define upper and lower case letters to enable case conversion --> + <xsl:variable name="ucase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable> + <xsl:variable name="lcase">abcdefghijklmnopqrstuvwxyz</xsl:variable> + <!-- define SQL keywords to police these out of field names --> + <xsl:variable name="sqlkeywords-multiline"> + ADD EXCEPT PERCENT + ALL EXEC PLAN + ALTER EXECUTE PRECISION + AND EXISTS PRIMARY + ANY EXIT PRINT + AS FETCH PROC + ASC FILE PROCEDURE + AUTHORIZATION FILLFACTOR PUBLIC + BACKUP FOR RAISERROR + BEGIN FOREIGN READ + BETWEEN FREETEXT READTEXT + BREAK FREETEXTTABLE RECONFIGURE + BROWSE FROM REFERENCES + BULK FULL REPLICATION + BY FUNCTION RESTORE + CASCADE GOTO RESTRICT + CASE GRANT RETURN + CHECK GROUP REVOKE + CHECKPOINT HAVING RIGHT + CLOSE HOLDLOCK ROLLBACK + CLUSTERED IDENTITY ROWCOUNT + COALESCE IDENTITY_INSERT ROWGUIDCOL + COLLATE IDENTITYCOL RULE + COLUMN IF SAVE + COMMIT IN SCHEMA + COMPUTE INDEX SELECT + CONSTRAINT INNER SESSION_USER + CONTAINS INSERT SET + CONTAINSTABLE INTERSECT SETUSER + CONTINUE INTO SHUTDOWN + CONVERT IS SOME + CREATE JOIN STATISTICS + CROSS KEY SYSTEM_USER + CURRENT KILL TABLE + CURRENT_DATE LEFT TEXTSIZE + CURRENT_TIME LIKE THEN + CURRENT_TIMESTAMP LINENO TO + CURRENT_USER LOAD TOP + CURSOR NATIONAL TRAN + DATABASE NOCHECK TRANSACTION + DBCC NONCLUSTERED TRIGGER + DEALLOCATE NOT TRUNCATE + DECLARE NULL TSEQUAL + DEFAULT NULLIF UNION + DELETE OF UNIQUE + DENY OFF UPDATE + DESC OFFSETS UPDATETEXT + DISK ON USE + DISTINCT OPEN USER + DISTRIBUTED OPENDATASOURCE VALUES + DOUBLE OPENQUERY VARYING + DROP OPENROWSET VIEW + DUMMY OPENXML WAITFOR + DUMP OPTION WHEN + ELSE OR WHERE + END ORDER WHILE + ERRLVL OUTER WITH + ESCAPE OVER WRITETEXT + </xsl:variable> + <xsl:variable name="sqlkeywords" select="concat(' ', normalize-space($sqlkeywords-multiline), ' ')"/> + + + <xsl:template match="adl:application"> ------------------------------------------------------------------------------------------------- -- - -- Database for application <xsl:value-of select="@name"/> version <xsl:value-of select="@version"/> - -- Generated for PostgreSQL [7|8] using adl2psql.xsl $Revision: 1.2 $ + -- <xsl:value-of select="$product-version"/> -- + -- Database for application <xsl:value-of select="@name"/> version <xsl:value-of select="@version"/> + -- Generated for PostgreSQL [7|8] using adl2psql.xsl $Revision: 1.3 $ + -- + -- <xsl:value-of select="@revision"/> + -- -- Code generator (c) 2006 Simon Brooke [simon@weft.co.uk] -- http://www.weft.co.uk/library/jacquard/ -- ------------------------------------------------------------------------------------------------- + <xsl:if test="string-length( $database) > 0"> + use "<xsl:value-of select="$database"/>"; + </xsl:if> + ------------------------------------------------------------------------------------------------- -- authentication roles ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="group"/> + <xsl:apply-templates select="adl:group"/> ------------------------------------------------------------------------------------------------- -- tables, views and permissions ------------------------------------------------------------------------------------------------- - <xsl:apply-templates select="entity"/> + <xsl:apply-templates select="adl:entity"/> ------------------------------------------------------------------------------------------------- -- referential integrity constraints ------------------------------------------------------------------------------------------------- - <xsl:for-each select="entity"> + <xsl:for-each select="adl:entity"> <xsl:variable name="nearside" select="@name"/> - <xsl:for-each select="property[@type='entity']"> + <xsl:for-each select="adl:property[@type='entity']"> <xsl:call-template name="referentialintegrity"> <xsl:with-param name="nearside" select="$nearside"/> </xsl:call-template> </xsl:for-each> - <xsl:for-each select="property[@type='link']"> + <xsl:for-each select="adl:property[@type='link']"> <xsl:call-template name="linkintegrity"> <xsl:with-param name="nearside" select="$nearside"/> </xsl:call-template> @@ -81,7 +180,15 @@ ------------------------------------------------------------------------------------------------- </xsl:template> - <xsl:template match="group"> + <xsl:template match="adl:documentation"> + /* <xsl:apply-templates/> */ + </xsl:template> + + <xsl:template match="adl:group"> + ------------------------------------------------------------------------------------------------- + -- security group <xsl:value-of select="@name"/> + ------------------------------------------------------------------------------------------------- + <xsl:apply-templates select="adl:documentation"/> CREATE GROUP <xsl:value-of select="@name"/>; </xsl:template> @@ -108,7 +215,7 @@ </xsl:template> - <xsl:template match="entity"> + <xsl:template match="adl:entity"> <xsl:variable name="table" select="@name"/> ------------------------------------------------------------------------------------------------- @@ -116,12 +223,17 @@ ------------------------------------------------------------------------------------------------- CREATE TABLE <xsl:value-of select="@name"/> ( - <xsl:apply-templates select="property[@type!='link']"/> - <xsl:value-of select="@name"/>_id SERIAL NOT NULL PRIMARY KEY + <xsl:for-each select="descendant::adl:property[@type!='link']"> + <xsl:apply-templates select="."/><xsl:choose> + <xsl:when test="position() = last()"/> + <xsl:otherwise>,<xsl:text> + </xsl:text></xsl:otherwise> + </xsl:choose> + </xsl:for-each> ); ---- permissions ------------------------------------------------------------------------------ - <xsl:for-each select="permission"> + <xsl:for-each select="adl:permission"> <xsl:call-template name="permission"> <xsl:with-param name="table" select="$table"/> </xsl:call-template> @@ -130,7 +242,7 @@ -- convenience view lv<xsl:value-of select="concat( '_', @name)"/> for lists ------------------------------------------------------------------------------------------------- CREATE VIEW lv<xsl:value-of select="concat( '_', @name)"/> AS - SELECT <xsl:for-each select="property[@type!='link']"> + SELECT <xsl:for-each select="adl:property[@type!='link']"> <xsl:choose> <xsl:when test="@type='entity'"> <xsl:call-template name="distinctfield"> @@ -147,10 +259,10 @@ </xsl:choose> </xsl:for-each> FROM <xsl:value-of select="@name"/> - <xsl:for-each select="property[@type='entity']">, <xsl:value-of select="@entity"/> AS <xsl:value-of select="@name"/></xsl:for-each> + <xsl:for-each select="adl:property[@type='entity']">, <xsl:value-of select="@entity"/> AS <xsl:value-of select="@name"/></xsl:for-each> <xsl:text> </xsl:text> - <xsl:for-each select="property[@type='entity']"> + <xsl:for-each select="adl:property[@type='entity']"> <xsl:choose> <xsl:when test="position() = 1">WHERE </xsl:when> <xsl:otherwise>AND </xsl:otherwise> @@ -159,14 +271,14 @@ </xsl:for-each>; ---- permissions ------------------------------------------------------------------------------ - <xsl:for-each select="permission"> + <xsl:for-each select="adl:permission"> <xsl:call-template name="viewpermission"> <xsl:with-param name="table" select="$table"/> </xsl:call-template> </xsl:for-each> <!-- link tables --> - <xsl:for-each select="property[@type='link']"> + <xsl:for-each select="adl:property[@type='link']"> <xsl:call-template name="linktable"> <xsl:with-param name="nearside" select="$table"/> </xsl:call-template> @@ -273,14 +385,13 @@ </xsl:template> - <xsl:template match="property[@type='entity']"> + <xsl:template match="adl:property[@type='entity']"> <xsl:value-of select="@name"/> INT<xsl:if test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if>,<xsl:text> - </xsl:text> + test="@required='true'"> NOT NULL</xsl:if> </xsl:template> - <xsl:template match="property[@type='defined']"> + <xsl:template match="adl:property[@type='defined']"> <xsl:variable name="name"><xsl:value-of select="@definition"/></xsl:variable> <xsl:variable name="definitiontype"><xsl:value-of select="/application/definition[@name=$name]/@type"/></xsl:variable> <xsl:value-of select="@name"/><xsl:text> </xsl:text><xsl:choose> @@ -290,37 +401,40 @@ <xsl:when test="$definitiontype='real'">DOUBLE PRECISION</xsl:when> <xsl:otherwise><xsl:value-of select="$definitiontype"/></xsl:otherwise> </xsl:choose><xsl:if - test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if>,<xsl:text> - </xsl:text> + test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose> + <xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when> + <xsl:when test="@required='true'"> NOT NULL</xsl:when> + </xsl:choose> </xsl:template> - <xsl:template match="property[@type='string']"> + <xsl:template match="adl:property[@type='string']"> <xsl:value-of select="@name"/> VARCHAR( <xsl:value-of select="@size"/>)<xsl:if - test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if>,<xsl:text> - </xsl:text> + test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose> + <xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when> + <xsl:when test="@required='true'"> NOT NULL</xsl:when> + </xsl:choose> </xsl:template> - <xsl:template match="property[@type='integer']"> + <xsl:template match="adl:property[@type='integer']"> <xsl:value-of select="@name"/> INT<xsl:if - test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if>,<xsl:text> - </xsl:text> + test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose> + <xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when> + <xsl:when test="@required='true'"> NOT NULL</xsl:when> + </xsl:choose> </xsl:template> - <xsl:template match="property[@type='real']"> + <xsl:template match="adl:property[@type='real']"> <xsl:value-of select="@name"/> DOUBLE PRECISION<xsl:if test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if>,<xsl:text> - </xsl:text> + test="@required='true'"> NOT NULL</xsl:if> </xsl:template> - <xsl:template match="property"> + <xsl:template match="adl:property"> <xsl:value-of select="@name"/> <xsl:text> </xsl:text><xsl:value-of select="@type"/><xsl:if - test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if - test="@required='true'"> NOT NULL</xsl:if>,<xsl:text> - </xsl:text> + test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose> + <xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when> + <xsl:when test="@required='true'"> NOT NULL</xsl:when> + </xsl:choose> </xsl:template> </xsl:stylesheet> diff --git a/transforms/adl2views.xslt b/transforms/adl2views.xslt index ae0d729..53ace20 100755 --- a/transforms/adl2views.xslt +++ b/transforms/adl2views.xslt @@ -1,2059 +1,2068 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns:msxsl="urn:schemas-microsoft-com:xslt" - xmlns:exsl="urn:schemas-microsoft-com:xslt" - extension-element-prefixes="exsl"> - <!-- - Application Description Language framework - adl2views.xsl - - (c) 2007 Cygnet Solutions Ltd - - Transform ADL into velocity view templates - - $Author: sb $ - $Revision: 1.65 $ - $Date: 2010-01-12 17:20:17 $ - --> - <!-- WARNING WARNING WARNING: Do NOT reformat this file! - Whitespace (or lack of it) is significant! --> - - <xsl:include href="base-type-include.xslt"/> - <xsl:include href="permissions-include.xslt"/> - <!-- bug 1896 : boilerplate text in views should be tailored to the locale of - the expected user. Unfortunately I haven't yet worked out how to do - conditional includes in XSLT, so this is a step on the way to a solution, - not a solution in itself. --> - <xsl:include href="i18n-en-GB-include.xslt"/> - - <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/> - - <!-- The locale for which these views are generated - TODO: we need to generate views for each available locale, but this is not - yet implemented. When it is we will almost certainly still need a 'default locale' --> - <xsl:param name="locale" select="en-GB"/> - - <!-- whether or not to auto-generate site navigation - by default, don't --> - <xsl:param name="generate-site-navigation" select="'false'"/> - - <!-- whether or not to layout errors - they may be in the default layout --> - <xsl:param name="show-errors" select="'false'"/> - <!-- whether or not to layout messages - they may be in the default layout --> - <xsl:param name="show-messages" select="'false'"/> - - <!-- the maximum width, in characters, we're prepared to allocate to widgets --> - <xsl:param name="max-widget-width" select="40"/> - - <!-- the name and version of the product being built --> - <xsl:param name="product-version" select="'Application Description Language Framework'"/> - - <!-- bug 1800 : the name of the Velocity layout to use. If you are to - be able to usefully define content in ADL, then the default ADL layout - needs to be empty, but if ADL-generated pages are to 'play nice' in - largely non-ADL applications, they must be able to use standard layouts. - If you are going to use a non-default layout, however, you're responsible - for making sure it loads all the scripts, etc, that an ADL controller - expects. --> - <xsl:param name="layout-name"/> - <!-- bug 1800 : the name of the area (i.e. URL path part) to use --> - <xsl:param name="area-name" select="auto"/> - <!-- the base url of the whole site --> - <xsl:param name="site-root" select="'..'"/> - <!-- Whether to authenticate at application or at database layer. - If not 'Application', then 'Database'. --> - <xsl:param name="authentication-layer" select="'Application'"/> - - <!-- bug 2847: how long to wait on a page before it auto-redirects to the default URL --> - <xsl:param name="page-timeout" select="300"/> - <!-- bug 2847: the default URL, probably a 'please login' screen --> - <xsl:param name="default-url" select="'../default.aspx'"/> - - <xsl:template match="adl:application"> - <output> - <!-- 'output' is a dummy wrapper root tag to make the entire output work as - an XML document; the actual output later gets cut into chunks and the - wrapper tag is discarded. --> - <xsl:apply-templates select="adl:entity"/> - <!-- make sure extraneous junk doesn't get into the last file generated, - by putting it into a separate file --> - <xsl:text> - </xsl:text> - <xsl:comment> [ cut here: next file 'tail.txt' ] </xsl:comment> - </output> - </xsl:template> - - <xsl:template match="adl:entity[@foreign='true']"/> - <!-- Don't bother generating anything for foreign entities --> - - <xsl:template match="adl:entity"> - <xsl:comment>Layout is <xsl:value-of select="$layout-name"/></xsl:comment> - <xsl:choose> - <xsl:when test="$layout-name"> - <xsl:apply-templates select="." mode="non-empty-layout"/> - </xsl:when> - <xsl:otherwise> - <xsl:apply-templates select="." mode="empty-layout"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- generate views for an entity, assuming a non-empty layout - i.e. - I'm not responsible for the html, the head, or for the body tag --> - <xsl:template match="adl:entity" mode="non-empty-layout"> - <xsl:variable name="keyfield"> - <xsl:choose> - <xsl:when test="adl:key/adl:property"> - <xsl:value-of select="adl:key/adl:property[position()=1]/@name"/> - </xsl:when> - <xsl:otherwise>[none]</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:apply-templates select="adl:form" mode="non-empty-layout"/> - <xsl:apply-templates select="adl:list" mode="non-empty-layout"/> - <xsl:text> - </xsl:text> - <xsl:comment> [ cut here: next file '<xsl:value-of select="concat( @name, '/maybedelete.auto.vm')"/>' ] </xsl:comment> - <xsl:text> - </xsl:text> - <xsl:variable name="really-delete"> - <xsl:call-template name="i18n-really-delete"/> - </xsl:variable> - #set( $title = "<xsl:value-of select="concat( $really-delete, ' ', @name)"/> $instance.UserIdentifier") - #capturefor( headextras) - <xsl:comment> - Auto generated Velocity maybe-delete form for <xsl:value-of select="@name"/>, - </xsl:comment> - <xsl:call-template name="head"/> - #end - <xsl:call-template name="maybe-delete"> - <xsl:with-param name="entity" select="."/> - </xsl:call-template> - </xsl:template> - - <!-- generate views for an entity, assuming an empty layout - (i.e. I'm responsible for html, head and body tags) --> - <xsl:template match="adl:entity" mode="empty-layout"> - <xsl:variable name="keyfield"> - <xsl:choose> - <xsl:when test="adl:key/adl:property"> - <xsl:value-of select="adl:key/adl:property[position()=1]/@name"/> - </xsl:when> - <xsl:otherwise>[none]</xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:apply-templates select="adl:form" mode="empty-layout"/> - <xsl:apply-templates select="adl:list" mode="empty-layout"/> - <xsl:text> - </xsl:text> - <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( @name, '/maybedelete.auto.vm')"/>' ]</xsl:comment> - <xsl:text> - </xsl:text> - <html> - <xsl:variable name="really-delete"> - <xsl:call-template name="i18n-really-delete"/> - </xsl:variable> - #set( $title = "<xsl:value-of select="concat( $really-delete, ' ', @name)"/> $instance.UserIdentifier") - <head> - <xsl:comment> - Auto generated Velocity maybe-delete form for <xsl:value-of select="@name"/>, - </xsl:comment> - <xsl:call-template name="head"/> - <xsl:call-template name="install-scripts"/> - </head> - <body> - <div id="page"> - <xsl:call-template name="top"/> - <xsl:call-template name="maybe-delete"> - <xsl:with-param name="entity" select="."/> - </xsl:call-template> - <xsl:call-template name="foot"/> - </div> - </body> - </html> - </xsl:template> - - <!-- the guts of the maybe-delete form, whether or not we're using an empty layout --> - <xsl:template name="maybe-delete"> - <xsl:param name="entity"/> - <div class="content"> - <xsl:if test="$show-errors = 'true'"> - #if ( $instance.NoDeleteReason) - <ul class="errors"> - <li>$instance.NoDeleteReason</li> - </ul> - #end - #if ( $errors) - #if ( $errors.Count != 0) - <ul class="errors"> - #foreach($e in $errors) - #if($e.Message) - <li>$t.Error($e)</li> - #else - <li>$t.Enc($e)</li> - #end - #end - </ul> - #end - #end - </xsl:if> - <xsl:if test="$show-messages = 'true'"> - #if( $messages) - #if ( $messages.Count != 0) - <ul class="information"> - #foreach ( $message in $messages) - <li>$message</li> - #end - </ul> - #end - #end - </xsl:if> - <form action="delete.rails" method="post"> - <xsl:for-each select="$entity/adl:key/adl:property"> - <xsl:choose> - <xsl:when test="@type='entity'"> - <xsl:variable name="entityname" select="@entity"/> - <xsl:variable name="entitykeyname" select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]/@name"/> - <input type="hidden"> - <xsl:attribute name="name"> - <xsl:value-of select="concat( 'instance.', @name)"/> - </xsl:attribute> - <xsl:attribute name="value"> - <xsl:value-of select="concat('$instance.', @name, '.', $entitykeyname)"/> - </xsl:attribute> - </input> - </xsl:when> - <xsl:otherwise> - <input type="hidden"> - <xsl:attribute name="name"> - <xsl:value-of select="concat( 'instance.', @name)"/> - </xsl:attribute> - <xsl:attribute name="value"> - <xsl:value-of select="concat('$instance.', @name)"/> - </xsl:attribute> - </input> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - <table> - <tr align="left" valign="top" class="actionDangerous"> - <td class="actionDangerous"> - <xsl:call-template name="i18n-really-delete"/> - </td> - <td class="widget"> - <select name="reallydelete"> - <option value="false"> - <xsl:call-template name="i18n-really-delete-no"/> - </option> - <option value="true"> - <xsl:call-template name="i18n-really-delete-yes"/> - </option> - </select> - </td> - <td class="actionDangerous" style="text-align:right"> - <input type="submit" name="command" value="Go" /> - </td> - </tr> - </table> - </form> - </div> - </xsl:template> - - <!-- layout of forms --> - <xsl:template match="adl:form" mode="non-empty-layout"> - <xsl:variable name="form" select="."/> - <xsl:text> - </xsl:text> - <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( ancestor::adl:entity/@name, '/', @name)"/>.auto.vm' ]</xsl:comment> - <xsl:text> - </xsl:text> - #capturefor( title) - #if ( $instance) - #if ( ! $instance.IsNew) - <xsl:value-of select="concat( 'Edit ', ' ', ancestor::adl:entity/@name)"/> $instance.UserIdentifier - #else - <xsl:call-template name="i18n-add-a-new"> - <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> - </xsl:call-template> - #end - #else - <xsl:call-template name="i18n-add-a-new"> - <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> - </xsl:call-template> - #end - #end - #capturefor( headextras) - <xsl:comment> - Auto generated Velocity form for <xsl:value-of select="ancestor::adl:entity/@name"/>, - </xsl:comment> - <xsl:call-template name="head"/> - <xsl:call-template name="generate-head-javascript"> - <xsl:with-param name="form" select="."/> - <xsl:with-param name="locale" select="$locale"/> - </xsl:call-template> - - ${StylesHelper.InstallStylesheet( "Epoch")} - - <style type="text/css"> - <xsl:for-each select="ancestor::adl:entity//adl:property[@required='true']"> - #<xsl:value-of select="concat( 'advice-required-instance_', @name)"/> - { - color: white; - background-color: rgb( 198, 0, 57); - font-style: italic; - } - </xsl:for-each> - </style> - #end - #capturefor(bodyattributes) - onload="performInitialisation()" - #end - <xsl:call-template name="top"/> - <xsl:call-template name="form-content"> - <xsl:with-param name="form" select="."/> - </xsl:call-template> - <xsl:call-template name="foot"/> - </xsl:template> - - <xsl:template match="adl:form" mode="empty-layout"> - <xsl:variable name="form" select="."/> - <xsl:text> - </xsl:text> - <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( ancestor::adl:entity/@name, '/', @name)"/>.auto.vm' ]</xsl:comment> - <xsl:text> - </xsl:text> - <html> - <xsl:comment> - #if ( $instance) - #if ( ! $instance.IsNew) - #set( $title = "<xsl:value-of select="concat( 'Edit ', ' ', ancestor::adl:entity/@name)"/> $instance.UserIdentifier") - #else - #set( $title = "<xsl:call-template name="i18n-add-a-new"> - <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> - </xsl:call-template>") - #end - #else - #set( $title = "<xsl:call-template name="i18n-add-a-new"> - <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> - </xsl:call-template>") - #end - </xsl:comment> - <head> - <xsl:comment> - Auto generated Velocity form for <xsl:value-of select="ancestor::adl:entity/@name"/>, - </xsl:comment> - <xsl:call-template name="head"/> - <xsl:if test="$page-timeout > 0"> - <meta http-equiv="refresh" content="5; URL=http://www.cryer.co.uk"> - <xsl:attribute name="content"> - <xsl:value-of select="concat($page-timeout, '; URL=', $default-url)"/> - </xsl:attribute> - </meta> - </xsl:if> - <xsl:call-template name="install-scripts"/> - <xsl:call-template name="generate-head-javascript"> - <xsl:with-param name="form" select="."/> - <xsl:with-param name="locale" select="$locale"/> - </xsl:call-template> - - ${StylesHelper.InstallStylesheet( "Epoch")} - - <style type="text/css"> - <xsl:for-each select="ancestor::adl:entity//adl:property[@required='true']"> - #<xsl:value-of select="concat( 'advice-required-instance_', @name)"/> - { - color: white; - background-color: rgb( 198, 0, 57); - font-style: italic; - } - </xsl:for-each> - </style> - </head> - <body onload="performInitialisation()"> - <div id="page"> - <xsl:call-template name="top"/> - <xsl:call-template name="form-content"> - <xsl:with-param name="form" select="."/> - </xsl:call-template> - <xsl:call-template name="foot"/> - </div> - </body> - </html> - </xsl:template> - - <!-- the content of a form, whether or not the layout is empty --> - <xsl:template name="form-content"> - <!-- an entity of type form --> - <xsl:param name="form"/> - <div class="content"> - #if ( $instance.NoDeleteReason) - <ul class="errors"> - <li>$instance.NoDeleteReason</li> - </ul> - #end - <xsl:if test="$show-errors = 'true'"> - #if ( $errors) - #if ( $errors.Count != 0) - <ul class="errors"> - #foreach($e in $errors) - #if($e.Message) - <li>$t.Error($e)</li> - #else - <li>$t.Enc($e)</li> - #end - #end - </ul> - #end - #end - </xsl:if> - <xsl:if test="$show-messages = 'true'"> - #if( $messages) - #if ( $messages.Count != 0) - <ul class="information"> - #foreach ( $message in $messages) - <li>$message</li> - #end - </ul> - #end - #end - </xsl:if> - <form method="post" onsubmit="invokeSubmitHandlers(this);return trapEnterSubmissions(event, this);" onkeypress="trapKeyPress(event, this)" class="tabbed"> - <xsl:attribute name="action"> - <xsl:value-of select="concat( $form/@name, 'SubmitHandler.rails')"/> - </xsl:attribute> - <xsl:attribute name="name"> - <xsl:value-of select="$form/@name"/> - </xsl:attribute> - <xsl:attribute name="id"> - <xsl:value-of select="$form/@name"/> - </xsl:attribute> - <xsl:attribute name="enctype"> - <xsl:choose> - <xsl:when test="$form/ancestor::adl:entity//adl:property[@type='uploadable']"> - <xsl:value-of select="'multipart/form-data'"/> - </xsl:when> - <xsl:when test="$form/ancestor::adl:entity//adl:property[@type='image']"> - <xsl:value-of select="'multipart/form-data'"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="'application/x-www-form-urlencoded'"/> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <input type="hidden" name="currentpane" value="$!currentpane" /> - <xsl:for-each select="$form/ancestor::adl:entity/adl:key/adl:property"> - <xsl:variable name="keyname" select="@name"/> - <xsl:choose> - <xsl:when test="$form//adl:field[@property=$keyname]"> - <!-- it's already a field of the form - no need to add a hidden one --> - </xsl:when> - <xsl:otherwise> - <!-- create a hidden widget for the natural primary key --> - #if ( $instance) - #if ( ! ( $instance.IsNew)) - ${FormHelper.HiddenField( "instance.<xsl:value-of select="$keyname"/>")} - #end - #end - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - <xsl:apply-templates select="$form/adl:fieldgroup"/> - <div class="non-pane"> - <table> - <xsl:choose> - <xsl:when test="@properties='listed'"> - <xsl:apply-templates select="$form/adl:field|adl:auxlist"/> - </xsl:when> - <xsl:otherwise> - <xsl:apply-templates select="$form/ancestor::adl:entity/adl:property"/> - </xsl:otherwise> - </xsl:choose> - </table> - <ul class="verbs"> - <xsl:apply-templates select="adl:verb"/> - <xsl:choose> - <xsl:when test="$authentication-layer='Database'"> - <xsl:variable name="savegroups"> - <xsl:call-template name="entity-save-groups"> - <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="updategroups"> - <xsl:call-template name="entity-update-groups"> - <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> - </xsl:call-template> - </xsl:variable> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause - cause the Velocity parser to break! --> - #if ( $instance) - #if ( $instance.IsNew) - #if ( <xsl:for-each select="exsl:node-set( $savegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:call-template name="save-widget-row"/> - #end - #else - #if ( <xsl:for-each select="exsl:node-set( $updategroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) - <xsl:call-template name="save-widget-row"/> - #end - #end - #else - <!-- for application-layer authentication, we may not actually have an instance at this stage --> - #if ( <xsl:for-each select="exsl:node-set( $savegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) - <xsl:call-template name="save-widget-row"/> - #end - #end - <xsl:variable name="deletegroups"> - <xsl:call-template name="entity-delete-groups"> - <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> - </xsl:call-template> - </xsl:variable> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause - cause the Velocity parser to break! --> - #if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) - <xsl:call-template name="delete-widget-row"/> - #end - </xsl:when> - <xsl:when test="$authentication-layer='Application'"> - <xsl:call-template name="save-widget-row"/> - <xsl:call-template name="delete-widget-row"/> - </xsl:when> - </xsl:choose> - </ul> - </div> - </form> - </div> - </xsl:template> - - <!-- output a complete table row containing a save widget --> - <xsl:template name="save-widget-row"> - <li class="standard-verb actionSafe"> - <button type="submit" name="command" value="store"> - <xsl:attribute name="title"> - <xsl:call-template name='i18n-save-prompt'/> - </xsl:attribute> - Save - </button> - </li> - </xsl:template> - - <!-- output a complete table row containing a delete widget --> - <xsl:template name="delete-widget-row"> - <li class="standard-verb actionDangerous"> - #if ( $instance) - #if ( !$instance.IsNew) - #if ( $instance.NoDeleteReason) - <button type="submit" disabled="disabled" title="$instance.NoDeleteReason" name="command" value="delete">Delete this</button> - #else - <button type="submit" name="command" value="delete"> - <xsl:attribute name="title"> - <xsl:call-template name="i18n-delete-prompt"/> - </xsl:attribute> - Delete this - </button> - #end - #end - #end - </li> - </xsl:template> - - <xsl:template match="adl:fieldgroup"> - <xsl:if test="$authentication-layer = 'Database'"> - <xsl:variable name="property" select="."/> - <xsl:variable name="readgroups"> - <xsl:call-template name="fieldgroup-read-groups"> - <xsl:with-param name="fieldgroup" select="."/> - </xsl:call-template> - </xsl:variable> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause cause the Velocity parser to break! --> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - </xsl:if> - - <div class="tab-pane"> - <xsl:attribute name="id"> - <xsl:value-of select="concat( @name, 'pane')"/> - </xsl:attribute> - <xsl:attribute name="style"> - <xsl:choose> - <xsl:when test="position() = 1"/> - <xsl:otherwise>display: none</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <h3 class="title"> - <xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@name"/> - <xsl:with-param name="entity" select="ancestor::adl:entity"/> - <xsl:with-param name="locale" select="$locale"/> - </xsl:call-template> - </h3> - <table> - <xsl:apply-templates select="adl:field|adl:auxlist"/> - </table> - <xsl:if test="adl:verb"> - <ul class="verbs"> - <xsl:apply-templates select="adl:verb"/> - </ul> - </xsl:if> - </div> - <xsl:if test="$authentication-layer = 'Database'"> - #end - </xsl:if> - </xsl:template> - - <xsl:template match="adl:auxlist"> - <xsl:variable name="listprop" select="@property"/> - <xsl:variable name="farent" select="ancestor::adl:entity//adl:property[@name=$listprop]/@entity"/> - <xsl:variable name="nearent" select="ancestor::adl:entity/@name"/> - <xsl:variable name="farid"> - <xsl:value-of select="//adl:entity[@name=$farent]/adl:key//adl:property[position()=1]/@name"/> - </xsl:variable> - <xsl:variable name="farkey"> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$farent]//adl:property[@entity=$nearent]/@farkey"> - <xsl:value-of select="//adl:entity[@name=$farent]//adl:property[@entity=$nearent]/@farkey"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="//adl:entity[@name=$farent]//adl:property[@entity=$nearent]/@name"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="nearkey"> - <xsl:choose> - <xsl:when test="ancestor::adl:entity/adl:key/adl:property[position()=1 and @type='entity']"> - <xsl:value-of select="concat( ancestor::adl:entity/adl:key/adl:property[position()=1]/@name, '_Value')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="ancestor::adl:entity/adl:key/adl:property[position()=1]/@name"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="action" select="concat( '../', $farent, '/', @onselect)"/> - <xsl:if test="@canadd='true'"> - <tr> - <td> - <xsl:attribute name="colspan"> - <xsl:value-of select="count( field)"/> - </xsl:attribute> - <a> - <xsl:attribute name="href"> - <xsl:value-of select="concat( $action, 'With', $farkey, '.rails?', $farkey, '=$instance.', $nearkey)"/> - </xsl:attribute> - <xsl:call-template name="i18n-add-a-new"> - <xsl:with-param name="entity-name" select="$farent"/> - </xsl:call-template> - </a> - </td> - </tr> - </xsl:if> - <tr> - <td> - <xsl:attribute name="colspan"> - <xsl:value-of select="count( field)"/> - </xsl:attribute> - - <xsl:choose> - <xsl:when test="@properties='listed'"> - <xsl:comment>auxlist with listed fields: <xsl:value-of select="$farent/@name"/></xsl:comment> - <xsl:call-template name="internal-with-fields-list"> - <xsl:with-param name="entity" select="//adl:entity[@name=$farent]"/> - <xsl:with-param name="fields" select="adl:field"/> - <xsl:with-param name="instance-list" select="concat( 'instance.', $listprop)"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:comment>auxlist with computed fields: <xsl:value-of select="$farent/@name"/></xsl:comment> - <xsl:call-template name="internal-with-properties-list"> - <xsl:with-param name="entity" select="//adl:entity[@name=$farent]"/> - <xsl:with-param name="properties" select="//adl:entity[@name=$farent]//adl:property[(@distinct='user' or @distinct='all') and not( @type='link' or @type='list')]"/> - <xsl:with-param name="instance-list" select="concat( 'instance.', $listprop)"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </td> - </tr> - </xsl:template> - - <xsl:template match="adl:verb"> - <xsl:variable name="executegroups"> - <xsl:call-template name="verb-execute-groups"> - <xsl:with-param name="verb" select="."/> - </xsl:call-template> - </xsl:variable> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause - cause the Velocity parser to break! --> - #if ( <xsl:for-each select="exsl:node-set( $executegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:variable name="class"> - <xsl:choose> - <xsl:when test="@dangerous='true'">actionDangerous</xsl:when> - <xsl:otherwise>actionSafe</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <!-- don't emit a verb unless there is an instance for it to act on --> - #if( $instance) - #if( ! $instance.IsNew) - <li> - <xsl:attribute name="class"> - <xsl:value-of select="concat( 'custom-verb ', $class)"/> - </xsl:attribute> - <button name="command"> - <xsl:attribute name="value"> - <xsl:value-of select="@verb"/> - </xsl:attribute> - <xsl:attribute name="title"> - <xsl:apply-templates select="adl:help[@locale = $locale]"/> - </xsl:attribute> - <xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@verb"/> - </xsl:call-template> - </button> - </li> - #end - #end - #end - </xsl:template> - - <xsl:template match="adl:field"> - <xsl:variable name="propname"> - <xsl:value-of select="@property"/> - </xsl:variable> - <xsl:choose> - <xsl:when test="ancestor::adl:entity//adl:property[@name=$propname]"> - <!-- there is a real property --> - <xsl:apply-templates select="ancestor::adl:entity//adl:property[@name=$propname]"> - <xsl:with-param name="oddness"> - <xsl:choose> - <xsl:when test="position() mod 2 = 0">even</xsl:when> - <xsl:otherwise>odd</xsl:otherwise> - </xsl:choose> - </xsl:with-param> - </xsl:apply-templates> - </xsl:when> - <xsl:otherwise> - <!-- it's presumably intended to be a computed field --> - <xsl:comment> - Computed field (<xsl:value-of select="$propname"/>)? TODO: Not yet implememented - </xsl:comment> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template match="adl:property[@type='message']"> - <!-- HIHGLY experimental - an internationalised message --> - <xsl:param name="oddness" select="odd"/> - <tr> - <xsl:attribute name="class"> - <xsl:value-of select="$oddness"/> - </xsl:attribute> - <td class="label"> - ${FormHelper.LabelFor( "instance.<xsl:value-of select="@name"/>", "<xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@name"/> - </xsl:call-template>")} - </td> - <td class="widget" colspan="2"> - #if( $instance) - #if( <xsl:value-of select="concat( '$instance.', @name)"/>) - <xsl:value-of select="concat( '$t.Msg( $instance.', @name, ')')"/> - #else - <input type="text"> - <xsl:attribute name="name"> - <xsl:value-of select="concat('i18n.instance.', @name)"/> - </xsl:attribute> - </input> - #end - #else - <input type="text"> - <xsl:attribute name="name"> - <xsl:value-of select="concat('i18n.instance.', @name)"/> - </xsl:attribute> - </input> - #end - </td> - </tr> - </xsl:template> - - <xsl:template match="adl:property[@type='link'or @type='list']"> - <!-- note! this template is only intended to match properties in the context of a form: - it may be we need to add a mode to indicate this! --> - <!-- for links and lists we implement a shuffle widget, which extends over both columns --> - <xsl:param name="oddness" select="odd"/> - <xsl:if test="$authentication-layer = 'Database'"> - <xsl:variable name="property" select="."/> - <xsl:variable name="readgroups"> - <xsl:call-template name="entity-read-groups"> - <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> - </xsl:call-template> - </xsl:variable> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause cause the Velocity parser to break! --> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) - </xsl:if> - <tr> - <xsl:attribute name="class"> - <xsl:value-of select="$oddness"/> - </xsl:attribute> - <td class="label" rowspan="2"> - ${FormHelper.LabelFor( "instance.<xsl:value-of select="@name"/>", "<xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@name"/> - </xsl:call-template>")} - </td> - <td class="widget shuffle" colspan="2"> - <xsl:call-template name="shuffle-widget"> - <xsl:with-param name="property" select="."/> - </xsl:call-template> - </td> - </tr> - <tr> - <xsl:attribute name="class"> - <xsl:choose> - <xsl:when test="position() mod 2 = 0">even</xsl:when> - <xsl:otherwise>odd</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <td class="help" colspan="2"> - <xsl:apply-templates select="adl:help[@locale = $locale]"/> - </td> - </tr> - <xsl:if test="$authentication-layer = 'Database'"> - #end - </xsl:if> - </xsl:template> - - <xsl:template name="shuffle-widget"> - <xsl:param name="property" select="."/> - #if ( $instance) - #if ( ! $instance.IsNew) - <table class="shuffle"> - <tr> - <td class="widget shuffle-all" rowspan="2"> - ${ShuffleWidgetHelper.UnselectedOptions( "<xsl:value-of select="concat( $property/@name, '_unselected')"/>", <xsl:value-of select="concat( '$all_', $property/@name)"/>, $instance.<xsl:value-of select="$property/@name"/>)} - </td> - <td class="widget shuffle-action"> - <input type="button" value="include >>"> - <xsl:attribute name="onclick"> - <xsl:value-of select="concat( 'shuffle(', $property/@name, '_unselected, ', $property/@name, ')')"/> - </xsl:attribute> - </input> - </td> - <td class="widget shuffle-selected" rowspan="2"> - <xsl:variable name="entityname" select="$property/@entity"/> - <xsl:variable name="foreignkey" select="$property/@farkey"/> - <xsl:variable name="allow-shuffle-back"> - <xsl:choose> - <xsl:when test="$property/@type='list' and //adl:entity[@name=$entityname]//adl:property[@name=$foreignkey and @required='true']"> - <xsl:value-of select="'false'"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="'true'"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - ${ShuffleWidgetHelper.SelectedOptions( "<xsl:value-of select="$property/@name"/>", $instance.<xsl:value-of select="$property/@name"/>, <xsl:value-of select="$allow-shuffle-back"/>)} - </td> - </tr> - <tr> - <td class="widget shuffle-action"> - <input type="button" value="<< exclude"> - <xsl:attribute name="onclick"> - <xsl:value-of select="concat( 'shuffle(', @name, ', ', @name, '_unselected)')"/> - </xsl:attribute> - </input> - </td> - </tr> - </table> - #else - <i>You must create your <xsl:value-of select="$property/ancestor::adl:entity/@name"/> record before you can add <xsl:value-of select="$property/@name"/> to it</i> - #end - #end - </xsl:template> - - <xsl:template match="adl:property"> - <xsl:param name="oddness" select="odd"/> - <!-- note! this template is only intended to match properties in the context of a form: - it may be we need to add a mode to indicate this! --> - <xsl:variable name="property" select="."/> - <xsl:variable name="editgroups"> - <xsl:call-template name="property-edit-groups"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="insertgroups"> - <xsl:call-template name="property-insert-groups"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="readgroups"> - <xsl:call-template name="property-read-groups"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:if test="$authentication-layer = 'Database'"> - <xsl:choose> - <xsl:when test="exsl:node-set( $readgroups)/*"> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) - </xsl:when> - <xsl:otherwise> - <xsl:comment>we haven't found any group of users who are entitled to see this field.</xsl:comment> - #if ( false) - </xsl:otherwise> - </xsl:choose> - </xsl:if> - <tr> - <xsl:attribute name="class"> - <xsl:value-of select="$oddness"/> - </xsl:attribute> - <td class="label"> - ${FormHelper.LabelFor( "instance.<xsl:value-of select="@name"/>", "<xsl:call-template name="showprompt"> - <xsl:with-param name="fallback" select="@name"/> - </xsl:call-template>")} - </td> - <td class="widget"> - <xsl:choose> - <xsl:when test="$authentication-layer = 'Application'"> - <xsl:call-template name="property-widget"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="mode" select="'Editable'"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$authentication-layer = 'Database'"> - <xsl:if test="exsl:node-set( $editgroups)/*"> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause - cause the Velocity parser to break! --> - #if ( <xsl:for-each select="exsl:node-set( $editgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:choose> - <xsl:when test="$property/@immutable='true'"> - <xsl:call-template name="property-widget"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="mode" select="'Immutable'"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="property-widget"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="mode" select="'Editable'"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - #else - </xsl:if> - <xsl:if test="exsl:node-set( $insertgroups)/*"> - #if ( <xsl:for-each select="exsl:node-set( $insertgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:call-template name="property-widget"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="mode" select="'Immutable'"/> - </xsl:call-template> - #else - </xsl:if> - <xsl:if test="exsl:node-set( $readgroups)/*"> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:call-template name="property-widget"> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="mode" select="'DisplayAndHidden'"/> - </xsl:call-template> - #else - </xsl:if> - [Not authorised] - <xsl:if test="exsl:node-set( $readgroups)/*"> - #end - </xsl:if> - <xsl:if test="exsl:node-set( $insertgroups)/*"> - #end - </xsl:if> - <xsl:if test="exsl:node-set( $editgroups)/*"> - #end - </xsl:if> - </xsl:when> - </xsl:choose> - </td> - <td class="help"> - <xsl:apply-templates select="adl:help[@locale = $locale]"/> - </td> - </tr> - <xsl:if test="$authentication-layer = 'Database'"> - #end - </xsl:if> - - </xsl:template> - - - <!-- layout of lists --> - <!-- layout of a list assuming a non-empty layout --> - <xsl:template match="adl:list" mode="non-empty-layout"> - <xsl:text> - </xsl:text> - <xsl:comment> [ cut here: next file '<xsl:value-of select="concat( ../@name, '/', @name)"/>.auto.vm' ]</xsl:comment> - <xsl:text> - </xsl:text> - <xsl:variable name="withpluralsuffix"> - <xsl:call-template name="i18n-plural"> - <xsl:with-param name="noun" select="ancestor::adl:entity/@name"/> - </xsl:call-template> - </xsl:variable> - - #capturefor( title) - <xsl:value-of select="normalize-space( concat( 'List ', $withpluralsuffix))"/> - #end - #capturefor( headextras) - <xsl:comment> - Auto generated Velocity list for <xsl:value-of select="ancestor::adl:entity/@name"/>, - </xsl:comment> - <xsl:call-template name="head"/> - #end - <xsl:call-template name="top"/> - <xsl:call-template name="list"> - <xsl:with-param name="list" select="."/> - </xsl:call-template> - <xsl:call-template name="foot"/> - </xsl:template> - - - <xsl:template match="adl:option"> - <option> - <xsl:attribute name="value"> - <xsl:value-of select="@value"/> - </xsl:attribute> - <xsl:attribute name="id"> - <xsl:value-of select="concat( ancestor::adl:property/@name, '-', @value)"/> - </xsl:attribute> - <xsl:call-template name="showprompt"> - <xsl:with-param name="fallback" select="@value"/> - </xsl:call-template> - </option> - </xsl:template> - - - <!-- layout of a list assuming an empty layout --> - <xsl:template match="adl:list" mode="empty-layout"> - <xsl:variable name="action" select="@onselect"/> - <xsl:text> - </xsl:text> - <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( ../@name, '/', @name)"/>.auto.vm' ]</xsl:comment> - <xsl:text> - </xsl:text> - <xsl:variable name="withpluralsuffix"> - <xsl:call-template name="i18n-plural"> - <xsl:with-param name="noun" select="ancestor::adl:entity/@name"/> - </xsl:call-template> - </xsl:variable> - <html> - <head> - #set( $title = "<xsl:value-of select="normalize-space( concat( 'List ', $withpluralsuffix))"/>") - <xsl:comment> - Auto generated Velocity list for <xsl:value-of select="ancestor::adl:entity/@name"/>, - </xsl:comment> - <xsl:call-template name="head"/> - <xsl:call-template name="install-scripts"/> - </head> - <body> - <div id="page"> - <xsl:call-template name="top"/> - <xsl:call-template name="list"> - <xsl:with-param name="list" select="."/> - </xsl:call-template> - <xsl:call-template name="foot"/> - </div> - </body> - </html> - </xsl:template> - - <!-- layout the content of a list, whether or not the layout is empty --> - <xsl:template name="list"> - <!-- an entity of type adl:list --> - <xsl:param name="list"/> - <div class="content"> - <div class="controls"> - <span class="pagination status"> - Showing $instances.FirstItem - $instances.LastItem of $instances.TotalItems - </span> - #if ( <xsl:for-each select="adl:field"> - <xsl:variable name="field" select="."/> - <xsl:variable name="search-name" - select="concat('$search_', ancestor::adl:entity//adl:property[@name=$field/@property]/@name)"/> - <xsl:value-of select="$search-name"/> - <xsl:if test="not( position() = last())">||</xsl:if> - </xsl:for-each> ) - <span class="pagination status">(Suppressing pagination in favour of search)</span> - #else - <span class="pagination control"> - #if($instances.HasFirst) - $PaginationHelper.CreatePageLink( 1, "<<" ) - #end - #if(!$instances.HasFirst) << #end - </span> - <span class="pagination control"> - #if($instances.HasPrevious) $PaginationHelper.CreatePageLink( $instances.PreviousIndex, "<" ) #end - #if(!$instances.HasPrevious) < #end - </span> - <span class="pagination control"> - #if($instances.HasNext) $PaginationHelper.CreatePageLink( $instances.NextIndex, ">" ) #end - #if(!$instances.HasNext) > #end - </span> - <span class="pagination control"> - #if($instances.HasLast) $PaginationHelper.CreatePageLink( $instances.LastIndex, ">>" ) #end - #if(!$instances.HasLast) >> #end - </span> - #end - <xsl:if test="$list/../adl:form"> - <span class="add"> - <a> - <xsl:attribute name="href"> - <xsl:value-of select="concat( ancestor::adl:entity/adl:form[position()=1]/@name, '.rails')"/> - </xsl:attribute> - <xsl:call-template name="i18n-add-a-new"> - <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> - </xsl:call-template> - </a> - </span> - </xsl:if> - </div> - <form> - <xsl:attribute name="action"> - <xsl:value-of select="concat( $list/@name, '.rails')"/> - </xsl:attribute> - <xsl:call-template name="internal-with-fields-list"> - <xsl:with-param name="entity" select="$list/ancestor::adl:entity"/> - <xsl:with-param name="fields" select="$list/adl:field"/> - <xsl:with-param name="can-search" select="'true'"/> - </xsl:call-template> - </form> - </div> - </xsl:template> - - <xsl:template name="internal-with-fields-list"> - <!-- a node-list of entities of type 'adl:field' or 'adl:field', each indicating a property - of the same entity, to be shown in columns of this list --> - <xsl:param name="fields"/> - <!-- the entity of type 'adl:entity' on which the properties for all those fields can be found --> - <xsl:param name="entity"/> - <!-- the name of the list of instances of this entity, available to Velocity at runtime - as an ICollection, which is to be layed out in this list --> - <xsl:param name="instance-list" select="'instances'"/> - <!-- NOTE NOTE NOTE: To be searchable, internal-with-fields-list must not only be called with can-search - equal to 'true', but also within a form! --> - <!-- NOTE NOTE NOTE: It's obvious that internal-with-fields-list and internal-with-properties-list - ought to be replaced with a single template, but that template proves to be extremely hard to get - right --> - <xsl:param name="can-search"/> - <table class="sortable" id="concat($entity/@name, '-list')"> - <tr> - <xsl:for-each select="$fields"> - <xsl:variable name="field" select="."/> - <th> - <xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@property"/> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="locale" select="$locale"/> - </xsl:call-template> - </th> - </xsl:for-each> - <xsl:for-each select="$entity/adl:form"> - <th class="unsortable">-</th> - </xsl:for-each> - </tr> - <xsl:if test="$can-search = 'true'"> - <tr class="search sorttop"> - <xsl:for-each select="$fields"> - <xsl:variable name="field" select="."/> - <td class="search"> - <xsl:variable name="size"> - <xsl:choose> - <!-- can't search non-concrete fields --> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@concrete='false'">0</xsl:when> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='string'"> - <xsl:choose> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@size > 20">20</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$entity//adl:property[@name=$field/@property]/@size"/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='integer'">8</xsl:when> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='real'">8</xsl:when> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='money'">8</xsl:when> - <!-- xsl:when test="$entity//adl:property[@name=$field/@property]/@type='message'">20</xsl:when doesn't work yet --> - <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='text'">20</xsl:when> - <!-- xsl:when test="$entity//adl:property[@name=$field/@property]/@type='enity'">20</xsl:when doesn't work yet --> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:if test="$size != 0"> - <input> - <xsl:variable name="search-name" select="concat('search_',$entity//adl:property[@name=$field/@property]/@name)"/> - <xsl:attribute name="name"> - <xsl:value-of select="$search-name"/> - </xsl:attribute> - <xsl:attribute name="size"> - <xsl:choose> - <xsl:when test="$size > 8">8</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$size"/> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:attribute name="value"> - <xsl:value-of select="concat( '$!', $search-name)"/> - </xsl:attribute> - </input> - </xsl:if> - </td> - </xsl:for-each> - <td> - <input type="submit" name="search-button" value="Search"/> - </td> - </tr> - </xsl:if> - <xsl:if test="not( $entity/@name)"> - <xsl:message terminate="yes"> - Unknown entity whilst trying to generate list - </xsl:message> - </xsl:if> - <xsl:variable name="readgroups"> - <xsl:call-template name="entity-read-groups"> - <xsl:with-param name="entity" select="$entity"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$authentication-layer = 'Application'"> - <xsl:call-template name="internal-with-fields-rows"> - <xsl:with-param name="instance-list" select="$instance-list"/> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="fields" select="$fields"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$authentication-layer = 'Database'"> - <!-- NOTE NOTE NOTE: This is whitespace-sensitive! --> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:call-template name="internal-with-fields-rows"> - <xsl:with-param name="instance-list" select="$instance-list"/> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="fields" select="$fields"/> - </xsl:call-template> - #else - <tr> - <td colspan="5">[You are not authorised to view this data]</td> - </tr> - #end - </xsl:when> - </xsl:choose> - </table> - </xsl:template> - - <xsl:template name="internal-with-fields-rows"> - <xsl:param name="instance-list"/> - <xsl:param name="entity"/> - <xsl:param name="fields"/> - #foreach( <xsl:value-of select="concat( '$', $entity/@name)"/> in <xsl:value-of select="concat('$', $instance-list)"/>) - #if ( $velocityCount % 2 == 0) - #set( $oddity = "even") - #else - #set( $oddity = "odd") - #end - <tr class="$oddity"> - <xsl:for-each select="$fields"> - <xsl:variable name="field" select="."/> - <xsl:call-template name="list-field"> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="property" select="$entity//adl:property[@name=$field/@property]"/> - <xsl:with-param name="objectvar" select="$entity/@name"/> - </xsl:call-template> - </xsl:for-each> - <xsl:variable name="keys"> - <xsl:call-template name="entity-keys-fragment"> - <xsl:with-param name="entity" select="$entity"/> - </xsl:call-template> - </xsl:variable> - <xsl:for-each select="$entity/adl:form"> - <!-- by default create a link to each form declared for the entity. - We probably need a means of overriding this --> - <td> - <a> - <xsl:attribute name="href"> - <xsl:value-of select="concat( '../', $entity/@name, '/', @name, '.rails', $keys)"/> - </xsl:attribute> - <xsl:value-of select="@name"/> - </a> - </td> - </xsl:for-each> - </tr> - #end - </xsl:template> - - <xsl:template name="internal-with-properties-list"> - <!-- a node-list of entities of type 'adl:property', each a property of the same entity, to be shown - in columns of this list --> - <xsl:param name="properties"/> - <!-- the entity of type 'adl:entity' on which the properties for all those fields can be found --> - <xsl:param name="entity"/> - <!-- the name of the list of instances of this entity, available to Velocity at runtime - as an ICollection, which is to be layed out in this list --> - <xsl:param name="instance-list" select="'instances'"/> - <!-- NOTE NOTE NOTE: To be searchable, internal-with-properties-list must not only be called with can-search - equal to 'true', but also within a form! --> - <!-- NOTE NOTE NOTE: It's obvious that internal-with-fields-list and internal-with-properties-list - ought to be replaced with a single template, but that template proves to be extremely hard to get - right --> - <xsl:param name="can-search"/> - <table class="sortable"> - <tr> - <xsl:for-each select="$properties"> - <th> - <xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@name"/> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="locale" select="$locale"/> - </xsl:call-template> - </th> - </xsl:for-each> - <xsl:for-each select="$entity/adl:form"> - <th>-</th> - </xsl:for-each> - </tr> - <xsl:if test="$can-search = 'true'"> - <tr class="search"> - <xsl:for-each select="$properties"> - <td class="search"> - <xsl:variable name="size"> - <xsl:choose> - <xsl:when test="@type='string'"> - <xsl:choose> - <xsl:when test="@size > 8">8</xsl:when> - <xsl:otherwise> - <xsl:value-of select="@size"/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="@type='integer'">8</xsl:when> - <xsl:when test="@type='real'">8</xsl:when> - <xsl:when test="@type='money'">8</xsl:when> - <!-- xsl:when test="@type='message'">20</xsl:when doesn't work yet --> - <xsl:when test="@type='text'">8</xsl:when> - <!-- xsl:when test="@type='enity'">20</xsl:when doesn't work yet --> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:if test="$size != 0"> - <input> - <xsl:attribute name="name"> - <xsl:value-of select="concat('search_', @name)"/> - </xsl:attribute> - <xsl:attribute name="size"> - <xsl:value-of select="$size"/> - </xsl:attribute> - <xsl:attribute name="value"> - <xsl:value-of select="concat( '$!search_', @name)"/> - </xsl:attribute> - </input> - </xsl:if> - </td> - </xsl:for-each> - <td> - <input type="submit" name="search-button" size="8" value="Search"/> - </td> - </tr> - </xsl:if> - #foreach( <xsl:value-of select="concat( '$', $entity/@name)"/> in <xsl:value-of select="concat('$', $instance-list)"/>) - #if ( $velocityCount % 2 == 0) - #set( $oddity = "even") - #else - #set( $oddity = "odd") - #end - <tr class="$oddity"> - <xsl:for-each select="$properties"> - <xsl:call-template name="list-field"> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="property" select="."/> - <xsl:with-param name="objectvar" select="$entity/@name"/> - </xsl:call-template> - </xsl:for-each> - <xsl:variable name="keys"> - <!-- assemble keys in a Velocity-friendly format, then splice it into - the HREF below --> - <xsl:for-each select="$entity/adl:key/adl:property"> - <xsl:variable name="sep"> - <xsl:choose> - <xsl:when test="position()=1">?</xsl:when> - <xsl:otherwise>&</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="@type='entity'"> - <xsl:value-of select="concat( $sep, @name, '=$', $entity/@name, '.', @name, '_Value')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat( $sep, @name, '=$', $entity/@name, '.', @name)"/> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - </xsl:variable> - <xsl:for-each select="$entity/adl:form"> - <!-- by default create a link to each form declared for the entity. - We probably need a means of overriding this --> - <td> - <a> - <xsl:attribute name="href"> - <xsl:value-of select="concat( '../', $entity/@name, '/', @name, '.rails', $keys)"/> - </xsl:attribute> - <xsl:value-of select="@name"/> - </a> - </td> - </xsl:for-each> - </tr> - #end - </table> - </xsl:template> - - <!-- output a list field --> - <xsl:template name="list-field"> - <xsl:param name="entity"/> - <xsl:param name="property"/> - <xsl:param name="objectvar" select="instance"/> - <xsl:variable name="readgroups"> - <xsl:call-template name="property-read-groups"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <td> - <xsl:choose> - <xsl:when test="$authentication-layer = 'Application'"> - <xsl:call-template name="list-field-inner"> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="objectvar" select="$objectvar"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$authentication-layer = 'Database'"> - <!-- NOTE NOTE NOTE: This is whitespace-sensitive! --> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - <xsl:if test="$property/@type='entity'"> - <!-- right, this is horrible. You can't read the field unless you can read the property; - but even if you can read the property, if its an entity property you still can't read it - unless you can also read the entity --> - <xsl:variable name="entityreadgroups"> - <xsl:call-template name="entity-read-groups"> - <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> - </xsl:call-template> - </xsl:variable> - #if ( <xsl:for-each select="exsl:node-set( $entityreadgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - </xsl:if> - <xsl:call-template name="list-field-inner"> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="objectvar" select="$objectvar"/> - </xsl:call-template> - <xsl:if test="$property/@type='entity'"> - #else - [Not authorised] - #end - </xsl:if> - #else - [Not authorised] - #end - </xsl:when> - </xsl:choose> - </td> - </xsl:template> - - <xsl:template name="list-field-inner"> - <xsl:param name="entity"/> - <xsl:param name="property"/> - <xsl:param name="objectvar" select="instance"/> - <xsl:choose> - <xsl:when test="$property/adl:option"> - <xsl:for-each select="$property/adl:option"> - <xsl:variable name="val"> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$base-type = 'string'"> - <xsl:value-of select="concat( '"', @value, '"')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="@value"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - #if( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/> == <xsl:value-of select="$val"/>) - <xsl:call-template name="showprompt"> - <xsl:with-param name="node" select="."/> - <xsl:with-param name="fallback" select="@value"/> - </xsl:call-template> - #end - </xsl:for-each> - </xsl:when> - <xsl:when test="$property/@type = 'date'"> - #if ( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) - <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>.ToString( 'd') - #end - </xsl:when> - <xsl:when test="$property/@type='message'"> - #if ( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) - $t.Msg( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) - #end - </xsl:when> - <xsl:when test="$property/@type='entity'"> - #if( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) - <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name, '.UserIdentifier')"/> - #end - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat( '$!', $entity/@name, '.', $property/@name)"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- generate head javascript for a form --> - <xsl:template name="generate-head-javascript"> - <xsl:param name="form"> - <!-- assumed to be an instance of adl:form --> - </xsl:param> - <xsl:param name="locale"/> - <script type='text/javascript' language='JavaScript1.2'> - #if ( ${site-root}) - var siteRoot = '$siteRoot'; - #else - var siteRoot = '<xsl:value-of select='$site-root'/>'; - #end - - var enterPressed = false; - - function trapKeyPress(event, form){ - if(event.which == 13){ - enterPressed = true; - } else { - enterPressed = false; - } - } - - function trapEnterSubmissions(event, form){ - if(enterPressed){ - enterPressed = false; //we have trapped this, can stand down - return false; - } - } - - function performInitialisation() - { - #if ( $instance) - #if ( ! $instance.IsNew) - <xsl:for-each select="$form/ancestor::adl:entity/adl:property[@type='link']"> - <xsl:variable name="propname" select="@name"/> - <xsl:choose> - <xsl:when test="$form/@properties='all'"> - <xsl:value-of select="concat( 'document.',$form/@name, '.', @name, '.submitHandler = shuffleSubmitHandler;')"/> - </xsl:when> - <xsl:when test="$form//adl:field[@property=$propname]"> - <xsl:value-of select="concat( 'document.',$form/@name, '.', @name, '.submitHandler = shuffleSubmitHandler;')"/> - </xsl:when> - <!-- if we're not doing all properties, and if this property is not the property of a field, - we /don't/ set up a submit handler. --> - </xsl:choose> - </xsl:for-each> - #end - #end - var validator = new Validation('<xsl:value-of select="$form/@name"/>', {immediate : true, useTitles : true}); - } - - <xsl:for-each select="//adl:typedef"> - <xsl:variable name="errormsg"> - <xsl:choose> - <xsl:when test="adl:help[@locale=$locale]"> - <xsl:apply-templates select="adl:help[@locale=$locale]"/> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="i18n-bad-format"> - <xsl:with-param name="format-name" select="@name"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - Validation.add( '<xsl:value-of select="concat('validate-custom-', @name)"/>', - '<xsl:value-of select="normalize-space( $errormsg)"/>', - { - <xsl:choose> - <xsl:when test="@pattern"> - pattern : new RegExp("<xsl:value-of select="@pattern"/>","gi")<xsl:if test="@size"> - , maxLength : <xsl:value-of select="@size"/> - </xsl:if> - </xsl:when> - <xsl:when test="@minimum"> - min : <xsl:value-of select="@minimum"/><xsl:if test="@maximum"> - , max : <xsl:value-of select="@maximum"/> - </xsl:if> - </xsl:when> - </xsl:choose> - }); - </xsl:for-each> - </script> - </xsl:template> - - <!-- this template outputs MOST types of widget, but NOT shuffle widgets --> - <xsl:template name="property-widget"> - <xsl:param name="property"/> - <xsl:param name="mode"/> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="href"> - <xsl:choose> - <xsl:when test="$property/@type='entity' and //adl:entity[@name=$property/@entity]/adl:form[@name='edit']"> - <!-- if this is an entity property, and the entity which it wraps has an edit form --> - <xsl:variable name="keys"> - <xsl:call-template name="entity-keys-fragment"> - <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> - <xsl:with-param name="instance" select="concat( 'instance.', $property/@name)"/> - </xsl:call-template> - </xsl:variable> - <xsl:value-of select="concat( '../', $property/@entity, '/edit.rails', $keys)"/> - </xsl:when> - </xsl:choose> - </xsl:variable> - <xsl:variable name="if-missing"> - <xsl:choose> - <xsl:when test="$property/adl:if-missing[@locale = $locale]"> - <xsl:value-of select="$property/adl:if-missing[@locale = $locale]"/> - </xsl:when> - <xsl:when test="$property/@required='true'"> - <xsl:call-template name="i18n-value-required"> - <xsl:with-param name="property-name" select="$property/@name"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$property/@type='defined'"> - <xsl:call-template name="i18n-value-defined"> - <xsl:with-param name="property-name" select="$property/@name"/> - <xsl:with-param name="definition-name" select="$property/@typedef"/> - </xsl:call-template> - </xsl:when> - <xsl:when test="$property/@type='entity'"> - <xsl:call-template name="i18n-value-entity"> - <xsl:with-param name="property-name" select="$property/@name"/> - <xsl:with-param name="entity-name" select="$property/@entity"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="i18n-value-type"> - <xsl:with-param name="property-name" select="$property/@name"/> - <xsl:with-param name="type-name" select="$property/@type"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="cssclass"> - <xsl:if test="$property/@required='true'">required </xsl:if> - <xsl:choose> - <xsl:when test="$property/@type='defined'"> - <xsl:choose> - <xsl:when test="//adl:typedef[@name=$property/@typedef]/@pattern"> - <xsl:value-of select="concat( 'validate-custom-', $property/@typedef)"/> - </xsl:when> - <xsl:when test="//adl:typedef[@name=$property/@typedef]/@minimum"> - <xsl:value-of select="concat( 'validate-custom-', $property/@typedef)"/> - </xsl:when> - </xsl:choose> - </xsl:when> - <xsl:when test="$base-type='integer'">validate-digits</xsl:when> - <xsl:when test="$base-type='real'">validate-number</xsl:when> - <xsl:when test="$base-type='money'">validate-number</xsl:when> - <xsl:when test="$base-type='date'">date-field validate-date</xsl:when> - </xsl:choose> - </xsl:variable> - <xsl:variable name="maxlength"> - <xsl:call-template name="base-size"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="size"> - <xsl:choose> - <xsl:when test="$maxlength > $max-widget-width"> - <xsl:value-of select="$max-widget-width"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$maxlength"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="rows"> - <!-- number of rows, if textarea emitted --> - <xsl:choose> - <xsl:when test="$base-type = 'text'">8</xsl:when> - <xsl:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="cols"> - <!-- number of rows, if textarea emitted --> - <xsl:choose> - <xsl:when test="$base-type = 'text'"> - <xsl:value-of select="$max-widget-width"/> - </xsl:when> - <xsl:otherwise>10</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="required"> - <xsl:choose> - <xsl:when test="$property/@required='true'">true</xsl:when> - <xsl:otherwise>false</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="$property/adl:option"> - <!-- emit a menu of options --> - <!-- it would be better to do this through a field helper but I haven't yet worked out how --> - <select> - <xsl:attribute name="name"> - <xsl:value-of select="concat( 'instance.', $property/@name)"/> - </xsl:attribute> - <xsl:attribute name="id"> - <xsl:value-of select="concat( 'instance_', $property/@name)"/> - </xsl:attribute> - <xsl:attribute name="class"> - <xsl:value-of select="concat( 'instance.', $property/@name)"/> - </xsl:attribute> - <xsl:if test="not( $property/@required='true')"> - <option value="'-1'">[unselected]</option> - </xsl:if> - <xsl:apply-templates select="$property/adl:option"/> - </select> - <script type="text/javascript" language="javascript"> - // <![CDATA[ - #set ( <xsl:value-of select="concat( '$', $property/@name, '_sel_opt')"/>="<xsl:value-of select="concat( $property/@name, '-$instance.', $property/@name)"/>") - option = document.getElementById( "<xsl:value-of select="concat( '$', $property/@name, '_sel_opt')"/>"); - - if ( option != null) - { - option.selected = true; - } - // ]]> - </script> - - </xsl:when> - <xsl:when test="$property/@type = 'defined'"> - <!-- it would be better to do this through a field helper but I haven't yet worked out how --> - <xsl:variable name="definition" select="//adl:typedef[@name=$property/@typedef]"/> - <xsl:variable name="minimum" select="$definition/@minimum"/> - <xsl:choose> - <xsl:when test="$base-type='string'"> - ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} - </xsl:when> - <xsl:when test="string-length($definition/@minimum) > 0 and string-length( $definition/@maximum) > 0"> - <xsl:call-template name="slider-widget"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="minimum" select="$definition/@minimum"/> - <xsl:with-param name="maximum" select="$definition/@maximum"/> - </xsl:call-template> - ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="concat('slider, ', normalize-space($cssclass))"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} - </xsl:when> - <xsl:otherwise> - ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="$property/@type = 'entity'"> - <!-- once again, not only must you have access to the property but also to the entity --> - <xsl:variable name="readgroups"> - <xsl:call-template name="entity-read-groups"> - <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> - </xsl:call-template> - </xsl:variable> - <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause cause the Velocity parser to break! --> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} - #else - [Not authorised] - #end - </xsl:when> - <xsl:otherwise> - ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',cols='<xsl:value-of select="normalize-space($cols)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template name="slider-widget"> - <xsl:param name="property"/> - <xsl:param name="minimum" select="0"/> - <xsl:param name="maximum" select="100"/> - <xsl:if test="string-length( $minimum) > 0 and string-length( $maximum) > 0"> - <div style="width:200px; height:20px; background: transparent url(../images/slider-images-track-right.png) no-repeat top right;"> - <xsl:attribute name="id"> - <xsl:value-of select="concat( $property/@name, '-track')"/> - </xsl:attribute> - <div style="position: absolute; width: 5px; height: 20px; background: transparent url(../images/slider-images-track-left.png) no-repeat top left"> - <xsl:attribute name="id"> - <xsl:value-of select="concat( $property/@name, '-track-left')"/> - </xsl:attribute> - </div> - <div style="width:19px; height:20px;"> - <xsl:attribute name="id"> - <xsl:value-of select="concat( $property/@name, '-slider')"/> - </xsl:attribute> - <img src="../images/slider-images-handle.png" alt="" style="float: left;" /> - </div> - </div> - <script type="text/javascript" language="javascript"> - // <![CDATA[ - new Control.Slider('<xsl:value-of select="$property/@name"/>-slider','<xsl:value-of select="$property/@name"/>-track',{ - onSlide:function(v){$('<xsl:value-of select="concat( 'instance_', $property/@name)"/>').value = <xsl:value-of select="$minimum"/>+ Math.floor(v*(<xsl:value-of select="$maximum - $minimum"/>))} - }); - // ]]> - </script> - </xsl:if> - </xsl:template> - - <!-- assemble keys for this entity in a Velocity-friendly format, to splice into an HREF below --> - <xsl:template name="entity-keys-fragment"> - <xsl:param name="entity"/> - <xsl:param name="instance" select="$entity/@name"/> - <xsl:for-each select="$entity/adl:key/adl:property"> - <xsl:variable name="sep"> - <xsl:choose> - <xsl:when test="position()=1">?</xsl:when> - <xsl:otherwise>&</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="@type='entity'"> - <xsl:value-of select="concat( $sep, @name, '=$', $instance, '.', @name, '_Value')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat( $sep, @name, '=$', $instance, '.', @name)"/> - </xsl:otherwise> - </xsl:choose> - </xsl:for-each> - </xsl:template> - - <!-- overall page layout --> - - <xsl:template match="adl:content"/> - - <xsl:template match="adl:help"> - <xsl:apply-templates/> - </xsl:template> - - <!-- assuming an empty layout, install all the standard scripts - which an ADL page may need --> - <xsl:template name="install-scripts"> - ${ScriptsHelper.InstallScript( "ShuffleWidget")} - - ${Ajax.InstallScripts()} - ${FormHelper.InstallScripts()} - ${Validation.InstallScripts()} - ${Scriptaculous.InstallScripts()} - ${DateTimeHelper.InstallScripts()} - - ${ScriptsHelper.InstallScript( "Sitewide")} - ${ScriptsHelper.InstallScript( "Behaviour")} - ${ScriptsHelper.InstallScript( "Epoch")} - ${ScriptsHelper.InstallScript( "Panes")} - ${ScriptsHelper.InstallScript( "SortTable")} - </xsl:template> - - <!-- standard header material - auto-timeout, etc --> - <xsl:template name="head"> - <xsl:comment> - <xsl:value-of select="/adl:application/@name"/> <xsl:value-of select="$product-version"/> - <xsl:value-of select="/adl:application/@revision"/> - Auto generated Velocity macro for <xsl:value-of select="@name"/>, - generated from ADL. - - Generated using adl2views.xslt <xsl:value-of select="substring( '$Revision: 1.65 $', 10)"/> - Generation parameters were: - area-name: <xsl:value-of select="$area-name"/> - default-url: <xsl:value-of select="$default-url"/> - generate-site-navigation: <xsl:value-of select="$generate-site-navigation"/> - layout-name: <xsl:value-of select="$layout-name"/> - locale: <xsl:value-of select="$locale"/> - max-widget-width: <xsl:value-of select="$max-widget-width"/> - product-version: <xsl:value-of select="$product-version"/> - page-timeout: <xsl:value-of select="$page-timeout"/> - show-errors: <xsl:value-of select="$show-errors"/> - show-messages: <xsl:value-of select="$show-messages"/> - </xsl:comment> - <xsl:if test="$page-timeout > 0"> - <meta http-equiv="refresh"> - <xsl:attribute name="content"> - <xsl:value-of select="concat($page-timeout, '; URL=', $default-url)"/> - </xsl:attribute> - </meta> - </xsl:if> - <xsl:choose> - <xsl:when test="adl:head"> - <xsl:for-each select="adl:head/*"> - <xsl:apply-templates select="."/> - </xsl:for-each> - </xsl:when> - <xsl:otherwise> - <xsl:for-each select="//adl:content/adl:head/*"> - <xsl:apply-templates select="."/> - </xsl:for-each> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- standard top area content on all pages (navigation, etc) --> - <xsl:template name="top"> - <xsl:choose> - <xsl:when test="adl:top"> - <xsl:for-each select="adl:top/*"> - <xsl:apply-templates select="."/> - </xsl:for-each> - </xsl:when> - <xsl:otherwise> - <xsl:for-each select="//adl:content/adl:top/*"> - <xsl:apply-templates select="."/> - </xsl:for-each> - </xsl:otherwise> - </xsl:choose> - <xsl:if test="$authentication-layer = 'Database'"> - #if ( ${SecurityHelper.GetUserName()}) - <!-- the #else and #end of this #if is generated in the foot template --> - </xsl:if> - <xsl:variable name="current-entity" select="ancestor::adl:entity/@name"/> - <xsl:if test="$generate-site-navigation = 'true'"> - <ul class="generatednav"> - <xsl:for-each select="//adl:entity[adl:list[@name='list']]"> - <xsl:variable name="readgroups"> - <xsl:call-template name="page-read-groups"> - <xsl:with-param name="page" select="."/> - </xsl:call-template> - </xsl:variable> - <xsl:if test="$authentication-layer = 'Database'"> - #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) - </xsl:if> - <li> - <xsl:attribute name="class"> - <xsl:choose> - <xsl:when test="@name = $current-entity">selected-nav</xsl:when> - <xsl:otherwise>navigation</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <a> - <xsl:attribute name="href"> - <xsl:choose> - <xsl:when test="string-length( $site-root) > 0"> - <xsl:choose> - <xsl:when test="string-length( $area-name) > 0"> - <xsl:value-of select="concat( $site-root, '/', $area-name, '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat( $site-root, '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="string-length( $area-name) > 0"> - <xsl:value-of select="concat( '/', $area-name, '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat( '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:call-template name="showprompt"> - <xsl:with-param name="fallback" select="@name"/> - <xsl:with-param name="entity" select="."/> - </xsl:call-template> - </a> - </li> - <xsl:if test="$authentication-layer = 'Database'"> - #end - </xsl:if> - </xsl:for-each> - </ul> - </xsl:if> - </xsl:template> - - <!-- standard footer on all pages; product identifier and version --> - <xsl:template name="foot"> - <xsl:if test="$authentication-layer = 'Database'"> - <!-- the #if for this #else and #end is generated in the head template --> - #else - <div class="content"> - <p> - To view this page you must first <a href="../dblogin/login.rails">Log in</a> - </p> - </div> - #end - </xsl:if> - <div class="pagefoot"> - <xsl:choose> - <xsl:when test="adl:foot"> - <xsl:for-each select="adl:foot/*"> - <xsl:apply-templates select="."/> - </xsl:for-each> - </xsl:when> - <xsl:otherwise> - <xsl:for-each select="//adl:content/adl:foot/*"> - <xsl:apply-templates select="."/> - </xsl:for-each> - </xsl:otherwise> - </xsl:choose> - <p class="product-version"> - <xsl:value-of select="$product-version"/>; built with <xsl:value-of select="$authentication-layer"/>-layer authentication. - </p> - </div> - </xsl:template> - - <!-- if this node (default to current node) has a child of type prompt for the current locale, - show that prompt; else show the first prompt child with locale='default' if any; - else show the value of the fallback param --> - <xsl:template name="showprompt"> - <xsl:param name="fallback" select="'Unknown'"/> - <xsl:param name="node" select="."/> - <xsl:param name="entity" select="$node/ancestor::adl:entity"/> - <xsl:param name="locale" select="'en-GB'"/> - <xsl:choose> - <xsl:when test="$node/adl:prompt[@locale=$locale]"> - <xsl:value-of select="$node/adl:prompt[@locale=$locale][1]/@prompt"/> - </xsl:when> - <xsl:when test="$node/adl:prompt[@locale='default']"> - <xsl:value-of select="$node/adl:prompt[@locale='default'][1]/@prompt"/> - </xsl:when> - <xsl:when test="$node/@property"> - <!-- it's (probably) a field which doesn't have any prompt of its own - - fetch from its property --> - <xsl:variable name="propname" select="@property"/> - <xsl:call-template name="showprompt"> - <xsl:with-param name="fallback" select="$fallback"/> - <xsl:with-param name="node" select="$entity//adl:property[@name=$propname]"/> - <xsl:with-param name="entity" select="$entity"/> - <xsl:with-param name="locale" select="$locale"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$fallback"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- compose the list of search parameters to append to a pagination request; note that this does - not currently work but I have some hopes that in future it will and in the meantime it costs us - little --> - <xsl:template name="pagination-search-params"> - <xsl:param name="form" select="."/> - "%{<xsl:for-each select="$form/adl:field"> - <xsl:variable name="field" select="."/> - <xsl:variable name="search-name" - select="concat('search_',$form/ancestor::adl:entity//adl:property[@name=$field/@property]/@name)"/> - <xsl:value-of select="concat( $search-name, '=$', $search-name)"/> - <xsl:if test="not( position() = last())">,</xsl:if> - </xsl:for-each>}" - </xsl:template> - - <xsl:template match="groups"> - <xsl:apply-templates/> - </xsl:template> - - <!-- just copy anything we can't match --> - <xsl:template match="@* | node()"> - <xsl:copy> - <xsl:apply-templates select="@* | node()"/> - </xsl:copy> - </xsl:template> - +<?xml version="1.0" encoding="UTF-8" ?> +<xsl:stylesheet version="1.0" + xmlns="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:msxsl="urn:schemas-microsoft-com:xslt" + xmlns:exsl="urn:schemas-microsoft-com:xslt" + extension-element-prefixes="exsl"> + <!-- + Application Description Language framework + adl2views.xsl + + (c) 2007 Cygnet Solutions Ltd + + Transform ADL into velocity view templates + + $Author: simon $ + $Revision: 1.66 $ + $Date: 2010-07-20 19:53:40 $ + --> + <!-- WARNING WARNING WARNING: Do NOT reformat this file! + Whitespace (or lack of it) is significant! --> + + <xsl:include href="base-type-include.xslt"/> + <xsl:include href="permissions-include.xslt"/> + <!-- bug 1896 : boilerplate text in views should be tailored to the locale of + the expected user. Unfortunately I haven't yet worked out how to do + conditional includes in XSLT, so this is a step on the way to a solution, + not a solution in itself. --> + <xsl:include href="i18n-en-GB-include.xslt"/> + + <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/> + + <!-- The locale for which these views are generated + TODO: we need to generate views for each available locale, but this is not + yet implemented. When it is we will almost certainly still need a 'default locale' --> + <xsl:param name="locale" select="en-GB"/> + + <!-- whether or not to auto-generate site navigation - by default, don't --> + <xsl:param name="generate-site-navigation" select="'false'"/> + + <!-- whether or not to layout errors - they may be in the default layout --> + <xsl:param name="show-errors" select="'false'"/> + <!-- whether or not to layout messages - they may be in the default layout --> + <xsl:param name="show-messages" select="'false'"/> + + <!-- the maximum width, in characters, we're prepared to allocate to widgets --> + <xsl:param name="max-widget-width" select="40"/> + + <!-- the name and version of the product being built --> + <xsl:param name="product-version" select="'Application Description Language Framework'"/> + + <!-- bug 1800 : the name of the Velocity layout to use. If you are to + be able to usefully define content in ADL, then the default ADL layout + needs to be empty, but if ADL-generated pages are to 'play nice' in + largely non-ADL applications, they must be able to use standard layouts. + If you are going to use a non-default layout, however, you're responsible + for making sure it loads all the scripts, etc, that an ADL controller + expects. --> + <xsl:param name="layout-name"/> + <!-- bug 1800 : the name of the area (i.e. URL path part) to use --> + <xsl:param name="area-name" select="auto"/> + <!-- the base url of the whole site --> + <xsl:param name="site-root" select="'..'"/> + <!-- Whether to authenticate at application or at database layer. + If not 'Application', then 'Database'. --> + <xsl:param name="authentication-layer" select="'Application'"/> + + <!-- bug 2847: how long to wait on a page before it auto-redirects to the default URL --> + <xsl:param name="page-timeout" select="300"/> + <!-- bug 2847: the default URL, probably a 'please login' screen --> + <xsl:param name="default-url" select="'../default.aspx'"/> + + <xsl:template match="adl:application"> + <output> + <!-- 'output' is a dummy wrapper root tag to make the entire output work as + an XML document; the actual output later gets cut into chunks and the + wrapper tag is discarded. --> + <xsl:apply-templates select="adl:entity"/> + <!-- make sure extraneous junk doesn't get into the last file generated, + by putting it into a separate file --> + <xsl:text> + </xsl:text> + <xsl:comment> [ cut here: next file 'tail.txt' ] </xsl:comment> + </output> + </xsl:template> + + <xsl:template match="adl:entity[@foreign='true']"/> + <!-- Don't bother generating anything for foreign entities --> + + <xsl:template match="adl:entity"> + <xsl:comment>Layout is <xsl:value-of select="$layout-name"/></xsl:comment> + <xsl:choose> + <xsl:when test="$layout-name"> + <xsl:apply-templates select="." mode="non-empty-layout"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="." mode="empty-layout"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- generate views for an entity, assuming a non-empty layout - i.e. + I'm not responsible for the html, the head, or for the body tag --> + <xsl:template match="adl:entity" mode="non-empty-layout"> + <xsl:variable name="keyfield"> + <xsl:choose> + <xsl:when test="adl:key/adl:property"> + <xsl:value-of select="adl:key/adl:property[position()=1]/@name"/> + </xsl:when> + <xsl:otherwise>[none]</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:apply-templates select="adl:form" mode="non-empty-layout"/> + <xsl:apply-templates select="adl:list" mode="non-empty-layout"/> + <xsl:text> + </xsl:text> + <xsl:comment> [ cut here: next file '<xsl:value-of select="concat( @name, '/maybedelete.auto.vm')"/>' ] </xsl:comment> + <xsl:text> + </xsl:text> + <xsl:variable name="really-delete"> + <xsl:call-template name="i18n-really-delete"/> + </xsl:variable> + #set( $title = "<xsl:value-of select="concat( $really-delete, ' ', @name)"/> $instance.UserIdentifier") + #capturefor( headextras) + <xsl:comment> + Auto generated Velocity maybe-delete form for <xsl:value-of select="@name"/>, + </xsl:comment> + <xsl:call-template name="head"/> + #end + <xsl:call-template name="maybe-delete"> + <xsl:with-param name="entity" select="."/> + </xsl:call-template> + </xsl:template> + + <!-- generate views for an entity, assuming an empty layout + (i.e. I'm responsible for html, head and body tags) --> + <xsl:template match="adl:entity" mode="empty-layout"> + <xsl:variable name="keyfield"> + <xsl:choose> + <xsl:when test="adl:key/adl:property"> + <xsl:value-of select="adl:key/adl:property[position()=1]/@name"/> + </xsl:when> + <xsl:otherwise>[none]</xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:apply-templates select="adl:form" mode="empty-layout"/> + <xsl:apply-templates select="adl:list" mode="empty-layout"/> + <xsl:text> + </xsl:text> + <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( @name, '/maybedelete.auto.vm')"/>' ]</xsl:comment> + <xsl:text> + </xsl:text> + <html> + <xsl:variable name="really-delete"> + <xsl:call-template name="i18n-really-delete"/> + </xsl:variable> + #set( $title = "<xsl:value-of select="concat( $really-delete, ' ', @name)"/> $instance.UserIdentifier") + <head> + <xsl:comment> + Auto generated Velocity maybe-delete form for <xsl:value-of select="@name"/>, + </xsl:comment> + <xsl:call-template name="head"/> + <xsl:call-template name="install-scripts"/> + </head> + <body> + <div id="page"> + <xsl:call-template name="top"/> + <xsl:call-template name="maybe-delete"> + <xsl:with-param name="entity" select="."/> + </xsl:call-template> + <xsl:call-template name="foot"/> + </div> + </body> + </html> + </xsl:template> + + <!-- the guts of the maybe-delete form, whether or not we're using an empty layout --> + <xsl:template name="maybe-delete"> + <xsl:param name="entity"/> + <div class="content"> + <xsl:if test="$show-errors = 'true'"> + #if ( $instance.NoDeleteReason) + <ul class="errors"> + <li>$instance.NoDeleteReason</li> + </ul> + #end + #if ( $errors) + #if ( $errors.Count != 0) + <ul class="errors"> + #foreach($e in $errors) + #if($e.Message) + <li>$t.Error($e)</li> + #else + <li>$t.Enc($e)</li> + #end + #end + </ul> + #end + #end + </xsl:if> + <xsl:if test="$show-messages = 'true'"> + #if( $messages) + #if ( $messages.Count != 0) + <ul class="information"> + #foreach ( $message in $messages) + <li>$message</li> + #end + </ul> + #end + #end + </xsl:if> + <form action="delete.rails" method="post"> + <xsl:for-each select="$entity/adl:key/adl:property"> + <xsl:choose> + <xsl:when test="@type='entity'"> + <xsl:variable name="entityname" select="@entity"/> + <xsl:variable name="entitykeyname" select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]/@name"/> + <input type="hidden"> + <xsl:attribute name="name"> + <xsl:value-of select="concat( 'instance.', @name)"/> + </xsl:attribute> + <xsl:attribute name="value"> + <xsl:value-of select="concat('$instance.', @name, '.', $entitykeyname)"/> + </xsl:attribute> + </input> + </xsl:when> + <xsl:otherwise> + <input type="hidden"> + <xsl:attribute name="name"> + <xsl:value-of select="concat( 'instance.', @name)"/> + </xsl:attribute> + <xsl:attribute name="value"> + <xsl:value-of select="concat('$instance.', @name)"/> + </xsl:attribute> + </input> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <table> + <tr align="left" valign="top" class="actionDangerous"> + <td class="actionDangerous"> + <xsl:call-template name="i18n-really-delete"/> + </td> + <td class="widget"> + <select name="reallydelete"> + <option value="false"> + <xsl:call-template name="i18n-really-delete-no"/> + </option> + <option value="true"> + <xsl:call-template name="i18n-really-delete-yes"/> + </option> + </select> + </td> + <td class="actionDangerous" style="text-align:right"> + <input type="submit" name="command" value="Go" /> + </td> + </tr> + </table> + </form> + </div> + </xsl:template> + + <!-- layout of forms --> + <xsl:template match="adl:form" mode="non-empty-layout"> + <xsl:variable name="form" select="."/> + <xsl:text> + </xsl:text> + <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( ancestor::adl:entity/@name, '/', @name)"/>.auto.vm' ]</xsl:comment> + <xsl:text> + </xsl:text> + #capturefor( title) + #if ( $instance) + #if ( ! $instance.IsNew) + <xsl:value-of select="concat( 'Edit ', ' ', ancestor::adl:entity/@name)"/> $instance.UserIdentifier + #else + <xsl:call-template name="i18n-add-a-new"> + <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> + </xsl:call-template> + #end + #else + <xsl:call-template name="i18n-add-a-new"> + <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> + </xsl:call-template> + #end + #end + #capturefor( headextras) + <xsl:comment> + Auto generated Velocity form for <xsl:value-of select="ancestor::adl:entity/@name"/>, + </xsl:comment> + <xsl:call-template name="head"/> + <xsl:call-template name="generate-head-javascript"> + <xsl:with-param name="form" select="."/> + <xsl:with-param name="locale" select="$locale"/> + </xsl:call-template> + + ${StylesHelper.InstallStylesheet( "Epoch")} + + <style type="text/css"> + <xsl:for-each select="ancestor::adl:entity//adl:property[@required='true']"> + #<xsl:value-of select="concat( 'advice-required-instance_', @name)"/> + { + color: white; + background-color: rgb( 198, 0, 57); + font-style: italic; + } + </xsl:for-each> + </style> + #end + #capturefor(bodyattributes) + onload="performInitialisation()" + #end + <xsl:call-template name="top"/> + <xsl:call-template name="form-content"> + <xsl:with-param name="form" select="."/> + </xsl:call-template> + <xsl:call-template name="foot"/> + </xsl:template> + + <xsl:template match="adl:form" mode="empty-layout"> + <xsl:variable name="form" select="."/> + <xsl:text> + </xsl:text> + <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( ancestor::adl:entity/@name, '/', @name)"/>.auto.vm' ]</xsl:comment> + <xsl:text> + </xsl:text> + <html> + <xsl:comment> + #if ( $instance) + #if ( ! $instance.IsNew) + #set( $title = "<xsl:value-of select="concat( 'Edit ', ' ', ancestor::adl:entity/@name)"/> $instance.UserIdentifier") + #else + #set( $title = "<xsl:call-template name="i18n-add-a-new"> + <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> + </xsl:call-template>") + #end + #else + #set( $title = "<xsl:call-template name="i18n-add-a-new"> + <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> + </xsl:call-template>") + #end + </xsl:comment> + <head> + <xsl:comment> + Auto generated Velocity form for <xsl:value-of select="ancestor::adl:entity/@name"/>, + </xsl:comment> + <xsl:call-template name="head"/> + <xsl:if test="$page-timeout > 0"> + <meta http-equiv="refresh" content="5; URL=http://www.cryer.co.uk"> + <xsl:attribute name="content"> + <xsl:value-of select="concat($page-timeout, '; URL=', $default-url)"/> + </xsl:attribute> + </meta> + </xsl:if> + <xsl:call-template name="install-scripts"/> + <xsl:call-template name="generate-head-javascript"> + <xsl:with-param name="form" select="."/> + <xsl:with-param name="locale" select="$locale"/> + </xsl:call-template> + + ${StylesHelper.InstallStylesheet( "Epoch")} + + <style type="text/css"> + <xsl:for-each select="ancestor::adl:entity//adl:property[@required='true']"> + #<xsl:value-of select="concat( 'advice-required-instance_', @name)"/> + { + color: white; + background-color: rgb( 198, 0, 57); + font-style: italic; + } + </xsl:for-each> + </style> + </head> + <body onload="performInitialisation()"> + <div id="page"> + <xsl:call-template name="top"/> + <xsl:call-template name="form-content"> + <xsl:with-param name="form" select="."/> + </xsl:call-template> + <xsl:call-template name="foot"/> + </div> + </body> + </html> + </xsl:template> + + <!-- the content of a form, whether or not the layout is empty --> + <xsl:template name="form-content"> + <!-- an entity of type form --> + <xsl:param name="form"/> + <div class="content"> + #if ( $instance.NoDeleteReason) + <ul class="errors"> + <li>$instance.NoDeleteReason</li> + </ul> + #end + <xsl:if test="$show-errors = 'true'"> + #if ( $errors) + #if ( $errors.Count != 0) + <ul class="errors"> + #foreach($e in $errors) + #if($e.Message) + <li>$t.Error($e)</li> + #else + <li>$t.Enc($e)</li> + #end + #end + </ul> + #end + #end + </xsl:if> + <xsl:if test="$show-messages = 'true'"> + #if( $messages) + #if ( $messages.Count != 0) + <ul class="information"> + #foreach ( $message in $messages) + <li>$message</li> + #end + </ul> + #end + #end + </xsl:if> + <form method="post" onsubmit="invokeSubmitHandlers(this);return trapEnterSubmissions(event, this);" onkeypress="trapKeyPress(event, this)" class="tabbed"> + <xsl:attribute name="action"> + <xsl:value-of select="concat( $form/@name, 'SubmitHandler.rails')"/> + </xsl:attribute> + <xsl:attribute name="name"> + <xsl:value-of select="$form/@name"/> + </xsl:attribute> + <xsl:attribute name="id"> + <xsl:value-of select="$form/@name"/> + </xsl:attribute> + <xsl:attribute name="enctype"> + <xsl:choose> + <xsl:when test="$form/ancestor::adl:entity//adl:property[@type='uploadable']"> + <xsl:value-of select="'multipart/form-data'"/> + </xsl:when> + <xsl:when test="$form/ancestor::adl:entity//adl:property[@type='image']"> + <xsl:value-of select="'multipart/form-data'"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="'application/x-www-form-urlencoded'"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <input type="hidden" name="currentpane" value="$!currentpane" /> + <xsl:for-each select="$form/ancestor::adl:entity/adl:key/adl:property"> + <xsl:variable name="keyname" select="@name"/> + <xsl:choose> + <xsl:when test="$form//adl:field[@property=$keyname]"> + <!-- it's already a field of the form - no need to add a hidden one --> + </xsl:when> + <xsl:otherwise> + <!-- create a hidden widget for the natural primary key --> + #if ( $instance) + #if ( ! ( $instance.IsNew)) + ${FormHelper.HiddenField( "instance.<xsl:value-of select="$keyname"/>")} + #end + #end + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <xsl:apply-templates select="$form/adl:fieldgroup"/> + <div class="non-pane"> + <table> + <xsl:choose> + <xsl:when test="@properties='listed'"> + <xsl:apply-templates select="$form/adl:field|adl:auxlist"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$form/ancestor::adl:entity/adl:property"/> + </xsl:otherwise> + </xsl:choose> + </table> + <ul class="verbs"> + <xsl:apply-templates select="adl:verb"/> + <xsl:choose> + <xsl:when test="$authentication-layer='Database'"> + <xsl:variable name="savegroups"> + <xsl:call-template name="entity-save-groups"> + <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="updategroups"> + <xsl:call-template name="entity-update-groups"> + <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> + </xsl:call-template> + </xsl:variable> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause + cause the Velocity parser to break! --> + #if ( $instance) + #if ( $instance.IsNew) + #if ( <xsl:for-each select="exsl:node-set( $savegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:call-template name="save-widget-row"/> + #end + #else + #if ( <xsl:for-each select="exsl:node-set( $updategroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) + <xsl:call-template name="save-widget-row"/> + #end + #end + #else + <!-- for application-layer authentication, we may not actually have an instance at this stage --> + #if ( <xsl:for-each select="exsl:node-set( $savegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) + <xsl:call-template name="save-widget-row"/> + #end + #end + <xsl:variable name="deletegroups"> + <xsl:call-template name="entity-delete-groups"> + <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> + </xsl:call-template> + </xsl:variable> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause + cause the Velocity parser to break! --> + #if ( <xsl:for-each select="exsl:node-set( $deletegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) + <xsl:call-template name="delete-widget-row"/> + #end + </xsl:when> + <xsl:when test="$authentication-layer='Application'"> + <xsl:call-template name="save-widget-row"/> + <xsl:call-template name="delete-widget-row"/> + </xsl:when> + </xsl:choose> + </ul> + </div> + </form> + </div> + </xsl:template> + + <!-- output a complete table row containing a save widget --> + <xsl:template name="save-widget-row"> + <li class="standard-verb actionSafe"> + <button type="submit" name="command" value="store"> + <xsl:attribute name="title"> + <xsl:call-template name='i18n-save-prompt'/> + </xsl:attribute> + Save + </button> + </li> + </xsl:template> + + <!-- output a complete table row containing a delete widget --> + <xsl:template name="delete-widget-row"> + <li class="standard-verb actionDangerous"> + #if ( $instance) + #if ( !$instance.IsNew) + #if ( $instance.NoDeleteReason) + <button type="submit" disabled="disabled" title="$instance.NoDeleteReason" name="command" value="delete">Delete this</button> + #else + <button type="submit" name="command" value="delete"> + <xsl:attribute name="title"> + <xsl:call-template name="i18n-delete-prompt"/> + </xsl:attribute> + Delete this + </button> + #end + #end + #end + </li> + </xsl:template> + + <xsl:template match="adl:fieldgroup"> + <xsl:if test="$authentication-layer = 'Database'"> + <xsl:variable name="property" select="."/> + <xsl:variable name="readgroups"> + <xsl:call-template name="fieldgroup-read-groups"> + <xsl:with-param name="fieldgroup" select="."/> + </xsl:call-template> + </xsl:variable> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause cause the Velocity parser to break! --> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + </xsl:if> + + <div class="tab-pane"> + <xsl:attribute name="id"> + <xsl:value-of select="concat( @name, 'pane')"/> + </xsl:attribute> + <xsl:attribute name="style"> + <xsl:choose> + <xsl:when test="position() = 1"/> + <xsl:otherwise>display: none</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <h3 class="title"> + <xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@name"/> + <xsl:with-param name="entity" select="ancestor::adl:entity"/> + <xsl:with-param name="locale" select="$locale"/> + </xsl:call-template> + </h3> + <table> + <xsl:apply-templates select="adl:field|adl:auxlist"/> + </table> + <xsl:if test="adl:verb"> + <ul class="verbs"> + <xsl:apply-templates select="adl:verb"/> + </ul> + </xsl:if> + </div> + <xsl:if test="$authentication-layer = 'Database'"> + #end + </xsl:if> + </xsl:template> + + <xsl:template match="adl:auxlist"> + <xsl:variable name="listprop" select="@property"/> + <xsl:variable name="farent" select="ancestor::adl:entity//adl:property[@name=$listprop]/@entity"/> + <xsl:variable name="nearent" select="ancestor::adl:entity/@name"/> + <xsl:variable name="farid"> + <xsl:value-of select="//adl:entity[@name=$farent]/adl:key//adl:property[position()=1]/@name"/> + </xsl:variable> + <xsl:variable name="farkey"> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$farent]//adl:property[@entity=$nearent]/@farkey"> + <xsl:value-of select="//adl:entity[@name=$farent]//adl:property[@entity=$nearent]/@farkey"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="//adl:entity[@name=$farent]//adl:property[@entity=$nearent]/@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="nearkey"> + <xsl:choose> + <xsl:when test="ancestor::adl:entity/adl:key/adl:property[position()=1 and @type='entity']"> + <xsl:value-of select="concat( ancestor::adl:entity/adl:key/adl:property[position()=1]/@name, '_Value')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="ancestor::adl:entity/adl:key/adl:property[position()=1]/@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="action" select="concat( '../', $farent, '/', @onselect)"/> + <xsl:if test="@canadd='true'"> + <tr> + <td> + <xsl:attribute name="colspan"> + <xsl:value-of select="count( field)"/> + </xsl:attribute> + <a> + <xsl:attribute name="href"> + <xsl:value-of select="concat( $action, 'With', $farkey, '.rails?', $farkey, '=$instance.', $nearkey)"/> + </xsl:attribute> + <xsl:call-template name="i18n-add-a-new"> + <xsl:with-param name="entity-name" select="$farent"/> + </xsl:call-template> + </a> + </td> + </tr> + </xsl:if> + <tr> + <td> + <xsl:attribute name="colspan"> + <xsl:value-of select="count( field)"/> + </xsl:attribute> + + <xsl:choose> + <xsl:when test="@properties='listed'"> + <xsl:comment>auxlist with listed fields: <xsl:value-of select="$farent/@name"/></xsl:comment> + <xsl:call-template name="internal-with-fields-list"> + <xsl:with-param name="entity" select="//adl:entity[@name=$farent]"/> + <xsl:with-param name="fields" select="adl:field"/> + <xsl:with-param name="instance-list" select="concat( 'instance.', $listprop)"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:comment>auxlist with computed fields: <xsl:value-of select="$farent/@name"/></xsl:comment> + <xsl:call-template name="internal-with-properties-list"> + <xsl:with-param name="entity" select="//adl:entity[@name=$farent]"/> + <xsl:with-param name="properties" select="//adl:entity[@name=$farent]//adl:property[(@distinct='user' or @distinct='all') and not( @type='link' or @type='list')]"/> + <xsl:with-param name="instance-list" select="concat( 'instance.', $listprop)"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + </xsl:template> + + <xsl:template match="adl:verb"> + <xsl:variable name="executegroups"> + <xsl:call-template name="verb-execute-groups"> + <xsl:with-param name="verb" select="."/> + </xsl:call-template> + </xsl:variable> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause + cause the Velocity parser to break! --> + #if ( <xsl:for-each select="exsl:node-set( $executegroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:variable name="class"> + <xsl:choose> + <xsl:when test="@dangerous='true'">actionDangerous</xsl:when> + <xsl:otherwise>actionSafe</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <!-- don't emit a verb unless there is an instance for it to act on --> + #if( $instance) + #if( ! $instance.IsNew) + <li> + <xsl:attribute name="class"> + <xsl:value-of select="concat( 'custom-verb ', $class)"/> + </xsl:attribute> + <button name="command"> + <xsl:attribute name="value"> + <xsl:value-of select="@verb"/> + </xsl:attribute> + <xsl:attribute name="title"> + <xsl:apply-templates select="adl:help[@locale = $locale]"/> + </xsl:attribute> + <xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@verb"/> + </xsl:call-template> + </button> + </li> + #end + #end + #end + </xsl:template> + + <xsl:template match="adl:field"> + <xsl:variable name="propname"> + <xsl:value-of select="@property"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="ancestor::adl:entity//adl:property[@name=$propname]"> + <!-- there is a real property --> + <xsl:apply-templates select="ancestor::adl:entity//adl:property[@name=$propname]"> + <xsl:with-param name="oddness"> + <xsl:choose> + <xsl:when test="position() mod 2 = 0">even</xsl:when> + <xsl:otherwise>odd</xsl:otherwise> + </xsl:choose> + </xsl:with-param> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <!-- it's presumably intended to be a computed field --> + <xsl:comment> + Computed field (<xsl:value-of select="$propname"/>)? TODO: Not yet implememented + </xsl:comment> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="adl:property[@type='message']"> + <!-- HIHGLY experimental - an internationalised message --> + <xsl:param name="oddness" select="odd"/> + <tr> + <xsl:attribute name="class"> + <xsl:value-of select="$oddness"/> + </xsl:attribute> + <td class="label"> + ${FormHelper.LabelFor( "instance.<xsl:value-of select="@name"/>", "<xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@name"/> + </xsl:call-template>")} + </td> + <td class="widget" colspan="2"> + #if( $instance) + #if( <xsl:value-of select="concat( '$instance.', @name)"/>) + <xsl:value-of select="concat( '$t.Msg( $instance.', @name, ')')"/> + #else + <input type="text"> + <xsl:attribute name="name"> + <xsl:value-of select="concat('i18n.instance.', @name)"/> + </xsl:attribute> + </input> + #end + #else + <input type="text"> + <xsl:attribute name="name"> + <xsl:value-of select="concat('i18n.instance.', @name)"/> + </xsl:attribute> + </input> + #end + </td> + </tr> + </xsl:template> + + <xsl:template match="adl:property[@type='link'or @type='list']"> + <!-- note! this template is only intended to match properties in the context of a form: + it may be we need to add a mode to indicate this! --> + <!-- for links and lists we implement a shuffle widget, which extends over both columns --> + <xsl:param name="oddness" select="odd"/> + <xsl:if test="$authentication-layer = 'Database'"> + <xsl:variable name="property" select="."/> + <xsl:variable name="readgroups"> + <xsl:call-template name="entity-read-groups"> + <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> + </xsl:call-template> + </xsl:variable> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause cause the Velocity parser to break! --> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) + </xsl:if> + <tr> + <xsl:attribute name="class"> + <xsl:value-of select="$oddness"/> + </xsl:attribute> + <td class="label" rowspan="2"> + ${FormHelper.LabelFor( "instance.<xsl:value-of select="@name"/>", "<xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@name"/> + </xsl:call-template>")} + </td> + <td class="widget shuffle" colspan="2"> + <xsl:call-template name="shuffle-widget"> + <xsl:with-param name="property" select="."/> + </xsl:call-template> + </td> + </tr> + <tr> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="position() mod 2 = 0">even</xsl:when> + <xsl:otherwise>odd</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <td class="help" colspan="2"> + <xsl:apply-templates select="adl:help[@locale = $locale]"/> + </td> + </tr> + <xsl:if test="$authentication-layer = 'Database'"> + #end + </xsl:if> + </xsl:template> + + <xsl:template name="shuffle-widget"> + <xsl:param name="property" select="."/> + #if ( $instance) + #if ( ! $instance.IsNew) + <table class="shuffle"> + <tr> + <td class="widget shuffle-all" rowspan="2"> + ${ShuffleWidgetHelper.UnselectedOptions( "<xsl:value-of select="concat( $property/@name, '_unselected')"/>", <xsl:value-of select="concat( '$all_', $property/@name)"/>, $instance.<xsl:value-of select="$property/@name"/>)} + </td> + <td class="widget shuffle-action"> + <input type="button" value="include >>"> + <xsl:attribute name="onclick"> + <xsl:value-of select="concat( 'shuffle(', $property/@name, '_unselected, ', $property/@name, ')')"/> + </xsl:attribute> + </input> + </td> + <td class="widget shuffle-selected" rowspan="2"> + <xsl:variable name="entityname" select="$property/@entity"/> + <xsl:variable name="foreignkey" select="$property/@farkey"/> + <xsl:variable name="allow-shuffle-back"> + <xsl:choose> + <xsl:when test="$property/@type='list' and //adl:entity[@name=$entityname]//adl:property[@name=$foreignkey and @required='true']"> + <xsl:value-of select="'false'"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="'true'"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + ${ShuffleWidgetHelper.SelectedOptions( "<xsl:value-of select="$property/@name"/>", $instance.<xsl:value-of select="$property/@name"/>, <xsl:value-of select="$allow-shuffle-back"/>)} + </td> + </tr> + <tr> + <td class="widget shuffle-action"> + <input type="button" value="<< exclude"> + <xsl:attribute name="onclick"> + <xsl:value-of select="concat( 'shuffle(', @name, ', ', @name, '_unselected)')"/> + </xsl:attribute> + </input> + </td> + </tr> + </table> + #else + <i>You must create your <xsl:value-of select="$property/ancestor::adl:entity/@name"/> record before you can add <xsl:value-of select="$property/@name"/> to it</i> + #end + #end + </xsl:template> + + <xsl:template match="adl:property"> + <xsl:param name="oddness" select="odd"/> + <!-- note! this template is only intended to match properties in the context of a form: + it may be we need to add a mode to indicate this! --> + <xsl:variable name="property" select="."/> + <xsl:variable name="editgroups"> + <xsl:call-template name="property-edit-groups"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="insertgroups"> + <xsl:call-template name="property-insert-groups"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="readgroups"> + <xsl:call-template name="property-read-groups"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:if test="$authentication-layer = 'Database'"> + <xsl:choose> + <xsl:when test="exsl:node-set( $readgroups)/*"> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} || </xsl:for-each> false) + </xsl:when> + <xsl:otherwise> + <xsl:comment>we haven't found any group of users who are entitled to see this field.</xsl:comment> + #if ( false) + </xsl:otherwise> + </xsl:choose> + </xsl:if> + <tr> + <xsl:attribute name="class"> + <xsl:value-of select="$oddness"/> + </xsl:attribute> + <td class="label"> + ${FormHelper.LabelFor( "instance.<xsl:value-of select="@name"/>", "<xsl:call-template name="showprompt"> + <xsl:with-param name="fallback" select="@name"/> + </xsl:call-template>")} + </td> + <td class="widget"> + <xsl:choose> + <xsl:when test="$authentication-layer = 'Application'"> + <xsl:call-template name="property-widget"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="mode" select="'Editable'"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$authentication-layer = 'Database'"> + <xsl:if test="exsl:node-set( $editgroups)/*"> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause + cause the Velocity parser to break! --> + #if ( <xsl:for-each select="exsl:node-set( $editgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:choose> + <xsl:when test="$property/@immutable='true'"> + <xsl:call-template name="property-widget"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="mode" select="'Immutable'"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="property-widget"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="mode" select="'Editable'"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + #else + </xsl:if> + <xsl:if test="exsl:node-set( $insertgroups)/*"> + #if ( <xsl:for-each select="exsl:node-set( $insertgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:call-template name="property-widget"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="mode" select="'Immutable'"/> + </xsl:call-template> + #else + </xsl:if> + <xsl:if test="exsl:node-set( $readgroups)/*"> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:call-template name="property-widget"> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="mode" select="'DisplayAndHidden'"/> + </xsl:call-template> + #else + </xsl:if> + [Not authorised] + <xsl:if test="exsl:node-set( $readgroups)/*"> + #end + </xsl:if> + <xsl:if test="exsl:node-set( $insertgroups)/*"> + #end + </xsl:if> + <xsl:if test="exsl:node-set( $editgroups)/*"> + #end + </xsl:if> + </xsl:when> + </xsl:choose> + </td> + <td class="help"> + <xsl:apply-templates select="adl:help[@locale = $locale]"/> + </td> + </tr> + <xsl:if test="$authentication-layer = 'Database'"> + #end + </xsl:if> + + </xsl:template> + + + <!-- layout of lists --> + <!-- layout of a list assuming a non-empty layout --> + <xsl:template match="adl:list" mode="non-empty-layout"> + <xsl:text> + </xsl:text> + <xsl:comment> [ cut here: next file '<xsl:value-of select="concat( ../@name, '/', @name)"/>.auto.vm' ]</xsl:comment> + <xsl:text> + </xsl:text> + <xsl:variable name="withpluralsuffix"> + <xsl:call-template name="i18n-plural"> + <xsl:with-param name="noun" select="ancestor::adl:entity/@name"/> + </xsl:call-template> + </xsl:variable> + + #capturefor( title) + <xsl:value-of select="normalize-space( concat( 'List ', $withpluralsuffix))"/> + #end + #capturefor( headextras) + <xsl:comment> + Auto generated Velocity list for <xsl:value-of select="ancestor::adl:entity/@name"/>, + </xsl:comment> + <xsl:call-template name="head"/> + #end + <xsl:call-template name="top"/> + <xsl:call-template name="list"> + <xsl:with-param name="list" select="."/> + </xsl:call-template> + <xsl:call-template name="foot"/> + </xsl:template> + + + <xsl:template match="adl:option"> + <option> + <xsl:attribute name="value"> + <xsl:value-of select="@value"/> + </xsl:attribute> + <xsl:attribute name="id"> + <xsl:value-of select="concat( ancestor::adl:property/@name, '-', @value)"/> + </xsl:attribute> + <xsl:call-template name="showprompt"> + <xsl:with-param name="fallback" select="@value"/> + </xsl:call-template> + </option> + </xsl:template> + + + <!-- layout of a list assuming an empty layout --> + <xsl:template match="adl:list" mode="empty-layout"> + <xsl:variable name="action" select="@onselect"/> + <xsl:text> + </xsl:text> + <xsl:comment>[ cut here: next file '<xsl:value-of select="concat( ../@name, '/', @name)"/>.auto.vm' ]</xsl:comment> + <xsl:text> + </xsl:text> + <xsl:variable name="withpluralsuffix"> + <xsl:call-template name="i18n-plural"> + <xsl:with-param name="noun" select="ancestor::adl:entity/@name"/> + </xsl:call-template> + </xsl:variable> + <html> + <head> + #set( $title = "<xsl:value-of select="normalize-space( concat( 'List ', $withpluralsuffix))"/>") + <xsl:comment> + Auto generated Velocity list for <xsl:value-of select="ancestor::adl:entity/@name"/>, + </xsl:comment> + <xsl:call-template name="head"/> + <xsl:call-template name="install-scripts"/> + </head> + <body> + <div id="page"> + <xsl:call-template name="top"/> + <xsl:call-template name="list"> + <xsl:with-param name="list" select="."/> + </xsl:call-template> + <xsl:call-template name="foot"/> + </div> + </body> + </html> + </xsl:template> + + <!-- layout the content of a list, whether or not the layout is empty --> + <xsl:template name="list"> + <!-- an entity of type adl:list --> + <xsl:param name="list"/> + <div class="content"> + <div class="controls"> + <span class="pagination status"> + Showing $instances.FirstItem - $instances.LastItem of $instances.TotalItems + </span> + #if ( <xsl:for-each select="adl:field"> + <xsl:variable name="field" select="."/> + <xsl:variable name="search-name" + select="concat('$search_', ancestor::adl:entity//adl:property[@name=$field/@property]/@name)"/> + <xsl:value-of select="$search-name"/> + <xsl:if test="not( position() = last())">||</xsl:if> + </xsl:for-each> ) + <span class="pagination status">(Suppressing pagination in favour of search)</span> + #else + <span class="pagination control"> + #if($instances.HasFirst) + $PaginationHelper.CreatePageLink( 1, "<<" ) + #end + #if(!$instances.HasFirst) << #end + </span> + <span class="pagination control"> + #if($instances.HasPrevious) $PaginationHelper.CreatePageLink( $instances.PreviousIndex, "<" ) #end + #if(!$instances.HasPrevious) < #end + </span> + <span class="pagination control"> + #if($instances.HasNext) $PaginationHelper.CreatePageLink( $instances.NextIndex, ">" ) #end + #if(!$instances.HasNext) > #end + </span> + <span class="pagination control"> + #if($instances.HasLast) $PaginationHelper.CreatePageLink( $instances.LastIndex, ">>" ) #end + #if(!$instances.HasLast) >> #end + </span> + #end + <xsl:if test="$list/../adl:form"> + <span class="add"> + <a> + <xsl:attribute name="href"> + <xsl:value-of select="concat( ancestor::adl:entity/adl:form[position()=1]/@name, '.rails')"/> + </xsl:attribute> + <xsl:call-template name="i18n-add-a-new"> + <xsl:with-param name="entity-name" select="ancestor::adl:entity/@name"/> + </xsl:call-template> + </a> + </span> + </xsl:if> + </div> + <form> + <xsl:attribute name="action"> + <xsl:value-of select="concat( $list/@name, '.rails')"/> + </xsl:attribute> + <xsl:call-template name="internal-with-fields-list"> + <xsl:with-param name="entity" select="$list/ancestor::adl:entity"/> + <xsl:with-param name="fields" select="$list/adl:field"/> + <xsl:with-param name="can-search" select="'true'"/> + </xsl:call-template> + </form> + </div> + </xsl:template> + + <xsl:template name="internal-with-fields-list"> + <!-- a node-list of entities of type 'adl:field' or 'adl:field', each indicating a property + of the same entity, to be shown in columns of this list --> + <xsl:param name="fields"/> + <!-- the entity of type 'adl:entity' on which the properties for all those fields can be found --> + <xsl:param name="entity"/> + <!-- the name of the list of instances of this entity, available to Velocity at runtime + as an ICollection, which is to be layed out in this list --> + <xsl:param name="instance-list" select="'instances'"/> + <!-- NOTE NOTE NOTE: To be searchable, internal-with-fields-list must not only be called with can-search + equal to 'true', but also within a form! --> + <!-- NOTE NOTE NOTE: It's obvious that internal-with-fields-list and internal-with-properties-list + ought to be replaced with a single template, but that template proves to be extremely hard to get + right --> + <xsl:param name="can-search"/> + <table class="sortable" id="concat($entity/@name, '-list')"> + <tr> + <xsl:for-each select="$fields"> + <xsl:variable name="field" select="."/> + <th> + <xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@property"/> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="locale" select="$locale"/> + </xsl:call-template> + </th> + </xsl:for-each> + <xsl:for-each select="$entity/adl:form"> + <th class="unsortable">-</th> + </xsl:for-each> + </tr> + <xsl:if test="$can-search = 'true'"> + <tr class="search sorttop"> + <xsl:for-each select="$fields"> + <xsl:variable name="field" select="."/> + <td class="search"> + <xsl:variable name="size"> + <xsl:choose> + <!-- can't search non-concrete fields --> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@concrete='false'">0</xsl:when> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='string'"> + <xsl:choose> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@size > 20">20</xsl:when> + <xsl:otherwise> + <xsl:value-of select="$entity//adl:property[@name=$field/@property]/@size"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='integer'">8</xsl:when> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='real'">8</xsl:when> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='money'">8</xsl:when> + <!-- xsl:when test="$entity//adl:property[@name=$field/@property]/@type='message'">20</xsl:when doesn't work yet --> + <xsl:when test="$entity//adl:property[@name=$field/@property]/@type='text'">20</xsl:when> + <!-- xsl:when test="$entity//adl:property[@name=$field/@property]/@type='enity'">20</xsl:when doesn't work yet --> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:if test="$size != 0"> + <input> + <xsl:variable name="search-name" select="concat('search_',$entity//adl:property[@name=$field/@property]/@name)"/> + <xsl:attribute name="name"> + <xsl:value-of select="$search-name"/> + </xsl:attribute> + <xsl:attribute name="size"> + <xsl:choose> + <xsl:when test="$size > 8">8</xsl:when> + <xsl:otherwise> + <xsl:value-of select="$size"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:attribute name="value"> + <xsl:value-of select="concat( '$!', $search-name)"/> + </xsl:attribute> + </input> + </xsl:if> + </td> + </xsl:for-each> + <td> + <input type="submit" name="search-button" value="Search"/> + </td> + </tr> + </xsl:if> + <xsl:if test="not( $entity/@name)"> + <xsl:message terminate="yes"> + Unknown entity whilst trying to generate list + </xsl:message> + </xsl:if> + <xsl:variable name="readgroups"> + <xsl:call-template name="entity-read-groups"> + <xsl:with-param name="entity" select="$entity"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$authentication-layer = 'Application'"> + <xsl:call-template name="internal-with-fields-rows"> + <xsl:with-param name="instance-list" select="$instance-list"/> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="fields" select="$fields"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$authentication-layer = 'Database'"> + <!-- NOTE NOTE NOTE: This is whitespace-sensitive! --> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:call-template name="internal-with-fields-rows"> + <xsl:with-param name="instance-list" select="$instance-list"/> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="fields" select="$fields"/> + </xsl:call-template> + #else + <tr> + <td colspan="5">[You are not authorised to view this data]</td> + </tr> + #end + </xsl:when> + </xsl:choose> + </table> + </xsl:template> + + <xsl:template name="internal-with-fields-rows"> + <xsl:param name="instance-list"/> + <xsl:param name="entity"/> + <xsl:param name="fields"/> + #foreach( <xsl:value-of select="concat( '$', $entity/@name)"/> in <xsl:value-of select="concat('$', $instance-list)"/>) + #if ( $velocityCount % 2 == 0) + #set( $oddity = "even") + #else + #set( $oddity = "odd") + #end + <tr class="$oddity"> + <xsl:for-each select="$fields"> + <xsl:variable name="field" select="."/> + <xsl:call-template name="list-field"> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="property" select="$entity//adl:property[@name=$field/@property]"/> + <xsl:with-param name="objectvar" select="$entity/@name"/> + </xsl:call-template> + </xsl:for-each> + <xsl:variable name="keys"> + <xsl:call-template name="entity-keys-fragment"> + <xsl:with-param name="entity" select="$entity"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="$entity/adl:form"> + <!-- by default create a link to each form declared for the entity. + We probably need a means of overriding this --> + <td> + <a> + <xsl:attribute name="href"> + <xsl:value-of select="concat( '../', $entity/@name, '/', @name, '.rails', $keys)"/> + </xsl:attribute> + <xsl:value-of select="@name"/> + </a> + </td> + </xsl:for-each> + </tr> + #end + </xsl:template> + + <xsl:template name="internal-with-properties-list"> + <!-- a node-list of entities of type 'adl:property', each a property of the same entity, to be shown + in columns of this list --> + <xsl:param name="properties"/> + <!-- the entity of type 'adl:entity' on which the properties for all those fields can be found --> + <xsl:param name="entity"/> + <!-- the name of the list of instances of this entity, available to Velocity at runtime + as an ICollection, which is to be layed out in this list --> + <xsl:param name="instance-list" select="'instances'"/> + <!-- NOTE NOTE NOTE: To be searchable, internal-with-properties-list must not only be called with can-search + equal to 'true', but also within a form! --> + <!-- NOTE NOTE NOTE: It's obvious that internal-with-fields-list and internal-with-properties-list + ought to be replaced with a single template, but that template proves to be extremely hard to get + right --> + <xsl:param name="can-search"/> + <table class="sortable"> + <tr> + <xsl:for-each select="$properties"> + <th> + <xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@name"/> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="locale" select="$locale"/> + </xsl:call-template> + </th> + </xsl:for-each> + <xsl:for-each select="$entity/adl:form"> + <th>-</th> + </xsl:for-each> + </tr> + <xsl:if test="$can-search = 'true'"> + <tr class="search"> + <xsl:for-each select="$properties"> + <td class="search"> + <xsl:variable name="size"> + <xsl:choose> + <xsl:when test="@type='string'"> + <xsl:choose> + <xsl:when test="@size > 8">8</xsl:when> + <xsl:otherwise> + <xsl:value-of select="@size"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="@type='integer'">8</xsl:when> + <xsl:when test="@type='real'">8</xsl:when> + <xsl:when test="@type='money'">8</xsl:when> + <!-- xsl:when test="@type='message'">20</xsl:when doesn't work yet --> + <xsl:when test="@type='text'">8</xsl:when> + <!-- xsl:when test="@type='enity'">20</xsl:when doesn't work yet --> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:if test="$size != 0"> + <input> + <xsl:attribute name="name"> + <xsl:value-of select="concat('search_', @name)"/> + </xsl:attribute> + <xsl:attribute name="size"> + <xsl:value-of select="$size"/> + </xsl:attribute> + <xsl:attribute name="value"> + <xsl:value-of select="concat( '$!search_', @name)"/> + </xsl:attribute> + </input> + </xsl:if> + </td> + </xsl:for-each> + <td> + <input type="submit" name="search-button" size="8" value="Search"/> + </td> + </tr> + </xsl:if> + #foreach( <xsl:value-of select="concat( '$', $entity/@name)"/> in <xsl:value-of select="concat('$', $instance-list)"/>) + #if ( $velocityCount % 2 == 0) + #set( $oddity = "even") + #else + #set( $oddity = "odd") + #end + <tr class="$oddity"> + <xsl:for-each select="$properties"> + <xsl:call-template name="list-field"> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="property" select="."/> + <xsl:with-param name="objectvar" select="$entity/@name"/> + </xsl:call-template> + </xsl:for-each> + <xsl:variable name="keys"> + <!-- assemble keys in a Velocity-friendly format, then splice it into + the HREF below --> + <xsl:for-each select="$entity/adl:key/adl:property"> + <xsl:variable name="sep"> + <xsl:choose> + <xsl:when test="position()=1">?</xsl:when> + <xsl:otherwise>&</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="@type='entity'"> + <xsl:value-of select="concat( $sep, @name, '=$', $entity/@name, '.', @name, '_Value')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat( $sep, @name, '=$', $entity/@name, '.', @name)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </xsl:variable> + <xsl:for-each select="$entity/adl:form"> + <!-- by default create a link to each form declared for the entity. + We probably need a means of overriding this --> + <td> + <a> + <xsl:attribute name="href"> + <xsl:value-of select="concat( '../', $entity/@name, '/', @name, '.rails', $keys)"/> + </xsl:attribute> + <xsl:value-of select="@name"/> + </a> + </td> + </xsl:for-each> + </tr> + #end + </table> + </xsl:template> + + <!-- output a list field --> + <xsl:template name="list-field"> + <xsl:param name="entity"/> + <xsl:param name="property"/> + <xsl:param name="objectvar" select="instance"/> + <xsl:variable name="readgroups"> + <xsl:call-template name="property-read-groups"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <td> + <xsl:choose> + <xsl:when test="$authentication-layer = 'Application'"> + <xsl:call-template name="list-field-inner"> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="objectvar" select="$objectvar"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$authentication-layer = 'Database'"> + <!-- NOTE NOTE NOTE: This is whitespace-sensitive! --> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + <xsl:if test="$property/@type='entity'"> + <!-- right, this is horrible. You can't read the field unless you can read the property; + but even if you can read the property, if its an entity property you still can't read it + unless you can also read the entity --> + <xsl:variable name="entityreadgroups"> + <xsl:call-template name="entity-read-groups"> + <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> + </xsl:call-template> + </xsl:variable> + #if ( <xsl:for-each select="exsl:node-set( $entityreadgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + </xsl:if> + <xsl:call-template name="list-field-inner"> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="objectvar" select="$objectvar"/> + </xsl:call-template> + <xsl:if test="$property/@type='entity'"> + #else + [Not authorised] + #end + </xsl:if> + #else + [Not authorised] + #end + </xsl:when> + </xsl:choose> + </td> + </xsl:template> + + <xsl:template name="list-field-inner"> + <xsl:param name="entity"/> + <xsl:param name="property"/> + <xsl:param name="objectvar" select="instance"/> + <xsl:choose> + <xsl:when test="$property/adl:option"> + <xsl:for-each select="$property/adl:option"> + <xsl:variable name="val"> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$base-type = 'string'"> + <xsl:value-of select="concat( '"', @value, '"')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@value"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + #if( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/> == <xsl:value-of select="$val"/>) + <xsl:call-template name="showprompt"> + <xsl:with-param name="node" select="."/> + <xsl:with-param name="fallback" select="@value"/> + </xsl:call-template> + #end + </xsl:for-each> + </xsl:when> + <xsl:when test="$property/@type = 'image'"> + #if ( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) + <img class="thumbnail" alt="thumbnail"> + <xsl:attribute name="src"> + <xsl:value-of select="normalize-space(concat( '../Uploads/$', $entity/@name, '.', $property/@name))"/> + </xsl:attribute> + </img> + #end + </xsl:when> + <xsl:when test="$property/@type = 'date'"> + #if ( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) + <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>.ToString( 'd') + #end + </xsl:when> + <xsl:when test="$property/@type='message'"> + #if ( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) + $t.Msg( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) + #end + </xsl:when> + <xsl:when test="$property/@type='entity'"> + #if( <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name)"/>) + <xsl:value-of select="concat( '$', $entity/@name, '.', $property/@name, '.UserIdentifier')"/> + #end + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat( '$!', $entity/@name, '.', $property/@name)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- generate head javascript for a form --> + <xsl:template name="generate-head-javascript"> + <xsl:param name="form"> + <!-- assumed to be an instance of adl:form --> + </xsl:param> + <xsl:param name="locale"/> + <script type='text/javascript' language='JavaScript1.2'> + #if ( ${site-root}) + var siteRoot = '$siteRoot'; + #else + var siteRoot = '<xsl:value-of select='$site-root'/>'; + #end + + var enterPressed = false; + + function trapKeyPress(event, form){ + if(event.which == 13){ + enterPressed = true; + } else { + enterPressed = false; + } + } + + function trapEnterSubmissions(event, form){ + if(enterPressed){ + enterPressed = false; //we have trapped this, can stand down + return false; + } + } + + function performInitialisation() + { + #if ( $instance) + #if ( ! $instance.IsNew) + <xsl:for-each select="$form/ancestor::adl:entity/adl:property[@type='link' or @type='list']"> + <xsl:variable name="propname" select="@name"/> + <xsl:choose> + <xsl:when test="$form/@properties='all'"> + <xsl:value-of select="concat( 'document.',$form/@name, '.', @name, '.submitHandler = shuffleSubmitHandler;')"/> + </xsl:when> + <xsl:when test="$form//adl:field[@property=$propname]"> + <xsl:value-of select="concat( 'document.',$form/@name, '.', @name, '.submitHandler = shuffleSubmitHandler;')"/> + </xsl:when> + <!-- if we're not doing all properties, and if this property is not the property of a field, + we /don't/ set up a submit handler. --> + </xsl:choose> + </xsl:for-each> + #end + #end + var validator = new Validation('<xsl:value-of select="$form/@name"/>', {immediate : true, useTitles : true}); + } + + <xsl:for-each select="//adl:typedef"> + <xsl:variable name="errormsg"> + <xsl:choose> + <xsl:when test="adl:help[@locale=$locale]"> + <xsl:apply-templates select="adl:help[@locale=$locale]"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="i18n-bad-format"> + <xsl:with-param name="format-name" select="@name"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + Validation.add( '<xsl:value-of select="concat('validate-custom-', @name)"/>', + '<xsl:value-of select="normalize-space( $errormsg)"/>', + { + <xsl:choose> + <xsl:when test="@pattern"> + pattern : new RegExp("<xsl:value-of select="@pattern"/>","gi")<xsl:if test="@size"> + , maxLength : <xsl:value-of select="@size"/> + </xsl:if> + </xsl:when> + <xsl:when test="@minimum"> + min : <xsl:value-of select="@minimum"/><xsl:if test="@maximum"> + , max : <xsl:value-of select="@maximum"/> + </xsl:if> + </xsl:when> + </xsl:choose> + }); + </xsl:for-each> + </script> + </xsl:template> + + <!-- this template outputs MOST types of widget, but NOT shuffle widgets --> + <xsl:template name="property-widget"> + <xsl:param name="property"/> + <xsl:param name="mode"/> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="href"> + <xsl:choose> + <xsl:when test="$property/@type='entity' and //adl:entity[@name=$property/@entity]/adl:form[@name='edit']"> + <!-- if this is an entity property, and the entity which it wraps has an edit form --> + <xsl:variable name="keys"> + <xsl:call-template name="entity-keys-fragment"> + <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> + <xsl:with-param name="instance" select="concat( 'instance.', $property/@name)"/> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="concat( '../', $property/@entity, '/edit.rails', $keys)"/> + </xsl:when> + </xsl:choose> + </xsl:variable> + <xsl:variable name="if-missing"> + <xsl:choose> + <xsl:when test="$property/adl:if-missing[@locale = $locale]"> + <xsl:value-of select="$property/adl:if-missing[@locale = $locale]"/> + </xsl:when> + <xsl:when test="$property/@required='true'"> + <xsl:call-template name="i18n-value-required"> + <xsl:with-param name="property-name" select="$property/@name"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$property/@type='defined'"> + <xsl:call-template name="i18n-value-defined"> + <xsl:with-param name="property-name" select="$property/@name"/> + <xsl:with-param name="definition-name" select="$property/@typedef"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$property/@type='entity'"> + <xsl:call-template name="i18n-value-entity"> + <xsl:with-param name="property-name" select="$property/@name"/> + <xsl:with-param name="entity-name" select="$property/@entity"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="i18n-value-type"> + <xsl:with-param name="property-name" select="$property/@name"/> + <xsl:with-param name="type-name" select="$property/@type"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="cssclass"> + <xsl:if test="$property/@required='true'">required </xsl:if> + <xsl:choose> + <xsl:when test="$property/@type='defined'"> + <xsl:choose> + <xsl:when test="//adl:typedef[@name=$property/@typedef]/@pattern"> + <xsl:value-of select="concat( 'validate-custom-', $property/@typedef)"/> + </xsl:when> + <xsl:when test="//adl:typedef[@name=$property/@typedef]/@minimum"> + <xsl:value-of select="concat( 'validate-custom-', $property/@typedef)"/> + </xsl:when> + </xsl:choose> + </xsl:when> + <xsl:when test="$base-type='integer'">validate-digits</xsl:when> + <xsl:when test="$base-type='real'">validate-number</xsl:when> + <xsl:when test="$base-type='money'">validate-number</xsl:when> + <xsl:when test="$base-type='date'">date-field validate-date</xsl:when> + </xsl:choose> + </xsl:variable> + <xsl:variable name="maxlength"> + <xsl:call-template name="base-size"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="size"> + <xsl:choose> + <xsl:when test="$maxlength > $max-widget-width"> + <xsl:value-of select="$max-widget-width"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$maxlength"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="rows"> + <!-- number of rows, if textarea emitted --> + <xsl:choose> + <xsl:when test="$base-type = 'text'">8</xsl:when> + <xsl:otherwise>1</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="cols"> + <!-- number of rows, if textarea emitted --> + <xsl:choose> + <xsl:when test="$base-type = 'text'"> + <xsl:value-of select="$max-widget-width"/> + </xsl:when> + <xsl:otherwise>10</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="required"> + <xsl:choose> + <xsl:when test="$property/@required='true'">true</xsl:when> + <xsl:otherwise>false</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="$property/adl:option"> + <!-- emit a menu of options --> + <!-- it would be better to do this through a field helper but I haven't yet worked out how --> + <select> + <xsl:attribute name="name"> + <xsl:value-of select="concat( 'instance.', $property/@name)"/> + </xsl:attribute> + <xsl:attribute name="id"> + <xsl:value-of select="concat( 'instance_', $property/@name)"/> + </xsl:attribute> + <xsl:attribute name="class"> + <xsl:value-of select="concat( 'instance.', $property/@name)"/> + </xsl:attribute> + <xsl:if test="not( $property/@required='true')"> + <option value="'-1'">[unselected]</option> + </xsl:if> + <xsl:apply-templates select="$property/adl:option"/> + </select> + <script type="text/javascript" language="javascript"> + // <![CDATA[ + #set ( <xsl:value-of select="concat( '$', $property/@name, '_sel_opt')"/>="<xsl:value-of select="concat( $property/@name, '-$instance.', $property/@name)"/>") + option = document.getElementById( "<xsl:value-of select="concat( '$', $property/@name, '_sel_opt')"/>"); + + if ( option != null) + { + option.selected = true; + } + // ]]> + </script> + + </xsl:when> + <xsl:when test="$property/@type = 'defined'"> + <!-- it would be better to do this through a field helper but I haven't yet worked out how --> + <xsl:variable name="definition" select="//adl:typedef[@name=$property/@typedef]"/> + <xsl:variable name="minimum" select="$definition/@minimum"/> + <xsl:choose> + <xsl:when test="$base-type='string'"> + ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} + </xsl:when> + <xsl:when test="string-length($definition/@minimum) > 0 and string-length( $definition/@maximum) > 0"> + <xsl:call-template name="slider-widget"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="minimum" select="$definition/@minimum"/> + <xsl:with-param name="maximum" select="$definition/@maximum"/> + </xsl:call-template> + ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="concat('slider, ', normalize-space($cssclass))"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} + </xsl:when> + <xsl:otherwise> + ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="$property/@type = 'entity'"> + <!-- once again, not only must you have access to the property but also to the entity --> + <xsl:variable name="readgroups"> + <xsl:call-template name="entity-read-groups"> + <xsl:with-param name="entity" select="//adl:entity[@name=$property/@entity]"/> + </xsl:call-template> + </xsl:variable> + <!-- NOTE! NOTE! NOTE! Whitespace is significant - any linefeeds inside the #if ( ) clause cause the Velocity parser to break! --> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*">${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(')"/> "<xsl:value-of select="concat( 'instance.', $property/@name)"/>", "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',href='<xsl:value-of select="normalize-space($href)"/>'}")} + #else + [Not authorised] + #end + </xsl:when> + <xsl:otherwise> + ${<xsl:value-of select="concat( $property/ancestor::adl:entity/@name, 'FieldHelper', '.', $mode, '(', '"instance.', $property/@name, '"')"/>, "%{class='<xsl:value-of select="normalize-space($cssclass)"/>',required='<xsl:value-of select="normalize-space( $required)"/>',title='<xsl:value-of select="normalize-space($if-missing)"/>',size='<xsl:value-of select="normalize-space($size)"/>',maxlength='<xsl:value-of select="normalize-space($maxlength)"/>',rows='<xsl:value-of select="normalize-space($rows)"/>',cols='<xsl:value-of select="normalize-space($cols)"/>',href='<xsl:value-of select="normalize-space($href)"/>',adltype='<xsl:value-of select="$property/@type"/>'}")} + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="slider-widget"> + <xsl:param name="property"/> + <xsl:param name="minimum" select="0"/> + <xsl:param name="maximum" select="100"/> + <xsl:if test="string-length( $minimum) > 0 and string-length( $maximum) > 0"> + <div style="width:200px; height:20px; background: transparent url(../images/slider-images-track-right.png) no-repeat top right;"> + <xsl:attribute name="id"> + <xsl:value-of select="concat( $property/@name, '-track')"/> + </xsl:attribute> + <div style="position: absolute; width: 5px; height: 20px; background: transparent url(../images/slider-images-track-left.png) no-repeat top left"> + <xsl:attribute name="id"> + <xsl:value-of select="concat( $property/@name, '-track-left')"/> + </xsl:attribute> + </div> + <div style="width:19px; height:20px;"> + <xsl:attribute name="id"> + <xsl:value-of select="concat( $property/@name, '-slider')"/> + </xsl:attribute> + <img src="../images/slider-images-handle.png" alt="" style="float: left;" /> + </div> + </div> + <script type="text/javascript" language="javascript"> + // <![CDATA[ + new Control.Slider('<xsl:value-of select="$property/@name"/>-slider','<xsl:value-of select="$property/@name"/>-track',{ + onSlide:function(v){$('<xsl:value-of select="concat( 'instance_', $property/@name)"/>').value = <xsl:value-of select="$minimum"/>+ Math.floor(v*(<xsl:value-of select="$maximum - $minimum"/>))} + }); + // ]]> + </script> + </xsl:if> + </xsl:template> + + <!-- assemble keys for this entity in a Velocity-friendly format, to splice into an HREF below --> + <xsl:template name="entity-keys-fragment"> + <xsl:param name="entity"/> + <xsl:param name="instance" select="$entity/@name"/> + <xsl:for-each select="$entity/adl:key/adl:property"> + <xsl:variable name="sep"> + <xsl:choose> + <xsl:when test="position()=1">?</xsl:when> + <xsl:otherwise>&</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="@type='entity'"> + <xsl:value-of select="concat( $sep, @name, '=$', $instance, '.', @name, '_Value')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat( $sep, @name, '=$', $instance, '.', @name)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </xsl:template> + + <!-- overall page layout --> + + <xsl:template match="adl:content"/> + + <xsl:template match="adl:help"> + <xsl:apply-templates/> + </xsl:template> + + <!-- assuming an empty layout, install all the standard scripts + which an ADL page may need --> + <xsl:template name="install-scripts"> + ${ScriptsHelper.InstallScript( "ShuffleWidget")} + + ${Ajax.InstallScripts()} + ${FormHelper.InstallScripts()} + ${Validation.InstallScripts()} + ${Scriptaculous.InstallScripts()} + ${DateTimeHelper.InstallScripts()} + + ${ScriptsHelper.InstallScript( "Sitewide")} + ${ScriptsHelper.InstallScript( "Behaviour")} + ${ScriptsHelper.InstallScript( "Epoch")} + ${ScriptsHelper.InstallScript( "Panes")} + ${ScriptsHelper.InstallScript( "SortTable")} + </xsl:template> + + <!-- standard header material - auto-timeout, etc --> + <xsl:template name="head"> + <xsl:comment> + <xsl:value-of select="/adl:application/@name"/> <xsl:value-of select="$product-version"/> - <xsl:value-of select="/adl:application/@revision"/> + Auto generated Velocity macro for <xsl:value-of select="@name"/>, + generated from ADL. + + Generated using adl2views.xslt <xsl:value-of select="substring( '$Revision: 1.66 $', 10)"/> + Generation parameters were: + area-name: <xsl:value-of select="$area-name"/> + default-url: <xsl:value-of select="$default-url"/> + generate-site-navigation: <xsl:value-of select="$generate-site-navigation"/> + layout-name: <xsl:value-of select="$layout-name"/> + locale: <xsl:value-of select="$locale"/> + max-widget-width: <xsl:value-of select="$max-widget-width"/> + product-version: <xsl:value-of select="$product-version"/> + page-timeout: <xsl:value-of select="$page-timeout"/> + show-errors: <xsl:value-of select="$show-errors"/> + show-messages: <xsl:value-of select="$show-messages"/> + </xsl:comment> + <xsl:if test="$page-timeout > 0"> + <meta http-equiv="refresh"> + <xsl:attribute name="content"> + <xsl:value-of select="concat($page-timeout, '; URL=', $default-url)"/> + </xsl:attribute> + </meta> + </xsl:if> + <xsl:choose> + <xsl:when test="adl:head"> + <xsl:for-each select="adl:head/*"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </xsl:when> + <xsl:otherwise> + <xsl:for-each select="//adl:content/adl:head/*"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- standard top area content on all pages (navigation, etc) --> + <xsl:template name="top"> + <xsl:choose> + <xsl:when test="adl:top"> + <xsl:for-each select="adl:top/*"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </xsl:when> + <xsl:otherwise> + <xsl:for-each select="//adl:content/adl:top/*"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + <xsl:if test="$authentication-layer = 'Database'"> + #if ( ${SecurityHelper.GetUserName()}) + <!-- the #else and #end of this #if is generated in the foot template --> + </xsl:if> + <xsl:variable name="current-entity" select="ancestor::adl:entity/@name"/> + <xsl:if test="$generate-site-navigation = 'true'"> + <ul class="generatednav"> + <xsl:for-each select="//adl:entity[adl:list[@name='list']]"> + <xsl:variable name="readgroups"> + <xsl:call-template name="page-read-groups"> + <xsl:with-param name="page" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:if test="$authentication-layer = 'Database'"> + #if ( <xsl:for-each select="exsl:node-set( $readgroups)/*"> ${SecurityHelper.InGroup( "<xsl:value-of select="./@name"/>")} ||</xsl:for-each> false) + </xsl:if> + <li> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="@name = $current-entity">selected-nav</xsl:when> + <xsl:otherwise>navigation</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <a> + <xsl:attribute name="href"> + <xsl:choose> + <xsl:when test="string-length( $site-root) > 0"> + <xsl:choose> + <xsl:when test="string-length( $area-name) > 0"> + <xsl:value-of select="concat( $site-root, '/', $area-name, '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat( $site-root, '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="string-length( $area-name) > 0"> + <xsl:value-of select="concat( '/', $area-name, '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat( '/', @name, '/', adl:list[position()=1]/@name, '.rails')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:call-template name="showprompt"> + <xsl:with-param name="fallback" select="@name"/> + <xsl:with-param name="entity" select="."/> + </xsl:call-template> + </a> + </li> + <xsl:if test="$authentication-layer = 'Database'"> + #end + </xsl:if> + </xsl:for-each> + </ul> + </xsl:if> + </xsl:template> + + <!-- standard footer on all pages; product identifier and version --> + <xsl:template name="foot"> + <xsl:if test="$authentication-layer = 'Database'"> + <!-- the #if for this #else and #end is generated in the head template --> + #else + <div class="content"> + <p> + To view this page you must first <a href="../dblogin/login.rails">Log in</a> + </p> + </div> + #end + </xsl:if> + <div class="pagefoot"> + <xsl:choose> + <xsl:when test="adl:foot"> + <xsl:for-each select="adl:foot/*"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </xsl:when> + <xsl:otherwise> + <xsl:for-each select="//adl:content/adl:foot/*"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + <p class="product-version"> + <xsl:value-of select="$product-version"/>; built with <xsl:value-of select="$authentication-layer"/>-layer authentication. + </p> + </div> + </xsl:template> + + <!-- if this node (default to current node) has a child of type prompt for the current locale, + show that prompt; else show the first prompt child with locale='default' if any; + else show the value of the fallback param --> + <xsl:template name="showprompt"> + <xsl:param name="fallback" select="'Unknown'"/> + <xsl:param name="node" select="."/> + <xsl:param name="entity" select="$node/ancestor::adl:entity"/> + <xsl:param name="locale" select="'en-GB'"/> + <xsl:choose> + <xsl:when test="$node/adl:prompt[@locale=$locale]"> + <xsl:value-of select="$node/adl:prompt[@locale=$locale][1]/@prompt"/> + </xsl:when> + <xsl:when test="$node/adl:prompt[@locale='default']"> + <xsl:value-of select="$node/adl:prompt[@locale='default'][1]/@prompt"/> + </xsl:when> + <xsl:when test="$node/@property"> + <!-- it's (probably) a field which doesn't have any prompt of its own - + fetch from its property --> + <xsl:variable name="propname" select="@property"/> + <xsl:call-template name="showprompt"> + <xsl:with-param name="fallback" select="$fallback"/> + <xsl:with-param name="node" select="$entity//adl:property[@name=$propname]"/> + <xsl:with-param name="entity" select="$entity"/> + <xsl:with-param name="locale" select="$locale"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$fallback"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- compose the list of search parameters to append to a pagination request; note that this does + not currently work but I have some hopes that in future it will and in the meantime it costs us + little --> + <xsl:template name="pagination-search-params"> + <xsl:param name="form" select="."/> + "%{<xsl:for-each select="$form/adl:field"> + <xsl:variable name="field" select="."/> + <xsl:variable name="search-name" + select="concat('search_',$form/ancestor::adl:entity//adl:property[@name=$field/@property]/@name)"/> + <xsl:value-of select="concat( $search-name, '=$', $search-name)"/> + <xsl:if test="not( position() = last())">,</xsl:if> + </xsl:for-each>}" + </xsl:template> + + <xsl:template match="groups"> + <xsl:apply-templates/> + </xsl:template> + + <!-- just copy anything we can't match --> + <xsl:template match="@* | node()"> + <xsl:copy> + <xsl:apply-templates select="@* | node()"/> + </xsl:copy> + </xsl:template> + </xsl:stylesheet> \ No newline at end of file diff --git a/transforms/base-type-include.xslt b/transforms/base-type-include.xslt index 4671480..4f43590 100755 --- a/transforms/base-type-include.xslt +++ b/transforms/base-type-include.xslt @@ -1,75 +1,75 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<!-- - Application Description Language framework - base-type-include.xslt - - (c) 2007 Cygnet Solutions Ltd - - An xsl transform intended to be included into other XSL stylesheets, - intended to keep lookup of the ADL base type from ADL properties in - one place for ease of maintenance - - $Author: sb $ - $Revision: 1.4 $ - $Date: 2010-01-12 17:20:17 $ - --> - -<xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - exclude-result-prefixes="adl"> - - - <!-- return the base ADL type of the property which is passed as a parameter --> - <xsl:template name="base-type"> - <xsl:param name="property"/> - <xsl:choose> - <xsl:when test="$property/@type='defined'"> - <xsl:variable name="definition"> - <xsl:value-of select="$property/@typedef"/> - </xsl:variable> - <xsl:value-of select="/adl:application/adl:typedef[@name=$definition]/@type"/> - </xsl:when> - <xsl:when test="$property/@type='serial'">integer</xsl:when> - <xsl:when test="$property/@type='message'">integer</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$property/@type"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- return the size of the type of the property which is passed as a parameter --> - <xsl:template name="base-size"> - <xsl:param name="property"/> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$property/@type='defined'"> - <xsl:variable name="definition"> - <xsl:value-of select="$property/@typedef"/> - </xsl:variable> - <xsl:value-of select="/adl:application/adl:typedef[@name=$definition]/@size"/> - </xsl:when> - <!-- type='text' should really be unlimited, but in the real world it isn't. - Furthermore, setting null values may currently break the smart form components - parser --> - <xsl:when test="$base-type='text'">4294967296</xsl:when> - <xsl:when test="$base-type='integer'">8</xsl:when> - <xsl:when test="$base-type='real'">8</xsl:when> - <xsl:when test="$base-type='money'">10</xsl:when> - <xsl:when test="$base-type='date'">10</xsl:when> - <xsl:when test="$base-type='time'">8</xsl:when> - <xsl:when test="$property/@size > 0"> - <xsl:value-of select="$property/@size"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$base-type"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - -</xsl:stylesheet> +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + Application Description Language framework + base-type-include.xslt + + (c) 2007 Cygnet Solutions Ltd + + An xsl transform intended to be included into other XSL stylesheets, + intended to keep lookup of the ADL base type from ADL properties in + one place for ease of maintenance + + $Author: simon $ + $Revision: 1.5 $ + $Date: 2010-07-20 19:53:40 $ + --> + +<xsl:stylesheet version="1.0" + xmlns="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + exclude-result-prefixes="adl"> + + + <!-- return the base ADL type of the property which is passed as a parameter --> + <xsl:template name="base-type"> + <xsl:param name="property"/> + <xsl:choose> + <xsl:when test="$property/@type='defined'"> + <xsl:variable name="definition"> + <xsl:value-of select="$property/@typedef"/> + </xsl:variable> + <xsl:value-of select="/adl:application/adl:typedef[@name=$definition]/@type"/> + </xsl:when> + <xsl:when test="$property/@type='serial'">integer</xsl:when> + <xsl:when test="$property/@type='message'">integer</xsl:when> + <xsl:otherwise> + <xsl:value-of select="$property/@type"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- return the size of the type of the property which is passed as a parameter --> + <xsl:template name="base-size"> + <xsl:param name="property"/> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$property/@type='defined'"> + <xsl:variable name="definition"> + <xsl:value-of select="$property/@typedef"/> + </xsl:variable> + <xsl:value-of select="/adl:application/adl:typedef[@name=$definition]/@size"/> + </xsl:when> + <!-- type='text' should really be unlimited, but in the real world it isn't. + Furthermore, setting null values may currently break the smart form components + parser --> + <xsl:when test="$base-type='text'">4294967296</xsl:when> + <xsl:when test="$base-type='integer'">8</xsl:when> + <xsl:when test="$base-type='real'">8</xsl:when> + <xsl:when test="$base-type='money'">10</xsl:when> + <xsl:when test="$base-type='date'">10</xsl:when> + <xsl:when test="$base-type='time'">8</xsl:when> + <xsl:when test="$property/@size > 0"> + <xsl:value-of select="$property/@size"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$base-type"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> diff --git a/transforms/csharp-type-include.xslt b/transforms/csharp-type-include.xslt index 9582085..b51fba5 100755 --- a/transforms/csharp-type-include.xslt +++ b/transforms/csharp-type-include.xslt @@ -1,99 +1,100 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<!-- - Application Description Language framework - csharp-type-include.xslt - - (c) 2007 Cygnet Solutions Ltd - - An XSL transform intended to be included into other XSL stylesheets, - intended to keep lookup of the C# type from ADL properties in - one place for ease of maintenance - - $Author: sb $ - $Revision: 1.4 $ - $Date: 2010-01-12 17:20:17 $ - --> - -<xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - exclude-result-prefixes="adl"> - - <xsl:include href="base-type-include.xslt"/> - - <!-- return the primitive C# type of the property which is passed as - a parameter - i.e. if csharp-type is an entity, then the csharp-type - of the keyfield of that entity, and so on. --> - <xsl:template name="csharp-base-type"> - <xsl:param name="property"/> - <xsl:param name="entityns"/> - <xsl:choose> - <xsl:when test="$property/@type = 'entity'"> - <xsl:variable name="entityname" select="$property/@entity"/> - <xsl:choose> - <xsl:when test="//adl:entity[@name=$entityname]/adl:key/adl:property"> - <!-- recurse... --> - <xsl:call-template name="csharp-base-type"> - <xsl:with-param name="property" - select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]"/> - <xsl:with-param name="entityns" select="$entityns"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:message terminate="yes"> - ADL: ERROR: could not find C# base type of property <xsl:value-of select="$property/@name"/> - </xsl:message> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="csharp-type"> - <xsl:with-param name="property" select="$property"/> - <xsl:with-param name="entityns" select="$entityns"/> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- return the C# type of the property which is passed as a parameter --> - <xsl:template name="csharp-type"> - <xsl:param name="property"/> - <xsl:param name="entityns"/> - <xsl:variable name="base-type"> - <xsl:call-template name="base-type"> - <xsl:with-param name="property" select="$property"/> - </xsl:call-template> - </xsl:variable> - <xsl:choose> - <xsl:when test="$property/@type = 'message'">Message</xsl:when> - <xsl:when test="$base-type = 'link'"> - ICollection<<xsl:value-of select="@entity"/>> - </xsl:when> - <xsl:when test="$base-type = 'list'"> - ICollection<<xsl:value-of select="@entity"/>> - </xsl:when> - <xsl:when test="$base-type = 'date'">DateTime</xsl:when> - <xsl:when test="$base-type = 'time'">DateTime</xsl:when> - <xsl:when test="$base-type = 'string'">String</xsl:when> - <xsl:when test="$base-type = 'text'">String</xsl:when> - <xsl:when test="$base-type = 'boolean'">Boolean</xsl:when> - <xsl:when test="$base-type = 'timestamp'">DateTime</xsl:when> - <xsl:when test="$base-type = 'integer'">int</xsl:when> - <xsl:when test="$base-type = 'real'">double</xsl:when> - <xsl:when test="$base-type = 'money'">Decimal</xsl:when> - <xsl:when test="$base-type = 'entity'"> - <xsl:choose> - <xsl:when test="$entityns"> - <xsl:value-of select="concat( $entityns, '.', $property/@entity)"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$property/@entity"/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise>[unknown?]</xsl:otherwise> - </xsl:choose> - </xsl:template> - -</xsl:stylesheet> +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + Application Description Language framework + csharp-type-include.xslt + + (c) 2007 Cygnet Solutions Ltd + + An XSL transform intended to be included into other XSL stylesheets, + intended to keep lookup of the C# type from ADL properties in + one place for ease of maintenance + + $Author: simon $ + $Revision: 1.5 $ + $Date: 2010-07-20 19:53:40 $ + --> + +<xsl:stylesheet version="1.0" + xmlns="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + exclude-result-prefixes="adl"> + + <xsl:include href="base-type-include.xslt"/> + + <!-- return the primitive C# type of the property which is passed as + a parameter - i.e. if csharp-type is an entity, then the csharp-type + of the keyfield of that entity, and so on. --> + <xsl:template name="csharp-base-type"> + <xsl:param name="property"/> + <xsl:param name="entityns"/> + <xsl:choose> + <xsl:when test="$property/@type = 'entity'"> + <xsl:variable name="entityname" select="$property/@entity"/> + <xsl:choose> + <xsl:when test="//adl:entity[@name=$entityname]/adl:key/adl:property"> + <!-- recurse... --> + <xsl:call-template name="csharp-base-type"> + <xsl:with-param name="property" + select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]"/> + <xsl:with-param name="entityns" select="$entityns"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + ADL: ERROR: could not find C# base type of property <xsl:value-of select="$property/@name"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="csharp-type"> + <xsl:with-param name="property" select="$property"/> + <xsl:with-param name="entityns" select="$entityns"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- return the C# type of the property which is passed as a parameter --> + <xsl:template name="csharp-type"> + <xsl:param name="property"/> + <xsl:param name="entityns"/> + <xsl:variable name="base-type"> + <xsl:call-template name="base-type"> + <xsl:with-param name="property" select="$property"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$property/@type = 'message'">Message</xsl:when> + <xsl:when test="$base-type = 'link'"> + ICollection<<xsl:value-of select="@entity"/>> + </xsl:when> + <xsl:when test="$base-type = 'list'"> + ICollection<<xsl:value-of select="@entity"/>> + </xsl:when> + <xsl:when test="$base-type = 'date'">DateTime</xsl:when> + <xsl:when test="$base-type = 'time'">DateTime</xsl:when> + <xsl:when test="$base-type = 'string'">String</xsl:when> + <xsl:when test="$base-type = 'text'">String</xsl:when> + <xsl:when test="$base-type = 'image'">String</xsl:when> + <xsl:when test="$base-type = 'boolean'">Boolean</xsl:when> + <xsl:when test="$base-type = 'timestamp'">DateTime</xsl:when> + <xsl:when test="$base-type = 'integer'">int</xsl:when> + <xsl:when test="$base-type = 'real'">double</xsl:when> + <xsl:when test="$base-type = 'money'">Decimal</xsl:when> + <xsl:when test="$base-type = 'entity'"> + <xsl:choose> + <xsl:when test="$entityns"> + <xsl:value-of select="concat( $entityns, '.', $property/@entity)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$property/@entity"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise>[unknown?]</xsl:otherwise> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> diff --git a/transforms/i18n-en-GB-include.xslt b/transforms/i18n-en-GB-include.xslt index 90a3559..7cb8362 100755 --- a/transforms/i18n-en-GB-include.xslt +++ b/transforms/i18n-en-GB-include.xslt @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns="http://bowyer.journeyman.cc/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"> @@ -21,9 +21,9 @@ (iii) take arguments which are strings only, not nodesets. Templates are listed in alphabetical order. - $Author: sb $ - $Revision: 1.7 $ - $Date: 2010-01-12 17:20:17 $ + $Author: simon $ + $Revision: 1.8 $ + $Date: 2010-07-20 19:53:40 $ --> <xsl:template name="i18n-add-a-new"> diff --git a/transforms/permissions-include.xslt b/transforms/permissions-include.xslt index 1e20161..de441e7 100755 --- a/transforms/permissions-include.xslt +++ b/transforms/permissions-include.xslt @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" - xmlns="http://libs.cygnets.co.uk/adl/1.4/" - xmlns:adl="http://libs.cygnets.co.uk/adl/1.4/" + xmlns="http://bowyer.journeyman.cc/adl/1.4/" + xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:exsl="urn:schemas-microsoft-com:xslt" @@ -14,9 +14,9 @@ Utility templates to find permissions on various things - $Author: sb $ - $Revision: 1.6 $ - $Date: 2010-01-12 17:20:17 $ + $Author: simon $ + $Revision: 1.7 $ + $Date: 2010-07-20 19:53:40 $ --> <!-- collect all groups which can edit the specified property -->