[Checkins] SVN: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/ addressbook working and added sqlmessage

Darryl Cousins darryl at darrylcousins.net.nz
Fri Jul 13 03:36:44 EDT 2007


Log message for revision 77800:
  addressbook working and added sqlmessage

Changed:
  U   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.py
  U   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.txt
  U   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/browser/index.pt
  U   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/configure.zcml
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/README.txt
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/__init__.py
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/add.pt
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/MSG.grl
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/msg.gfd
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/display.pt
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/edit.pt
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/overview.pt
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/rdb.zcml
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.css
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.py
  A   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.txt
  U   Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/tests.py

-=-
Modified: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.py
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.py	2007-07-13 07:36:39 UTC (rev 77799)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.py	2007-07-13 07:36:43 UTC (rev 77800)
@@ -8,7 +8,7 @@
 from z3c.form.interfaces import IFormLayer, INPUT_MODE
 from z3c.formdemo.addressbook import interfaces, browser, dateselect
 
-SESSION_KEY = 'mars.formdemo.addressbook'
+SESSION_KEY = 'z3c.formdemo.addressbook'
 
 import grok
 
@@ -19,10 +19,12 @@
 
 mars.layer.layer(IDemoBrowserLayer)
 
+
 class DateSelectWidget(mars.adapter.AdapterFactory):
-    mars.adapter.factory(dateselect.DateSelectFieldWidget)
+    mars.adapter.factory(dateselect.DateSelectDataConverter)
 
 class ContactLabel(mars.adapter.AdapterFactory):
