savetest
Introduction
mira, 7 September 2010 (created 7 September 2010)
  • not tagging
  • no tags
Welcome to testdrive for Java

td4j is a prototyping framework for domain models written in Java. It enables you to define essential structure and behaviour in code and try it out instantly.

Why ?
When designing the domain model of a software system, it's important to have feedback on the models fitness early in the process. This is especially true, if the designer is not a domain expert and if requirements are not exhaustive or inconsistent.

What ?
Verify that you are designing the right concepts the right way by taking them for a testdrive.

How ?
td4j analyzes and instruments the domain model using Java reflection and creates a GUI for you to work with the model directly.

Tell me more!

Copyright Michael Rauch
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
[[Introduction]]
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
This guide will walk you through a simple prototyping scenario. We will start of with a very basic model and refine it as we go on. At the end of this guide, you will be able to start prototyping your own domain models with td4j.

The model is simple, we have a //Person// with its //Address//. So we start of by writing those two classes and a main method to create test-data and launch the workbench with it.

{{{
public class Person {
                
  public String firstName;
  public String lastName;
                
  public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }             
}
}}}
{{{
public class Address {

  public Person person;
  public String street;
  public String zip;
  public String city;

  public Address(Person person, String street, String zip, String city) {
    this.person = person;
    this.street = street;
    this.zip = zip;
    this.city = city;
  }
}
}}}
{{{
public static void main(String[] args) {
  Person homer = new Person("Homer", "Simpson");
  Address address = new Address(homer, "742 Evergreen Terrace", "99001", "Springfield");

  org.td4j.swing.workbench.Workbench.start(address, Person.class, Address.class);
}
}}}

Not that exciting so far. //Address// takes the person as constructor argument to mimic that address existence is bound to the person living at this address (a composition).

When we run the application, we get this UI:

[img[img/getting_started/gs_01.png]]

The blue text looks a bit cryptic, because we have forgotten to implement ''toString()'' in both //Address// and //Person//. Let's fix that and run it again.

{{{
public String toString() {
  return "" + firstName + " " + lastName;
}
}}}
{{{
public String toString() {
  return "" + street + ", " + zip + " " + city;
}
}}}

[img[img/getting_started/gs_02.png]]

Looks much better now. As you might guess, the underlined blue text is a link that will take us from the //Address// to the //Person//. 

[img[img/getting_started/gs_03.png]]

----

Done that, you will notice that we don't have a link to go back from the person to its address. This is because we only have a one-way association from //Address// to //Person//, but no association the other way around. A quick solution would be to simply introduce a field for the address in //Person// and set the field in our main method.

