merge 25480a710422
authorLaure Bourgois <Laure.Bourgois@logilab.fr>
Thu, 02 Apr 2009 15:21:55 +0200
branch25480a710422
changeset 1215 9db3648c476d
parent 1214 25480a710422 (current diff)
parent 1212 76de1c3aaef3 (diff)
child 1216 6ce1383b50ca
merge
--- a/doc/book/en/A020-tutorial.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/A020-tutorial.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -20,6 +20,7 @@
 This tutorial will show how to create a `cube` and how to use it as an
 application to run an `instance`.
 
+.. include:: Z013-blog-less-ten-minutes.en.txt
 .. include:: A02a-create-cube.en.txt
 .. include:: A02b-components.en.txt
 .. include:: A02c-maintemplate.en.txt
--- a/doc/book/en/B0010-define-schema.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/B0010-define-schema.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -1,10 +1,10 @@
 .. -*- coding: utf-8 -*-
 
-Data model definition (*schema*)
-================================
+Data model definition: the *schema*
+===================================
 
-The schema is the core piece of a `CubicWeb` application as it defines
-the data model handled. It is based on entity types that are either already
+The **schema** is the core piece of a `CubicWeb` application as it defines
+the handled data model. It is based on entity types that are either already
 defined in the `CubicWeb` standard library; or more specific types, that 
 `CubicWeb` expects to find in one or more Python files under the directory 
 `schema`.
--- a/doc/book/en/B0011-schema-stdlib.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/B0011-schema-stdlib.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -10,7 +10,7 @@
 
 System schemas
 ``````````````
-The system entities available are:
+The available system entities are:
 
 * `EUser`, system users
 * `EGroup`, users groups