+    grok.name('title')
     mars.adapter.factory(button.StaticButtonActionAttribute(
                         u'Add Contact', 
                         button=form.AddForm.buttons['add'], 
@@ -84,7 +86,7 @@
     grok.template('addressbook.pt')
 
 class ContactAddTemplate(mars.template.TemplateFactory):
-    grok.context(browser.ContactEditForm)
+    grok.context(browser.ContactAddForm)
     grok.template('contact.pt')
 
 class ContactTemplate(mars.template.TemplateFactory):

Modified: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.txt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.txt	2007-07-13 07:36:39 UTC (rev 77799)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/addressbook/addressbook.txt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -21,4 +21,182 @@
 on the "Address Book" link:
 
   >>> user.open(skinURL + '/addressbook')
-  >>> print user.contents
+
+There is only one screen for this demo. In it you see the table of all
+contacts on the left side and on the right side is the contact
+form. Initially, this is an add form.
+
+  >>> testing.printElement(user, "//h1")
+  <h1><span>Address Book Demo</span></h1>
+
+So let's start by filling out the add form. The first portion contains basic
+personal information:
+
+  >>> user.getControl('First Name').value = 'Stephan'
+  >>> user.getControl('Last Name').value = 'Richter'
+
+  >>> user.getControl(name='contact.add.widgets.birthday.day:list')\
+  ...     .getControl('25').click()
+  >>> user.getControl(name='contact.add.widgets.birthday.year:list')\
+  ...     .getControl('1980').click()
+
+In the second portion we can add any number of addresses. Let's just add a
+home address:
+
+  >>> user.getControl('Add', index=0).click()
+
+  >>> user.getControl('Street').value = '110 Main Street'
+  >>> user.getControl('City').value = 'Maynard'
+  >>> user.getControl('State').value = 'MA'
+  >>> user.getControl('ZIP').value = '01754'
+
+You cannot add the same address twice:
+
+  >>> user.getControl('Add', index=0).click()
+  >>> testing.printElement(user, "//div[@class='summary']")
+  <div class="summary">Address already provided for contact.</div>
+
+When accidently adding another address, ...
+
+  >>> user.getControl(name='contact.add.addresses.widgets.addressName:list')\
+  ...     .getControl('Work').click()
+  >>> user.getControl('Add', index=0).click()
+
+you can delete it any time:
+
+  >>> user.getControl('Delete', index=1).click()
+
+Let's now add the home phone number, because it is a required field:
+
+  >>> user.getControl(name='contact.add.phones.homePhone.widgets.countryCode')\
+  ...     .value = '+1'
+  >>> user.getControl(name='contact.add.phones.homePhone.widgets.areaCode')\
+  ...     .value = '555'
+  >>> user.getControl(name='contact.add.phones.homePhone.widgets.number')\
+  ...     .value = '127-1284'
+
+Finally, the user is requested to enter the E-mail addresses of the contact;
+we have two in this case:
+
+  >>> user.getControl(name='contact.add.emails.widgets.fullAddress')\
+  ...     .value = 'srichter at gmail.com'
+  >>> user.getControl('Add', index=1).click()
+
+  >>> user.getControl(name='contact.add.emails.widgets.fullAddress')\
+  ...     .value = 'srichter at tufts.edu'
+  >>> user.getControl('Add', index=1).click()
+
+Once all the information has been provided, we can add the contact:
+
+  >>> user.getControl('Add Contact').click()
+
+The new contact appears now in the contact list:
+
+  >>> testing.printElement(user, "//table/tbody/tr[1]")
+  <tr class="odd"><td class="sorted-on">
+      <a href="...?selectContact=contact-0">Richter</a>
+    </td>
+    <td class="">
+      <a href="...?selectContact=contact-0">Stephan</a>
+    </td>
+  </tr>
+
+By clicking on the name, the edit form for Stephan is shown:
+
+  >>> user.getLink('Richter').click()
+
+Note that the row is highlighted now:
+
+  >>> testing.printElement(user, "//table/tbody/tr[1]")
+  <tr class="selected"><td class="sorted-on">
+      <a href="...?selectContact=contact-0">Richter</a>
+    </td>
+    <td class="">
+      <a href="...?selectContact=contact-0">Stephan</a>
+    </td>
+  </tr>
+
+After adding a work phone number and deleting one of the two E-mail addresses,
+
+  >>> user.getControl(name='contact.edit.phones.workPhone.widgets.countryCode')\
+  ...     .value = '+1'
+  >>> user.getControl(name='contact.edit.phones.workPhone.widgets.areaCode')\
+  ...     .value = '555'
+  >>> user.getControl(name='contact.edit.phones.workPhone.widgets.number')\
+  ...     .value = '346-3573'
+
+  >>> user.getControl('Delete', index=1).click()
+
+we now save the contact changes:
+
+  >>> user.getControl('Apply').click()
+
+This submission saves all the data but stays in the edit form of the
+contact. Only by pressing the "Done" button, the add form will return.
+
+  >>> user.getControl('Done').click()
+  >>> user.getControl('Add Contact')
+  <SubmitControl name='contact.add.buttons.add' type='submit'>
+
+You will also notice that the contact is not highlighted in the table
+anymore. Let's nwo add a second contact:
+
+  >>> user.getControl('First Name').value = 'Roger'
+  >>> user.getControl('Last Name').value = 'Ineichen'
+
+  >>> user.getControl(name='contact.add.phones.homePhone.widgets.countryCode')\
+  ...     .value = '+41'
+  >>> user.getControl(name='contact.add.phones.homePhone.widgets.areaCode')\
+  ...     .value = '43'
+  >>> user.getControl(name='contact.add.phones.homePhone.widgets.number')\
+  ...     .value = '12 23 23'
+
+  >>> user.getControl('Add Contact').click()
+
+You can now sort the contacts by last and first name now, of course. Clicking
+on the "Last Name" table header cell, will leave the order, since the ordering
+must be initialized. The second time the order is reversed:
+
+  >>> user.getLink('Last Name').click()
+  >>> user.getLink('Last Name').click()
+
+  >>> testing.printElement(user, "//table/tbody/tr/td[1]/a/text()",
+  ...                      multiple=True, serialize=False)
+  Richter
+  Ineichen
+
+Selecting another header will sort on it. Let's choose the first name;
+clicking on it once sorts it in ascending order:
+
+  >>> user.getLink('First Name').click()
+  >>> testing.printElement(user, "//table/tbody/tr/td[2]/a/text()",
+  ...                      multiple=True, serialize=False)
+  Roger
+  Stephan
+
+Clicking it again, reverses the order:
+
+  >>> user.getLink('First Name').click()
+  >>> testing.printElement(user, "//table/tbody/tr/td[2]/a/text()",
+  ...                      multiple=True, serialize=False)
+  Stephan
+  Roger
+
+To delete a contact, you must first select it:
+
+  >>> user.getLink('Roger').click()
+
+At the bototm of the contact form is a delete button that will delete the
+entire contact:
+
+  >>> user.getControl('Delete').click()
+
+The user is now gone from the table and we are returned to the add form:
+
+  >>> user.getLink('Roger')
+  Traceback (most recent call last):
+  ...
+  LinkNotFoundError
+
+  >>> user.getControl('Add Contact')
+  <SubmitControl name='contact.add.buttons.add' type='submit'>

Modified: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/browser/index.pt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/browser/index.pt	2007-07-13 07:36:39 UTC (rev 77799)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/browser/index.pt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -30,7 +30,13 @@
     <a href="../wizard">Wizard</a>
   </div>
   <div>
+    <a href="../addressbook">Address Book</a>
+  </div>
+  <div>
     <a href="../spreadsheet">Spreadsheet</a>
   </div>
+  <div>
+    <a href="/showallsql">SQL Hello World</a>
+  </div>
 </div>
 

Modified: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/configure.zcml
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/configure.zcml	2007-07-13 07:36:39 UTC (rev 77799)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/configure.zcml	2007-07-13 07:36:43 UTC (rev 77800)
@@ -15,5 +15,7 @@
     </resourceLibrary>
   </configure>
 
+  <include package=".sqlmessage" file="rdb.zcml" />
+
 </configure>
 

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/README.txt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/README.txt	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/README.txt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,9 @@
+============================
+SQL Hello World Message Demo
+============================
+
+The purpose of the SQL Hello World Message demo is to demonstrate how
+non-object data can be manipulated and displayed using the form framework.
+
+The original doctest is at ./sqlmessage.txt.
+


Property changes on: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/README.txt
___________________________________________________________________
Name: svn:keywords
   + Date Author

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/__init__.py
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/__init__.py	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/__init__.py	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1 @@
+#


Property changes on: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/add.pt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/add.pt	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/add.pt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,5 @@
+<h1>Hello World Message Add Form</h1>
+
+<div id="body">
+  <div metal:use-macro="macro:form" />
+</div>

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/MSG.grl
===================================================================
(Binary files differ)


Property changes on: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/MSG.grl
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/msg.gfd
===================================================================
(Binary files differ)


Property changes on: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/db/msg/msg.gfd
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/display.pt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/display.pt	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/display.pt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,14 @@
+<h1>
+  A <span tal:replace="structure view/widgets/what/render" /> Hello World
+  from <span tal:replace="structure view/widgets/who/render" />
+  on <span tal:replace="structure view/widgets/when/render" />!
+</h1>
+
+<div id="body">
+  <div class="actions">
+    <a href="./edit.html"
+       tal:attributes="href string:editsql?id=${request/id}">
+      [Edit Message]</a>
+    <a href="showallsql">[Show All Messages]</a>
+  </div>
+</div>

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/edit.pt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/edit.pt	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/edit.pt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,10 @@
+<h1>Hello World Message Edit Form</h1>
+
+<div id="body">
+  <div metal:use-macro="macro:form">
+    <metal:block fill-slot="above-buttons">
+      <input type="hidden" name="id" value=""
+             tal:attributes="value request/form/id" />
+    </metal:block>
+  </div>
+</div>

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/overview.pt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/overview.pt	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/overview.pt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,21 @@
+<h1>SQL Hello World Message Demo</h1>
+
+<div id="body">
+  <div class="status"
+         tal:define="status view/status"
+         tal:condition="status">
+    <div class="summary"
+         tal:content="status">
+      status summary
+    </div>
+  </div>
+
+  <div tal:replace="structure view/table" />
+
+  <div class="actions">
+    <a href="addsql">[Add message]</a>
+    <a href="showallsql?initialize=1">
+      [Initialize the database]
+    </a>
+  </div>
+</div>

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/rdb.zcml
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/rdb.zcml	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/rdb.zcml	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,14 @@
+<configure
+    xmlns:rdb="http://namespaces.zope.org/rdb"
+    i18n_domain="mars.formdemo">
+
+  <!-- RDB setup -->
+
+  <rdb:gadflyRoot path="./db" />
+
+  <rdb:provideConnection
+      name="msg"
+      component="zope.rdb.gadflyda.GadflyAdapter"
+      dsn="dbi://msg" />
+
+</configure>

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.css
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.css	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.css	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,85 @@
+body {
+  background: #EBE6D3;
+}
+
+a:visited {
+  color: #D91813;
+}
+
+a:hover {
+  color: #D91813;
+}
+
+h1 {
+  background: #574E3F;
+  color: #D5CDC6;
+  font-weight: bold;
+  padding: 5px;
+  border-bottom: 3px solid #900002;
+}
+
+input[type=text] {
+ padding: 2px;
+}
+
+input[type=submit] {
+  border: 1px solid black;
+  background: #900002;
+  color: white;
+  font-weight: bold;
+  padding: 2px;
+  -moz-border-radius: 5px;
+}
+
+div#content {
+  margin: 0;
+  padding: 0;
+}
+
+div#body {
+  margin: 20px;
+}
+
+div.status {
+  background-color: #F5F2EB;
+  border: 1px solid #CAC8C2;
+  color: #D91813;
+  font-style: italic;
+  margin: 10px 0px;
+  padding: 7px;
+  -moz-border-radius: 5px;
+}
+
+div.actions, div.buttons {
+  background-color: #F5F2EB;
+  border: 1px solid #CAC8C2;
+  margin-top: 10px;
+  padding: 7px;
+  -moz-border-radius: 5px;
+}
+
+table.message-list th {
+  background: #A79E8D;
+  padding: 3px;
+}
+
+table.message-list td {
+  color: #574E3F;
+  padding: 2px 0px;
+}
+
+table.message-list tr.even {
+  background-color: #F5F2EB;
+}
+
+table.message-list td a {
+  color: #574E3F;
+}
+
+table.message-list td a:hover {
+  color: #574E3F;
+}
+
+table.message-list td a:visited {
+  color: #574E3F;
+}

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.py
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.py	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.py	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,207 @@
+import datetime
+
+import zope.interface
+import zope.rdb
+from zope.traversing.browser import absoluteURL
+from zope.viewlet.viewlet import CSSViewlet
+
+from zc.table import column
+from zc.table.interfaces import ISortableColumn
+
+from z3c.form import widget, field, form, button
+from z3c.form.interfaces import IAddForm
+from z3c.formui import layout
+from z3c.formdemo.sqlmessage import sql
+from z3c.formdemo.browser import formatter
+from z3c.formdemo.sqlmessage.interfaces import IHelloWorld
+from z3c.formdemo.sqlmessage.browser import (ISQLMessagePage,
+                                             SQLColumn,
+                                             DateSQLColumn,
+                                             DeleteSQLColumn)
+                                              
+import grok
+
+import mars.adapter
+import mars.resource
+import mars.viewlet
+import mars.view
+import mars.layer
+
+from mars.formdemo.layer import IDemoBrowserLayer
+from mars.formdemo.skin import skin
+
+mars.layer.layer(IDemoBrowserLayer)
+
+SESSION_KEY = 'mars.formdemo.sqlmessage'
+
+
+class DefaultDate(mars.adapter.AdapterFactory):
+    grok.name('default')
+    mars.adapter.factory(widget.ComputedWidgetAttribute(
+                        lambda adapter: datetime.date.today(),
+                        field=IHelloWorld['when'], view=IAddForm))
+
+## CSS requirement
+class MessageStyle(mars.resource.ResourceFactory):
+    """File resource"""
+    grok.name('sqlmessage.css')
+    mars.resource.file('sqlmessage.css')
+
+MessageCSS = CSSViewlet('sqlmessage.css')
+class MessageCSSViewlet(mars.viewlet.SimpleViewlet, MessageCSS):
+    """css viewlet"""
+    weight = 1000
+    grok.name('sqlmessage.css')
+    grok.context(zope.interface.Interface)
+    mars.viewlet.view(ISQLMessagePage)
+    mars.viewlet.manager(skin.CSSManager)
+
+class AddForm(mars.view.FormView, layout.AddFormLayoutSupport, form.AddForm):
+    grok.context(zope.interface.Interface)
+    grok.name('addsql')
+    zope.interface.implements(ISQLMessagePage)
+
+    fields = field.Fields(IHelloWorld)
+
+    def create(self, data):
+        return data
+
+    def add(self, data):
+        data['id'] = sql.getNextId()
+        data['when'] = data['when'].toordinal()
+        sql.addMessage(data)
+        return data
+
+    def nextURL(self):
+        url = absoluteURL(self.context, self.request)
+        return url + '/showallsql'
+
+class EditForm(mars.view.FormView, layout.FormLayoutSupport, form.EditForm):
+    grok.context(zope.interface.Interface)
+    grok.name('editsql')
+    zope.interface.implements(ISQLMessagePage)
+
+    form.extends(form.EditForm)
+    fields = field.Fields(IHelloWorld)
+
+    def getContent(self):
+        msg = sql.getMessage(self.request.form['id'])
+        content = dict(
+            [(name, getattr(msg, name.upper()))
+             for name in self.fields.keys()] )
+        content['when'] = datetime.date.fromordinal(content['when'])
+        return content
+
+    def applyChanges(self, data):
+        changed = False
+        for name, value in self.getContent().items():
+            if data[name] != value:
+                changed = True
+        data['when'] = data['when'].toordinal()
+        if changed:
+            id = self.request.form['id']
+            sql.updateMessage(id, data)
+        return changed
+
+    @button.buttonAndHandler(u'Apply and View', name='applyView')
+    def handleApplyView(self, action):
+        self.handleApply(self, action)
+        if not self.widgets.errors:
+            url = absoluteURL(self.context, self.request)
+            url += '/showsql?id=' + self.request['id']
+            self.request.response.redirect(url)
+
+class DisplayForm(mars.view.FormView, layout.FormLayoutSupport, form.DisplayForm):
+    grok.context(zope.interface.Interface)
+    grok.name('showsql')
+    zope.interface.implements(ISQLMessagePage)
+
+    fields = field.Fields(IHelloWorld)
+
+    def getContent(self):
+        msg = sql.getMessage(self.request.form['id'])
+        content = dict(
+            [(name, getattr(msg, name.upper()))
+             for name in self.fields.keys()] )
+        content['when'] = datetime.date.fromordinal(content['when'])
+        return content
+
+class SQLColumn(column.GetterColumn):
+    zope.interface.implements(ISortableColumn)
+
+    def getter(self, item, formatter):
+        return getattr(item, self.name.upper())
+
+    def cell_formatter(self, value, item, formatter):
+        return '<a href="showsql?id=%s">%s</a>' %(
+            item.ID, unicode(value))
+
+class DateSQLColumn(SQLColumn):
+
+    def getter(self, item, formatter):
+        value = super(DateSQLColumn, self).getter(item, formatter)
+        return datetime.date.fromordinal(value)
+
+class DeleteSQLColumn(column.Column):
+
+    def renderCell(self, item, formatter):
+        link = '<a href="showallsql?delete=%i">[Delete]</a>'
+        return link % item.ID
+
+class Overview(mars.view.PageletView):
+    grok.context(zope.interface.Interface)
+    grok.name('showallsql')
+    zope.interface.implements(ISQLMessagePage)
+
+    status = None
+
+    columns = (
+        SQLColumn(u'Id', name='id'),
+        SQLColumn(u'Who', name='who'),
+        DateSQLColumn(u'When', name='when'),
+        SQLColumn(u'What', name='what'),
+        DeleteSQLColumn(u'', name='delete')
+        )
+
+    def update(self):
+        if 'initialize' in self.request.form:
+            try:
+                sql.initialize()
+            except zope.rdb.DatabaseException, exc:
+                self.status = "Database Message: " + exc.message
+        elif 'delete' in self.request.form:
+            try:
+                sql.deleteMessage(self.request.form['delete'])
+            except zope.rdb.DatabaseException, exc:
+                self.status = "Database Message: " + exc.message
+
+        try:
+            messages = sql.queryAllMessages()
+        except zope.rdb.DatabaseException, exc:
+            # No message table exists yet.
+            messages = ()
+
+        self.table = formatter.ListFormatter(
+            self.context, self.request, messages,
+            prefix = SESSION_KEY + '.', columns=self.columns,
+            sort_on=[('id', False)])
+        self.table.sortKey = 'z3c.formdemo.sqlmessage.sort-on'
+        self.table.cssClasses['table'] = 'message-list'
+        self.table.widths = (50, 200, 100, 150, 100)
+
+class AddFormTemplate(mars.template.TemplateFactory):
+    grok.context(AddForm)
+    grok.template('add.pt')
+
+class EditFormTemplate(mars.template.TemplateFactory):
+    grok.context(EditForm)
+    grok.template('edit.pt')
+
+class DisplayFormTemplate(mars.template.TemplateFactory):
+    grok.context(DisplayForm)
+    grok.template('display.pt')
+
+class OverviewTemplate(mars.template.TemplateFactory):
+    grok.context(Overview)
+    grok.template('overview.pt')
+


