Brussels, 26 November 2013
Dave Raggett <dsr@w3.org>
This is an exploration of the design requirements, challenges and applicable technologies, rather than a finished editor.
This talk is available at http://www.w3.org/2013/Talks/quill/
Serenoa is an EU FP7 research project focusing on model-based user interface design, and dynamic adaptation to changes in the context of use.
This project has received funding from the European Commission’s Seventh Framework Programme under grant agreement nº 258030 (FP7-ICT-2009-5. Internet of Services, Software and Virtualization – STREP).
Note: many of the slide bullet points expand to reveal further details, click on the text to expand or contract the bullet point.
with rules for dynamic adaptation to changes in the context of use
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:ctic="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl/xsd0.xsd"> <xs:include schemaLocation="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl/xsd0.xsd"> </xs:include> <xs:complexType name="uiDataType"> <xs:sequence> <xs:element ref="login"/> <xs:element ref="user"/> <xs:element ref="agencies"/> <xs:element ref="cars"/> <xs:element ref="subscribe"/> </xs:sequence> <xs:attribute name="user_id" type="xs:string"/> <xs:attribute name="selected_agency" type="xs:string"/> <xs:attribute name="selected_car" type="xs:string"/> </xs:complexType> <xs:element name="uiData" type="uiDataType"/> </xs:schema>
@import "clauses.txt" @import "vehicles.txt" interface customer { first_name string; last_name string; email email_address; phone phone; young_driver boolean; marketing_opt_in boolean; } interface card { type {MasterCard, VISA, AMEX}; number string; expiry_month month; expiry_year year; } interface itinerary { pickup_date date_time; return_date date_time; pickup_location location using find_location(); return_to_origin boolean; return_location location using find_location(); pay {now, at_location}; #relevant return_location !return_to_origin #default return_location pickup_location } interface agreement { customer customer; itinerary itinerary; pay_with card; readonly included : clause[]; readonly excluded : clause[]; vehicle from vehicles(itinerary: itinerary) : vehicle[]; extras extras; #relevant pay_with itinerary.pay=now; } interface address { name string; street string; town_city string; state_province string; zip_postal_code string; country string; } interface extras { gps boolean; infant_seat integer; booster_seat integer; child_seat integer; } abstract interface clause { name string; } abstract readonly interface location { type {normal, airport, station}; airport_code string; address address; #relevant airport_code type=airport } abstract readonly interface vehicle { category {economy, compact, intermediate, standard}; type {car, van}; model string; photo image; doors {"2-4", "4-5"}; passengers number; shift {manual, auto}; luggage string; aircon boolean; miles_per_gallon number; price_per_day number; #relevant doors type=car #relevant luggage type=car }
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <TaskModel xmlns:coop="http://giove.isti.cnr.it/cttcoop" xmlns="http://giove.isti.cnr.it/ctt" NameTaskModelID="Make Car Reservation"> <Task Identifier="Make Car Reservation" Category="abstraction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <SubTask> <Task Identifier="Enter Info" Category="interaction" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <TemporalOperator name="Disabling"/> <Parent name="Make Car Reservation"/> <SiblingRight name="Submit Request"/> <SubTask> <Task Identifier="Enter Car Info" Category="interaction" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <TemporalOperator name="Interleaving"/> <Parent name="Enter Info"/> <SiblingRight name="Enter User Info"/> <SubTask> <Task Identifier="Enter Category" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter Car Info"/> <SiblingRight name="Enter Colour"/> </Task> <Task Identifier="Enter Colour" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter Car Info"/> <SiblingLeft name="Enter Category"/> <SiblingRight name="Enter Model"/> </Task> <Task Identifier="Enter Model" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter Car Info"/> <SiblingLeft name="Enter Colour"/> <SiblingRight name="Enter Engine"/> </Task> <Task Identifier="Enter Engine" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <Parent name="Enter Car Info"/> <SiblingLeft name="Enter Model"/> </Task> </SubTask> </Task> <Task Identifier="Enter User Info" Category="interaction" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <TemporalOperator name="Interleaving"/> <Parent name="Enter Info"/> <SiblingLeft name="Enter Car Info"/> <SiblingRight name="Enter Other Info"/> <SubTask> <Task Identifier="EnterName" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingRight name="EnterSurname"/> </Task> <Task Identifier="EnterSurname" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="EnterName"/> <SiblingRight name="EnterAddress"/> </Task> <Task Identifier="EnterAddress" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="EnterSurname"/> <SiblingRight name="EnterCity"/> </Task> <Task Identifier="EnterCity" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="EnterAddress"/> <SiblingRight name="EnterZIPCode"/> </Task> <Task Identifier="EnterZIPCode" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="EnterCity"/> <SiblingRight name="EnterCountry"/> </Task> <Task Identifier="EnterCountry" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="EnterZIPCode"/> <SiblingRight name="SelectGender"/> </Task> <Task Identifier="SelectGender" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Selection/Single_Choice</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="EnterCountry"/> <SiblingRight name="EnterBirthDate"/> </Task> <Task Identifier="EnterBirthDate" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter User Info"/> <SiblingLeft name="SelectGender"/> <SiblingRight name="EnterEmail"/> </Task> <Task Identifier="EnterEmail" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Monitoring</Type> <Parent name="Enter User Info"/> <SiblingLeft name="EnterBirthDate"/> </Task> </SubTask> </Task> <Task Identifier="Enter Other Info" Category="interaction" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <TemporalOperator name="Interleaving"/> <Parent name="Enter Info"/> <SiblingLeft name="Enter User Info"/> <SiblingRight name="Set Preferences"/> <SubTask> <Task Identifier="Enter Comments" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <TemporalOperator name="Interleaving"/> <Parent name="Enter Other Info"/> <SiblingRight name="EnterMaxBudget"/> </Task> <Task Identifier="EnterMaxBudget" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Edit</Type> <Parent name="Enter Other Info"/> <SiblingLeft name="Enter Comments"/> </Task> </SubTask> </Task> <Task Identifier="Set Preferences" Category="interaction" Iterative="true" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Selection/Multiple_Choice</Type> <Parent name="Enter Info"/> <SiblingLeft name="Enter Other Info"/> </Task> </SubTask> </Task> <Task Identifier="Submit Request" Category="interaction" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Control</Type> <TemporalOperator name="SequentialEnablingInfo"/> <Parent name="Make Car Reservation"/> <SiblingLeft name="Enter Info"/> <SiblingRight name="AccessService"/> </Task> <Task Identifier="AccessService" Category="application" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <TemporalOperator name="SequentialEnablingInfo"/> <Parent name="Make Car Reservation"/> <SiblingLeft name="Submit Request"/> <SiblingRight name="ShowResults"/> </Task> <Task Identifier="ShowResults" Category="application" Iterative="false" Optional="false" PartOfCooperation="false" Frequency=" "> <Name>name</Name> <Type>Visualize</Type> <Parent name="Make Car Reservation"/> <SiblingLeft name="AccessService"/> </Task> </SubTask> </Task> </TaskModel>
task "Make car reservation" { enables { task "Enter info" { task "Enter car info" { task "Enter category" using car.category; task "Enter colour" using car.colour; task "Enter model" using car.model; task "Enter engine" using car.engine_size; } task "Enter user info" { task "Enter name" using user.given_name; task "Enter surname" using user.family_name; task "Enter address" using address.street; task "Enter city" using address.city; task "Enter Zip Code" using address.zip_code; task "Enter country" using address.country; task "Select gender" using user.gender; task "Enter date of birth" using user.birth_date; task "Enter email" using user.email; } task "Enter other info" { task "Enter comments" using misc.comments; task "Enter max budget" using misc.max_budget; } task "Set preferences" using rental.preferences; } task "Access service" application; task "Show results" application; } }
task "make a reservation" { task "Customer details" using customer; enables { task "Pick up and return" { task "pick up details" { concurrent { task "find rental location" using itinerary.pickup_location; task "enter date and time" using itinerary.pickup_date; task "Return to pickup location" using itinerary.return_to_origin; } } task "return details" { concurrent { task "find location" using itinerary.return_location #precondition !itinerary.return_to_origin; task "enter date and time" using itinerary.return_date; } } task "Pay now or at pickup" using itinerary.pay; } task "pick car model" using agreement.vehicle; task "Choose extras" using extras; task "Review and book" using agreement; } }
<?xml version="1.0" encoding="UTF-8"?> <abstractUIModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" currentUnit="login_iu" xmlns="http://www.serenoa-fp7.eu/"> <externalModelList> <externalModel URI="dataModel.xsd" id="data"/> </externalModelList> <!-- External Functions from http://idi.fundacionctic.org/mobSerenoaWS/application.wadl --> <externalFunctionList> <externalFunction name="login" > <rest resource="http://idi.fundacionctic.org/mobSerenoaWS/login/{user}/password/{password}" method="POST" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> <input name="user"> <simpleType type="string"/> </input> <input name="password"> <simpleType type="string"/> </input> <input name="id"> <simpleType type="string"/> </input> <output name="login"> <complexType xPath="/xs:complexType[name='login']" externalModelId="data" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> </output> </externalFunction> <externalFunction name="putUser"> <rest resource="http://idi.fundacionctic.org/mobSerenoaWS/user/{id}" method="PUT" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> <input name="id"> <simpleType type="string"/> </input> <input name="user"> <complexType xPath="/xs:complexType[name='user']" externalModelId="data"/> </input> </externalFunction> <externalFunction name="getUser" > <rest resource="http://idi.fundacionctic.org/mobSerenoaWS/user/{id}" method="GET" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl" /> <input name="id"> <simpleType type="string"/> </input> <output name="user" > <complexType xPath="/xs:complexType[name='user']" externalModelId="data" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> </output> </externalFunction> <externalFunction name="getAgencies" > <rest resource="http://idi.fundacionctic.org/mobSerenoaWS/agencies/user/{id}" method="GET" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> <input name="id"> <simpleType type="string"/> </input> <output name="agencies"> <complexType xPath="/xs:element[name='agencies']" externalModelId="data"/> </output> </externalFunction> <externalFunction name="getCars" > <rest resource="http://idi.fundacionctic.org/mobSerenoaWS/cars/user/{id}" method="GET" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> <input name="id"> <simpleType type="string"/> </input> <output name="cars"> <complexType xPath="/xs:element[name='cars']" externalModelId="data"/> </output> </externalFunction> <externalFunction name="getCarsByAgency" > <rest resource="http://idi.fundacionctic.org/mobSerenoaWS/cars/agency/{id}" method="GET" definitionURL="http://idi.fundacionctic.org/mobSerenoaWS/application.wadl"/> <input name="id"> <simpleType type="string"/> </input> <output name="cars"> <complexType xPath="/xs:element[name='cars']" externalModelId="data"/> </output> </externalFunction> </externalFunctionList> <!--Login--> <abstractInteractionUnit id="login_iu" name="Login" role="Init"> <connections> <connection id="registration"> <target interactionUnitId="registration_iu"/> </connection> <connection id="login_home"> <target interactionUnitId="home_iu"> <condition operator="neq"> <entityReference xPath="/uiData/user/user_id" externalModelId="data"/> <constant value="-1" type="integer"/> </condition> </target> </connection> <back id="back_login"/> </connections> <grouping id="login_group"> <edit id="login_username"/> <edit id="login_password"/> <activator id="login_activator" connectionReference="login_home"> <events> <activation> <eventHandler> <invokeFunction name="login"> <input name="username"> <value> <entityReference xPath="/descendant::edit[@id='login_username']/@value"/> </value> </input> <input name="password"> <value> <entityReference xPath="/descendant::edit[@id='login_password']/@value"/> </value> </input> <input name="id"> <value> <constant value="-1" type="string"/> </value> </input> <output name="login" xPath="/uiData/user/login" externalModelId="data"/> </invokeFunction> <!-- if login is successful, initialize the user data --> <if> <condition operator="eq"> <entityReference xPath="/uiData/login/valid" externalModelId="data"/> <constant value="true" type="boolean"/> </condition> <then> <invokeFunction name="getUser"> <input name="id"> <value> <entityReference xPath="/uiData/user/@id" externalModelId="data"/> </value> </input> <output name="user" xPath="/uiData/user" externalModelId="data"/> </invokeFunction> </then> </if> </eventHandler> </activation> </events> </activator> <!-- [davide] added a navigation grouping here --> <grouping id="login_navigation" role="navigation"> <navigator id="registration_navigator" connectionReference="registration"/> <navigator id="login_back" connectionReference="back_login"/> </grouping> </grouping> </abstractInteractionUnit> <!--CTIC: According to the Data Structure section available at the wiki (http://serenoa.morfeo-project.org/wiki/index.php/Demonstrator_M18#Data_structure) there are some mandatory fields to be filled in by the user as part of the registration process [davide] The data model has minOccurs="1" for the mandatory fields... --> <!--Registration--> <abstractInteractionUnit id="registration_iu" name="Registration" role="Init"> <connections> <connection id="registration_home"> <target interactionUnitId="home_iu"> <condition operator="neq"> <entityReference xPath="/uiData/user/@id" externalModelId="data"/> <constant type="integer" value="-1"/> </condition> </target> </connection> <connection id="registration_login"> <target interactionUnitId="login_iu"/> </connection> <back id="back_registration"/> </connections> <grouping id="register_main"> <!-- [davide] I added username and password for managing the login --> <edit id="registration_username"> <binding xPath="/uiData/user/preferences/preference[@name='username']/value" externalModelId="data"/> </edit> <edit id="registration_password"> <binding xPath="/uiData/user/preferences/preference[@name='password']/value" externalModelId="data"/> </edit> <edit id="registration_name"> <binding xPath="/uiData/user/preferences/preference[@name='first name']/value" externalModelId="data"/> </edit> <edit id="registration_lastName"> <binding xPath="/uiData/user/preferences/preference[@name='last name']/value" externalModelId="data"/> </edit> <singleChoice id="registration_gender"> <binding xPath="/uiData/user/preferences/preference[@name='gender']/value" externalModelId="data"/> <choiceElement value="male"/> <choiceElement value="female"/> </singleChoice> <edit id="registration_email"> <binding xPath="/uiData/user/preferences/preference[@name='email']/value" externalModelId="data"/> </edit> <edit id="registration_birth_date"> <binding xPath="/uiData/user/preferences/preference[@name='birth date']/value" externalModelId="data"/> </edit> <grouping id="registration_address"> <edit id="registration_street"> <binding xPath="/uiData/user/preferences/preference[@name='street']/value" externalModelId="data"/> </edit> <edit id="registration_poBox"> <binding xPath="/uiData/user/preferences/preference[@name='PO box']/value" externalModelId="data"/> </edit> <edit id="registration_zip_code"> <binding xPath="/uiData/user/preferences/preference[@name='zip Code']/value" externalModelId="data"/> </edit> <edit id="registration_location"> <binding xPath="/uiData/user/preferences/preference[@name='location']/value" externalModelId="data"/> </edit> <singleChoice id="registration_country"> <binding xPath="/uiData/user/preferences/preference[@name='country']/value" externalModelId="data"/> <choiceElement value="Italy"/> <choiceElement value="Poland"/> <choiceElement value="Spain"/> <!-- many more --> </singleChoice> </grouping> <activator id="registration_activator" connectionReference="registration_home"> <events> <activation> <eventHandler> <invokeFunction name="putUser"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <input name="user"> <value> <entityReference xPath="/uiData/user" externalModelId="data"/> </value> </input> </invokeFunction> </eventHandler> </activation> </events> </activator> <!-- [davide] added a navigation grouping here --> <grouping id="registration_navigation" role="navigation"> <navigator id="login_navigator" connectionReference="registration_login"/> <navigator id="registration_back" connectionReference="back_registration"/> </grouping> </grouping> <events> <onRender> <eventHandler> <!-- assumption: call getUser with id = -1 in order to get an empty one --> <invokeFunction name="getUser"> <input name="id"> <value> <entityReference xPath="/uiData/user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/user" externalModelId="data"/> </invokeFunction> </eventHandler> </onRender> </events> </abstractInteractionUnit> <abstractInteractionUnit role="main-menu" id="home_iu" name="Main menu"> <connections> <connection id="home2preferences"> <target interactionUnitId="preferences_iu"/> </connection> <connection id="home2userInfo"> <target interactionUnitId="userInfo_iu"/> </connection> <connection id="home2searchInfo"> <target interactionUnitId="searchInfo_iu"/> </connection> <connection id="home2login"> <target interactionUnitId="login_iu"/> </connection> <back id="back_home"/> </connections> <!-- [davide] added a the role navigation here --> <grouping id="home_main" role="navigation"> <navigator id="home_preferences" connectionReference="home2preferences"/> <navigator id="home_userInfo" connectionReference="home2userInfo"/> <navigator id="home_searchInfo" connectionReference="home2searchInfo"/> <navigator id="home_back" connectionReference="back_home"/> <activator id="home_logout" connectionReference="home2login"> <events> <activation> <eventHandler> <update> <entityReference xPath="/uiData/user_id" externalModelId="data"/> <value> <!-- resets the user id --> <constant value="-1" type="string"/> </value> </update> </eventHandler> </activation> </events> </activator> </grouping> </abstractInteractionUnit> <abstractInteractionUnit id="preferences_iu" name="Preferences" role="Preferences"> <connections> <connection id="preferences2home"> <target interactionUnitId="home_iu"/> </connection> <connection id="preferences2userInfo"> <target interactionUnitId="userInfo_iu"/> </connection> <back id="back_preferences" /> </connections> <grouping id="preferences_main"> <grouping id="serenoa_preferences"> <singleChoice id="location_awareness"> <binding xPath="/uiData/user/preferences/preference[@name='location_awareness']/value"/> <choiceElement value="yes"/> <choiceElement value="no"/> </singleChoice> <singleChoice id="color_blindness"> <binding xPath="/uiData/user/preferences/preference[@name='color_blindness']/value"/> <choiceElement value="yes"/> <choiceElement value="no"/> </singleChoice> </grouping> <grouping id="application_preferences"> <singleChoice id="choose_by_agency"> <binding xPath="/uiData/user/preferences/preference[@name='choose_by_agency']/value"/> <choiceElement value="yes"/> <choiceElement value="no"/> </singleChoice> <singleChoice id="ordering"> <binding xPath="/uiData/user/preferences/preference[@name='ordering']/value"/> <choiceElement value="price"/> <choiceElement value="name"/> </singleChoice> <singleChoice id="location_selection"> <binding xPath="/uiData/user/preferences/preference[@name='location_selection']/value"/> <choiceElement value="map"/> <choiceElement value="list"/> </singleChoice> </grouping> <activator id="preferences_userInfo" connectionReference="preferences2userInfo"> <events> <activation> <eventHandler> <!-- save preferences --> <invokeFunction name="putUser"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <input name="user"> <value> <entityReference xPath="/uiData/user" externalModelId="data"/> </value> </input> </invokeFunction> </eventHandler> </activation> </events> </activator> <!--CTIC: We have added a new home role in order to semantically annotate the navigators pointing to the main-menu interaction unit [davide] such information is redundant, it is possible to calculate it from the connection + the role of the referenced abstract interaction unit --> <!-- [davide] added a navigation grouping here --> <grouping id="preferences_navigation" role="navigation"> <navigator id="preferences_home" connectionReference="preferences2home"/> <navigator id="preferences_back" connectionReference="back_preferences"/> </grouping> </grouping> <events> <onRender> <eventHandler> <invokeFunction name="getUser"> <input name="id"> <value> <entityReference xPath="/uiData/user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/user" externalModelId="data"/> </invokeFunction> </eventHandler> </onRender> </events> </abstractInteractionUnit> <abstractInteractionUnit id="userInfo_iu" role="User" name="User Information"> <connections> <connection id="userInfo2home"> <target interactionUnitId="home_iu"/> </connection> <connection id="userInfo2searchInfo"> <target interactionUnitId="searchInfo_iu"/> </connection> <back id="back_userInfo"/> </connections> <!-- more groupings ? --> <grouping id="userInfo_main"> <!-- [davide] this interaction unit is actually really similar to the registration one... Can we collapse them? --> <edit id="userInfo_password"> <binding xPath="/uiData/user/preferences/preference[@name='password']/value" externalModelId="data"/> </edit> <edit id="userInfo_name"> <binding xPath="/uiData/user/preferences/preference[@name='first name']/value" externalModelId="data"/> </edit> <edit id="userInfo_lastName"> <binding xPath="/uiData/user/preferences/preference[@name='last name']/value" externalModelId="data"/> </edit> <singleChoice id="userInfo_gender"> <binding xPath="/uiData/user/preferences/preference[@name='gender']/value" externalModelId="data"/> <choiceElement value="male"/> <choiceElement value="female"/> </singleChoice> <edit id="userInfo_email"> <binding xPath="/uiData/user/preferences/preference[@name='email']/value" externalModelId="data"/> </edit> <edit id="userInfo_birth_date"> <binding xPath="/uiData/user/preferences/preference[@name='birth date']/value" externalModelId="data"/> </edit> <grouping id="userInfo_address"> <edit id="userInfo_street"> <binding xPath="/uiData/user/preferences/preference[@name='street']/value" externalModelId="data"/> </edit> <edit id="userInfo_poBox"> <binding xPath="/uiData/user/preferences/preference[@name='PO box']/value" externalModelId="data"/> </edit> <edit id="userInfo_zip_code"> <binding xPath="/uiData/user/preferences/preference[@name='zip Code']/value" externalModelId="data"/> </edit> <edit id="userInfo_location"> <binding xPath="/uiData/user/preferences/preference[@name='location']/value" externalModelId="data"/> </edit> <singleChoice id="userInfo_country"> <binding xPath="/uiData/user/preferences/preference[@name='country']/value" externalModelId="data"/> <choiceElement value="Italy"/> <choiceElement value="Poland"/> <choiceElement value="Spain"/> <!-- many more --> </singleChoice> </grouping> <activator id="userInfo_activator" connectionReference="registration_home"> <events> <activation> <eventHandler> <!-- save preferences --> <invokeFunction name="putUser"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <input name="user"> <value> <entityReference xPath="/uiData/user" externalModelId="data"/> </value> </input> </invokeFunction> </eventHandler> </activation> </events> </activator> <!-- [davide] added a navigation grouping here --> <grouping id="userInfo_navigation" role="navigation"> <navigator id="userInfo_home" connectionReference="userInfo2home"/> <navigator id="userInfo_searchInfo" connectionReference="userInfo2searchInfo"/> <navigator id="userInfo_back" connectionReference="back_userInfo"/> </grouping> </grouping> <events> <onRender> <eventHandler> <invokeFunction name="getUser"> <input name="id"> <value> <entityReference xPath="/uiData/user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/user" externalModelId="data"/> </invokeFunction> </eventHandler> </onRender> </events> </abstractInteractionUnit> <abstractInteractionUnit id="searchInfo_iu" role="Search" name="Car Search"> <connections> <connection id="searchInfo2home"> <target interactionUnitId="home_iu"/> </connection> <connection id="submit_data"> <target interactionUnitId="agencyList_iu"> <condition operator="and"> <condition operator="eq"> <entityReference xPath="/uiData/user/preferences/preference[@name='choose_by_agency']/value" externalModelId="data"/> <constant value="yes" type="string"/> </condition> <condition operator="eq"> <entityReference xPath="/uiData/user/preferences/preference[@name='location_selection']/value" externalModelId="data"/> <constant value="list" type="string"/> </condition> </condition> </target> <target interactionUnitId="geoAgencyList_iu"> <condition operator="and"> <condition operator="eq"> <entityReference xPath="/uiData/user/preferences/preference[@name='choose_by_agency']/value" externalModelId="data"/> <constant value="yes" type="string"/> </condition> <condition operator="eq"> <entityReference xPath="/uiData/user/preferences/preference[@name='location_selection']/value" externalModelId="data"/> <constant value="map" type="string"/> </condition> </condition> </target> <target interactionUnitId="resultsList_iu" > <condition operator="eq"> <entityReference xPath="/uiData/user/preferences/preference[@name='choose_by_agency']/value" externalModelId="data"/> <constant value="no" type="string"/> </condition> </target> </connection> <!-- [davide] added a navigation grouping here --> <grouping role="navigation" id="searchInfo_navigation"> <back id="back_searchInfo"/> </grouping> </connections> <grouping id="searchInfo_main"> <!-- I assume that all the search preferences are saved as user properties and that the get agencies/cars operations will take into account them Maybe the cars and agencies resources should have the user id as parameter --> <edit id="searchInfo_location"> <binding xPath="/uiData/user/preferences/preference[@name='location']/value" externalModelId="data"/> </edit> <edit id="accepted_distance"> <binding xPath="/uiData/user/preferences/preference[@name='accepted_distance']/value" externalModelId="data"/> </edit> <singleChoice id="color"> <binding xPath="/uiData/user/preferences/preference[@name='color']/value" externalModelId="data"/> <choiceElement value="red"/> <choiceElement value="green"/> <choiceElement value="blue"/> <!-- many more --> </singleChoice> <!-- [davide] I removed the grouping because there was only one child --> <activator id="request_submit" connectionReference="submit_data"> <events> <activation> <eventHandler> <!-- save the currently edited preferences --> <invokeFunction name="putUser"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <input name="user"> <value> <entityReference xPath="/uiData/user" externalModelId="data"/> </value> </input> </invokeFunction> </eventHandler> </activation> </events> </activator> <!-- [davide] added a navigation grouping here --> <grouping id="searchInfo_navigation" role="navigation"> <navigator id="submitRequest_home" connectionReference="searchInfo2home"/> <navigator id="searchInfo_back" connectionReference="back_searchInfo"/> </grouping> </grouping> <events> <onRender> <!-- refresh the current user preferences --> <eventHandler> <invokeFunction name="getUser"> <input name="id"> <value> <entityReference xPath="/uiData/user/user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/user" externalModelId="data"/> </invokeFunction> </eventHandler> </onRender> </events> </abstractInteractionUnit> <abstractInteractionUnit id="agencyList_iu" role="Search" name="Agency List"> <connections> <connection id="agencyList2home"> <target interactionUnitId="home_iu"/> </connection> <connection id="agencyList2results"> <target interactionUnitId="resultsList_iu"/> </connection> <back id="back_agencyList"/> </connections> <grouping id="agencyList_main"> <!-- list reference and list item refence needed here --> <repetition id="agencyTemplate" listElementAlias="ag"> <listReference xPath="/uiData/agencies/agency" externalModelId="data"/> <onlyOutput id="agencyList_itemName"> <binding xPath="ag/@name"/> </onlyOutput> <navigator id="agency_detail" connectionReference="agencyList2results"> <events> <activation> <eventHandler> <update> <entityReference xPath="/uiData/@selected_agency" externalModelId="data"/> <value> <entityReference xPath="ag/@id" externalModelId="data"/> </value> </update> </eventHandler> </activation> </events> </navigator> </repetition> <!-- [davide] added a navigation grouping here --> <grouping id="agencyList_navigation" role="navigation"> <navigator id="agencyList_home" connectionReference="agencyList2home"/> <navigator id="agencyList_back" connectionReference="back_agencyList"/> </grouping> </grouping> <events> <onRender> <eventHandler> <invokeFunction name="getAgencies"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/agencies" externalModelId="data"/> </invokeFunction> </eventHandler> </onRender> </events> </abstractInteractionUnit> <!-- CTIC: Geolocated information --> <abstractInteractionUnit id="geoAgencyList_iu" role="Search" name="Agency Map"> <connections> <connection id="geoAgencyList2home"> <target interactionUnitId="home_iu"/> </connection> <connection id="geoAgencyList2results"> <target interactionUnitId="resultsList_iu"/> </connection> <back id="back_geoAgencyList"/> </connections> <!-- CTIC: role added to support geolocation --> <grouping role="geo" id="geoAgencyList_main"> <!-- list reference and list item refence needed here --> <repetition id="geoAgencyTemplate"> <listReference xPath="/uiData/agencies/agency" externalModelId="data"/> <navigator id="geo_agency_detail" connectionReference="geoAgencyList2results"> <!-- [davide] please check if it is ok --> <events> <activation> <eventHandler> <update> <entityReference xPath="/uiData/@selected_agency"/> <value> <entityReference xPath="ag/@id" externalModelId="data"/> </value> </update> </eventHandler> </activation> </events> </navigator> </repetition> <!-- [davide] added a navigation grouping here --> <grouping id="geoAgencyList_navigation" role="navigation"> <navigator id="geoAgencyList_home" connectionReference="geoAgencyList2home"/> <navigator id="geoAgencyList_back" connectionReference="back_geoAgencyList"/> </grouping> </grouping> <events> <onRender> <eventHandler> <invokeFunction name="getAgencies"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/agencies" externalModelId="data"/> </invokeFunction> </eventHandler> </onRender> </events> </abstractInteractionUnit> <abstractInteractionUnit id="resultsList_iu" role="Search" name="Car Results"> <connections> <connection id="resultList2home"> <target interactionUnitId="home_iu"/> </connection> <connection id="resultList2CarDetail"> <target interactionUnitId="carDetail_iu"/> </connection> <back id="back_resultsList"/> </connections> <grouping id="resultList_main"> <repetition id="carTemplate" listElementAlias="car"> <listReference xPath="/uiData/cars/car" externalModelId="data"/> <onlyOutput id="car_model"> <binding xPath="car/@model"/> </onlyOutput> <onlyOutput id="car_price"> <binding xPath="car/@price" /> </onlyOutput> <navigator id="car_detail" connectionReference="resultList2CarDetail"> <events> <activation> <eventHandler> <update> <entityReference xPath="/uiData/@selected_car" externalModelId="data"/> <value> <constant value="car/@id" type="string"/> </value> </update> </eventHandler> </activation> </events> </navigator> </repetition> <!-- [davide] added a navigation grouping here --> <grouping id="resultList_navigation" role="navigation"> <navigator id="resultList_home" connectionReference="resultList2home"/> <navigator id="resultsList_back" connectionReference="back_resultsList"/> </grouping> </grouping> <events> <onRender> <eventHandler> <if> <!-- [davide] there was a not needed eq operator here. --> <condition> <entityReference xPath="/uiData/user/preferences/preference[@name='choose_by_agency']/value" externalModelId="data"/> </condition> <then> <!-- [davide] changed to use the new car service --> <invokeFunction name="getCarsByAgency"> <input name="id"> <value> <entityReference xPath="/uiData/agencies/agency[@id=/selected_agency]" externalModelId="data"/> </value> </input> <output xPath="/uiData/cars" externalModelId="data"/> </invokeFunction> </then> <else> <!-- get the resource from the web service --> <invokeFunction name="getCars"> <input name="id"> <value> <entityReference xPath="/uiData/user/@user_id" externalModelId="data"/> </value> </input> <output xPath="/uiData/cars" externalModelId="data"/> </invokeFunction> </else> </if> </eventHandler> </onRender> </events> </abstractInteractionUnit> <abstractInteractionUnit id="carDetail_iu" role="Search" name="Car Detail"> <connections> <connection id="carDetail2home"> <target interactionUnitId="home_iu"/> </connection> <back id="back_carDetail"/> </connections> <grouping id="carDetail_main"> <onlyOutput id="carDetail_description"> <binding xPath="/uiData/cars/car[@id=selected_car]/@description"/> </onlyOutput> <onlyOutput id="carDetail_price"> <binding xPath="/uiData/cars/car[@id=selected_car]/@price"/> </onlyOutput> <!-- [davide] added a navigation grouping here --> <grouping id="carDetail_navigation" role="navigation"> <navigator id="carDetail_home" connectionReference="carDetail2home"/> <navigator id="carDetail_back" connectionReference="back_carDetail"/> </grouping> </grouping> </abstractInteractionUnit> </abstractUIModel>
dialog "Login" login_iu { connections { "Registration"; "Main menu" when user.user_id != -1; $Back; } } dialog "Registration" registration_iu { connections { "Main menu" when user.id != -1; "Login"; $Back; } event onRender{ call getUser(); } } dialog "Main menu" home_iu { connections { "Preferences"; "User Information"; "Car Search"; "Login"; $Back; } } dialog "Preferences" preferences_iu { connections { "Main menu"; "User Information"; $Back; } event onRender{ call getUser(); } } dialog "User Information" userInfo_iu { connections { "Main menu"; "Car Search"; $Back; } event onRender{ call getUser(); } } dialog "Car Search" searchInfo_iu { connections { "Main menu"; "Agency List" when user.preferences.choose_by_agency == "yes" && user.preferences.location_selection == "list"; "Agency Map" when user.preferences.choose_by_agency == "yes" && user.preferences.location_selection == "map"; "Car Results" when user.preferences.choose_by_agency == "no"; $Back; } event onRender{ call getUser(); } } dialog "Agency List" agencyList_iu { connections { "Main menu"; "Car Results"; $Back; } event onRender{ call getAgencies(); } } dialog "Agency Map" geoAgencyList_iu { connections { "Main menu"; "Car Results"; $Back; } event onRender{ call getAgencies(); } } dialog "Car Results" resultsList_iu { connections { "Main menu"; "Car Detail"; $Back; } event onRender{ if user.preferences.choose_by_agency then { call getCarsByAgency(); } else { call getCars(); } } } dialog "Car Detail" carDetail_iu { connections { "Main menu"; $Back; } }
on event if condition then actions
<?xml version="1.0" encoding="UTF-8"?> <!-- Document : london_rules.xml Created on : 14 giugno 2013, 11.06 Author : Marco Description: Purpose of the document follows. --> <ruleModel xmlns="http://www.serenoa-fp7.eu/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.serenoa-fp7.eu/ file:../ruleModel.xsd"> <ext_model_ref URI="http://urano.isti.cnr.it/cm/schema1.xsd" model_id="ctx"/> <ext_model_ref URI="http://urano.isti.cnr.it/cm/schema2.xsd" model_id="cui"/> <rule priority="0" name="outputGraphical" id="rule1"> <event> <simple_event event_name="onEnvironmentNoiseLevelIncrease" xPath="/user/environment/@noise_level" externalModelId="ctx"/> </event> <condition operator="gt"> <entityReference xPath="/user/environment/@noise_level" externalModelId="ctx"/> <constant value="1000" type="int"/> </condition> <action> <foreach> <in> <entityReference xPath="//*" externalModelId="uiModel"/> </in> <do> <if> <condition operator="eq"> <entityReference xPath="class" externalModelId="uiModel" /> <constant value="inputElement" type="string" /> </condition> <then> <update> <entityReference xPath="./@input" externalModelId="uiModel" /> <value> <constant value="graphical_assignment" type="string"/> </value> </update> </then> </if> <if> <condition operator="eq"> <entityReference xPath="class" externalModelId="uiModel"/> <constant value="tts" type="string"/> </condition> <then> <update> <entityReference xPath="./@output"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> </then> </if> </do> </foreach> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@input" externalModelId="cui"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@prompt" externalModelId="cui"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@feedback" externalModelId="cui"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> </action> </rule> <rule priority="0" name="outputRedundant" id="rule2"> <event> <simple_event event_name="onUserMoving" xPath="/user/userActivity/@activityType" externalModelId="ctx"/> </event> <condition operator="or"> <condition operator="eq"> <entityReference xPath="/user/userActivity/@activityType" externalModelId="ctx"/> <constant value="walking" type="string"/> </condition> <condition operator="eq"> <entityReference xPath="/user/userActivity/@activityType" externalModelId="ctx"/> <constant value="running" type="string"/> </condition> </condition> <action> <foreach> <in> <entityReference xPath="//*" externalModelId="uiModel"/> </in> <do> <if> <condition operator="eq"> <entityReference xPath="class" externalModelId="uiModel" /> <constant value="inputElement" type="string" / > </condition> <then> <update> <entityReference xPath="./@input" externalModelId="uiModel" /> <value> <constant value="equivalent" type="string"/> </value> </update> </then> </if> <if> <condition operator="eq"> <entityReference xPath="class" externalModelId="uiModel"/> <constant value="no_tts" type="string"/> </condition> <then> <update> <entityReference xPath="./@output"/> <value> <constant value="redundancy" type="string"/> </value> </update> </then> </if> </do> </foreach> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@input" externalModelId="cui"/> <value> <constant value="equivalence" type="string"/> </value> </update> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@prompt" externalModelId="cui"/> <value> <constant value="redundancy" type="string"/> </value> </update> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@feedback" externalModelId="cui"/> <value> <constant value="redundancy" type="string"/> </value> </update> </action> </rule> <rule priority="0" name="outputGraphical" id="rule3"> <event> <simple_event event_name="onUserStill" xPath="/user/userActivity/@activityType" externalModelId="ctx"/> </event> <condition operator="eq"> <entityReference xPath="/user/userActivity/@activityType" externalModelId="ctx"/> <constant value="standing/seating" type="string"/> </condition> <action> <foreach> <in> <entityReference xPath="//*" externalModelId="uiModel"/> </in> <do> <if> <condition operator="eq"> <entityReference xPath="class" externalModelId="uiModel" /> <constant value="inputElement" type="string" /> </condition> <then> <update> <entityReference xPath="./@input" externalModelId="uiModel" /> <value> <constant value="graphical_assignment" type="string"/> </value> </update> </then> </if> <if> <condition operator="eq"> <entityReference xPath="class" externalModelId="uiModel"/> <constant value="tts" type="string"/> </condition> <then> <update> <entityReference xPath="./@output"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> </then> </if> </do> </foreach> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@input" externalModelId="cui"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@prompt" externalModelId="cui"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> <update> <entityReference xPath="/descendant::single_choice[@id='order_status']/@feedback" externalModelId="cui"/> <value> <constant value="graphical_assignment" type="string"/> </value> </update> </action> </rule> </ruleModel>
rule 1 "outputGraphical" on EnvironmentNoiseLevelIncrease (noise_level) if user.environment.noise_level > 1000 then begin foreach * begin if class == "inputElement" then begin input = "graphical_assignment"; end if class == "tts" then begin output = "graphical_assignment"; end end single_choice.order_status.input = "graphical_assignment"; single_choice.order_status.prompt = "graphical_assignment"; single_choice.order_status.feedback = "graphical_assignment"; end rule 2 "outputRedundant" on UserMoving (activityType) if user.userActivity.activityType == "walking" || user.userActivity.activityType == "running" then begin foreach * begin if class == "inputElement" then begin input = "equivalent"; end if class == "no_tts" then begin output = "redundancy"; end end single_choice.order_status.input = "equivalence"; single_choice.order_status.prompt = "redundancy"; single_choice.order_status.feedback = "redundancy"; end rule 3 "outputGraphical" on UserStill (activityType) if user.userActivity.activityType == "standing/seating" then begin foreach * begin if class == "inputElement" then begin input = "graphical_assignment"; end if class == "tts" then begin output = "graphical_assignment"; end end single_choice.order_status.input = "graphical_assignment"; single_choice.order_status.prompt = "graphical_assignment"; single_choice.order_status.feedback = "graphical_assignment"; end
Note that the desktop and smart phone interfaces offer different capabilities -- one is not a subset of the other!
cd ~/Projects/quill/server
node wsd.js
Project properties dialog
Abstract UI Tab
Concrete UI Tab