@@ -34,7 +34,7 @@
 (The first 'E' in some of the names is the first letter of 'Erudi', 
 `CubicWeb`'s old name; it might be changed/removed some day.)
 
-Cubes available
+Available cubes
 ```````````````
 
 An application is based on several basic cubes. In the set of available
--- a/doc/book/en/B0012-schema-definition.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/B0012-schema-definition.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -148,8 +148,8 @@
   not prevent another entity to be selected.
 
 
-Relation definition
--------------------
+Definition of relations
+-----------------------
 
 XXX add note about defining relation type / definition
 
@@ -221,8 +221,8 @@
 Permissions definition
 ``````````````````````
 
-Define permissions is set through to the attribute `permissions` of entities and
-relations types. It defines a dictionnary where the keys are the access types
+Setting permissions is done with the attribute `permissions` of entities and
+relation types. It defines a dictionnary where the keys are the access types
 (action), and the values are the authorized groups or expressions.
 
 For an entity type, the possible actions are `read`, `add`, `update` and
@@ -377,9 +377,9 @@
 Updating your application with your new schema
 ``````````````````````````````````````````````
 
-If you modified your schema, the update is not automatic; this is 
-indeed in general not a good idea.
-Instead, we call a shell on  your application, which is a 
+If you modified your schema, the update is not automatic; indeed, this is 
+in general not a good idea.
+Instead, you call a shell on your application, which is a 
 an interactive python shell, with an appropriate
 cubicweb environment ::
 
--- a/doc/book/en/B0020-define-workflows.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/B0020-define-workflows.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -5,43 +5,22 @@
 Workflow definition
 ===================
 
+[TODO :  All this is too obscure and often not very understandable...]
+
 General
 -------
 
-A workflow can be defined in a `CubicWeb` application thanks to the system 
-entities ``State`` and ``Transition``. Those are defined within all 
-`CubicWeb` application and can be set-up through the main administrator interface.
-
-Once your schema is defined, you can start creating the set of states and
-the required transitions for your applications entities.
-
-You first need to define the states and then the transitions between those
-to complete your workflow.
-
-A ``State`` defines the status of an entity. While creating a new state, 
-you will be first given the option to select the entity type the state
-can be applied to. By choosing ``Apply``, a new section will be displayed
-in the editing screen to enable you to add relation to the state you are
-creating.
-
-A ``Transition`` is also based on an entity type it can be applied to.
-By choosing ``Apply``, a new section will be displayed in the editing 
-screen to enable you to add relation to the transition you are
-creating.
-
-At the transition level you will also define the group of user which can
-aplly this transition to an object.
-
+[XXX define what a "Workflow" is: states, transitions, transition graph ]
 
 Example of a simple workflow
 ----------------------------
 
-Please see the tutorial to view and example of a simple workflow.
+Please see the tutorial to view an example of a simple workflow.
 
 
 [Create a simple workflow for BlogDemo, to have a moderator approve new blog 
-entry to be published. This implies, specify a dedicated group of blog
-moderator as well as hide the view of a blog entry to the user until
+entry to be published. This implies specifying a dedicated group of blog
+moderator as well as hiding the view of a blog entry to the user until
 it reaches the state published]
 
 Set-up a workflow
@@ -49,31 +28,24 @@
 
 We want to create a workflow to control the quality of the BlogEntry 
 submitted on your application. When a BlogEntry is created by a user
-its state should be `submitted`. To be visible to all, it needs to
-be in the state `published`. To move from `submitted` to `published`
-we need a transition that we can name `approve_blogentry`.
-
-We do not want every user to be allowed to change the state of a 
-BlogEntry. We need to define a group of user, `moderators`, and 
-this group will have appropriate permissions to approve BlogEntry
-to be published and visible to all.
+its state should be `submitted`. To be visible to all, it has to
+be in the state `published`. To move it from `submitted` to `published`,
+we need a transition that we can call `approve_blogentry`.
 
-There are two ways to create a workflow, form the user interface,
-and also by defining it in ``migration/postcreate.py``. 
+A BlogEntry state should not be modifiable by every user.
+So we have to define a group of users, `moderators`, and 
+this group will have appropriate permissions to publish a BlogEntry.
+
+There are two ways to create a workflow: from the user interface,
+or by defining it in ``migration/postcreate.py``. 
 This script is executed each time a new ``cubicweb-ctl db-init`` is done. 
-If you create the states and transitions through the user interface
-this means that next time you will need to initialize the database
-you will have to re-create all the entities. 
-We strongly recommand you create the workflow in ``migration\postcreate.py``
-and we will now show you how.
-The user interface would only be a reference for you to view the states 
-and transitions but is not the appropriate interface to define your
-application workflow.
+We strongly recommand to create the workflow in ``migration/postcreate.py``
+and we will now show you how. Read `Under the hood`_ to understand why.
 
 Update the schema
 ~~~~~~~~~~~~~~~~~
-To enable a BlogEntry to have a State, we have to define a relation
-``in_state`` in the schema of BlogEntry. Please do as follows, add
+If we want a State for our BlogEntry, we have to define a relation
+``in_state`` in the schema of BlogEntry. So we add
 the line ``in_state (...)``::
 
   class BlogEntry(EntityType):
@@ -86,59 +58,64 @@
       entry_of = SubjectRelation('Blog', cardinality='?*')
       in_state = SubjectRelation('State', cardinality='1*')
 
-As you updated the schema, you will have re-execute ``cubicweb-ctl db-init``
+As you updated the schema, you have to re-execute ``cubicweb-ctl db-init``
 to initialize the database and migrate your existing entities.
+
 [WRITE ABOUT MIGRATION]
 
 Create states, transitions and group permissions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-At the time the ``postcreate.py`` script is executed, several methods
-can be used. They are all defined in the ``class ServerMigrationHelper``.
-We will only discuss the method we use to create a wrokflow here.
+The ``postcreate.py`` script is executed in a special environment, adding
+several `CubicWeb` primitives that can be used.
+They are all defined in the ``class ServerMigrationHelper``.
+We will only discuss the methods we use to create a workflow in this example.
 
 To define our workflow for BlogDemo, please add the following lines
 to ``migration/postcreate.py``::
   
   _ = unicode
 
-  moderators      = add_entity('EGroup', name=u"moderators")
+  moderators = add_entity('EGroup', name=u"moderators")
+
+This adds the `moderators` user group.
+
+::
 
   submitted = add_state(_('submitted'), 'BlogEntry', initial=True)
   published = add_state(_('published'), 'BlogEntry')
 
+``add_state`` expects as first argument the name of the state you want
+to create, then the entity type on which the state can be applied,
+and an optional argument to say if it is supposed to be the initial state
+of the entity type.
+
+::
+
   add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),)
 
+
+``add_transition`` expects 
+
+  * as the first argument the name of the
+    transition, then the entity type on which the transition can be applied,
+  * then the list of states on which the transition can be trigged,
+  * the target state of the transition, 
+  * and the permissions
+    (e.g. a list of user groups who can apply the transition; the user
+    has to belong to at least one of the listed group to perform the action).
+
+::
+
   checkpoint()
 
 .. note::
   Do not forget to add the `_()` in front of all states and transitions names while creating
   a workflow so that they will be identified by the i18n catalog scripts.
 
-``add_entity`` is used here to define the new group of users that we
-need to define the transitions, `moderators`.
-If this group required by the transition is not defined before the
-transition is created, it will not create the relation `transition 
-require the group moderator`.
-
-``add_state`` expects as the first argument the name of the state you are
-willing to create, then the entity type on which the state can be applied, 
-and an optionnal argument to set if the state is the initial state
-of the entity type or not.
-
-``add_transition`` expects as the first argument the name of the 
-transition, then the entity type on which we can apply the transition,
-then the list of possible initial states from which the transition
-can be applied, the target state of the transition, and the permissions
-(e.g. list of the groups of users who can apply the transition, the user
-needs to belong to at least one of the listed group).
-
-
-We could have also added a RQL condition in addition to a group to 
-which the user should belong to. 
-
-If we use both RQL condition and group, the two must be satisfied 
-for the user to be allowed to apply the transition.
+In addition to the user group condition, we could have added a RQL condition. 
+In this case, the user can only perform the action if 
+the two conditions are satisfied. 
 
 If we use a RQL condition on a transition, we can use the following 
 variables:
@@ -150,8 +127,40 @@
 
 .. image:: images/lax-book.03-transitions-view.en.png
 
-You can now notice that in the actions box of a BlogEntry, the state
-is now listed as well as the possible transitions from this state
-defined by the workflow. This transition, as defined in the workflow,
-will only being displayed for the users belonging to the group
-moderators of managers.
+You can notice that in the action box of a BlogEntry, the state
+is now listed as well as the possible transitions defined by the workflow.
+The transitions will only be displayed for users having the right permissions.
+In our example, the transition `approve_blogentry` will only be displayed 
+for the users belonging to the group `moderators` or `managers`.
+
+
+Under the hood
+~~~~~~~~~~~~~~
+
+A workflow is a collection of entities of type ``State`` and of type ``Transition``
+which are standard `CubicWeb` entity types.
+For instance, the following lines::
+
+  submitted = add_state(_('submitted'), 'BlogEntry', initial=True)
+  published = add_state(_('published'), 'BlogEntry')
+
+will create two entities of type ``State``, one with name 'submitted', and the other
+with name 'published'. Whereas::
+
+  add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),)
+ 
+will create an entity of type ``Transition`` with name 'approve_blogentry' which will
+be linked to the ``State`` entities created before.
+As a consequence, we could use the administration interface to do these operations.
+But it is not recommanded because it will be uselessly complicated
+and will be only local to your instance.
+
+
+Indeed, if you create the states and transitions through the user interface,
+next time you initialize the database
+you will have to re-create all the entities. 
+The user interface should only be a reference for you to view the states 
+and transitions, but is not the appropriate interface to define your
+application workflow.
+
+
--- a/doc/book/en/B0030-data-as-objects.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/B0030-data-as-objects.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -4,15 +4,15 @@
 Data as objects
 ===============
 
-We will in this chapter introduce the objects that are used to handle
+In this chapter, we will introduce the objects that are used to handle
 the data stored in the database.
 
 Classes `Entity` and `AnyEntity`
 --------------------------------
 
-To provide a specific behavior for each entity, we just need to define
-a class inheriting from `cubicweb.entities.AnyEntity`. In general, we have
-to defined those classes in a module of `entities` package of an application
+To provide a specific behavior for each entity, we have to define
+a class inheriting from `cubicweb.entities.AnyEntity`. In general, we
+define this class in a module of `entities` package of an application
 so that it will be available on both server and client side.
 
 The class `AnyEntity` is loaded dynamically from the class `Entity` 
@@ -22,7 +22,7 @@
 Descriptors are added when classes are registered in order to initialize the class
 according to its schema:
 
-* we can access the defined attributes in the schema thanks the attributes of
+* we can access the defined attributes in the schema thanks to the attributes of
   the same name on instances (typed value)
 
 * we can access the defined relations in the schema thanks to the relations of
@@ -33,12 +33,12 @@
 * `has_eid()`, returns true is the entity has an definitive eid (e.g. not in the
   creation process)
         
-* `check_perm(action)`, checks if the user has the permission to execcute the
+* `check_perm(action)`, checks if the user has the permission to execute the
   requested action on the entity
 
 :Formatting and output generation:
 
-  * `view(vid, **kwargs)`, apply the given view to the entity
+  * `view(vid, **kwargs)`, applies the given view to the entity
 
   * `absolute_url(**kwargs)`, returns an absolute URL to access the primary view
     of an entity
@@ -118,30 +118,31 @@
 *rtags*
 -------
 
-*rtags* allows to specify certain behaviors of relations relative to a given
+*rtags* allow to specify certain behaviors of relations relative to a given
 entity type (see later). They are defined on the entity class by the attribute
-`rtags` which is a dictionnary with as its keys the triplet ::
+`rtags` which is a dictionnary with as keys the triplets ::
 
   <relation type>, <target entity type>, <context position ("subject" ou "object")>
 
-and as the values a `set` or a tuple of markers defining the properties that
+and as values a `set` or a tuple of markers defining the properties that
 apply to this relation.
 
 It is possible to simplify this dictionnary:
 
 * if we want to specifiy a single marker, it is not necessary to
-  use a tuple as the value, the marker by itself (characters string)
+  use a tuple as value, the marker by itself (character string)
   is enough
 * if we only care about a single type of relation and not about the target
   and the context position (or when this one is not ambigous), we can simply
-  use the name of the relation type as the key
+  use the name of the relation type as key
 * if we want a marker to apply independently from the target entity type,
-  we have to use the string `*` as the target entity type
+  we have to use the string `*` as target entity type
 
 
 Please note that this dictionnary is *treated at the time the class is created*.
 It is automatically merged with the parent class(es) (no need to copy the
-dictionnary from the parent class to modify it). Also, modify it after the 
+dictionnary from the parent class to modify it). Also, modifying it after the 
 class is created will not have any effect...
 
 .. include:: B0031-define-entities.en.txt
+
--- a/doc/book/en/B0031-define-entities.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/B0031-define-entities.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -5,8 +5,8 @@
 
 Dynamic default values
 ``````````````````````
-It is possible to define in the schema *static* default values.
-It is also possible to define in the schema *dynamic* default values
+It is possible to define *static* default values in the schema.
+It is also possible to define *dynamic* default values
 by defining in the entity class a method `default_<attribut name>` for
 a given attribute.
 
@@ -118,20 +118,22 @@
 1. we consider that the first column contains the entities to constraint
 2. we collect the first entity of the table (row 0) to represent all the 
    others
-3. for all the others variables defined in the original request:
+3. for all the other variables defined in the original request:
    
-   1. if the varaible is related to the main variable by at least one relation
+   1. if the variable is related to the main variable by at least one relation
    2. we call the method ``filterform_vocabulary(rtype, x)`` on the entity,
       if nothing is returned (meaning a tuple `Non`, see below), we go to the
       next variable, otherwise a form filtering element is created based on
       the vocabulary values returned
 
-4. there is no others limitations to the `RQL`, it can include sorting, grouping
-   conditions... Javascripts functions are used to regenerate a request based on the
+4. there are no other limitations to the `RQL`, it can include sorting, grouping
+   conditions... JavaScript functions are used to regenerate a request based on the
    initial request and on the selected values from the filtering form.
 
 The method ``filterform_vocabulary(rtype, x, var, rqlst, args, cachekey)`` takes 
-the name of a relation and the target as parameters, which indicates of the
+the name of a relation and the target as parameters,
+[XXX what does it mean ?]
+ which indicates of the
 entity on which we apply the method is subject or object of the relation. It
 has to return:
 
@@ -157,18 +159,18 @@
 
     class Ticket(AnyEntity):
 
-	...
+	    ...
 
-	def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey):
-	    _ = self.req._
-	    if rtype == 'type':
-		return 'string', [(x, _(x)) for x in ('bug', 'story')]
-	    if rtype == 'priority':
-		return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')]
-	    if rtype == 'done_in':
-		rql = insert_attr_select_relation(rqlst, var, rtype, 'num')
-		return 'eid', self.req.execute(rql, args, cachekey)
-	    return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst,
+    	def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey):
+	        _ = self.req._
+	        if rtype == 'type':
+        		return 'string', [(x, _(x)) for x in ('bug', 'story')]
+	        if rtype == 'priority':
+    	    	return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')]
+    	    if rtype == 'done_in':
+	        	rql = insert_attr_select_relation(rqlst, var, rtype, 'num')
+		        return 'eid', self.req.execute(rql, args, cachekey)
+	        return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst,
 							     args, cachekey)
 
 .. note::
--- a/doc/book/en/C011-installation.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/C011-installation.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -35,8 +35,14 @@
   apt-get install cubicweb
   apt-get install cubicweb-dev
 
+`cubicweb` installs the framework itself, allowing you to create
+new applications.
 
-This is it!
+`cubicweb-dev` installs the development environment allowing you to
+develop new cubes.
+
+There is also a wide variety of cubes listed on http://www.cubicweb.org/Project available as debian packages and tarball.
+
 
 Install from source
 ```````````````````
@@ -92,7 +98,7 @@
 Your new cubes will be placed in `/usr/share/cubicweb/cubes` and
 your applications will be placed in `/etc/cubicweb.d`.
 
-To use other directories you will have to configure the
+To use others directories then you will have to configure the
 following environment variables as follows::
 
     export CW_CUBES_PATH=~/lib/cubes
@@ -111,7 +117,7 @@
 
 .. note::
     If you already have an existing cluster and postgres server
-    running you do not require to execute the initilization step
+    running, you do not require to execute the initilization step
     of your Postgres database.
 
 * First you have to initialize the database Postgres with the command ``initdb``.
@@ -130,14 +136,24 @@
  
     $ chown username /path/to/pgsql
 
-* Create a superuser for `CubicWeb` instance::
+* The database authentication can be either set to `ident sameuser`
+  or `md5`. 
+  If set to `md5`, make sure to use an existing user
+  of your database.
+  If set to `ident sameuser`, make sure that your
+  client's operating system user name has a matching user in
+  the database. If not, please do as follow to create a user::
     
     $ su
     $ su - postgres
     $ createuser -s username
 
-  Initialize the password of the superuser you just created for your
-  database::
+  If created with the options -P (for password prompt, 
+  ``createuser -s -P username``), the password will be encrypted with
+  the method set in the configuration file ``pg_hba.conf``. 
+  If you do not use this option, then the default value will be null
+  and this require to set the password in the database itself.
+  To do so: ::
     
     $ su 
     $ su - postgres
@@ -151,13 +167,17 @@
   instance with `cubicweb-ctl create` to initialize the database of
   your application.
 
+.. note::
+    The authentication method can be configured in ``pg_hba.conf``.
+
+
 .. FIXME Are these steps really necessary? It seemed to work without.
 
-* installation of plain-text index extension ::
+* Installation of plain-text index extension ::
 
     cat /usr/share/postgresql/8.3/contrib/tsearch2.sql | psql -U username template1
 
-* installation of plpythonu language by default ::
+* Installation of plpythonu language by default ::
 
     createlang -U pgadmin plpythonu template1
 
--- a/doc/book/en/C040-rql.en.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/C040-rql.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -140,6 +140,14 @@
         X is Person, X name N, X first_name P
 
 
+  Note: You can not specify several types with * ... where X is FirstType or X is SecondType*.
+  To specify several types explicitely, you have to do
+
+  ::
+
+        Any X where X is in (FirstType, SecondType)
+
+
 Insertion query
 ---------------
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z013-blog-less-ten-minutes.en.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -0,0 +1,84 @@
+.. -*- coding: utf-8 -*-
+
+Have a blog ready in less than ten minutes!
+-------------------------------------------
+
+Installation
+~~~~~~~~~~~~
+
+You need to install the following packages::
+
+    cubicweb, cubicweb-blog
+
+The package `cubicweb` is installing the command `cubicweb-ctl` that
+will allow you to create new application.
+
+The package `cubicweb-blog` is installing the blogging support for the
+`CubicWeb` framework.
+
+Application creation
+~~~~~~~~~~~~~~~~~~~~
+
+Creation and initialization of your application by running::
+    
+    cubicweb-ctl create blog myblog
+
+*myblog* is the name of the application you are creating.
+
+*blog* is the name of the component on which your application
+is based. 
+
+Application launch
+~~~~~~~~~~~~~~~~~~
+
+Your application is now ready to go::
+
+    cubicweb-ctl start -D myblog
+
+This is it. Your blog is ready to you. Go to http://localhost:8080 and enjoy!!
+
+
+A little code snapshot from behind the scene
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The component `blog`, referred as a `cube` in the book 
+(see :ref:`TermsVocabulary` for a complete definition), defines
+a data model in ``/usr/share/cubicweb/cubes/blog/schema.py``. 
+Here is the corresponding Python code::
+
+    from cubicweb.schema import format_constraint
+
+    class Blog(EntityType):
+        title = String(maxsize=50, required=True)
+        description_format = String(meta=True, internationalizable=True, maxsize=50,
+                                    default='text/rest', constraints=[format_constraint])
+        description = String()
+        rss_url = String(maxsize=128, description=_('blog\'s rss url (useful for when using external site such as feedburner)'))
+
+
+    class BlogEntry(EntityType):
+        title = String(required=True, fulltextindexed=True, maxsize=256)
+        content_format = String(meta=True, internationalizable=True, maxsize=50,
+                                default='text/rest', constraints=[format_constraint])
+        content = String(required=True, fulltextindexed=True)
+        entry_of = SubjectRelation('Blog', cardinality='?*')
+
+Two types of entities are defined here: Blog and BlogEntry.
+
+A Blog is defined by a title, a description and its format and a
+RSS URL to provide RSS feed.
+
+A BlogEntry is defined by a title, a content and its format and
+a relation to a Blog, meaning a BlogEntry belongs to a Blog.
+
+
+Next step
+~~~~~~~~~
+
+This was a brief demonstration of the re-usability of cubes and a way
+to show how you can use `CubicWeb` straigth out of the box.
+
+As a developper, you'll want to know more about how to develop new
+cubes and cutomize the views and this is what we talk about now. 
+
+
--- a/doc/book/en/index.txt	Thu Apr 02 15:21:00 2009 +0200
+++ b/doc/book/en/index.txt	Thu Apr 02 15:21:55 2009 +0200
@@ -42,7 +42,6 @@
 
 
 .. toctree::
-   :maxdepth: 2
 
    A000-introduction.en.txt
    B000-development.en.txt
--- a/i18n/en.po	Thu Apr 02 15:21:00 2009 +0200
+++ b/i18n/en.po	Thu Apr 02 15:21:55 2009 +0200
@@ -1434,6 +1434,10 @@
 msgid "csv export"
 msgstr ""
 
+#, python-format
+msgid "currently attached file: %s"
+msgstr ""
+
 msgid "data directory url"
 msgstr ""
 
@@ -1546,7 +1550,8 @@
 msgid "destination_state_object"
 msgstr "destination of"
 
-msgid "detach attached file"
+#, python-format
+msgid "detach attached file %s"
 msgstr ""
 
 msgid "detailed schema view"
--- a/i18n/es.po	Thu Apr 02 15:21:00 2009 +0200
+++ b/i18n/es.po	Thu Apr 02 15:21:55 2009 +0200
@@ -104,6 +104,10 @@
 msgstr "%d&nbsp;semanas"
 
 #, python-format
+msgid "%d&nbsp;years"
+msgstr ""
+
+#, python-format
 msgid "%s error report"
 msgstr "%s reporte de errores"
 
@@ -1487,6 +1491,10 @@
 msgid "csv export"
 msgstr "exportar CSV"
 
+#, python-format
+msgid "currently attached file: %s"
+msgstr ""
+
 msgid "data directory url"
 msgstr "url del repertorio de datos"
 
@@ -1612,8 +1620,9 @@
 msgid "destination_state_object"
 msgstr "destino de"
 
-msgid "detach attached file"
-msgstr "soltar el archivo existente"
+#, python-format
+msgid "detach attached file %s"
+msgstr ""
 
 msgid "detailed schema view"
 msgstr "vista detallada del esquema"
@@ -2997,6 +3006,9 @@
 #~ "langue par dÈfaut (regarder le rÈpertoire i18n de l'application pour voir "
 #~ "les langues disponibles)"
 
+#~ msgid "detach attached file"
+#~ msgstr "soltar el archivo existente"
+
 #~ msgid "filter"
 #~ msgstr "filtrer"
 
--- a/i18n/fr.po	Thu Apr 02 15:21:00 2009 +0200
+++ b/i18n/fr.po	Thu Apr 02 15:21:55 2009 +0200
@@ -1492,6 +1492,10 @@
 msgid "csv export"
 msgstr "export CSV"
 
+#, python-format
+msgid "currently attached file: %s"
+msgstr "fichie actuellement attaché %s"
+
 msgid "data directory url"
 msgstr "url du répertoire de données"
 
@@ -1616,8 +1620,9 @@
 msgid "destination_state_object"
 msgstr "destination de"
 
-msgid "detach attached file"
-msgstr "détacher le fichier existant"
+#, python-format
+msgid "detach attached file %s"
+msgstr "détacher le fichier existant %s"
 
 msgid "detailed schema view"
 msgstr "vue détaillée du schéma"
@@ -3002,6 +3007,9 @@
 #~ "langue par défaut (regarder le répertoire i18n de l'application pour voir "
 #~ "les langues disponibles)"
 
+#~ msgid "detach attached file"
+#~ msgstr "détacher le fichier existant"
+
 #~ msgid "filter"
 #~ msgstr "filtrer"
 
--- a/web/widgets.py	Thu Apr 02 15:21:00 2009 +0200
+++ b/web/widgets.py	Thu Apr 02 15:21:55 2009 +0200
@@ -486,11 +486,15 @@
                     wdgs.append(ewdg.edit_render(entity, includehelp=True))
                     wdgs.append(u'<br/>')
             wdgs.append(u'</div>')
-        if entity.has_eid() and not self.required(entity):
-            # trick to be able to delete an uploaded file
-            wdgs.append(u'<br/>')
-            wdgs.append(checkbox(eid_param('__%s_detach' % self.rname, entity.eid), False))
-            wdgs.append(req._('detach attached file'))
+        if entity.has_eid():
+            if not self.required(entity):
+                # trick to be able to delete an uploaded file
+                wdgs.append(u'<br/>')
+                wdgs.append(checkbox(eid_param('__%s_detach' % self.rname, entity.eid), False))
+                wdgs.append(req._('detach attached file %s' % entity.dc_title()))
+            else:
+                wdgs.append(u'<br/>')
+                wdgs.append(req._('currently attached file: %s' % entity.dc_title()))
         return '\n'.join(wdgs)
     
     def _edit_render(self, entity):