Property changes on: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.txt
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.txt	                        (rev 0)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.txt	2007-07-13 07:36:43 UTC (rev 77800)
@@ -0,0 +1,195 @@
+============================
+SQL Hello World Message Demo
+============================
+
+The purpose of the SQL Hello World Message demo is to demonstrate how
+non-bject data can be manipulated and displayed using the form framework.
+
+To start, we need to open a browser and go to the demo applications overview
+screen:
+
+  >>> from z3c.formdemo import testing
+  >>> from z3c.etestbrowser.testing import ExtendedTestBrowser
+  >>> user = ExtendedTestBrowser()
+  >>> user.addHeader('Accept-Language', 'en')
+  >>> user.handleErrors = False
+  >>> skinURL = 'http://localhost:8080/++skin++marsformdemo'
+
+Since all demos are purely public, there is no need to log in. Let's now click
+on the "SQLMessage" link:
+
+  >>> user.open('http://localhost:8080/showallsql')
+
+
+The initial page of the demo is the list of all messages. This screen exists,
+because the ZMI management screens are not helpful for unmapped relational data.
+
+  >>> testing.printElement(user, "//h1")
+  <h1>SQL Hello World Message Demo</h1>
+
+Let's make sure the database is truly empty:
+
+  >>> testing.printElement(user, "//table/tbody", multiple=True)
+
+We can now initialize the database using one of the action links below the
+table:
+
+  >>> user.getLink('[Initialize the database]').click()
+  >>> testing.printElement(user, "//div[@class='summary']", multiple=True)
+
+The page returns with no notable messages. Clicking the link again results in
+an error, because the database is already initialized:
+
+  >>> user.getLink('[Initialize the database]').click()
+  >>> testing.printElement(user, "//div[@class='summary']")
+  <div class="summary">Database Message: cannot create MSG, exists</div>
+
+Let's now add a new message:
+
+  >>> user.getLink('[Add message]').click()
+
+You are now represented with the message add form.
+
+  >>> user.url
+  'http://localhost:8080/addsql'
+
+If we submit the form by clicking on add, ...
+
+  >>> user.getControl('Add').click()
+
+... the same page returns telling us we have some errors:
+
+  >>> testing.printElement(user, "//div[@class='summary']")
+  <div class="summary">There were some errors.</div>
+
+This is because we forgot to enter the "Who" field, which is required:
+
+  >>> testing.printElement(user, "//ul[@class='errors']/li")
+  <li>
+     Who: <div class="error">Required input is missing.</div>
+  </li>
+
+Let's now fill out all the required fields and try to add the message again:
+
+  >>> user.getControl('Who').value = u'Stephan'
+  >>> user.getControl('When').value = u'7/1/07'
+  >>> user.getControl('Add').click()
+
+Once submitted, the message is now added to the database and we are returned
+back to the overview:
+
+  >>> testing.printElement(user, "//table/tbody/tr[1]")
+  <tr class="odd"><td class="sorted-on">
+      <a href="showsql?id=0">0</a>
+    </td>
+    <td class="">
+      <a href="showsql?id=0">Stephan</a>
+    </td>
+    <td class="">
+      <a href="showsql?id=0">2007-07-01</a>
+    </td>
+    <td class="">
+      <a href="showsql?id=0">cool</a>
+    </td>
+    <td class="">
+      <a href="showallsql?delete=0">[Delete]</a>
+    </td>
+  </tr>
+
+Clicking on any data item, brings us to the message display screen:
+
+  >>> user.getLink('Stephan').click()
+  >>> testing.printElement(user, "//h1")
+  <h1>
+    A cool Hello World from Stephan on 7/1/07 !
+  </h1>
+
+The message's edit form can be accessed by clicking on the "Edit Message"
+link:
+
+  >>> user.getLink('Edit Message').click()
+
+When immediately pressing "Apply", a message appears telling us that no data
+has been changed:
+
+  >>> user.getControl('Apply', index=0).click()
+  >>> testing.printElement(user, "//div[@class='summary']")
+  <div class="summary">No changes were applied.</div>
+
+Let's now change the name and submit the form:
+
+  >>> user.getControl('Who').value = u'Roger'
+  >>> user.getControl('Apply', index=0).click()
+
+The page now informs us that the data has been updated:
+
+  >>> testing.printElement(user, "//div[@class='summary']")
+  <div class="summary">Data successfully updated.</div>
+
+When pressing the "Apply and View" button, the changed data is stored and the
+user is also forwarded to the view page again:
+
+  >>> user.getControl('What').getControl('best').click()
+  >>> user.getControl('Apply and View').click()
+
+Of course, the view shows the latest data:
+
+  >>> testing.printElement(user, "//h1")
+  <h1>
+    A best Hello World from Roger on 7/1/07 !
+  </h1>
+
+From the display screen you can also return to the overview:
+
+  >>> user.getLink('[Show All Messages]').click()
+  >>> user.url
+  'http://localhost:8080/showallsql'
+
+Let's now add a new message:
+
+  >>> user.getLink('[Add message]').click()
+
+  >>> user.getControl('Who').value = u'Stephan'
+  >>> user.getControl('When').value = u'7/2/07'
+  >>> user.getControl('Add').click()
+
+As you probably already guessed, the table headers can be used to sort
+items. Clicking on the "Id" table header cell, will leave the order,
+since the ordering must be initialized. The second time the order is reversed:
+
+  >>> user.getLink('Id').click()
+  >>> user.getLink('Id').click()
+
+  >>> testing.printElement(user, "//table/tbody/tr/td[1]/a/text()",
+  ...                      multiple=True, serialize=False)
+  1
+  0
+
+Selecting another header will sort on it. Let's choose the "Who" column;
+clicking on it once sorts it in ascending order:
+
+  >>> user.getLink('Who').click()
+  >>> testing.printElement(user, "//table/tbody/tr/td[2]/a/text()",
+  ...                      multiple=True, serialize=False)
+  Roger
+  Stephan
+
+Clicking it again, reverses the order:
+
+  >>> user.getLink('Who').click()
+  >>> testing.printElement(user, "//table/tbody/tr/td[2]/a/text()",
+  ...                      multiple=True, serialize=False)
+  Stephan
+  Roger
+
+To delete a contact, you Simply click on the "Delete" link of the
+corresponding row:
+
+  >>> user.getLink('[Delete]', index=1).click()
+
+The message is now gone from the table:
+
+  >>> user.getLink('Roger')
+  Traceback (most recent call last):
+  ...
+  LinkNotFoundError


Property changes on: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/sqlmessage/sqlmessage.txt
___________________________________________________________________
Name: svn:keywords
   + Date Author

Modified: Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/tests.py
===================================================================
--- Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/tests.py	2007-07-13 07:36:39 UTC (rev 77799)
+++ Sandbox/darrylcousins/mars.formdemo/src/mars/formdemo/tests.py	2007-07-13 07:36:43 UTC (rev 77800)
@@ -15,7 +15,8 @@
                     ('widgets', 'widgets.txt'),
                     ('spreadsheet', 'spreadsheet.txt'),
                     ('wizard', 'wizard.txt'),
-                  #  ('addressbook', 'addressbook.txt'),
+                    ('addressbook', 'addressbook.txt'),
+                    ('sqlmessage', 'sqlmessage.txt'),
                     ):
         suite = functional.FunctionalDocFileSuite(
             os.path.join(*docpath),



More information about the Checkins mailing list