{{{
public class Person {
                
  public String firstName;
  public String lastName;
  public Address address;
  ...
}}}
{{{
public static void main(String[] args) {
  Person homer = new Person("Homer", "Simpson");
  homer.address = new Address(homer, "742 Evergreen Terrace", "99001", "Springfield");
  ...
}}}

This would work, but is not a nice solution. Let's use some ideas from domain driven design and build an aggregate where the address is only manipulated through the person. That way, person keeps control of the manipulations on its address and the address is nicely tucked away.

{{{
public static class Person {            
...             
  public void setAddress(String street, String zip, String city) {
    address = new Address(this, street, zip, city);
  }
...
}}}
{{{
public static void main(String[] args) {
  Person homer = new Person("Homer", "Simpson");
  homer.setAddress("742 Evergreen Terrace", "99001", "Springfield");

  org.td4j.swing.workbench.Workbench.start(homer.address, Person.class, Address.class);
}
}}}

The code to create the test-data looks better now. But we are still able to change the address directly in the ~UIs address form without //Person// guarding against direct manipulations. To fix that, we are going to make the address form ''readonly'' and allow manipulations only through the //setAddress()// method . Making the address form readonly is easy, we change the fields visibility to private and add getter methods to read the fields values.

{{{
public class Address {

  private Person person;
  private String street;
  private String zip;
  private String city;
...             
  public Person getPerson() { return person; }
  public String getStreet() { return street; }
  public String getZip()    { return zip;    }
  public String getCity()   { return city;   }
...
}}}

[img[img/getting_started/gs_04.png]]

The address form is now readonly. To be able to change the address, we have to expose the //setAddress()// method with the ''@Operation'' annotation.

{{{
public class Person {
...
@Operation
public void setAddress(String street, String zip, String city) {
  address = new Address(this, street, zip, city);
}
...
}}}

[img[img/getting_started/gs_05.png]]

Now the address can be changed by invoking the //setAddress()// method from the operations menu in the right upper corner. Doing so shows a dialog to fill in the parameters for the method call. 

[img[img/getting_started/gs_06.png]]

td4j reads the domain model through reflection of the bytecode in the class files. The methods parameter names are only available in the sourcecode and are removed during compilation. To let td4j know the parameter names, we have to put them in the ''@Operation'' annotation.

{{{
public class Person {
...
@Operation(paramNames = { "street", "zip", "city" })
public void setAddress(String street, String zip, String city) {
  address = new Address(this, street, zip, city);
}
...
}}}

[img[img/getting_started/gs_07.png]]

[img[img/getting_started/gs_08.png]]

So far, we are able to change the address interactively but we cannot create a new person yet. Let's change that by exposing the constructor of class //Person//.

{{{
@Operation(paramNames = { "firstName", "lastName" })
public Person(String firstName, String lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
}}}

[img[img/getting_started/gs_09.png]]

[img[img/getting_started/gs_10.png]]

----

OK, that was easy. Now let's add a new requirement; Suppose that we are dealing with a web shop application where customers can fill their cart and at the time of checkout they can choose their shipping address from multiple addresses that are kept on file for them. This is convenient for the customer, as sometimes she might want her goods to be delivered to her home address and other times to her job address.

We will support multiple addresses by keeping a list instead of a single address instance. This only requires a slight change to the sourcecode.

{{{
public class Person {
...
public List<Address> addresses = new ArrayList<Address>();
...
@Operation(paramNames = { "street", "zip", "city" })
public void addAddress(String street, String zip, String city) {
  final Address address = new Address(this, street, zip, city);
  addresses.add(address);
}        
...
}}}

{{{
public static void main(String[] args) {
  ...
  homer.addAddress("742 Evergreen Terrace", "99001", "Springfield");
  ...
}
}}}

After those changes, the application looks like this: 

[img[img/getting_started/gs_11.png]]

To get rid of the unnecessary information in the column 'person', we add an annotation to show only the remaining properties of //Address//. 

{{{
@ShowProperties({"street", "zip", "city"})
public List<Address> addresses = new ArrayList<Address>();
}}}

[img[img/getting_started/gs_12.png]]

Now, for the very last step we complete the functionality by supporting address removal. 

{{{
public class Person {
...
public void removeAddress(Address address) {
  addresses.remove(address);          
}
}}}

{{{
public class Address {
...
@Operation
public Person delete() {
  person.removeAddress(this);
  final Person p = this.person;
  this.person = null;
  return p;
}
}}}

With this code we have to navigate to the address to be able to delete it. This is done by double-clicking the address in the table. Then we can trigger the deletion from the operations menu.

Because the {{{delete()}}} method returns the person to which the address was previously assigned to, we end up at the person.
<<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>
This is the five minute introduction to td4j.

!Step 1 - Creating the model

Our domain model is plain simple in this case. The only requirement is that we have to be able to change the receiver of the greeting.

{{{
public class HelloWorld {
  public String name = "world";
                
  public String getGreeting() {
    return String.format("Hello %s!", name);
  }
}
}}}
That's it. The domain model is done.

One might dislike the public field for the name because it breaks proper encapsulation and is not good programming practice. Normally this field should be private and access done via getter/setter methods, which would also be perfectly fine with td4j. But as we are prototyping, we want to be able to change things quickly and that's gonna be easier with concise code. 

!Step 2 - Running the model

To run the model an play with it, we use the td4j Workbench.

{{{
public static void main(String[] args) {
  org.td4j.swing.workbench.Workbench.start(new HelloWorld());
}
}}}

Doing so will give us this UI:

[img[helloworld|img/helloworld/hw_01.png]]

If we change the text in the ''Name'' field and press //<Enter>//, the greeting is updated accordingly.

Like it so far? Keep going with the [[GettingStartedGuide]]
//Welcome to testdrive for Java//

td4j is a prototyping framework for domain models written in Java. It enables you to define essential structure and behaviour in code and try it out instantly.

''Why ?''
When designing the domain model of a software system, it's important to have feedback on the models fitness early in the process. This is especially true, if the designer is not a domain expert and if requirements are not exhaustive or inconsistent.

''What ?''
Verify that you are designing the right concepts the right way by taking them for a testdrive.

''How ?''
td4j analyzes and instruments the domain model using Java reflection and creates a GUI for you to work with the model directly.

!Tell me more!
* Have a look at the [[HelloWorld Example|HelloWorldExample]]
* [[Download td4j | https://sourceforge.net/projects/td4j/files/]] and work through the [[Getting Started Guide|GettingStartedGuide]]
* Check out the examples contained in the download
* Get more detailed information about the concepts and features from the [[Reference]]
[[Introduction]]
[[HelloWorld|HelloWorldExample]]
[[Getting Started|GettingStartedGuide]]
[[Download | https://sourceforge.net/projects/td4j/files/]]
[[Reference]]
{{{
this stub needs elaboration
}}}

* need explicit declaration with ''@Operation''
* constructor, instance methods & static methods
* without parameter
* with parameters, specifying paramNames
* return value = navigation
** no navigation with return value of primitive type


!Companions
* provide operations separated from domain entities
* implement behaviour spanning multiple domain objects or static behaviour (factory, repository, test)
* ~SvcRepo & ~AppCtx
* injection of domain object (first parameter)
<!--{{{-->
<div id='header' class='header'>

<div class='headerShadow'>
<span class='searchBar' macro='search'></span>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
</div>

<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='HaemoSideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='contentFooter' refresh='content' tiddler='contentFooter'></div>
<!--}}}-->
Structure is expressed with classes and their properties. Classes are ~POJOs.
 
Properties are identified at runtime with Java Reflection. By default, public fields and public methods adhering to the Java Bean Specification are recognized as properties. If there is only a getter method, then the property will be readonly, whereas properties from fields are always read/write. As it is the case with the reflection API, ordering of properties is arbitrary and not guaranteed.

{{{
public class Person {

  public  String  firstName;
  private String  lastName;
  private String  secretData;

  public Person(String firstName, String lastName, String secretData) {
    this.firstName  = firstName;
    this.lastName   = lastName;
    this.secretData = secretData;
  }
	
  public String getLastName() {
    return lastName;
  }
}
}}}

[img[img/reference/basicproperties.png]]


The type of property you get depends on the cardinality of the return type of the getter method, respectively on the field type. If it's not a collection, you get an ~IndividualProperty. If it's a collection type then you get a ~ListProperty. Only ~IndividualProperties are directly modifiable in the UI.

!! Override default behaviour for property discovery
You can override the default behaviour by sprinkling your ~POJOs with annotations.

To declare explicitly which properties a class has and in which order, use the ''@~ShowProperties'' annotation on the class:
{{{
@ShowProperties({"firstName", "secretData"})
public class Person {
...
}
}}}


To show or hide a particular property, use one of ''@Show'' or ''@Hide'':
{{{
@Show private String secretData;
@Hide public String getLastName() { ... }
}}}

!! Properties in tables
~ListProperties are shown in a table an are readonly
* To customize which properties of a class to show in the table, use the ''@~ShowProperties'' annotation
* To customize the properties shown in the editor's list view, use the ''@~ShowPropertiesInEditorList'' annotation
{{{
@ShowPropertiesInEditorList({"firstName", "lastName"})
public class Person {
		
  public String firstName;
  public String lastName;
		
  @ShowProperties({"street", "zip", "city"})
  public List<Address> addresses = new ArrayList<Address>();
}
}}}


[img[img/reference/propertieseditorlist.png]]


Note that ''@~ShowProperties'', ''@Show'' and ''@Hide'' all influence the set of properties for a given class that are known in td4j. This set of properties can later only be reduced and not expanded. Therefore the following code will not work:

{{{
@ShowProperties("firstName")
@ShowPropertiesInEditorList( { "firstName", "lastName" })
public class Person {
  ...
}
}}}
* Structure is modeled with [[Classes and Properties|Properties]]
* Behaviour is modeled with [[Operations]]
* Take your model for a testdrive in the [[Workbench]]
prototyping framework for domain models written in Java
td4j userguide
/*{{{*/
/*Haemoglobin Theme for TiddlyWiki*/
/*Design and CSS by Saq Imtiaz*/
/*Version 1.0*/
/*}}}*/
/*{{{*/

#sidebarTabs {font-family:arial,helvetica;}

body
{background:#fefefe;}

#contentWrapper {
	font-family: Verdana, Arial, Tahoma, Sans-Serif;
	color: #555555;
margin:1.9em auto 1em ; width:800px;}

#header {background:#fefefe;}

.headerShadow {	padding: 1.4em 0em 0.5em 1em; }

.siteTitle {
			font-family: 'Trebuchet MS' sans-serif;
			font-weight: bold;
			font-size: 36px;
			color: #BF2323;
			background-color: #FFF;
}

.siteSubtitle {
	font-size: 1.0em;
        display: block;
        margin: .5em 3em; color: #999;
}

.clearAll {clear:both;}
.tagClear {clear:none;}
#sidebar {position:relative; float:right; display:inline; right:0;}

a{
color:#BF2323;
text-decoration: none; font-weight:normal;
}

a:hover{
color:#BF2323;
background-color: #fefefe;
border-bottom:1px solid #BF2323;
}

.viewer .button, .editorFooter .button{
color: #555;
border: 1px solid #BF2323;
}

.viewer .button:hover,
.editorFooter .button:hover{
color: #fff;
background: #BF2323;
border-color: #BF2323;
}

.viewer .button:active, .viewer .highlight,.editorFooter .button:active, .editorFooter .highlight{color:#fff; background:#9F1313;border-color:#9F1313;}

#topMenu br {display:none;}

#topMenu {padding:0.45em 1em; background:#BF2323;}

#topMenu a, #topMenu .tiddlyLink, #topMenu .button {color:#f1f1f1; padding:0.3em 0.45em; margin:0 4px;font-size:120%;font-weight:normal;font-variant: small-caps; border:none; background:#BF2323; text-decoration:none; }

#topMenu a:hover, #topMenu .tiddlyLink:hover, #topMenu .button:hover, #topMenu .button:active, #topMenu .highlight {color:#fff;text-decoration:none; background:#9F1313; }



#displayArea{margin:0 17em 2em 0.5em;}

.tiddler {padding-left:0;}

.title {color:#BF2323; border-bottom:1px solid#BF2323; }
.subtitle, .subtitle a { color: #999999; font-size: 1.0em;margin:0.2em;}
.shadow .title{color:#999;}

.toolbar {font-size:85%;}
.selected .toolbar a {color:#999999;}
.selected .toolbar a:hover {color:#333; background:transparent;border:1px solid #fff;}

.toolbar .button:hover, .toolbar .highlight, .toolbar .marked, .toolbar a.button:active{color:#333; background:transparent;border:1px solid #fff;}

    *  html .viewer pre {

margin-left: 0em;
}

    * html .editor textarea, * html .editor input {

width: 98%;
}

/***
!Sidebar
***/
#sidebar {position:relative;float:right; line-height: 1.4em; border-left:0px solid#000; display:inline; background:#fefefe; right:0; margin-bottom:2em !important; margin-bottom:1em;
width: 16em;}

/***
!SidebarOptions
***/
#sidebarOptions {padding-left:0.5em; padding-top:2em;}

#sidebarOptions a {
			color:#999;
			text-decoration: none;}

#sidebarOptions	a:hover, #sidebarOptions a:active {
			color:#CC0000;
			background-color:#f5f5f5;border:1px solid #f5f5f5;
		}

#sidebarOptions input {border:1px solid #999; }



 .listTitle {color:#888;}

#sidebarTabs .tabContents {background:#fefefe;}
#sidebarTabs .tabContents .tiddlyLink, #sidebarTabs .tabContents .button{color:#999;}
#sidebarTabs .tabContents .tiddlyLink:hover,#sidebarTabs .tabContents .button:hover{color:#CC0000;background:#fefefe; text-decoration:none;border:none;}

#sidebarTabs .tabContents .button:hover, #sidebarTabs .tabContents .highlight, #sidebarTabs .tabContents .marked, #sidebarTabs .tabContents a.button:active{color:#CC0000;background:#fefefe}


.tabSelected{color:#fefefe; background:#999;}



 .tabSelected, .tabSelected:hover {
 color: #555;
 background: #fefefe;
 border: solid 1px #ccc;

}

#sidebarTabs .tabUnselected:hover { border-bottom: none;padding-bottom:3px;color:#999;}

 .tabUnselected {
 color: #999;
 background: #eee;
 border: solid 1px #ccc;

}

.tabUnselected:hover {text-decoration:none; border:1px solid #ccc;}

#sidebarTabs .tabUnselected { border-bottom: none;padding-bottom:3px;}
#sidebarTabs .tabSelected{padding-bottom:3px;}

#sidebarOptions .sliderPanel {
	background: #eee; border:1px solid#ccc;
	font-size: .9em;
}

#sidebarOptions .sliderPanel input {border:1px solid #999;}
#sidebarOptions .sliderPanel .txtOptionInput {border:1px solid #999;width:9em;}

#sidebarOptions .sliderPanel a {font-weight:normal; color:#555;background-color: #eee; border-bottom:1px dotted #333;}


#sidebarOptions .sliderPanel a:hover {
color:#111;
background-color: #eee;
border:none;
border-bottom:1px dotted #111;
}

.tabContents {background:#fefefe;}




.tagging, .tagged {
border: 1px solid #eee;
background-color: #F7F7F7;
}

.selected .tagging, .selected .tagged {
background-color: #f7f7f7;
border: 1px solid #ccc;
}

.tagging .listTitle, .tagged .listTitle {
color: #bbb;
}

.selected .tagging .listTitle, .selected .tagged .listTitle {
color: #666;
}

.tagging .button, .tagged .button {
color:#ccc;
}
.selected .tagging .button, .selected .tagged .button {
color:#aaa;
}

.highlight, .marked {background:transparent; color:#111; border:none; text-decoration:underline;}

.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
border: none; background:transparent; text-decoration:underline; color:#333;
}

.popup {
background: #BF2323;
border: 1px solid #BF2323;
}

.popup li.disabled {
color: #000;
}

.popup li a, .popup li a:visited {
color: #eee;
border: none;
}

.popup li a:hover {
background: #bf1717;
color: #fff;
border: none;
}



   #messageArea {

border: 4px solid #BF2323;
background: #fefefe;
color: #555;
font-size:90%;
}

   #messageArea a:hover { background:#f5f5f5; border:none;}


   #messageArea .button{
color: #666;
border: 1px solid #BF2323;
}

   #messageArea .button:hover {
color: #fff;
background: #BF2323;
border-color: #BF2323;
}

   #contentFooter {background:#BF2323; color:#DF7D7D; clear: both; padding: 0.5em 1em; }


#contentFooter a {
color: #DF7D7D;
border-bottom: 1px dotted #DF7D7D; font-weight:normal;text-decoration:none;
}



#contentFooter a:hover {
color: #FFFFFF;
background-color:transparent;
border-bottom: 1px dotted #fff; text-decoration:none;
}




.searchBar {float:right;font-size: 1.0em;position:relative; margin-top:1.3em;}
.searchBar .button {color:#999;display:block;}
.searchBar .button:hover {border:1px solid #fefefe;color:#4F4B45;}
.searchBar input {			
                        background-color: #fefefe;
			color: #999999;
			border: 1px solid #CCC;		margin-right:3px;
}

.tiddler {padding-bottom:10px;}

.viewer blockquote {
border-left: 5px solid #BF2323;
}

.viewer table, .viewer td {
border: 1px solid #BF2323;
}

.viewer th, thead td {
background: #BF2323;
border: 1px solid #BF2323;
color: #fff;
}
.viewer pre {
	border: 1px solid #ccc;
	background: #f5f5f5;
}

.viewer code {
color: #111; background:#f5f5f5;
}

.viewer hr {
border-top: dashed 1px #555;
}

.editor input {
border: 1px solid #888; margin-top:5px;
}

.editor textarea {
border: 1px solid #888;
}

h1,h2,h3,h4,h5 { color: #BF2323; background: transparent; padding-bottom:2px; font-family: Arial, Helvetica, sans-serif; }
h1 {font-size:18px;}
h2 {font-size:16px;}
h3 {font-size: 14px;}
/*}}}*/
Here is a reference for the markup "language" used. See also [[Internal Macros]] (especially for the {{{<<br>>}}} macro that throws a new line).
!Basic Formatting
|!Format|!Markup|!Example|
|Bold|{{{''Bold''}}} (2 single quotes)|''Bold''|
|Highlight|{{{@@Highlight@@}}}|@@Highlight@@|
|CSS Extended Highlights|{{{@@some css;Highlight@@}}}<<br>>For backwards compatibility, the following highlight syntax is also accepted:{{{@@bgcolor(#ff0000):color(#ffffff):red coloured@@}}}|@@background-color:#ff0000;color:#ffffff;red coloured@@<<br>><<slider AtEg ./atEg 'Extended example ...'>>|
|Custom CSS Class|<html><code>{{wrappingClass{Text that is now accentuated}}}</code></html><<br>>By default, the text is placed in a <span>. To use a <div> instead, insert a line break before the text (after the single {)<<br>>In the CSS: {{{.wrappingClass {color: red;} }}}|Add .wrappingClass to StyleSheet|
|Italic|{{{//Italic//}}}|//Italic//|
|Monospaced text|<html><code>{{{ ... }}}</code></html>|{{{Monospaced text}}}|
|Monospaced block multiline|Put <html><code>{{{</code></html> and <html><code>}}}</code></html> on their own lines|<html><pre>{{{<br/>Monospaced<br/>Multi-line<br/>Block<br/>}}}</pre></html>|
|Strikethough|{{{==Strikethrough==}}}|==Strikethrough==|
|Subscript|{{{~~Subscript~~}}}|Text~~Subscript~~|
|Superscript|{{{^^Superscript^^}}}|Text^^Superscript^^|
|Underlined|{{{__Underline__}}}(2 underscores)|__Underscored__|
|Any HTML|{{{<html><span>any</span><br /><b>valid</b> <em>xhtml</em></html>}}}|<html><span>any</span><br /><b>valid</b> <em>xhtml</em></html>|
!"Document" Structure
|!Format|!Markup|!Example|
|Headings|{{{!Heading 1}}}<<br>>{{{!!Heading 2}}}|<html><h1>Heading 1</h1><h2>Heading 2</h2><h3>Heading 3</h3><h4>Heading 4</h4><h5>Heading 5</h5></html>|
|Any HTML|{{{<html><p>any valid xhtml</p></html>}}}|<html><p>any valid xhtml</p></html>|
|Block quotes|{{{>Blockquote}}}<<br>>Can be nested using multiple >|<html><blockquote>Blockquote<blockquote>Nested Blockquote</blockquote></blockquote></html>|
|Blockquotes - Multiline|<html><tt><<<</tt><br/>multi-line<br/>blockquote<br/><tt><<<</tt></html> |<html><blockquote>multi-line<br/>blockquote</blockquote></html>|
|Horizontal Rule|{{{----}}} (4 dashes on a line of their own)|<html><hr></html>|
|Images|{{{[img[favicon.ico]]}}}<<br>>Note that image files are always external to the TW file|[img[http://www.tiddlywiki.com/favicon.ico]]|
|Inline Comments|{{{/% .... %/}}}<<br>>Text between the markers will not be shown in view mode|Not shown: /% Not Shown %/|
|Links|Any WikiWord (creates a link to a tiddler whether it exists or not).<<br>>Note that a WikiWord has to start with a capital letter and have a further mix of upper and lower case.|PageTemplate|
|~|{{{[[Manual Link]]}}} (Especially for tiddlers with spaces in their titles)|[[Table of Contents]]|
|~|{{{[[Pretty Link|Some Crafty Link]]}}}<<br>>Note: Makes an external link if the target does not yet exist (e.g. {{{[[Not Yet A Tiddler|NotYetATiddler]]}}})|[[Pretty Link|MainMenu]]<<br>>[[Not Yet A Tiddler|NotYetATiddler]]|
|~|Automatic external link {{{http://www.knightnet.org.uk}}}|http://www.knightnet.org.uk|
|~|Pretty external link<<br>>{{{[[My Home Page|http://www.knightnet.org.uk]]}}}|[[My Home Page|http://www.knightnet.org.uk]]|
|~|OS Folder link<<br>>Windows Share: {{{file://///server/share}}}<<br>>Windows Local: {{{file:///c:/folder/file}}}<<br>>Un*x Local File: {{{file://folder/file}}}<<br>>Relative File: {{{folder/file}}}||
|List - Bulleted|{{{* List entry}}}|<html><ul><li>Bullet List</li></ul></html>|
|List - Numbered|{{{# List entry}}}|<html><ol><li>Numbered List</li></ol></html>|
|List - Nested|Both list types can be nested by using multiple * or #<<br>>Note that * and # must be the first character of the line as with all block format markup.<<br>>{{{* 1st level}}}<<br>>{{{** 2nd level}}}|<<tiddler ./nestedListEg>>|
|Tables| {{{|}}} |Column Seperator |
|~| {{{!}}} |Header (Row or Column) |
|~| {{{>}}} |Column Span |
|~| {{{~}}} |Row Span |
|~| {{{|Left |}}} |Left Align |
|~| {{{| Right|}}} |Right Align|
|~| {{{| Center |}}} |Center Align |
|~| {{{|Caption|c}}} |Table Caption (Can be at top or bottom)|
|~| {{{|Header|h}}} |Marks the row as being a header row (will be wrapped with a {{{<thead>}}} and so all entries are automatically formatted as per {{{|!}}} cells)|
|~| {{{|Footer|f}}} |Marks the row as being a footer row (will be wrapped with a {{{<tfoot>}}}, no special formatting is pre-defined for this but can be added to your own CSS)|
|~| {{{|CSSclass|k}}} |Applies a CSS class to the table to allow additional formatting (NB: only works if no whitespace after the k)|
|~|>|Note that the additional CSS classes evenRow and oddRow are automatically applied to all rows of the table. But evenRow is applied to the "first" row as per JavaScript convention (it is the zero'th row which is strangely considered even!).|
|~|>|To have a table with no borders at all. Use {{{|noBorder|k}}} with the CSS (in your StyleSheet tiddler):<<br>>{{{ .noBorder,.noBorder td,.noBorder th,.noBorder tr{border:0 !important} }}}|
|Table Sample|<<tiddler ./tblMarkup>>|<<tiddler ./tblShow>>|
!Notes
You can use the custom CSS formatter in combination with headers and lists to allow new lines within the entry. e.g.:
{{{
#{{block{
Bullet 1
Some text in the same bullet
(Note that "block" can be anything, it is the formatters CSS class name)
 }}}
# Bullet 2 
}}}
#{{block{
Bullet 1
Some text in the same bullet
}}}
# Bullet 2 

(Julian Knight, 2006-05-11)
<part atEg hidden>
{{{
This is before the indented text
@@display:block;margin-left:2em;This text will be indented...
...and can even span across several lines...

...or even include blank lines.
@@This is after the indented text 
}}}
This is before the indented text
@@display:block;margin-left:2em;This text will be indented...
...and can even span across several lines...

...or even include blank lines.
@@This is after the indented text 
</part>
<part tblMarkup hidden>
{{{
|table caption at top|c
|header|header|h
|text, more text, more text|text, more text, more text|
|!heading|!heading|
|>|colspan=2|
|rowspan|left align |
|~| center |
|bgcolor(green):green| right|
|footer|footer|f
|table caption at bottom|c
}}}
</part>
<part tblShow hidden>
|table caption at top|c
|header|header|h
|text, more text, more text|text, more text, more text|
|!heading|!heading|
|>|colspan=2|
|rowspan|left align |
|~| center |
|bgcolor(green):green| right|
|footer|footer|f
|table caption at bottom|c
</part>
<part nestedListEg hidden>
* 1st Level
** 2nd Level
</part>
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
{{{
this stub needs elaboration
}}}

* Sidebar
* ~ListView Content (Operations, Link)
* Selection & Visibility
* ~DetailView
* ~Operations-Menu

* SRC Simple Launch
* SRC Launch with ~AppContext 
Copyright [[Michael Rauch|http://www.miranet.ch]]