Index: main/plugin-forms/cms-ribbon.xml
===================================================================
--- main/plugin-forms/cms-ribbon.xml	(revision 39963)
+++ main/plugin-forms/cms-ribbon.xml	(working copy)
@@ -809,6 +809,7 @@
                 <group label="plugin.forms:RIBBON_TABS_TAB_FORM_ENTRY_ACTIONS_LABEL" icon="">
                     <large/>
                     <medium>
+                        <control id="org.ametys.plugins.forms.entries.ExportFormEntries"/>
                         <control id="org.ametys.plugins.forms.entries.DeleteEntry"/>
                         <control id="org.ametys.plugins.forms.entries.ClearEntries"/>
                         <control id="org.ametys.plugins.forms.entries.ViewRequest"/>
Index: main/plugin-forms/i18n/messages_en.xml
===================================================================
--- main/plugin-forms/i18n/messages_en.xml	(revision 39963)
+++ main/plugin-forms/i18n/messages_en.xml	(working copy)
@@ -24,6 +24,8 @@
     <message key="PLUGINS_FORMS_RIGHTS_DELETE_FORM_ENTRY_DESCRIPTION">Authorize the deletion of the data submitted by the visitors through forms</message>
     <message key="PLUGINS_FORMS_RIGHTS_VIEW_SQL_LABEL">Generate Select Statement</message>
     <message key="PLUGINS_FORMS_RIGHTS_VIEW_SQL_DESCRIPTION">Authorize the view of the SQL request used to retrieve the data submitted by the visitors through forms</message>
+	<message key="PLUGINS_FORMS_RIGHTS_FORMS_LIST_HANDLE_LABEL">Forms list</message>
+    <message key="PLUGINS_FORMS_RIGHTS_FORMS_LIST_HANDLE_DESCRIPTION">Allow to visualize the list of forms of a site in a given language</message>
 	
 	<message key="CONTENT_EDITION_FORMS_INSERTMENU_LABEL">Form</message>
 	<message key="CONTENT_EDITION_FORMS_INSERTMENU_DESCRIPTION">Insert a web form for the visitors. The form can be sent to you by email or stored in Ametys for a later management.</message>
@@ -32,24 +34,35 @@
 	<message key="CONTENT_EDITION_FORMS_INSERTEXTERNAL_LABEL">Form to an external web site</message>
 	<message key="CONTENT_EDITION_FORMS_INSERTEXTERNAL_DESCRIPTION">Insert a web form for the visitors. The form is send to an external web site.</message>
 	
-    <message key="PLUGINS_FORMS_UI_LABEL">Form data export</message>
-    <message key="PLUGINS_FORMS_UI_DESCRIPTION">Export the user data of a form contained in one of the selected contents</message>
     <message key="PLUGINS_FORMS_UI_TOOLTIP">You can export the data users have submitted on a form among the selected contents, as an excel stylesheet.</message>
     <message key="PLUGINS_FORMS_UI_NO_FORMS_TOOLTIP">None of the selected contents contains a form.</message>
     <message key="PLUGINS_FORMS_UI_NAME">Name</message>
     
-    <message key="PLUGINS_SHOW_OR_EXPORT_FORMS_LABEL">Forms data</message>
-    <message key="PLUGINS_SHOW_OR_EXPORT_FORMS_DESCRIPTION">Show and export form data</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_EXPORT_LABEL">Export</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_EXPORT_DESCRIPTION">Click here in order to export the form's entries to an Excel spreadsheet.</message>
+    
+    <message key="PLUGINS_SHOW_FORMS_UI_LABEL">Form entries</message>
+    <message key="PLUGINS_SHOW_FORMS_UI_DESCRIPTION">Show the data of a form contained in one of the selected contents.</message>
     
-    <message key="PLUGINS_SHOW_FORMS_UI_LABEL">Show form data</message>
-    <message key="PLUGINS_SHOW_FORMS_UI_DESCRIPTION">Show the user data of a form contained in one of the selected contents</message>
+    <!-- Forms list tool -->
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_LABEL">Forms</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_DESCRIPTION">This tool lists all the forms of the site in the selected language.</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_FOOTER">See help for further details.</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_LANGUAGE">Language</message>
+    
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_NAME">Form</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_CONTENT_NAME">Content holding the form</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_ANSWERS_AMOUNT">Answers</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_LAST_ANSWER">Last answer</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_GET_LANGUAGES_ERROR">An error occurred : unable to retrieve the list of available languages for this site.</message>
     
     <message key="UITOOL_FORM_RESULTS_LABEL">Form</message>
     <message key="UITOOL_FORM_RESULTS_DESCRIPTION">Tool to show form data</message>
     <message key="PLUGINS_FORMS_UITOOL_BUTTON_DELETE_ENTRY_LABEL">Delete</message>
     <message key="PLUGINS_FORMS_UITOOL_BUTTON_DELETE_ENTRY_DESCRIPTION">Delete the selected entries from the current form.</message>
     <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_LABEL">Delete all</message>
-    <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_DESCRIPTION">Delete all entries from the current form.</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_DESCRIPTION">Delete all entries from the selected form(s).</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_NO_ENTRIES_DESCRIPTION">There is no form entry to delete in the current selection.</message>
     
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_OPENINNEWWINDOW_LABEL">Submit in a new window</message>	
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_OPENINNEWWINDOW_DESCRIPTION">When the visitor sumbits the form, a new window opens with the thank message or the errors depending on the case. He can then close this window to continue.</message>
@@ -289,14 +302,14 @@
 	<message key="PLUGINS_FORMS_FORMS_RENDER_ERRORS_1">The form has </message>
 	<message key="PLUGINS_FORMS_FORMS_RENDER_ERRORS_2"> error(s).\nPlease correct it (them) before proceeding.\n\nYou can let the cursor over a highlighted field to see an explaination.</message>
     
-    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_TITLE">Export/Show the form data as an excel spreadsheet</message>
+    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_TITLE">Entries of a form</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_BUTTON_OK">OK</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_BUTTON_CANCEL">Cancel</message>
-    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_FORM_LIST_ERROR">An error occured while getting the form list.</message>
+    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_FORM_LIST_ERROR">An error occurred while getting the form list.</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION">Form selection</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NORESULT">No form was found in the selected contents.</message>
-    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED">You must select a form to export/show.</message>
-    <message key="PLUGINS_FORMS_CHOOSE_SHOW_FORM_ERROR">An error occured while getting form data.</message>
+    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED">You must select a form to show.</message>
+    <message key="PLUGINS_FORMS_CHOOSE_SHOW_FORM_ERROR">An error occurred while getting form data.</message>
     <message key="PLUGINS_FORMS_CHOOSE_SHOW_FORM_SUBMISSION_DATE">Submission datetime</message>
     
     <message key="PLUGINS_FORMS_EXPORT_COLUMN_ID">ID</message>
@@ -383,7 +396,8 @@
     <message key="PLUGINS_FORMS_DELETE_ENTRY_CONFIRM">Do you really want to delete the selected entries from the form ?</message>
     <message key="PLUGINS_FORMS_DELETE_ENTRY_ERROR">An error occurred, the selected entries could not be deleted.</message>
     <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_TITLE">Delete all</message>
-    <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM">Do you really want to delete all the entries from the form ?</message>
+    <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_SINGLE">Do you really want to delete all the entries from this form ?</message>
+    <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_SEVERAL">Do you really want to delete all the entries from the selected forms ?</message>
     <message key="PLUGINS_FORMS_CLEAR_ENTRIES_ERROR">An error occurred, the entries of the form could not be deleted.</message>
     <message key="PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_1">Entries </message>
     <message key="PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_2"> - </message>
@@ -396,5 +410,18 @@
     <message key="PLUGINS_FORMS_VIEW_REQUEST_DIALOG_TITLE">Select Statement</message>
     <message key="PLUGINS_FORMS_VIEW_REQUEST_DIALOG_TABLENAME_FIELD">Table name</message>
     <message key="PLUGINS_FORMS_VIEW_REQUEST_DIALOG_REQUEST_FIELD">Statement</message>
-        
+     
+     <!-- Administration -->
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_LABEL">Orphan form data</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_DESCRIPTION">Access to the list of the forms that are no longer referenced by any content</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS">Actions</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE">Destroy the table</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_COL_NAME">Table name</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_COL_TOTAL">Amount of submissions</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_HELP_TITLE">Help</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_HELP_TEXT">This screen displays the list of forms that are stored in a data base but that are no longer used in the CMS.&lt;br/&gt;&lt;br/&gt;It also allows you to permanently remove the corresponding SQL tablesCet écran vous permet de visualiser les formulaires enregistrés en base de données mais qui ne sont plus référencés dans le CMS.&lt;br/&gt;&lt;br/&gt;Il vous permet aussi de supprimer de manière définitive les tables SQL correspondantes.Cet écran vous permet de visualiser les formulaires enregistrés en base de données mais qui ne sont plus référencés dans le CMS.&lt;br/&gt;&lt;br/&gt;Il vous permet aussi de supprimer de manière définitive les tables SQL correspondantes.</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE">Deletion</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE_TEXT_SINGLE">Are you sure you want to delete this table?</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE_TEXT_SEVERAL">Are you sure you want to delete these tables ?</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_ERROR">An error has occurred, the deletion has not completed.</message>
 </catalogue>
Index: main/plugin-forms/i18n/messages_fr.xml
===================================================================
--- main/plugin-forms/i18n/messages_fr.xml	(revision 39963)
+++ main/plugin-forms/i18n/messages_fr.xml	(working copy)
@@ -24,6 +24,8 @@
 	<message key="PLUGINS_FORMS_RIGHTS_DELETE_FORM_ENTRY_DESCRIPTION">Autorise la suppression des données envoyées par les visiteurs sur les formulaires</message>
 	<message key="PLUGINS_FORMS_RIGHTS_VIEW_SQL_LABEL">Voir la requête SQL</message>
 	<message key="PLUGINS_FORMS_RIGHTS_VIEW_SQL_DESCRIPTION">Autorise à visualiser la requête SQL utilisée pour obtenir les données envoyées par les visiteurs sur les formulaires</message>
+    <message key="PLUGINS_FORMS_RIGHTS_FORMS_LIST_HANDLE_LABEL">Listage des formulaires</message>
+    <message key="PLUGINS_FORMS_RIGHTS_FORMS_LIST_HANDLE_DESCRIPTION">Autorise à visualiser la liste des formulaires du site dans une langue donnée.</message>
 
 	<message key="CONTENT_EDITION_FORMS_INSERTMENU_LABEL">Formulaire</message>
 	<message key="CONTENT_EDITION_FORMS_INSERTMENU_DESCRIPTION">Insérer un formulaire web pour vos visiteurs. Le formulaire peut vous être envoyé par email ou stocké dans Ametys pour un traitement ultérieur.</message>
@@ -32,25 +34,36 @@
 	<message key="CONTENT_EDITION_FORMS_INSERTEXTERNAL_LABEL">Formulaire vers un site web externe</message>
 	<message key="CONTENT_EDITION_FORMS_INSERTEXTERNAL_DESCRIPTION">Insérer un formulaire web pour vos visiteurs. Le formulaire est envoyé à un site web externe.</message>
     
-    <message key="PLUGINS_FORMS_UI_LABEL">Exporter les données</message>
-    <message key="PLUGINS_FORMS_UI_DESCRIPTION">Exporter les données d'un des formulaires des contenus sélectionnés</message>
-    <message key="PLUGINS_FORMS_UI_TOOLTIP">Vous pouvez exporter les données d'un formulaire parmi les contenus sélectionnés au format Excel.</message>
+    <message key="PLUGINS_FORMS_UI_TOOLTIP">Vous pouvez visualiser les données d'un formulaire parmi les contenus sélectionnés.</message>
     <message key="PLUGINS_FORMS_UI_NO_FORMS_TOOLTIP">Aucun des contenus sélectionnés ne contient de formulaire.</message>
     <message key="PLUGINS_FORMS_UI_NAME">Nom</message>
     
-    <message key="PLUGINS_SHOW_OR_EXPORT_FORMS_LABEL">Entrées du formulaire</message>
-	<message key="PLUGINS_SHOW_OR_EXPORT_FORMS_DESCRIPTION">Visualisation et export des entrées du formulaire</message>
-
-	<message key="PLUGINS_SHOW_FORMS_UI_LABEL">Visualiser les entrées</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_EXPORT_LABEL">Exporter</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_EXPORT_DESCRIPTION">Cliquez ici afin d'exporter les entrées du formulaires vers un tableau Excel.</message>
+    
+	<message key="PLUGINS_SHOW_FORMS_UI_LABEL">Entrées du formulaire</message>
 	<message key="PLUGINS_SHOW_FORMS_UI_DESCRIPTION">Visualiser les entrées du formulaire</message>
- 
+    
+    <!-- Forms list tool -->
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_LABEL">Formulaires</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_DESCRIPTION">Cet outil liste tous les formulaires du site dans une langue choisie.</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_FOOTER">Voir l'aide pour plus de détails.</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_LANGUAGE">Langue</message>
+    
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_NAME">Formulaire</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_CONTENT_NAME">Contenu</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_ANSWERS_AMOUNT">Réponses</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_LAST_ANSWER">Dernière réponse</message>
+    <message key="PLUGINS_FORMS_UITOOL_FORMS_LIST_GET_LANGUAGES_ERROR">Une erreur est survenue : impossible de récupérer la liste des langues disponibles pour ce site.</message>
+    
 	<message key="UITOOL_FORM_RESULTS_LABEL">Formulaire</message>
 	<message key="UITOOL_FORM_RESULTS_DESCRIPTION">Outil de visualisation des donnés des formulaires</message>
     <message key="PLUGINS_FORMS_UITOOL_BUTTON_DELETE_ENTRY_LABEL">Supprimer</message>
     <message key="PLUGINS_FORMS_UITOOL_BUTTON_DELETE_ENTRY_DESCRIPTION">Supprime les entrées sélectionnées.</message>
     <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_LABEL">Effacer tout</message>
-    <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_DESCRIPTION">Supprime toutes les entrées du formulaire.</message>
-
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_DESCRIPTION">Supprime toutes les entrées du ou des formulaires sélectionnés.</message>
+    <message key="PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_NO_ENTRIES_DESCRIPTION">Il n'y aucune entrée de formulaire à supprimer dans la sélection courante.</message>
+ 
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_OPENINNEWWINDOW_LABEL">Soumettre dans une nouvelle fenêtre</message>	
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_OPENINNEWWINDOW_DESCRIPTION">Lorsque le visiteur soumet le formulaire une nouvelle fenêtre s'ouvre avec le message de remerciement ou les erreurs le cas échéant. Il peut ensuite fermer cette fenêtre et continuer sa navigation.</message>	
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_EXTERNAL_URL_LABEL">URL</message>	
@@ -145,7 +158,7 @@
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_LABEL">Valeur</message>
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_DESCRIPTION">Valeur par défaut à laquelle le champ sera initialisé.</message>
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_SELECT_LABEL">Choix de la liste</message>
-	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_SELECT_DESCRIPTION">Ce bouton permet de saisir les choix disponibles dans la liste déroulante</message>
+	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_SELEtablesCT_DESCRIPTION">Ce bouton permet de saisir les choix disponibles dans la liste déroulante</message>
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_SELECT_BOX_LABEL">Choix de la liste...</message>
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_SELECT_BOX_GRID_COL_LABEL">Libellé</message>
 	<message key="PLUGINS_FORMS_FORMS_EDITOR_VALUE_SELECT_BOX_GRID_COL_VALUE">Valeur</message>
@@ -289,17 +302,18 @@
 	<message key="PLUGINS_FORMS_FORMS_RENDER_ERRORS_1">Le formulaire contient </message>
 	<message key="PLUGINS_FORMS_FORMS_RENDER_ERRORS_2"> erreur(s).\nVeuillez la (ou les) corriger avant de recommencer.\n\nEn laissant votre curseur au dessus des champs mis en évidence, vous obtiendrez des messages explicatifs.</message>
     
-    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_TITLE">Visualiser ou exporter les données d'un formulaire</message>
+    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_TITLE">Entrées d'un formulaire</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_BUTTON_OK">Ok</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_BUTTON_CANCEL">Annuler</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_FORM_LIST_ERROR">Une erreur est survenue en récupérant la liste des formulaires.</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION">Sélection du formulaire</message>
     <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NORESULT">Aucun formulaire n'a été trouvé dans les contenus sélectionnés.</message>
-    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED">Vous devez sélectionner un formulaire à exporter ou visualiser.</message>
+    <message key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED">Vous devez sélectionner un formulaire à visualiser.</message>
     
     <message key="PLUGINS_FORMS_EXPORT_COLUMN_ID">ID</message>
     <message key="PLUGINS_FORMS_EXPORT_COLUMN_DATE">Date de soumission</message>
     
+    
     <message key="PLUGINS_FORMS_BOOLEAN_YES">Oui</message>
     <message key="PLUGINS_FORMS_DATETIME_FORMAT">d/m/Y à H:i</message>
     <message key="PLUGINS_FORMS_DATE_FORMAT">d/m/Y</message>
@@ -384,7 +398,8 @@
     <message key="PLUGINS_FORMS_DELETE_ENTRY_CONFIRM">Etes-vous sûrs de vouloir supprimer cette ou ces entrées ?</message>
     <message key="PLUGINS_FORMS_DELETE_ENTRY_ERROR">Une erreur est survenue, impossible de supprimer les entrées sélectionnées.</message>
     <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_TITLE">Supprimer tout</message>
-    <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM">Etes-vous sûrs de vouloir supprimer toutes les entrées du formulaire ?</message>
+    <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_SINGLE">Etes-vous sûrs de vouloir supprimer toutes les entrées du formulaire ?</message>
+    <message key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_SEVERAL">Etes-vous sûrs de vouloir supprimer toutes les entrées des formulaires sélectionnés ?</message>
     <message key="PLUGINS_FORMS_CLEAR_ENTRIES_ERROR">Une erreur est survenue, impossible de supprimer les entrées du formulaire.</message>
     <message key="PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_1">Entrées </message>
     <message key="PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_2"> - </message>
@@ -397,5 +412,17 @@
     <message key="PLUGINS_FORMS_VIEW_REQUEST_DIALOG_TITLE">Voir la requête SQL</message>
     <message key="PLUGINS_FORMS_VIEW_REQUEST_DIALOG_TABLENAME_FIELD">Nom de la table</message>
     <message key="PLUGINS_FORMS_VIEW_REQUEST_DIALOG_REQUEST_FIELD">Requête</message>
-        
+    
+    <!-- Administration -->
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_LABEL">Données de formulaires orphelines</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_DESCRIPTION">Accès à la liste des formulaires n'étant plus référencés par aucun contenu</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS">Actions</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE">Détruire la table</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_COL_NAME">Nom de la table</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_COL_TOTAL">Nombre d'entrées</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_HELP_TITLE">Aide</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_HELP_TEXT">Cet écran vous permet de visualiser les formulaires enregistrés en base de données mais qui ne sont plus référencés dans le CMS.&lt;br/&gt;&lt;br/&gt;Il vous permet aussi de supprimer de manière définitive les tables SQL correspondantes.</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE">Suppression</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE_TEXT">Etes-vous sûr de vouloir supprimer cette table ?</message>
+    <message key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_ERROR">Une erreur est survenue, la suppression n'a pas été réalisée.</message>
 </catalogue>
Index: main/plugin-forms/pages/administrator/orphan-forms/view.xsl
===================================================================
--- main/plugin-forms/pages/administrator/orphan-forms/view.xsl	(revision 0)
+++ main/plugin-forms/pages/administrator/orphan-forms/view.xsl	(revision 0)
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2016 Anyware Services
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   -->
+<xsl:stylesheet version="1.0" 
+                xmlns:i18n="http://apache.org/cocoon/i18n/2.1" 
+                xmlns:escape="org.apache.commons.lang.StringEscapeUtils"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+                exclude-result-prefixes="escape">
+    
+    <xsl:param name="contextPath"/>
+    <xsl:param name="pluginName"/>
+    <xsl:param name="workspaceName"/>
+    <xsl:param name="workspaceURI"/>
+    
+    <xsl:variable name="workspaceContext"><xsl:value-of select="$contextPath"/><xsl:value-of select="$workspaceURI"/></xsl:variable>
+    
+    <xsl:variable name="resourcesPath"><xsl:value-of select="$contextPath"/>/plugins/forms/resources</xsl:variable>
+    
+    <xsl:template match="/">
+        <html>
+            <head>
+                <title><i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_LABEL"/></title>
+            </head>
+            
+            <script>
+               <script type="text/javascript" src="{$contextPath}/plugins/{$pluginName}/resources/js/org/ametys/forms/OrphanForms.i18n.js"/>
+               
+               <script type="text/javascript">
+               
+                    org.ametys.forms.administration.OrphanForms.initialize ("<xsl:value-of select="$pluginName"/>");
+                    
+                    // Create the tool panel
+                    var panel = org.ametys.forms.administration.OrphanForms.createPanel ();
+                    <xsl:for-each select="table">
+                       org.ametys.forms.administration.OrphanForms.addElement (
+                           <xsl:value-of select="position()"/>,
+                           "<xsl:value-of select="@name"/>",
+                           "<xsl:value-of select="@total"/>"
+                       );
+                   </xsl:for-each>
+                   
+                   org.ametys.runtime.administrator.Panel.createPanel = function () 
+                   {
+                       return new Ext.Panel({
+                           region: 'center',
+                           
+                           baseCls: 'transparent-panel',
+                           border: false,
+                           layout: 'border',
+                           autoScroll: true,
+                           
+                           items : [
+                                org.ametys.forms.administration.OrphanForms._listView, 
+                                org.ametys.forms.administration.OrphanForms._rightPanel
+                           ]
+                       });
+                   }
+               </script>
+            </script>
+            
+            <body>
+            
+            </body>
+        </html>
+    </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
Index: main/plugin-forms/plugin.xml
===================================================================
--- main/plugin-forms/plugin.xml	(revision 39963)
+++ main/plugin-forms/plugin.xml	(working copy)
@@ -79,6 +79,30 @@
 			</extension>
     	</extensions>
     </feature>
+    
+    <feature name="forms.administration">
+        <extensions>
+             <extension point="org.ametys.runtime.workspaces.admin.DesktopManager" 
+                        id="org.ametys.plugins.forms.administrator.OrphanForms"
+                        class="org.ametys.runtime.plugins.core.ui.item.StaticAdminClientSideElement"
+                        logger="org.ametys.plugins.forms.administrator">
+                <action class="org.ametys.runtime.Link">
+                    <param name="Link">administrator/orphan-forms/view.html</param>
+                    <param name="Mode">plugin-wrapped</param>
+
+                    <param name="label" i18n="true">PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_LABEL</param>
+                    <param name="default-description" i18n="true">PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_DESCRIPTION</param>
+                    <param name="icon-small" file="true" plugin="web">img/administrator/forms/icon_dock.png</param>
+                    <param name="icon-medium" file="true" plugin="web">img/administrator/forms/icon_medium.gif</param>
+                    <param name="icon-large" file="true" plugin="web">img/administrator/forms/icon_large.png</param>
+                </action>                      
+                <Url>administrator/orphan-forms/view\.html</Url>
+                <css>
+                    <file>css/view.css</file>                
+                </css>
+            </extension>
+        </extensions>
+    </feature>
 
 	<feature name="userinterface.edition.forms">
     	<extensions>	
@@ -520,11 +544,6 @@
                     <description>PLUGINS_FORMS_RIGHTS_EDITION_ONLINE_FORMS_DESCRIPTION</description>
                     <category>plugin.cms:PLUGINS_CMS_RIGHTS_CONTENT_CATEGORY</category>
                 </right>
-                <right id="Runtime_Rights_Forms_Export">
-                    <label>PLUGINS_FORMS_RIGHTS_EXPORT_FORM_LABEL</label>
-                    <description>PLUGINS_FORMS_RIGHTS_EXPORT_FORM_DESCRIPTION</description>
-                    <category>PLUGINS_FORMS_RIGHTS_FORMS_CATEGORY</category>
-                </right>
             </extension>
     		
     		<extension id="org.ametys.plugins.forms.insert.InputText"
@@ -1387,17 +1406,17 @@
     	</extensions>
 	</feature>
 	
-    <feature name="forms.ui.export">
+    <feature name="forms.ui.show.entries">
         <extensions>
-            <extension id="org.ametys.forms.ShowAndExportForm"
+            <extension id="org.ametys.forms.ShowFormEntries"
                        point="org.ametys.cms.workspace.ribbon.RibbonControlsManager"
                        class="org.ametys.plugins.forms.data.FormsContentClientSideElement">
 				<action class="org.ametys.forms.buttons.FormsButton">
 					<param name="action">org.ametys.forms.buttons.Action.showForm</param>
 					
-					<param name="label" i18n="true">PLUGINS_SHOW_OR_EXPORT_FORMS_LABEL</param>
-					<param name="default-description" i18n="true">PLUGINS_SHOW_OR_EXPORT_FORMS_DESCRIPTION</param>
-                    <param name="description" i18n="true">PLUGINS_SHOW_OR_EXPORT_FORMS_DESCRIPTION</param>
+					<param name="label" i18n="true">PLUGINS_SHOW_FORMS_UI_LABEL</param>
+					<param name="default-description" i18n="true">PLUGINS_SHOW_FORMS_UI_DESCRIPTION</param>
+                    <param name="description" i18n="true">PLUGINS_SHOW_FORMS_UI_DESCRIPTION</param>
 					
                     <param name="tooltip" i18n="true">PLUGINS_FORMS_UI_TOOLTIP</param>
                     <param name="no-forms-tooltip" i18n="true">PLUGINS_FORMS_UI_NO_FORMS_TOOLTIP</param>
@@ -1406,21 +1425,6 @@
 					<param name="icon-medium" file="true">img/forms_32.png</param>
 					<param name="icon-large" file="true">img/forms_48.png</param>
 				</action> 
-                <right>Runtime_Rights_Forms_Export</right>
-				<menu-item id="org.ametys.forms.ExportForm">
-					<param name="action">org.ametys.forms.buttons.Action.exportForm</param>
-
-					<param name="label" i18n="true">PLUGINS_FORMS_UI_LABEL</param>
-					<param name="description" i18n="true">PLUGINS_FORMS_UI_DESCRIPTION</param>
-					<param name="iconSmall" file="true">img/forms_16.png</param>
-				</menu-item>
-				<menu-item id="org.ametys.forms.ShowForm">
-					<param name="action">org.ametys.forms.buttons.Action.showForm</param>
-
-					<param name="label" i18n="true">PLUGINS_SHOW_FORMS_UI_LABEL</param>
-					<param name="description" i18n="true">PLUGINS_SHOW_FORMS_UI_DESCRIPTION</param>
-					<param name="iconSmall" file="true">img/forms_16.png</param>
-				</menu-item>
 				<scripts>
 					<file>js/org/ametys/forms/FormsButton.js</file>
                     <file>js/org/ametys/forms/FormsActions.i18n.js</file>
@@ -1503,6 +1507,11 @@
                 <!-- 
                     Define the right for entries in forms
                  -->
+                <right id="Runtime_Rights_Forms_Export">
+                    <label>PLUGINS_FORMS_RIGHTS_EXPORT_FORM_LABEL</label>
+                    <description>PLUGINS_FORMS_RIGHTS_EXPORT_FORM_DESCRIPTION</description>
+                    <category>PLUGINS_FORMS_RIGHTS_FORMS_CATEGORY</category>
+                </right>
                 <right id="Runtime_Rights_Forms_Delete_Entry">
                     <label>PLUGINS_FORMS_RIGHTS_DELETE_FORM_ENTRY_LABEL</label>
                     <description>PLUGINS_FORMS_RIGHTS_DELETE_FORM_ENTRY_DESCRIPTION</description>
@@ -1514,18 +1523,38 @@
                     <category>PLUGINS_FORMS_RIGHTS_FORMS_CATEGORY</category>
                 </right>
             </extension>
-                
+            
             <extension id="org.ametys.plugins.forms.FormsEntriesTab"
                        point="org.ametys.cms.workspace.ribbon.RibbonTabsManager"
                        class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
-                <action class="org.ametys.cms.ribbon.tab.ToolTab">
-    				<param name="factory-id">^uitool-form-entries.+$</param>
+                <action class="org.ametys.cms.ribbon.tab.SelectionTab">
+    				<param name="target-type">^(content-form)$</param>
     			</action> 
     			<scripts>
-    				<file plugin="cms">js/org/ametys/cms/ribbon/tab/ToolTab.js</file>
+    				<file plugin="cms">js/org/ametys/cms/ribbon/tab/SelectionTab.js</file>
     			</scripts>   
             </extension>
             
+            <extension id="org.ametys.plugins.forms.entries.ExportFormEntries"
+                       point="org.ametys.cms.workspace.ribbon.RibbonControlsManager"
+                       class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
+                <action class="org.ametys.ribbon.control.button.ActionSelectionButton">
+                    <param name="action">org.ametys.forms.entry.exportFormEntries</param>
+                    <param name="target-type">^content-form$</param>
+                    <param name="enable-multiselection">false</param>
+    
+                    <param name="label" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_EXPORT_LABEL</param>
+                    <param name="default-description" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_EXPORT_DESCRIPTION</param>
+                    <param name="icon-small" file="true">img/forms_16.png</param>
+                    <param name="icon-medium" file="true">img/forms_32.png</param>
+                    <param name="icon-large" file="true">img/forms_48.png</param>
+                </action>
+                <right>Runtime_Rights_Forms_Export</right>
+                <scripts>
+                    <file>js/org/ametys/forms/FormsActions.i18n.js</file>
+                </scripts>
+            </extension>
+            
             <extension id="org.ametys.plugins.forms.entries.DeleteEntry"
                        point="org.ametys.cms.workspace.ribbon.RibbonControlsManager"
                        class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
@@ -1549,28 +1578,32 @@
             <extension id="org.ametys.plugins.forms.entries.ClearEntries"
                        point="org.ametys.cms.workspace.ribbon.RibbonControlsManager"
                        class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
-                <action class="org.ametys.ribbon.control.button.ActionButton">
+                <action class="org.ametys.forms.buttons.ClearFormEntriesButton">
                     <param name="action">org.ametys.forms.entry.ClearEntries</param>
                     <param name="target-type">^content-form$</param>
                     
                     <param name="label" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_LABEL</param>
                     <param name="default-description" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_DESCRIPTION</param>
+                    <param name="no-entries-description" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_CLEAR_ENTRIES_NO_ENTRIES_DESCRIPTION</param>
+                    
                     <param name="icon-small" file="true">img/clear_entries_16.png</param>
                     <param name="icon-medium" file="true">img/clear_entries_32.png</param>
                     <param name="icon-large" file="true">img/clear_entries_48.png</param>
                 </action>
-                <right>Runtime_Rights_Forms_Delete_Entry</right>
                 <scripts>
                     <file>js/org/ametys/forms/FormsActions.i18n.js</file>
+                    <file>js/org/ametys/forms/ClearFormEntriesButton.js</file>
                 </scripts>
+                <right>Runtime_Rights_Forms_Delete_Entry</right>
             </extension>
             
             <extension id="org.ametys.plugins.forms.entries.ViewRequest"
                        point="org.ametys.cms.workspace.ribbon.RibbonControlsManager"
                        class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
-                <action class="org.ametys.ribbon.control.button.ActionButton">
+                <action class="org.ametys.ribbon.control.button.ActionSelectionButton">
                     <param name="action">org.ametys.forms.entry.ViewRequest</param>
                     <param name="target-type">^content-form$</param>
+                    <param name="enable-multiselection">false</param>
                     
                     <param name="label" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_VIEW_REQUEST_LABEL</param>
                     <param name="default-description" i18n="true">PLUGINS_FORMS_UITOOL_BUTTON_VIEW_REQUEST_DESCRIPTION</param>
@@ -1585,6 +1618,59 @@
             </extension>
         </extensions>
     </feature>
-	
     
+    <!-- Tool used to list the forms of the current site -->	
+	<feature name="org.ametys.plugins.forms.list">
+	   <extensions>
+	       <extension point="org.ametys.runtime.plugins.core.right.RightsExtensionPoint"
+                       id="forms.rights.forms.list.handle">
+                <!-- "Handle" right. -->
+                <right id="Forms_Rights_Forms_List_Handle">
+                    <label>PLUGINS_FORMS_RIGHTS_FORMS_LIST_HANDLE_LABEL</label>
+                    <description>PLUGINS_FORMS_RIGHTS_FORMS_LIST_HANDLE_DESCRIPTION</description>
+                    <category>PLUGINS_FORMS_RIGHTS_FORMS_CATEGORY</category>
+                </right>
+            </extension>
+	   
+            <extension id="org.ametys.plugins.forms.FormsList"
+                       point="org.ametys.cms.workspace.ribbon.RibbonControlsManager"
+                       class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
+                <action class="org.ametys.ribbon.control.button.UniqueInstanceToolButton">
+                    <param name="role">uitool-forms-list</param>
+                    
+                    <param name="label" i18n="true">PLUGINS_FORMS_UITOOL_FORMS_LIST_LABEL</param>
+                    <param name="default-description" i18n="true">PLUGINS_FORMS_UITOOL_FORMS_LIST_DESCRIPTION</param>
+                    <param name="footer" i18n="true">PLUGINS_FORMS_UITOOL_FORMS_LIST_FOOTER</param>
+                    
+                    <param name="icon-small" file="true">img/forms_16.png</param>
+                    <param name="icon-medium" file="true">img/forms_32.png</param>
+                    <param name="icon-large" file="true">img/forms_48.png</param>
+                </action>
+                <right>Forms_Rights_Forms_List_Handle</right>
+            </extension>
+            
+            <extension id="org.ametys.plugins.forms.FormsListFactory"
+                       point="org.ametys.cms.workspace.uitool.UIToolsFactoriesManager"
+                       class="org.ametys.runtime.ui.impl.StaticClientSideElement">
+                <action class="org.ametys.forms.tool.FormsListToolFactory">
+                    <param name="role">uitool-forms-list</param>
+                    <param name="title" i18n="true">PLUGINS_FORMS_UITOOL_FORMS_LIST_LABEL</param>
+                    <param name="description" i18n="true">PLUGINS_FORMS_UITOOL_FORMS_LIST_DESCRIPTION</param>
+                    
+                    <param name="icon-small" file="true">img/forms_16.png</param>
+                    <param name="icon-medium" file="true">img/forms_32.png</param>
+                    <param name="icon-large" file="true">img/forms_48.png</param>
+                    
+                    <param name="default-location"></param>
+                </action>
+                <scripts>
+                    <file>js/org/ametys/forms/FormsListTool.i18n.js</file>
+                    <file>js/org/ametys/forms/FormsListToolFactory.js</file>
+                </scripts>
+                <css>
+                    <file>css/formslist-tool.css</file>
+                </css>
+            </extension>
+        </extensions>
+	</feature>
 </plugin>
Index: main/plugin-forms/resources/css/formslist-tool.css
===================================================================
--- main/plugin-forms/resources/css/formslist-tool.css	(revision 0)
+++ main/plugin-forms/resources/css/formslist-tool.css	(revision 0)
@@ -0,0 +1,52 @@
+/*
+ *  Copyright 2012 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+.formslist-tool-form .x-panel-body{
+    background-color: #eaeaea;
+    color: #404040;
+    padding: 1px 0;
+}
+
+.formslist-tool-form.x-form-item {
+    font-family: Arial, sans-serif !important;
+    font-size: 11px;
+    margin-bottom: 2px !important;
+}
+
+.formslist-tool-form .x-form-field-trigger-wrap,
+.formslist-tool-form .x-form-trigger,
+.formslist-tool-form .x-form-field 
+{
+    vertical-align: top;
+}
+
+.formslist-tool-lang label, .formslist-tool-lang input {
+    color: #404040;
+    font-size: 11px !important;
+    font-family: Arial, sans-serif !important;
+}
+
+.formslist-tool-lang label {
+    padding-left: 5px !important;
+    float: left;
+    padding-top: 5px;
+}
+
+.formslist-tool-lang .combo-list-lang-item {
+    background-repeat: no-repeat !important;
+    background-position: left !important;
+    font-size: 11px !important;
+}
Index: main/plugin-forms/resources/css/view.css
===================================================================
--- main/plugin-forms/resources/css/view.css	(revision 0)
+++ main/plugin-forms/resources/css/view.css	(revision 0)
@@ -0,0 +1,28 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+.orphan-forms-list .x-grid3 {
+    background: none !important;
+}
+
+/* Entete */
+.orphan-forms-list .x-grid3-hd-inner {
+    font-weight: bold;
+    font-family: arial, sans-serif !important;
+    font-size: 1.1em !important;
+}
+
+
Index: main/plugin-forms/resources/js/org/ametys/forms/ClearFormEntriesButton.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/ClearFormEntriesButton.js	(revision 0)
+++ main/plugin-forms/resources/js/org/ametys/forms/ClearFormEntriesButton.js	(revision 0)
@@ -0,0 +1,74 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.forms.buttons');
+
+org.ametys.forms.buttons.ClearFormEntriesButton = function(id, configuration, pluginName) 
+{
+	org.ametys.forms.buttons.ClearFormEntriesButton.superclass.constructor.call(this, id, configuration, pluginName);
+};
+
+Ext.extend(org.ametys.forms.buttons.ClearFormEntriesButton, org.ametys.ribbon.control.button.ActionSelectionButton, {});
+
+org.ametys.forms.buttons.ClearFormEntriesButton.prototype.onMessage = function (messages)
+{
+	for (var i=messages.length - 1; i >= 0; i--)
+	{
+		if (messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_SELECTIONCHANGED)
+		{
+			var targets = messages[i].getTargets();
+			var allContentFormTargets = org.ametys.messagebus.message.MessageTargetHelper.findAll(targets, this.checkTarget());
+			
+			// No content selected
+			if (allContentFormTargets.length == 0)
+			{
+				this.getElements().each(function(element) { element.setDisabled(true); });
+				this.updateTooltip(this.getConfiguration()["default-description"]);
+			}
+			else
+			{
+				for (var j=0; j < allContentFormTargets.length; j++)
+				{
+					var hasEntries = false;
+					var contentFormTarget = allContentFormTargets[j];
+					if (contentFormTarget.getParameters().hasEntries === true)
+					{
+						hasEntries = true;
+						break;
+					}
+				}
+				
+				this.getElements().each(function(element) { element.setDisabled(!hasEntries); });
+				
+				var tooltip = this.getConfiguration()["default-description"];
+				if (!hasEntries)
+				{
+					tooltip = this.getConfiguration()["no-entries-description"]
+				}
+				
+				this.updateTooltip(tooltip);
+				
+				return;
+			}
+		}
+	}
+}
+
+org.ametys.forms.buttons.ClearFormEntriesButton.prototype.checkTarget = function ()
+{
+	return function (target) { return target.getType() == 'content-form'; };
+}
+
Index: main/plugin-forms/resources/js/org/ametys/forms/FormsActions.i18n.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/FormsActions.i18n.js	(revision 39963)
+++ main/plugin-forms/resources/js/org/ametys/forms/FormsActions.i18n.js	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,34 +21,16 @@
 
 org.ametys.forms.buttons.Action = {};
 
-org.ametys.forms.buttons.Action.exportForm = function (button, state, configuration, index)
-{
-    org.ametys.forms.ChooseForm.act(button.ribbonControl, org.ametys.forms.buttons.Action.exportSelectedForm);
-}
-
-org.ametys.forms.buttons.Action.showForm = function (button, state, configuration, index) // (id, configuration, pluginName)
-{
-	var control = typeof button == "string" ? org.ametys.ribbon.RibbonManager.getInstance().getControls()[button] : button.ribbonControl;
-    org.ametys.forms.ChooseForm.act(control, org.ametys.forms.buttons.Action.showSelectedForm);
-}
-
-org.ametys.forms.buttons.Action.exportSelectedForm = function (id, encodedLabel, label)
+org.ametys.forms.buttons.Action.showForm = function (controlId, controlConfiguration, controlPluginName)
 {
-	if (id != null)
-    {
-        var pluginName = org.ametys.forms.ChooseForm._pluginName;
-        var url = '/' + context.parameters.siteName + '/export/' + id + '/' + encodedLabel + '.xls';
-        
-        window.location.href = getPluginDirectUrl(pluginName) + url;
-    }
+    org.ametys.forms.ChooseForm.act(org.ametys.ribbon.RibbonManager.getInstance().getControls()[controlId], org.ametys.forms.buttons.Action.showSelectedForm);
 }
 
 org.ametys.forms.buttons.Action.showSelectedForm = function(id, encodedLabel, label)
 {
-	org.ametys.uitool.ToolsManager.getInstance().openTool('uitool-form-entries', { id: id, label: label});
+	org.ametys.uitool.ToolsManager.getInstance().openTool('uitool-form-entries', { id: id, encodedLabel: encodedLabel, label: label});
 }
 
-
 org.ametys.forms.ChooseForm = {};
 
 /**
@@ -59,7 +41,7 @@
 org.ametys.forms.ChooseForm._listview;
 
 /**
- * The current selected form
+ * The form currently selected
  */
 org.ametys.forms.ChooseForm._currentForm;
 
@@ -88,8 +70,6 @@
     }
     
     org.ametys.forms.ChooseForm.load();
-    
-    org.ametys.forms.ChooseForm._box.show();
 }
 
 org.ametys.forms.ChooseForm.delayedInitialize = function ()
@@ -144,7 +124,6 @@
     org.ametys.forms.ChooseForm._initialized = true;
     
     return true;
-    
 }
 
 org.ametys.forms.ChooseForm.load = function()
@@ -161,14 +140,14 @@
     org.ametys.forms.ChooseForm._listview.getStore().removeAll();
     
     var contents = result.selectNodes("content-forms/content");
+    var formsAmount = 0;
     
     for (var i = 0; i &lt; contents.length; i++)
     {
         var contentId = contents[i].getAttribute('id');
         var contentTitle = contents[i].getAttribute('title');
         
-        var forms = contents[i].selectNodes("form");
-        
+        var forms = contents[i].selectNodes('form');
         for (var j=0; j &lt; forms.length;j++)
         {
             var id = forms[j].getAttribute('id');
@@ -178,9 +157,11 @@
             
             org.ametys.forms.ChooseForm._listview.addElement(id, {name: name, encodedName: encodedName, displayName: displayName});
         }
+        
+        formsAmount += forms.length;
     }
     
-    if (contents.length == 0)
+    if (formsAmount == 0)
     {
         Ext.Msg.show({
            title: "<i18n:text i18n:key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION"/>",
@@ -188,7 +169,35 @@
            buttons: Ext.Msg.OK,
            icon: Ext.MessageBox.INFO
         });
+        
+        return;
     }
+    
+    
+    if (formsAmount == 1)
+	{
+    	// Do not bother displaying a selection pop-up when there is only one form to select
+        // Select the first form "artificially", since the list view is never going to be rendered
+        var firstRecord = org.ametys.forms.ChooseForm._listview.store.getAt(0);
+        org.ametys.forms.ChooseForm._listview.getSelectionModel().selections.add(firstRecord);
+    	
+    	org.ametys.forms.ChooseForm.ok();
+	}
+    
+    if (formsAmount &gt; 1)
+	{
+    	// Select the first record after the dialog box list view is ready
+    	if (!org.ametys.forms.ChooseForm._listview.viewReady)
+		{
+    		org.ametys.forms.ChooseForm._listview.on('viewready', function(){org.ametys.forms.ChooseForm._listview.getSelectionModel().selectFirstRow();});
+		}
+    	else
+		{
+    		org.ametys.forms.ChooseForm._listview.getSelectionModel().selectFirstRow();
+		}
+
+    	org.ametys.forms.ChooseForm._box.show();
+	}
 }
 
 org.ametys.forms.ChooseForm.ok = function()
@@ -226,10 +235,34 @@
     org.ametys.forms.ChooseForm._box.hide();
 }
 
-
 //------------------------------------------------------------
 
 /**
+ * Export the form's entries to XLS
+ */
+org.ametys.forms.entry.exportFormEntries = function(controlId, controlConfiguration, controlPluginName)
+{
+	var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets();
+	var formTarget = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function (target) { return target.getType() == 'content-form'});
+	
+	if (formTarget.length == 0)
+    {
+        Ext.Msg.show({
+           title: "<i18n:text i18n:key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION"/>",
+           msg: "<i18n:text i18n:key="PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED"/>",
+           buttons: Ext.Msg.OK,
+           icon: Ext.MessageBox.INFO
+        });
+        return;
+    }
+	
+    var formId = formTarget.getParameters().id;
+    var formEncodedLabel = formTarget.getParameters().encodedLabel;
+
+    window.location.href = getPluginDirectUrl(controlPluginName) + '/' + context.parameters.siteName + '/export/' + formId + '/' + formEncodedLabel + '.xls';
+}
+
+/**
  * Delete selected form entries.
  */
 org.ametys.forms.entry.DeleteEntry = function(controlId, controlConfiguration, controlPluginName)
@@ -239,7 +272,8 @@
     
     if (formTarget != null)
     {
-    	var formId = formTarget.getParameters().id;
+    	var formIds = [];
+    	formIds.push(formTarget.getParameters().id);    	
     	
     	var targets = formTarget.getSubTargets('form-entry');
     	if (targets.length > 0)
@@ -258,11 +292,11 @@
     	                    var serverMessage = new org.ametys.servercomm.ServerMessage(
     	                        'forms',
     	                        '/form/delete-entries',
-    	                        {siteName: context.parameters.siteName, formId: formId, ids: entryIds}, 
+    	                        {siteName: context.parameters.siteName, formIds: formIds, ids: entryIds}, 
     	                        org.ametys.servercomm.ServerComm.PRIORITY_MAJOR,
     	                        org.ametys.forms.entry.DeleteEntry._deleteEntriesCb, 
     	                        this, 
-    	                        [entryIds, formId]
+    	                        [entryIds, formIds[0]]
     	                    );
     	                    org.ametys.servercomm.ServerComm.getInstance().send(serverMessage);
     	                }
@@ -285,7 +319,7 @@
     var entryIds = args[0];
     for (var i=0; i &lt; entryIds.length; i++)
 	{
-    	targets.push(org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('form-entry', {'id': entryIds[0], 'form': args[1] }));
+    	targets.push(org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('form-entry', {'id': entryIds[i], 'form': args[1] }));
 	}
     
     var message = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_DELETED, null, targets);
@@ -295,28 +329,34 @@
 //------------------------------------------------------------
 
 /**
- * Clear all entries from a form.
+ * Clear all entries from at least one form.
  */
 org.ametys.forms.entry.ClearEntries = function(controlId, controlConfiguration, controlPluginName)
 {
 	var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets();
-	var formTarget = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function (target) { return target.getType() == 'content-form'});
+	var allFormTargets = org.ametys.messagebus.message.MessageTargetHelper.findAll(targets, function (target) { return target.getType() == 'content-form'});
 
-	if (formTarget != null)
+	if (allFormTargets.length &gt; 0)
 	{
+		var formIds = [];
+		for (var i = 0; i &lt; allFormTargets.length; i++)
+		{
+			formIds.push(allFormTargets[i].getParameters().id);
+		}
+		
 		Ext.Msg.confirm("<i18n:text i18n:key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_TITLE"/>", 
-		        "<i18n:text i18n:key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM"/>", 
+				formIds.length &gt; 1 ? "<i18n:text i18n:key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_SEVERAL"/>" : "<i18n:text i18n:key="PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_SINGLE"/>", 
 		        function (answer) {
 		            if (answer == 'yes')
 		            {
 		                var serverMessage = new org.ametys.servercomm.ServerMessage(
 		                    'forms',
 		                    '/form/clear-entries',
-		                    {siteName: context.parameters.siteName, formId: formTarget.getParameters().id}, 
+		                    {siteName: context.parameters.siteName, formIds: formIds}, 
 		                    org.ametys.servercomm.ServerComm.PRIORITY_MAJOR,
 		                    org.ametys.forms.entry.ClearEntries._clearEntriesCb, 
 		                    this, 
-		                    [formTarget.getParameters().id]
+		                    [formIds]
 		                );
 		                org.ametys.servercomm.ServerComm.getInstance().send(serverMessage);
 		            }
@@ -333,8 +373,14 @@
         return;
     }
     
-    var formTarget = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("content-form", {'id': args[0]});
-    var message = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_METADATACHANGED, null, [formTarget]);
+    var formIds = args[0];
+    var targets = [];
+    for (var i = 0; i &lt; formIds.length; i++)
+	{
+    	targets.push(org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('content-form', {'id': formIds[i]}));
+	}
+    
+    var message = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_METADATACHANGED, null, targets);
     org.ametys.messagebus.MessageBus.getInstance().fireMessages([message]);
 }
 
Index: main/plugin-forms/resources/js/org/ametys/forms/FormsButton.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/FormsButton.js	(revision 39963)
+++ main/plugin-forms/resources/js/org/ametys/forms/FormsButton.js	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
 	org.ametys.forms.buttons.FormsButton.superclass.constructor.call(this, id, configuration, pluginName);
 };
 
-Ext.extend(org.ametys.forms.buttons.FormsButton, org.ametys.cms.ribbon.button.Menu, {});
+Ext.extend(org.ametys.forms.buttons.FormsButton, org.ametys.ribbon.control.button.ActionButton, {});
 
 /**
  * @private
Index: main/plugin-forms/resources/js/org/ametys/forms/FormsListTool.i18n.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/FormsListTool.i18n.js	(revision 0)
+++ main/plugin-forms/resources/js/org/ametys/forms/FormsListTool.i18n.js	(revision 0)
@@ -0,0 +1,397 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.forms.tool');
+
+org.ametys.forms.tool.FormsListTool = function(id, pluginName) 
+{
+    org.ametys.forms.tool.FormsListTool.superclass.constructor.call(this, id, pluginName);
+};
+
+Ext.extend(org.ametys.forms.tool.FormsListTool, org.ametys.uitool.tool.Tool, {});
+
+org.ametys.forms.tool.FormsListTool.prototype.createPanel = function()
+{
+    // The mapping for XML doc
+    var mapping = Ext.data.Record.create([
+        {name: 'id', mapping: '@id'},
+        {name: 'encodedLabel', mapping: '@encodedLabel'},
+        {name: 'name', mapping: 'name'},
+        {name: 'contentName', mapping: 'contentName'},
+        {name: 'answersAmount', mapping: 'answersAmount'},
+        {name: 'lastAnswer', mapping: 'lastAnswer'}
+    ]);
+    
+    // HTTP proxy
+    var proxy = new Ext.data.HttpProxy({
+        url: getPluginDirectUrl('forms') + '/forms-list.xml',
+        method: 'post',
+        timeout: 0
+    });
+    
+    // Data store
+    this._xmlStore = new Ext.data.Store({
+        proxy: proxy,
+        baseParams: {'siteName': context.parameters.siteName},
+        reader: new Ext.data.XmlReader({
+                record: 'form',
+                id: '@id'
+            },
+            mapping
+        ),
+    });
+    
+    this._xmlStore.on('beforeload', this._onBeforeLoad, this);
+    this._xmlStore.on('load', this._onLoad, this);
+    
+	this._langCombo = this._drawLanguageCombo();
+	this._loadLanguages();
+	
+	var langComboLabel = new Ext.form.Label({
+		width: 60, 
+		bodyStyle: {'textAlign': 'center'},
+    	text: "<i18n:text i18n:key='PLUGINS_FORMS_UITOOL_FORMS_LIST_LANGUAGE'/>"
+	});
+	
+	var langPanel = new Ext.Panel({
+		region: 'north',
+		border: false,
+		cls: 'formslist-tool-lang',
+		labelWidth: 30,
+		labelSeparator: '',
+        items: [langComboLabel, this._langCombo]
+    });
+	
+    this._grid = new Ext.grid.GridPanel({
+        region: 'center',
+        
+        store: this._xmlStore,
+        
+        viewConfig: {
+        	forceFit: true
+        },
+        
+        columns: [
+            {header: "<i18n:text i18n:key='PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_NAME'/>", width: 200, dataIndex: 'name'},
+            {header: "<i18n:text i18n:key='PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_CONTENT_NAME'/>", width: 200, dataIndex: 'contentName'},
+            {header: "<i18n:text i18n:key='PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_ANSWERS_AMOUNT'/>", width: 100, dataIndex: 'answersAmount'},
+            {header: "<i18n:text i18n:key='PLUGINS_FORMS_UITOOL_FORMS_LIST_COL_LAST_ANSWER'/>", width: 200, dataIndex: 'lastAnswer', renderer: this._renderDate}
+        ]
+    });
+    this._grid.getSelectionModel().on('selectionchange', this._onSelectForm, this);
+    this._grid.on('celldblclick', this._openFormEntriesTool, this);
+    
+    this._mainPanel = new Ext.Panel({
+        layout: 'border',
+        items: [langPanel, this._grid]
+    });
+    
+    this._mainPanel.addListener('focus', this._onFocus, this);
+    this._mainPanel.addListener('blur', this._onBlur, this);
+    this._mainPanel.addListener('afterrender', this.refresh, this);
+    this._mainPanel.addListener('close', this._onClose, this);
+    
+    return this._mainPanel;
+}
+
+org.ametys.forms.tool.FormsListTool.prototype.refresh = function(manual)
+{
+    this.refreshing();
+    
+    this._xmlStore.load();
+}
+
+/**
+ * Open the form entries tool corresponding to the clicked cell
+ * @param grid The grid
+ * @param rowIndex The selected row index
+ * @param columnIndex The selected column index
+ * @param e The event
+ */
+org.ametys.forms.tool.FormsListTool.prototype._openFormEntriesTool = function (grid, rowIndex, columnIndex, e)
+{
+	var record = grid.getSelectionModel().getSelected();
+	var id = record.get('id');
+	var label = record.get('name');
+	var encodedLabel = record.get('encodedLabel');
+	
+	org.ametys.uitool.ToolsManager.getInstance().openTool ("uitool-form-entries", { id: id, encodedLabel: encodedLabel, label: label});
+}
+
+/**
+ * @private
+ * Listener function invoked whenever the selection changes,
+ * Sends an selection event on the message bus
+ * @param Ext.grid.AbstractSelectionModel sm The selection model.
+ */
+org.ametys.forms.tool.FormsListTool.prototype._onSelectForm = function(sm)
+{
+	window.clearTimeout(this._sendTimeout);
+	this._sendTimeout = this._sendSelectionMessage.defer(10, this, [sm.getSelections()]);
+}
+
+org.ametys.forms.tool.FormsListTool.prototype._sendSelectionMessage = function(records)
+{
+    var targets = [];
+    
+    for (var i=0; i &lt; records.length; i++)
+    {
+    	targets.push(org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('content-form', {
+    		'id': records[i].data.id, 
+    		'encodedLabel': records[i].data.encodedLabel,
+    		'hasEntries': records[i].data.answersAmount > 0
+		}));
+    }
+	
+    var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_SELECTIONCHANGED, null, targets);
+	org.ametys.messagebus.MessageBus.getInstance().fireMessages([event]);
+}
+
+org.ametys.forms.tool.FormsListTool.prototype.onMessage = function(messages)
+{
+	for (var i = messages.length - 1; i >= 0; i--)
+    {
+    	var messageType = messages[i].getType().getName();
+        if (messageType == org.ametys.ribbon.RibbonManager.EVENTTYPE_METADATACHANGED)
+        {
+        	var targets = messages[i].getTargets();
+            var allTargets = org.ametys.messagebus.message.MessageTargetHelper.findAll(targets,function(target) { return target.getType() == "content-form" || target.getType() == "content";});
+        	
+            if (allTargets.length &gt; 0)
+        	{
+            	this.outOfDate();
+        	}
+        }
+        else if (messageType == org.ametys.ribbon.RibbonManager.EVENTTYPE_CREATED)
+    	{
+        	var targets = messages[i].getTargets();
+            var allTargets = org.ametys.messagebus.message.MessageTargetHelper.findAll(targets,function(target) { return target.getType() == "content";});
+        	
+            if (allTargets.length &gt; 0)
+        	{
+            	this.outOfDate();
+        	}
+    	}
+        else if (messageType == org.ametys.ribbon.RibbonManager.EVENTTYPE_DELETED)
+    	{
+        	var targets = messages[i].getTargets();
+            var allTargets = org.ametys.messagebus.message.MessageTargetHelper.findAll(targets,function(target) { return target.getType() == "content" || target.getType() == "form-entry";});
+        	
+            if (allTargets.length &gt; 0)
+        	{
+            	this.outOfDate();
+        	}
+    	}
+    }
+}
+
+org.ametys.forms.tool.FormsListTool.prototype._drawLanguageCombo = function()
+{
+    var langStore = new Ext.data.SimpleStore({
+        fields: ['lang', 'langlabel', 'langimage', 'langfull'],
+        data: []
+    });
+    
+    var combo = new Ext.form.ComboBox({
+        width: 160,
+        minListWidth: 120,
+        
+        forceSelection: true,
+        editable: false,
+        mode: 'local',
+        resizable: false,
+        triggerAction: 'all',
+        
+        store: langStore,
+        
+        name: 'lang',
+        valueField: 'lang',
+        displayField: 'langfull',
+        
+        tpl: new Ext.XTemplate(
+                '&lt;tpl for="."&gt;',
+                    '&lt;div class="x-combo-list-item combo-list-lang-item"&gt;',
+                        '&lt;img src="{langimage}" style="float:left; margin-right: 3px"/&gt;', 
+                        '{langlabel} &lt;em&gt;({lang})&lt;/em&gt;',
+                        '&lt;div class="x-clear"&gt;&lt;/div&gt;',
+                    '&lt;/div&gt;',
+                '&lt;/tpl&gt;')
+    });
+    
+    combo.addListener('select', this._langChange, this);
+    
+    return combo;
+}
+
+org.ametys.forms.tool.FormsListTool.prototype._loadLanguages = function()
+{
+    var serverMessage = new org.ametys.servercomm.ServerMessage('web', '/repository/languages.xml', {'siteName': context.parameters.siteName}, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, this._loadLanguagesCb, this, []);
+    org.ametys.servercomm.ServerComm.getInstance().send(serverMessage);
+}
+
+org.ametys.forms.tool.FormsListTool.prototype._loadLanguagesCb = function(response, args)
+{
+    if (org.ametys.servercomm.ServerComm.handleBadResponse("<i18n:text i18n:key='PLUGINS_FORMS_UITOOL_FORMS_LIST_GET_LANGUAGES_ERROR'/>", response, "org.ametys.forms.tool.FormsListTool._loadLanguagesCb"))
+    {
+        return;
+    }
+    
+    var store = this._langCombo.getStore();
+    store.removeAll();	
+    
+    this.defaultLang = null;
+    var isThereEn = false;
+    var ok = false;
+    
+    var languages = response.selectNodes('sitemaps/sitemap');
+    for (var i=0; i &lt; languages.length; i++)
+    {
+        if (!ok)
+        {
+            // Find the default language
+            if (this._lang == languages[i].getAttribute('name'))
+            {
+                this.defaultLang = languages[i].getAttribute('name');
+                ok = true;
+            }
+            else if (context.parameters.userLocale == languages[i].getAttribute('name'))
+            {
+                this.defaultLang = context.parameters.userLocale;
+            }
+            if (languages[i].getAttribute('name') == 'en')
+            {
+                isThereEn = true;
+            }
+        }
+        
+        var data = {
+            lang: languages[i].getAttribute('name'),
+            langlabel: languages[i].selectSingleNode('label')[org.ametys.servercomm.ServerComm.xmlTextContent],
+            langimage: context.contextPath + languages[i].selectSingleNode ('small-icon')[org.ametys.servercomm.ServerComm.xmlTextContent],
+            langfull: languages[i].selectSingleNode('label')[org.ametys.servercomm.ServerComm.xmlTextContent] + ' (' + languages[i].getAttribute('name') + ')'
+        };
+        store.add(new store.recordType(data));
+    }
+    
+    if (this.defaultLang == null)
+    {
+        if (isThereEn)
+        {
+            this.defaultLang = 'en';
+        }
+        else
+        {
+            this.defaultLang = languages[0].getAttribute('name');
+        }
+    }
+    
+    // Initialize with default value
+    this._langCombo.setValue(this.defaultLang);
+    this._lang = this.defaultLang;
+    store.sort('lang', 'ASC');
+    this.refresh();
+}
+
+org.ametys.forms.tool.FormsListTool.prototype._langChange = function(combo, record, index)
+{
+    if (this._lang == record.data.lang)
+    {
+        return;
+    }
+    
+    this._lang = record.data.lang;
+    
+    // Refresh the tool content.
+    this.refresh();
+}
+
+
+org.ametys.forms.tool.FormsListTool.prototype._renderDate = function(value, p, record)
+{
+	var dateFormat = "<i18n:text i18n:key="PLUGINS_FORMS_DATETIME_FORMAT"/>";
+	return Ext.util.Format.date(value, dateFormat);
+}
+
+/**
+ * Listens when the store is about to load or reload.
+ * @private
+ */
+org.ametys.forms.tool.FormsListTool.prototype._onBeforeLoad = function(store, options)
+{
+	// Let the load occur only if we know the language.
+	if (this._lang == null)
+	{
+		return false;
+	}
+	
+	store.baseParams.language = this._lang;
+}
+
+/**
+ * Listens when the store has loaded records.
+ * @private
+ */
+org.ametys.forms.tool.FormsListTool.prototype._onLoad = function(store, records, options)
+{
+    this.upToDate();
+    this._updateSelections();
+}
+
+/**
+ * Listens when the panel receives the focus.
+ * @private
+ */
+org.ametys.forms.tool.FormsListTool.prototype._onFocus = function(messages)
+{
+    this._hasFocus = true;
+    this._updateSelections();
+}
+
+/**
+ * Listens when the panel looses the focus.
+ * @private
+ */
+org.ametys.forms.tool.FormsListTool.prototype._onBlur = function(messages)
+{
+    this._hasFocus = false;
+}
+
+/**
+ * Listens when the panel is closed.
+ * @private
+ */
+org.ametys.forms.tool.FormsListTool.prototype._onClose = function(messages)
+{
+	if (this._hasFocus)
+	{
+		var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_SELECTIONCHANGED, null, []);
+		var eventBus =  org.ametys.messagebus.MessageBus.getInstance();
+		eventBus.fireMessages([event]);
+	}
+}
+
+/**
+ * @private
+ * Update the selections
+ */
+org.ametys.forms.tool.FormsListTool.prototype._updateSelections = function ()
+{
+	var records = this._grid.getSelectionModel().getSelections();
+	if (records.length &gt; 0)
+	{
+	    this._sendSelectionMessage(records);
+	}
+}
Index: main/plugin-forms/resources/js/org/ametys/forms/FormsListToolFactory.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/FormsListToolFactory.js	(revision 0)
+++ main/plugin-forms/resources/js/org/ametys/forms/FormsListToolFactory.js	(revision 0)
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.forms.tool');
+
+org.ametys.forms.tool.FormsListToolFactory = function(id, config, pluginName) 
+{
+	org.ametys.forms.tool.FormsListToolFactory.superclass.constructor.call(this, id, config, pluginName);
+};
+
+Ext.extend(org.ametys.forms.tool.FormsListToolFactory, org.ametys.uitool.tool.impl.UniqueInstanceToolFactory,
+{
+	createTool: function (id)
+	{
+		var tool = new org.ametys.forms.tool.FormsListTool(id, this.getPluginName());
+		tool.setConfiguration (this._config);
+		return tool;
+	}
+});
+
Index: main/plugin-forms/resources/js/org/ametys/forms/FormsTool.i18n.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/FormsTool.i18n.js	(revision 39963)
+++ main/plugin-forms/resources/js/org/ametys/forms/FormsTool.i18n.js	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2012 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
 	    fields: [],
 	    data: []
 	});
-	
+
     this._pagingBar = new Ext.PagingToolbar({
         pageSize: org.ametys.forms.tool.FormsTool.PAGE_SIZE,
         store: store,
@@ -60,22 +60,30 @@
 org.ametys.forms.tool.FormsTool.prototype._sendCurrentSelection = function ()
 {
 	var records = this._resultGrid.getSelectionModel().getSelections();
-
-	var formTarget = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('content-form', {'id': org.ametys.forms.tool.FormsTool._formId })
+	var hasEntries = this._resultGrid.getStore().getTotalCount() > 0;
+	
+	var formTarget = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('content-form', {
+			'id': this._formId, 
+			'encodedLabel': this._formEncodedLabel,
+			'hasEntries': hasEntries
+	});
 	
-    for (var i=0; i &lt; records.length; i++)
+    for (var i = 0; i &lt; records.length; i++)
     {
-		formTarget.getSubTargets().push(org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('form-entry', {'id': records[i].data.entryId, 'form': org.ametys.forms.tool.FormsTool._formId}));
+		formTarget.getSubTargets().push(org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget('form-entry', {'id': records[i].data.entryId, 'form': this._formId}));
     }
     
     var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_SELECTIONCHANGED, null, [formTarget]);
     org.ametys.messagebus.MessageBus.getInstance().fireMessages([event]);
 }
 
-org.ametys.forms.tool.FormsTool._formId;
+org.ametys.forms.tool.FormsTool.prototype._formId;
+org.ametys.forms.tool.FormsTool.prototype._formEncodedLabel;
 org.ametys.forms.tool.FormsTool.prototype.setParams = function (params)
 {
-	org.ametys.forms.tool.FormsTool._formId = params.id;
+	this._formId = params.id;
+	this._formEncodedLabel = params.encodedLabel;
+	
 	this.refresh();
 }
 
@@ -86,7 +94,7 @@
 	var serverMessage = new org.ametys.servercomm.ServerMessage(
 		'forms',
 		'/form/entries.xml',
-		{siteName: context.parameters.siteName, id: org.ametys.forms.tool.FormsTool._formId, start: 0, limit: 0}, 
+		{siteName: context.parameters.siteName, id: this._formId, start: 0, limit: 0}, 
 		org.ametys.servercomm.ServerComm.PRIORITY_MAJOR,
 		this._displayFormEntries, 
 		this, 
@@ -97,7 +105,7 @@
 
 org.ametys.forms.tool.FormsTool.prototype.onMessage = function (messages)
 {
-    for (var i=messages.length - 1; i &gt;= 0; i--)
+    for (var i = messages.length - 1; i >= 0; i--)
     {
         if (messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_DELETED)
         {
@@ -108,7 +116,7 @@
             {
                 for (var j=0; j &lt; allTargets.length; j++)
                 {
-                    if (org.ametys.forms.tool.FormsTool._formId == allTargets[j].getParameters().form)
+                    if (this._formId == allTargets[j].getParameters().form)
                     {
                     	this.outOfDate(false);
                     	return;
@@ -119,12 +127,16 @@
         else if (messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_METADATACHANGED)
         {
         	var targets = messages[i].getTargets();
-            var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "content-form";});
+            var contentFormTargets = org.ametys.messagebus.message.MessageTargetHelper.findAll(targets, function(target) { return target.getType() == "content-form";});
             
-            if (target != null &amp;&amp; target.getParameters().id == org.ametys.forms.tool.FormsTool._formId)
-            {
-            	this.outOfDate(true);
-            }
+            for (var j = 0; j &lt; contentFormTargets.length; j++)
+        	{
+            	var contentFormTarget = contentFormTargets[j];
+	            if (contentFormTarget != null &amp;&amp; contentFormTarget.getParameters().id == this._formId)
+	            {
+	            	this.outOfDate(true);
+	            }
+        	}
         }
     }
 }
@@ -144,7 +156,7 @@
 	    url: getPluginDirectUrl('forms') + '/form/entries.xml',
 	    record: 'entry',
 	    totalProperty: '@total',
-        baseParams: {siteName: context.parameters.siteName, id: org.ametys.forms.tool.FormsTool._formId}
+        baseParams: {siteName: context.parameters.siteName, id: this._formId}
 	});
 	
 	var colModel = new Ext.grid.ColumnModel({
@@ -163,10 +175,14 @@
 	    params: {
 	        start: 0, 
 	        limit: org.ametys.forms.tool.FormsTool.PAGE_SIZE
-	    }
+	    },
+	    callback: function(){
+	    	this._sendCurrentSelection();
+	    	this.upToDate();
+	    },
+	    scope: this
 	});
 	
-	this.upToDate();
 }
 
 org.ametys.forms.tool.FormsTool.prototype._getFields = function (response)
@@ -400,5 +416,5 @@
 	
 	var fieldId = store.fields.get(colIndex).name;
 	var entryId = record.data.entryId;
-	return "&lt;a class='download' href='" + getPluginDirectUrl('forms') + "/" + context.parameters.siteName + "/download/" + org.ametys.forms.tool.FormsTool._formId + "/" + entryId + "/" + fieldId + "/" + value + "'&gt;" + "&lt;img src='" + iconPath  + "'/&gt;" + value + "&lt;/a&gt;";
+	return "&lt;a class='download' href='" + getPluginDirectUrl('forms') + "/" + context.parameters.siteName + "/download/" + this._formId + "/" + entryId + "/" + fieldId + "/" + value + "'&gt;" + "&lt;img src='" + iconPath  + "'/&gt;" + value + "&lt;/a&gt;";
 }
Index: main/plugin-forms/resources/js/org/ametys/forms/FormsToolFactory.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/FormsToolFactory.js	(revision 39963)
+++ main/plugin-forms/resources/js/org/ametys/forms/FormsToolFactory.js	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2012 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -17,11 +17,11 @@
 Ext.namespace('org.ametys.forms.tool');
 
 /**
- * Do not call this constructor. Decalred to and used by the {@see org.ametys.uitool.ToolsManager}
+ * Do not call this constructor. Declared to and used by the {@see org.ametys.uitool.ToolsManager}
  * @constructor
  * @class The factory to creates page tools.
  * @param {String} id The unique id of the factory
- * @param {Map} config Options are : 'url' : the url to use to display page, with a 'path' parameter to place the page path; 'default-location' : where to place the tool; 'description' : the tooltip to display with following parameters 'siteUrl', 'siteTitle', 'lang', 'path'.
+ * @param {Object} config Options are : 'url' : the url to use to display page, with a 'path' parameter to place the page path; 'default-location' : where to place the tool; 'description' : the tooltip to display with following parameters 'siteUrl', 'siteTitle', 'lang', 'path'.
  * @param {String} pluginName The name of the plugin where the factory was declared
  */
 org.ametys.forms.tool.FormsToolFactory = function(id, config, pluginName) 
@@ -34,7 +34,7 @@
 /**
  * Creates a tool of type {@see org.ametys.cms.tool.content.ContentTool} or activate the existing one.
  * There is one tool per content.
- * @param {Map} params The params used by the factory is 'id' that is the content id. Params are transmited the the content tool.
+ * @param {Object} params The params used by the factory is 'id' that is the content id. Parameters are transmitted to the content tool.
  * @return {Ext.org.ametys.uitool.tool.Tool} The tool to open.
  */
 org.ametys.forms.tool.FormsToolFactory.prototype.openTool = function (params)
Index: main/plugin-forms/resources/js/org/ametys/forms/OrphanForms.i18n.js
===================================================================
--- main/plugin-forms/resources/js/org/ametys/forms/OrphanForms.i18n.js	(revision 0)
+++ main/plugin-forms/resources/js/org/ametys/forms/OrphanForms.i18n.js	(revision 0)
@@ -0,0 +1,129 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.forms.administration.OrphanForms');
+
+org.ametys.forms.administration.OrphanForms.initialize = function (pluginName)
+{
+	org.ametys.forms.administration.OrphanForms.pluginName = pluginName;
+}
+
+org.ametys.forms.administration.OrphanForms.createPanel = function ()
+{
+	// The forms store
+	var store = new Ext.data.SimpleStore({
+		id:0,
+        fields: [
+           {name: 'name'},
+           {name: 'total'}
+        ]
+	});
+	
+	org.ametys.forms.administration.OrphanForms._listView = new org.ametys.ListView({
+        store: store,
+        
+		region: 'center',
+		baseCls: 'orphan-forms-list',
+        
+        viewConfig: {
+        	forceFit: true
+        },
+        
+        columns: [
+            {header: "<i18n:text i18n:key='PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_COL_NAME'/>", width: 200, dataIndex: 'name'},
+            {header: "<i18n:text i18n:key='PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_COL_TOTAL'/>", width: 100, dataIndex: 'total'}
+        ]
+    });
+	
+	org.ametys.forms.administration.OrphanForms._listView.addListener('rowclick', org.ametys.forms.administration.OrphanForms._selectTable, org.ametys.forms.administration.OrphanForms);
+	org.ametys.forms.administration.OrphanForms._listView.addListener('mouseup', org.ametys.forms.administration.OrphanForms._unselectTable, org.ametys.forms.administration.OrphanForms);
+	
+	// Actions panel
+	org.ametys.forms.administration.OrphanForms._actions = new org.ametys.ActionsPanel({title: "<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS"/>"});
+	org.ametys.forms.administration.OrphanForms._actions.addAction("<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE"/>", 
+																	getPluginResourcesUrl(org.ametys.forms.administration.OrphanForms.pluginName) + "/img/administrator/orphan-forms/remove.png", 
+																	org.ametys.forms.administration.OrphanForms.removeTable);
+	org.ametys.forms.administration.OrphanForms._actions.hide(0);
+	
+	// Help panel
+	var helpPanel = new org.ametys.TextPanel({title: "<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_HELP_TITLE"/>"});
+	helpPanel.addText("<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_HELP_TEXT"/>");
+	
+	
+	org.ametys.forms.administration.OrphanForms._rightPanel = new org.ametys.HtmlContainer({
+		region:'east',
+		cls: 'admin-right-panel',
+		width: 277,
+	    items: [org.ametys.forms.administration.OrphanForms._actions, helpPanel]
+	});
+}
+
+org.ametys.forms.administration.OrphanForms.addElement = function (id, name, total)
+{
+	org.ametys.forms.administration.OrphanForms._listView.addElement(id, {
+		'name': name,
+		'total': total
+	});	
+}
+
+org.ametys.forms.administration.OrphanForms.removeTable = function ()
+{
+	Ext.Msg.confirm("<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE"/>", 
+			"<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE_TEXT"/>", 
+			org.ametys.forms.administration.OrphanForms.doRemove, 
+			this
+	);
+}
+
+org.ametys.forms.administration.OrphanForms.doRemove = function (button)
+{
+	if (button == 'yes')
+	{
+		org.ametys.forms.administration.OrphanForms._mask = new org.ametys.msg.Mask();
+		
+		var record = org.ametys.forms.administration.OrphanForms._listView.getSelectionModel().getSelected();
+		
+		var serverMessage = new org.ametys.servercomm.ServerMessage('forms', 'administrator/delete-form', {'name': record.get('name')}, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, org.ametys.forms.administration.OrphanForms._doRemoveCb, this, [record]);
+		org.ametys.servercomm.ServerComm.getInstance().send(serverMessage);
+	}
+}
+org.ametys.forms.administration.OrphanForms._doRemoveCb = function (response, args)
+{
+	org.ametys.forms.administration.OrphanForms._mask.hide();
+	
+	if (org.ametys.servercomm.ServerComm.handleBadResponse("<i18n:text i18n:key="PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_ERROR"/>", response, "org.ametys.forms.administration.OrphanForms.remove"))
+	{
+		return;
+	}
+	
+	Ext.each(args[0], function(record){
+		org.ametys.forms.administration.OrphanForms._listView.getStore().remove(record);
+	});
+}
+
+org.ametys.forms.administration.OrphanForms._selectTable = function(grid, rowIndex, event)
+{
+	org.ametys.forms.administration.OrphanForms._actions.show();
+}
+
+org.ametys.forms.administration.OrphanForms._unselectTable = function(event)
+{
+	org.ametys.forms.administration.OrphanForms._actions.hide();
+}
+
+
+
+
Index: main/plugin-forms/sitemap.xmap
===================================================================
--- main/plugin-forms/sitemap.xmap	(revision 39963)
+++ main/plugin-forms/sitemap.xmap	(working copy)
@@ -26,6 +26,9 @@
             <map:generator name="results" src="org.ametys.plugins.forms.processing.FormResultsGenerator" logger="org.ametys.plugins.forms.processing.FormResultsGenerator"/>
             <map:generator name="receipt" src="org.ametys.plugins.forms.processing.FormResultsGenerator" logger="org.ametys.plugins.forms.processing.FormResultsGenerator"/>
 
+            <map:generator name="forms-list" src="org.ametys.plugins.forms.data.FormsListGenerator" logger="org.ametys.plugins.forms.data.FormsListGenerator"/>
+        
+            <map:generator name="administrator-orphan-forms" src="org.ametys.plugins.forms.OrphanFormsGenerator" logger="org.ametys.plugins.forms.OrphanFormsGenerator"/>
         </map:generators>
         
         <map:actions>
@@ -36,6 +39,9 @@
             <map:action name="delete-form-entries" src="org.ametys.plugins.forms.DeleteFormEntriesAction" logger="org.ametys.plugins.forms.DeleteFormEntriesAction"/>
             
             <map:action name="set-header" src="org.apache.cocoon.acting.HttpHeaderAction"/>
+            
+            <map:action name="administrator-is-system-user" src="org.ametys.runtime.plugins.core.right.actions.IsAdminAction" logger="org.ametys.runtime.plugins.web.administrator.sitemap.action.isAdmin"/>
+            <map:action name="delete-form" src="org.ametys.plugins.forms.DeleteFormTableAction" logger="org.ametys.plugins.forms.DeleteFormTableAction"/>
         </map:actions>
         
         <map:serializers>
@@ -219,7 +225,6 @@
                 </map:act>
             </map:match>
             
-            
             <map:match pattern="form/entries-statement.xml">
                 <map:generate type="form-entries-statement">
                     <map:parameter name="site" value="{request-param:siteName}"/>
@@ -228,6 +233,40 @@
                 <map:serialize type="xml"/>
             </map:match>
             
+            <map:match pattern="forms-list.xml">
+                <map:generate type="forms-list">
+                    <map:parameter name="siteName" value="{request-param:siteName}"/>
+                    <map:parameter name="language" value="{request-param:language}"/>
+                </map:generate>
+                <map:serialize type="xml"/>
+            </map:match>
+            
+            <!-- ********************* ADMIN ************************* -->
+            <map:match pattern="administrator/**">
+                <map:act type="administrator-is-system-user"/>
+            </map:match>
+            
+            <map:match pattern="administrator/orphan-forms/view.html">
+                <map:generate type="administrator-orphan-forms" label="content"/>
+                <map:transform type="xslt" src="pages/administrator/orphan-forms/view.xsl">
+                    <map:parameter name="contextPath" value="{request:contextPath}"/>
+                    <map:parameter name="pluginName" value="forms"/>
+                    <map:parameter name="workspaceName" value="{request-attr:workspaceName}"/>
+                    <map:parameter name="workspaceURI" value="{request-attr:workspaceURI}"/>
+                </map:transform>
+                <map:transform type="i18n">
+                    <map:parameter name="locale" value="{locale:locale}"/>
+                    <map:parameter name="plugin" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:serialize type="xml"/>
+            </map:match>
+            
+            <map:match pattern="administrator/delete-form">
+                <map:act type="delete-form">
+                    <map:generate type="action-result"/>
+                    <map:serialize type="xml"/>
+                </map:act>
+            </map:match>
         </map:pipeline>
 	</map:pipelines>
 </map:sitemap>
Index: main/plugin-forms/src/org/ametys/plugins/forms/DeleteFormEntriesAction.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/DeleteFormEntriesAction.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/DeleteFormEntriesAction.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2015 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
  */
 package org.ametys.plugins.forms;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -27,6 +26,7 @@
 import org.apache.cocoon.environment.ObjectModelHelper;
 import org.apache.cocoon.environment.Redirector;
 import org.apache.cocoon.environment.SourceResolver;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 
 import org.ametys.plugins.forms.jcr.FormPropertiesManager;
@@ -48,41 +48,43 @@
         _formTableManager = new FormTableManager();
     }
     
+    @SuppressWarnings("unchecked")
     @Override
     public Map<String, String> act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
     {
-        Map<String, String> result = new HashMap<String, String>();
         Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
 
         String mode = parameters.getParameter("mode");
         String siteName = (String) jsParameters.get("siteName");
-        String formId = (String) jsParameters.get("formId");
+        List<String> formIds = (List<String>) jsParameters.get("formIds");
         
-        if (StringUtils.isEmpty(siteName) || StringUtils.isEmpty(formId))
+        if (StringUtils.isEmpty(siteName) || CollectionUtils.isEmpty(formIds))
         {
             throw new ProcessingException("The site name and form ID must be provided.");
         }
-    
-        Form form = _formPropertiesManager.getForm(siteName, formId);
         
-        if (form == null)
+        for (String formId : formIds)
         {
-            throw new ProcessingException("The form of ID '" + formId + " can't be found in the site '" + siteName + "'.");
-        }
-        
-        if (mode.equals("delete"))
-        {
-            List<Integer> entriesIds = (List<Integer>) jsParameters.get("ids");
-            for (Integer entryId : entriesIds)
+            Form form = _formPropertiesManager.getForm(siteName, formId);
+            if (form == null)
             {
-                _formTableManager.deleteSubmission(form, entryId);
+                throw new ProcessingException("The form of ID '" + formId + " can't be found in the site '" + siteName + "'.");
             }
-        }
-        else if (mode.equals("clear"))
-        {
-            _formTableManager.deleteSubmission(form, null);
+            
+            if (mode.equals("delete"))
+            {
+                List<Integer> entriesIds = (List<Integer>) jsParameters.get("ids");
+                for (Integer entryId : entriesIds)
+                {
+                    _formTableManager.deleteSubmission(form, entryId);
+                }
+            }
+            else if (mode.equals("clear"))
+            {
+                _formTableManager.deleteSubmission(form, null);
+            }
         }
         
-        return result;
+        return EMPTY_MAP;
     }
 }
Index: main/plugin-forms/src/org/ametys/plugins/forms/DeleteFormTableAction.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/DeleteFormTableAction.java	(revision 0)
+++ main/plugin-forms/src/org/ametys/plugins/forms/DeleteFormTableAction.java	(revision 0)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.ametys.plugins.forms;
+
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.acting.AbstractAction;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.SourceResolver;
+
+import org.ametys.plugins.forms.table.FormTableManager;
+
+/**
+ * Delete a list of forms' tables
+ */
+public class DeleteFormTableAction extends AbstractAction implements Initializable
+{
+    /** The manager for form SQL Tables */
+    private FormTableManager _formTableManager;
+    
+    @Override
+    public void initialize() throws Exception
+    {
+        _formTableManager = new FormTableManager();
+    }
+    
+    @SuppressWarnings("unchecked")
+    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
+    {
+        Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
+        String tableName = (String) jsParameters.get("name");
+        
+        _formTableManager.dropTable(tableName);
+        
+        return EMPTY_MAP;
+    }
+}
Index: main/plugin-forms/src/org/ametys/plugins/forms/OrphanFormsGenerator.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/OrphanFormsGenerator.java	(revision 0)
+++ main/plugin-forms/src/org/ametys/plugins/forms/OrphanFormsGenerator.java	(revision 0)
@@ -0,0 +1,81 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.ametys.plugins.forms;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.generation.ServiceableGenerator;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.cocoon.xml.XMLUtils;
+import org.xml.sax.SAXException;
+
+import org.ametys.plugins.forms.jcr.FormPropertiesManager;
+import org.ametys.plugins.forms.table.FormTableManager;
+
+/**
+ * Generator listing all of the forms that are no longer referenced by any content
+ */
+public class OrphanFormsGenerator extends ServiceableGenerator
+{
+    /** Component gathering methods to query forms in JCR */
+    FormPropertiesManager _formPropertiesManager;
+    
+    /** Component gathering methods to manipulate SQL forms */
+    FormTableManager _formTableManager;
+    
+    @Override
+    public void service(ServiceManager serviceManager) throws ServiceException
+    {
+        _formPropertiesManager = (FormPropertiesManager) serviceManager.lookup(FormPropertiesManager.ROLE);
+        _formTableManager = new FormTableManager();
+    }
+    
+    public void generate() throws IOException, SAXException, ProcessingException
+    {
+        try
+        {
+            String formId = null;
+            Form form = null;
+            AttributesImpl attrs = new AttributesImpl();
+            
+            List<String> tableNames = _formTableManager.getTableNames();
+            contentHandler.startDocument();
+            for (String tableName : tableNames)
+            {
+                formId = tableName.substring(FormTableManager.TABLE_PREFIX.length()); 
+                form = _formPropertiesManager.getForm(formId);
+                if (form == null)
+                {
+                    attrs.addCDATAAttribute("name", tableName);
+                    attrs.addCDATAAttribute("total", Integer.toString(_formTableManager.getTotalSubmissions(formId)));
+                    
+                    XMLUtils.createElement(contentHandler, "table", attrs);
+                    
+                    attrs.clear();
+                }
+            }
+            contentHandler.endDocument();
+        }
+        catch (Exception e)
+        {
+            throw new ProcessingException("An error occurred while retrieving the orphan forms.", e);
+        }
+    }
+}
Index: main/plugin-forms/src/org/ametys/plugins/forms/data/ContentFormsGenerator.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/data/ContentFormsGenerator.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/data/ContentFormsGenerator.java	(working copy)
@@ -57,6 +57,7 @@
     }
     
     @Override
+    @SuppressWarnings("unchecked")
     public void generate() throws IOException, SAXException, ProcessingException
     {
         Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
Index: main/plugin-forms/src/org/ametys/plugins/forms/data/FormEntriesGenerator.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/data/FormEntriesGenerator.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/data/FormEntriesGenerator.java	(working copy)
@@ -93,7 +93,7 @@
             
             Map<String, FieldValue> columns = _formTableManager.getColumns(form);
             List<UserEntry> entries = _formTableManager.getSubmissions(form, columns, start, limit);
-            int totalSubmissions = _formTableManager.getTotalSubmissions(form);
+            int totalSubmissions = _formTableManager.getTotalSubmissions(form.getId());
             
             contentHandler.startDocument();
             
@@ -133,8 +133,8 @@
         }
         catch (FormsException e)
         {
-            getLogger().error("An error occurred while getting the results of a form.", e);
-            throw new ProcessingException("An error occurred while getting the results of a form.", e);
+            getLogger().error("An error occurred while getting the entries of a form.", e);
+            throw new ProcessingException("An error occurred while getting the entries of a form.", e);
         }
     }
     
Index: main/plugin-forms/src/org/ametys/plugins/forms/data/FormsContentClientSideElement.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/data/FormsContentClientSideElement.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/data/FormsContentClientSideElement.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,24 +19,22 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.commons.lang.StringUtils;
 
-import org.ametys.cms.clientsideelement.StaticMenu;
 import org.ametys.cms.repository.Content;
 import org.ametys.plugins.forms.Form;
 import org.ametys.plugins.forms.FormsException;
 import org.ametys.plugins.forms.jcr.FormPropertiesManager;
 import org.ametys.plugins.repository.AmetysObjectResolver;
+import org.ametys.runtime.ui.impl.StaticContextualClientSideElement;
 import org.ametys.runtime.util.I18nizableText;
 
 /**
  * This element creates a content button permitting to export the form data.
  */
-public class FormsContentClientSideElement extends StaticMenu
+public class FormsContentClientSideElement extends StaticContextualClientSideElement
 {
     
     /** The form properties manager. */
@@ -54,16 +52,11 @@
     }
     
     @Override
-    public void configure(Configuration configuration) throws ConfigurationException
-    {
-        super.configure(configuration);
-    }
-    
-    @Override
     public Map<String, I18nizableText> getCurrentParameters(Map<String, Object> parameters)
     {
         Map<String, I18nizableText> results = new HashMap<String, I18nizableText>();
         
+        @SuppressWarnings("unchecked")
         List<String> contentIds = (List<String>) parameters.get("targets");
         
         int formCount = 0;
Index: main/plugin-forms/src/org/ametys/plugins/forms/data/FormsListGenerator.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/data/FormsListGenerator.java	(revision 0)
+++ main/plugin-forms/src/org/ametys/plugins/forms/data/FormsListGenerator.java	(revision 0)
@@ -0,0 +1,124 @@
+package org.ametys.plugins.forms.data;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.generation.ServiceableGenerator;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.lang.StringUtils;
+import org.xml.sax.SAXException;
+
+import org.ametys.cms.transformation.xslt.URIDecoder;
+import org.ametys.plugins.forms.Form;
+import org.ametys.plugins.forms.jcr.FormPropertiesManager;
+import org.ametys.plugins.forms.table.FormTableManager;
+import org.ametys.runtime.util.parameter.ParameterHelper;
+
+/**
+ * This generator is used in order to retrieve information on the forms 
+ * of a given site in a given language
+ */
+public class FormsListGenerator extends ServiceableGenerator
+{
+    /** Component gathering methods to retrieve forms */
+    private FormPropertiesManager _formPropertiesManager;
+    
+    /** The form data manager */
+    private FormTableManager _formTableManager;
+    
+    @Override
+    public void service(ServiceManager serviceManager) throws ServiceException
+    {
+        _formPropertiesManager = (FormPropertiesManager) serviceManager.lookup(FormPropertiesManager.ROLE); 
+        _formTableManager = new FormTableManager();
+    }
+    
+    @Override
+    public void generate() throws IOException, SAXException, ProcessingException
+    {
+        String siteName = parameters.getParameter("siteName", "");
+        String language = parameters.getParameter("language", "");
+        
+        if (StringUtils.isEmpty(siteName) || StringUtils.isEmpty(language))
+        {
+            throw new ProcessingException("The site name and language must be provided.");
+        }
+        
+        contentHandler.startDocument();
+        XMLUtils.startElement(contentHandler, "forms");
+        
+        try
+        {
+            List<Node> contentNodes = _formPropertiesManager.getFormContentNodes(siteName, language);
+            
+            AttributesImpl attrs = new AttributesImpl();
+            for (Node contentNode : contentNodes)
+            {
+                String contentName = contentNode.getName();
+                
+                // Get the corresponding forms
+                List<Form> forms = _formPropertiesManager.getForms(contentNode);
+                for (Form form : forms)
+                {
+                    Map<String, FieldValue> columns = _formTableManager.getColumns(form);
+                    List<UserEntry> entries = _formTableManager.getSubmissions(form, columns, 0, Integer.MAX_VALUE);
+                    int totalSubmissions = _formTableManager.getTotalSubmissions(form.getId());
+                    Date lastSubmissionDate = _getLastSubmissionDate(entries);
+                    attrs.addCDATAAttribute("id", form.getId());
+                    attrs.addCDATAAttribute("encodedLabel", new URI(null, null,  URIDecoder.decode(form.getLabel()).replace('/', ' '), null).getRawPath());
+                    
+                    XMLUtils.startElement(contentHandler, "form", attrs);
+                    
+                    XMLUtils.createElement(contentHandler, "name", URIDecoder.decode(form.getLabel()));
+                    XMLUtils.createElement(contentHandler, "contentName", contentName);
+                    XMLUtils.createElement(contentHandler, "answersAmount", String.valueOf(totalSubmissions));
+                    XMLUtils.createElement(contentHandler, "lastAnswer", lastSubmissionDate != null ? ParameterHelper.valueToString(lastSubmissionDate) : "");
+                    
+                    XMLUtils.endElement(contentHandler, "form");
+                    
+                    attrs.clear();
+                }
+            }
+            
+            XMLUtils.endElement(contentHandler, "forms");
+            contentHandler.endDocument();
+        }
+        catch (Exception e)
+        {
+            throw new ProcessingException("An error occurred while processing the forms list.", e);
+        }
+    }
+    
+    /**
+     * Get the date of the most recent {@link UserEntry}
+     * @param entries the list of entries
+     * @return the date of the most recent entry
+     */
+    private Date _getLastSubmissionDate (List<UserEntry> entries)
+    {
+        Date lastSubmissionDate = null;
+        if (entries.size() > 0)
+        {
+            lastSubmissionDate = entries.get(0).getCreationDate();
+            for (UserEntry entry : entries)
+            {
+                Date creationDate = entry.getCreationDate();
+                if (lastSubmissionDate.before(creationDate))
+                {
+                    lastSubmissionDate = creationDate;
+                }
+            }
+        }
+        
+        return lastSubmissionDate;
+    }
+}
Index: main/plugin-forms/src/org/ametys/plugins/forms/jcr/FormPropertiesManager.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/jcr/FormPropertiesManager.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/jcr/FormPropertiesManager.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -73,6 +73,12 @@
     /** Forms node name. */
     public static final String FORMS_NODE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":forms";
     
+    /** Language property */
+    public static final String LANGUAGE_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":language";
+
+    /** Site property */
+    public static final String SITE_PROPERTY = RepositoryConstants.NAMESPACE_PREFIX+ ":site";
+    
     /** "ID" property name. */
     public static final String FORM_PROPERTY_ID = RepositoryConstants.NAMESPACE_PREFIX + ":id";
     
@@ -136,7 +142,18 @@
     
     /**
      * Get a form from the repository.
-     * @param siteName the site name.
+     * @param id the form ID.
+     * @return the Form or null if no form with this ID exists.
+     * @throws FormsException if an error occurs.
+     */
+    public Form getForm(String id) throws FormsException
+    {
+        return getForm(null, id);
+    }
+    
+    /**
+     * Get a form from the repository.
+     * @param siteName the site name
      * @param id the form ID.
      * @return the Form or null if no form with this ID exists.
      * @throws FormsException if an error occurs.
@@ -150,8 +167,15 @@
             
             Form form = null;
             
-            String xpathQuery = "//element(*, ametys:content)/" + FORMS_NODE + "/*[@" + FORM_PROPERTY_ID + " = '" + id + "']";
+            // Build the query
+            String xpathQuery = "//element(*, ametys:content)";
+            if (siteName != null)
+            {
+                xpathQuery += "[@" + SITE_PROPERTY + "='" + siteName + "']";
+            }
+            xpathQuery += "/" + FORMS_NODE + "/*[@" + FORM_PROPERTY_ID + " = '" + id + "']";
             
+            // Execute
             QueryManager queryManager = session.getWorkspace().getQueryManager();
             Query query = queryManager.createQuery(xpathQuery, Query.XPATH);
             NodeIterator nodeIterator = query.execute().getNodes();
@@ -159,7 +183,6 @@
             if (nodeIterator.hasNext())
             {
                 Node node = nodeIterator.nextNode();
-                
                 form = _extractForm(node);
             }
             
@@ -234,6 +257,89 @@
     }
     
     /**
+     * Get all the contents containing at least one form of the given site with the given language
+     * @param siteName the site name.
+     * @param language the language
+     * @return the forms' list or null if none was found
+     * @throws FormsException if an error occurs.
+     */
+    public List<Node> getFormContentNodes(String siteName, String language) throws FormsException
+    {
+        List<Node> contentNodes = new ArrayList<Node> ();
+        Session session = null;
+        try
+        {
+            session = _repository.login();
+            
+            String xpathQuery = "//element(*, ametys:content)[@" + SITE_PROPERTY + " = '" + siteName + "' and @" + LANGUAGE_PROPERTY + " = '" + language + "']";
+            
+            QueryManager queryManager = session.getWorkspace().getQueryManager();
+            Query query = queryManager.createQuery(xpathQuery, Query.XPATH);
+            NodeIterator nodeIterator = query.execute().getNodes();
+            
+            while (nodeIterator.hasNext())
+            {
+                Node node = nodeIterator.nextNode();
+                if (node.hasNode(FORMS_NODE))
+                {
+                    contentNodes.add(node);
+                }
+            }
+            
+            return contentNodes;
+        }
+        catch (RepositoryException e)
+        {
+            throw new FormsException("Error executing the query to find the forms of the site '" + siteName + "' and of language '" + language + "'.", e);
+        }
+        finally
+        {
+            if (session != null)
+            {
+                session.logout();
+            }
+        }
+    }    
+    
+    /**
+     * Extract all the form objects from a node
+     * @param node the node
+     * @return the forms list of this node
+     * @throws FormsException if an error occurs
+     * @throws RepositoryException if an error occurs when getting the properties of a node
+     */
+    public List<Form> getForms(Node node) throws FormsException, RepositoryException
+    {
+        List<Form> forms = new ArrayList<Form> ();
+        try
+        {
+            if (node.hasNode(FORMS_NODE))
+            {
+                Node formsNode = node.getNode(FORMS_NODE);
+                if (formsNode != null)
+                {
+                    NodeIterator formsNodeIterator = formsNode.getNodes();
+                    while (formsNodeIterator.hasNext())
+                    {
+                        Node formNode = formsNodeIterator.nextNode();
+                        Form form = _extractForm(formNode);
+                        if (form != null)
+                        {
+                            forms.add(form);
+                        }
+                    }
+                }
+            }
+            
+            return forms;
+        }
+        catch (RepositoryException e)
+        {
+            throw new FormsException("Error executing the query to find the forms of the node '" + node.getName() + "' (" + node.getIdentifier() + ").", e);
+        }
+    }
+    
+    /**
      * Store the properties of a form in the repository.
      * @param siteName the site name.
      * @param form the form object.
Index: main/plugin-forms/src/org/ametys/plugins/forms/processing/FormResultsGenerator.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/processing/FormResultsGenerator.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/processing/FormResultsGenerator.java	(working copy)
@@ -38,6 +38,7 @@
 public class FormResultsGenerator extends AbstractGenerator
 {
 
+    @SuppressWarnings("unchecked")
     @Override
     public void generate() throws IOException, SAXException, ProcessingException
     {
Index: main/plugin-forms/src/org/ametys/plugins/forms/processing/GetContentAction.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/processing/GetContentAction.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/processing/GetContentAction.java	(working copy)
@@ -15,7 +15,6 @@
  */
 package org.ametys.plugins.forms.processing;
 
-import java.net.URI;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
@@ -32,7 +31,6 @@
 import org.ametys.plugins.repository.UnknownAmetysObjectException;
 import org.ametys.plugins.repository.version.VersionableAmetysObject;
 import org.ametys.web.URIPrefixHandler;
-import org.ametys.web.renderingcontext.RenderingContext;
 import org.ametys.web.repository.content.WebContent;
 import org.ametys.web.repository.page.Page;
 import org.ametys.web.repository.site.Site;
@@ -92,7 +90,7 @@
             }
             else
             {
-                // We certainly come from a virtual page, try to get template from referer
+                // We certainly come from a virtual page, try to get template from referrer
                 Site site = _siteManager.getSite(siteName);
                 Sitemap sitemap = site.getSitemap(lang);
                 
@@ -106,7 +104,7 @@
                     {
                         Page page = sitemap.getChild(pathInSitemap.substring(0, pathInSitemap.indexOf(".html")));
                         
-                        // Get template from referer page
+                        // Get template from referrer page
                         template = page.getTemplate();
                     }
                     catch (UnknownAmetysObjectException e)
Index: main/plugin-forms/src/org/ametys/plugins/forms/table/FormTableManager.java
===================================================================
--- main/plugin-forms/src/org/ametys/plugins/forms/table/FormTableManager.java	(revision 39963)
+++ main/plugin-forms/src/org/ametys/plugins/forms/table/FormTableManager.java	(working copy)
@@ -1,17 +1,17 @@
 /*
- *  Copyright 2010 Anyware Services
+ * Copyright 2016 Anyware Services
  *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
  */
 package org.ametys.plugins.forms.table;
 
@@ -53,30 +53,30 @@
 
     /** Prefix for database tables */
     public static final String TABLE_PREFIX = "Forms_";
-    
+
     /** ID field name. */
     public static final String ID_FIELD = "id";
-    
+
     /** Creation date field name. */
     public static final String CREATION_DATE_FIELD = "creationDate";
-    
+
     /** Suffix for filename column. */
     public static final String FILE_NAME_COLUMN_SUFFIX = "-filename";
-    
+
     /** Constant for table state */
     public static final int TABLE_CREATED_AND_UP_TO_DATE = 2;
-    
+
     /** Constant for table state */
     public static final int TABLE_CREATED_BUT_NEED_UPDATE = 3;
-    
+
     /** Constant for table state */
     public static final int TABLE_NOT_CREATED = 1;
-    
+
     /** Constant for table state */
     public static final int TABLE_UNKOWN_STATUS = 0;
 
     private static Logger __logger = LoggerFactory.getLoggerFor(FormTableManager.class);
-    
+
     /**
      * Create database table to store results of content forms
      * @param form informations used to create table
@@ -88,7 +88,7 @@
         {
             throw new IllegalArgumentException("Form object can not be null");
         }
-        
+
         Map<String, FieldValue> columns = getColumns(form);
         if (!_createOrUpdateTable(form.getId(), columns))
         {
@@ -96,7 +96,7 @@
         }
         return true;
     }
-    
+
     /**
      * Drop the table by its name
      * 
@@ -110,13 +110,12 @@
 
         try
         {
-            // Effectuer la connexion à la base de donnees via un pool de
-            // connexion
+            // Use a connection pool to establish a connection to the data base
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
             String request = "DROP TABLE " + table;
 
             stmt = con.prepareStatement(request);
-            // Effectuer la requête et verifier le résultat
+            // Run the query and check the result
             stmt.executeUpdate();
         }
         catch (SQLException e)
@@ -126,18 +125,61 @@
         }
         finally
         {
-            // Fermer les ressources de connexion
+            // Clean up connection resources
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(con);
         }
 
         return true;
     }
-    
+
+    /**
+     * Get all the table names
+     * @return the list of all the forms' table names
+     */
+    public List<String> getTableNames()
+    {
+        List<String> formsTableNames = new ArrayList<String> ();
+        Connection con = null;
+        PreparedStatement stmt = null;
+        DatabaseMetaData metadata = null;
+        ResultSet tables = null;
+
+        try
+        {
+            // Use a connection pool to establish a connection to the data base
+            con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
+            metadata = con.getMetaData();
+            tables = metadata.getTables(null, null, "%", null);
+            
+            while (tables.next()) 
+            {
+                String tableName = tables.getString(3);
+                if (tableName.startsWith(TABLE_PREFIX))
+                {
+                    formsTableNames.add(tableName);
+                }
+            }
+        }
+        catch (SQLException e)
+        {
+            __logger.error("Error while retrieving the forms table names", e);
+        }
+        finally
+        {
+            // Clean up connection resources
+            ConnectionHelper.cleanup(stmt);
+            ConnectionHelper.cleanup(con);
+        }
+        
+        return formsTableNames;
+    }
+
     /**
      * Get all the submissions for a form.
+     * 
      * @param form the form object.
-     * @param columns 
+     * @param columns
      * @param offset The number of results to ignore.
      * @param length The maximum number of results to return.
      * @return the list of submissions.
@@ -146,24 +188,24 @@
     public List<UserEntry> getSubmissions(Form form, Map<String, FieldValue> columns, int offset, int length) throws FormsException
     {
         List<UserEntry> entries = new ArrayList<UserEntry>();
-        
+
         final String tableName = TABLE_PREFIX + form.getId();
-        
+
         Connection con = null;
         PreparedStatement stmt = null;
         ResultSet rs = null;
-        
+
         try
         {
             // Connect to the database.
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
             DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-            
+
             String request = "SELECT * FROM " + DbTypeHelper.escape(dbType, tableName);
-            
+
             // Limit the results
             DatabaseType datatype = ConnectionHelper.getDatabaseType(con);
-            
+
             if (datatype == DatabaseType.DATABASE_MYSQL || datatype == DatabaseType.DATABASE_POSTGRES || datatype == DatabaseType.DATABASE_HSQLDB)
             {
                 request = request + " LIMIT " + length + " OFFSET " + offset;
@@ -181,29 +223,29 @@
             {
                 __logger.warn("The request will not have the limit and offet set, since its type is unknown");
             }
-            
+
             stmt = con.prepareStatement(request);
-            
+
             // Execute the query.
             rs = stmt.executeQuery();
-            
+
             // Extract the results.
             while (rs.next())
             {
                 // First get the ID and submission date.
                 int id = rs.getInt(ID_FIELD);
                 Timestamp creationDate = rs.getTimestamp(CREATION_DATE_FIELD);
-                
+
                 List<FieldValue> entryValues = new ArrayList<FieldValue>();
-                
+
                 for (Map.Entry<String, FieldValue> column : columns.entrySet())
                 {
                     String columnLabel = column.getKey();
                     FieldValue columnValue = column.getValue();
-                    
+
                     // Extract the value.
                     FieldValue value = null;
-                    
+
                     switch (columnValue.getType())
                     {
                         case Types.VARCHAR:
@@ -224,7 +266,7 @@
                             String normalizedName = DbTypeHelper.normalizeName(dbType, fileNameColumn);
                             String fileName = rs.getString(normalizedName);
                             value = new FieldValue(columnValue);
-                            
+
                             if (DatabaseType.DATABASE_POSTGRES.equals(dbType))
                             {
                                 InputStream isValue = rs.getBinaryStream(columnLabel);
@@ -235,7 +277,7 @@
                                 Blob blobValue = rs.getBlob(columnLabel);
                                 value.setValue(blobValue == null ? null : fileName);
                             }
-                            
+
                             entryValues.add(value);
                             break;
                         case Types.INTEGER:
@@ -248,7 +290,7 @@
                             break;
                     }
                 }
-                
+
                 UserEntry entry = new UserEntry(id, creationDate, entryValues);
                 entries.add(entry);
             }
@@ -260,42 +302,42 @@
         }
         finally
         {
-            // Fermer les ressources de connexion
+            // Clean up connection resources
             ConnectionHelper.cleanup(rs);
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(con);
         }
-        
+
         return entries;
     }
-    
+
     /**
      * Get the total count of submissions for a form.
-     * @param form the form object.
+     * @param formId the id of the form
      * @return the total count of submissions, or -1 if an error occurs.
      * @throws FormsException if an error occurs.
      */
-    public int getTotalSubmissions(Form form) throws FormsException
+    public int getTotalSubmissions(String formId) throws FormsException
     {
-        final String tableName = TABLE_PREFIX + form.getId();
-        
+        final String tableName = TABLE_PREFIX + formId;
+
         Connection con = null;
         PreparedStatement stmt = null;
         ResultSet rs = null;
-        
+
         try
         {
             // Connect to the database.
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
             DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-            
+
             String request = "SELECT COUNT(*) FROM " + DbTypeHelper.escape(dbType, tableName);
-            
+
             stmt = con.prepareStatement(request);
-            
+
             // Execute the query.
             rs = stmt.executeQuery();
-            
+
             // Extract the result.
             if (rs.next())
             {
@@ -310,15 +352,15 @@
         }
         finally
         {
-            // Fermer les ressources de connexion
+            // Clean up connection resources
             ConnectionHelper.cleanup(rs);
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(con);
         }
-        
+
         return -1;
     }
-    
+
     /**
      * Form to tableinfo.
      * @param form the form.
@@ -327,14 +369,14 @@
     public Map<String, FieldValue> getColumns(Form form)
     {
         Map<String, FieldValue> columns = new LinkedHashMap<String, FieldValue>();
-        
+
         for (Field field : form.getFields())
         {
             final String id = field.getId();
             final String name = field.getName();
-            
+
             FieldValue fdValue = null;
-            
+
             switch (field.getType())
             {
                 case TEXT:
@@ -357,9 +399,9 @@
                         field.getProperties().put("size", String.valueOf(index));
                         field.getProperties().put("option-" + index + "-value", value);
                         field.getProperties().put("option-" + index + "-label", label);
-                        
+
                         field.getProperties().remove("value");
-                        
+
                         fdValue = new FieldValue(name, Types.VARCHAR, null, field);
                         columns.put(name, fdValue);
                     }
@@ -371,14 +413,14 @@
                             Field radioField = columns.get(name).getField();
                             int index = Integer.parseInt(radioField.getProperties().get("size"));
                             index++;
-                            
+
                             String value = field.getProperties().get("value");
                             String label = field.getLabel();
-                            
+
                             radioField.getProperties().put("size", String.valueOf(index));
                             radioField.getProperties().put("option-" + index + "-value", value);
                             radioField.getProperties().put("option-" + index + "-label", label);
-                            
+
                             Field dummyField = new Field(radioField.getId(), radioField.getType(), radioField.getName(), radioField.getLabel() + "/" + field.getLabel(), radioField.getProperties());
                             columns.get(name).setField(dummyField);
                         }
@@ -397,12 +439,12 @@
                 default:
                     break;
             }
-            
+
         }
-        
+
         return columns;
     }
-    
+
     /**
      * Get the full column type corresponding to the database type (with precision).
      * @param sqlType the sqltype value.
@@ -430,7 +472,7 @@
         }
         return colType;
     }
-    
+
     /**
      * Get the column type name (without precision) corresponding to the SQL type.
      * @param sqlType the SQL type value.
@@ -441,7 +483,7 @@
     {
         return StringUtils.substringBefore(_getColumnType(sqlType, dbType), "(");
     }
-    
+
     /**
      * Test if two columns have the same type.
      * @param column the column retrieved from the database.
@@ -455,66 +497,66 @@
         int currentColumnType = column.getSqlType();
         String newColumnTypeName = _getColumnTypeName(newColumnType, dbType);
         String currentColumnTypeName = column.getTypeName();
-        
+
         return currentColumnType == newColumnType || currentColumnTypeName.equals(newColumnTypeName);
     }
-    
+
     private boolean _createTable(String formId, Map<String, FieldValue> columns)
     {
         String tableName = TABLE_PREFIX + formId;
         Connection con = null;
         PreparedStatement stmt = null;
-        
+
         try
         {
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
             DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-            
+
             StringBuilder sql = new StringBuilder();
-            
+
             sql.append("CREATE TABLE ");
             sql.append(DbTypeHelper.escape(dbType, tableName));
             sql.append(" ( ").append(ID_FIELD).append(" ").append(DbTypeHelper.getIdentityType(dbType)).append(" ").append(DbTypeHelper.getIdentityMarker(dbType)).append(", ");
             sql.append(CREATION_DATE_FIELD).append(" ").append(DbTypeHelper.getDateTimeType(dbType)).append(" NOT NULL,");
-            
+
             for (Map.Entry<String, FieldValue> column : columns.entrySet())
             {
                 int sqlType = column.getValue().getType();
                 sql.append(DbTypeHelper.escape(dbType, column.getKey())).append(" ");
                 sql.append(_getColumnType(sqlType, dbType));
                 sql.append(" DEFAULT NULL,");
-                
+
                 // Add a column for the file name.
                 if (sqlType == Types.BLOB)
                 {
                     String fileNameColumn = column.getKey() + FILE_NAME_COLUMN_SUFFIX;
                     String normalizedName = DbTypeHelper.normalizeName(dbType, fileNameColumn);
-                    
+
                     sql.append(DbTypeHelper.escape(dbType, normalizedName)).append(" ");
                     sql.append(DbTypeHelper.getVarcharType(dbType));
                     sql.append(" DEFAULT NULL,");
                 }
             }
-            
+
             sql.append("PRIMARY KEY (").append(ID_FIELD).append("))");
-            
+
             if (__logger.isDebugEnabled())
             {
                 __logger.debug("Creating table : " + sql.toString());
             }
-            
+
             stmt = con.prepareStatement(sql.toString());
             stmt.executeUpdate();
             ConnectionHelper.cleanup(stmt);
-            
+
             // create sequence for oracle database
             if (DatabaseType.DATABASE_ORACLE.equals(dbType))
             {
-                String sqlQuery = "create sequence seq_" + formId; 
+                String sqlQuery = "create sequence seq_" + formId;
                 stmt = con.prepareStatement(sqlQuery);
                 stmt.executeUpdate();
             }
-            
+
             return true;
         }
         catch (SQLException e)
@@ -528,32 +570,32 @@
             ConnectionHelper.cleanup(con);
         }
     }
-    
+
     private boolean _alterTable(String formId, Map<String, FieldValue> newColumns)
     {
         String tableName = TABLE_PREFIX + formId;
-        
+
         Connection con = null;
-        
+
         try
         {
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
-            
+
             // Start transaction.
             con.setAutoCommit(false);
-            
+
             // Get the existing columns.
             Map<String, DbColumn> existingColumns = _getExistingColumns(con, tableName);
-            
+
             // Compute the modifications to make.
             DbColumnModifications modifications = _getColumnsToModify(con, existingColumns, newColumns);
-            
+
             // Move the columns that were deleted or replaced.
             _moveColumns(con, modifications.getColumnsToRemove(), existingColumns, tableName);
-            
+
             // Add the new columns.
             _addColumns(con, modifications.getColumnsToAdd(), tableName);
-            
+
             // Commit the transaction.
             con.commit();
         }
@@ -579,56 +621,56 @@
             ConnectionHelper.cleanup(con);
         }
         return true;
-        
+
     }
-    
+
     private int _checkTableStatus(String formId, Map<String, FieldValue> newColumns)
     {
         String tableName = TABLE_PREFIX + formId;
-        
+
         Connection con = null;
         ResultSet tables = null;
         ResultSet rs = null;
-        
+
         Map<String, DbColumn> currentColumns = new HashMap<String, DbColumn>();
-        
+
         try
         {
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
             DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-            
+
             tableName = DbTypeHelper.filterName(dbType, tableName);
-            
+
             DatabaseMetaData metadata = con.getMetaData();
             tables = metadata.getTables(con.getCatalog(), null, tableName, null);
-            
+
             if (!tables.next())
             {
                 return TABLE_NOT_CREATED;
             }
-            
+
             currentColumns = _getExistingColumns(con, tableName);
-            
+
             for (String newColumn : newColumns.keySet())
             {
                 String filteredColumn = DbTypeHelper.filterName(dbType, newColumn);
-                
+
                 // Test the existence of the column.
                 if (!currentColumns.containsKey(filteredColumn))
                 {
                     return TABLE_CREATED_BUT_NEED_UPDATE;
                 }
-                
+
                 // Test that the column type has not changed.
                 DbColumn currentColumn = currentColumns.get(filteredColumn);
                 FieldValue newColumnFv = newColumns.get(newColumn);
-                
+
                 if (!_isSameType(currentColumn, newColumnFv, dbType))
                 {
                     return TABLE_CREATED_BUT_NEED_UPDATE;
                 }
             }
-            
+
             return TABLE_CREATED_AND_UP_TO_DATE;
         }
         catch (SQLException e)
@@ -672,9 +714,9 @@
     private DbColumnModifications _getColumnsToModify(Connection con, Map<String, DbColumn> existingColumns, Map<String, FieldValue> newColumns)
     {
         DbColumnModifications modifications = new DbColumnModifications();
-        
+
         DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-        
+
         Map<String, FieldValue> columnsToAdd = new LinkedHashMap<String, FieldValue>();
         Map<String, DbColumn> columnsToRemove = new HashMap<String, DbColumn>();
         for (Map.Entry<String, FieldValue> newColumn : newColumns.entrySet())
@@ -682,14 +724,14 @@
             String filteredName = DbTypeHelper.filterName(dbType, newColumn.getKey());
             columnsToAdd.put(filteredName, newColumn.getValue());
         }
-        
+
         if (existingColumns != null)
         {
             for (String existingColName : existingColumns.keySet())
             {
                 DbColumn existingColumn = existingColumns.get(existingColName);
                 FieldValue newColumn = columnsToAdd.get(existingColName);
-                
+
                 // If the column does not already exist or if the type has changed,
                 // mark the current column to be removed and keep the new column in the "to be added" list.
                 if (newColumn != null && !_isSameType(existingColumn, newColumn, dbType))
@@ -703,13 +745,13 @@
                 }
             }
         }
-        
+
         modifications.setColumnsToAdd(columnsToAdd);
         modifications.setColumnsToRemove(columnsToRemove);
-        
+
         return modifications;
     }
-    
+
     private Map<String, DbColumn> _getExistingColumns(Connection con, String table)
     {
         ResultSet columns = null;
@@ -718,7 +760,7 @@
         {
             DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
             String filteredTableName = DbTypeHelper.filterName(dbType, table);
-            
+
             DatabaseMetaData metadata = con.getMetaData();
             columns = metadata.getColumns(con.getCatalog(), null, filteredTableName, null);
             while (columns.next())
@@ -727,9 +769,9 @@
                 Integer sqlType = columns.getInt("DATA_TYPE");
                 String typeName = columns.getString("TYPE_NAME");
                 Integer colSize = columns.getInt("COLUMN_SIZE");
-                
+
                 DbColumn col = new DbColumn(columnName, sqlType, typeName, colSize != null ? colSize : 0);
-                
+
                 toReturn.put(columnName, col);
             }
         }
@@ -744,49 +786,49 @@
         }
         return toReturn;
     }
-    
+
     private void _moveColumns(Connection con, Map<String, DbColumn> columnsToRemove, Map<String, DbColumn> existingColumns, String tableName) throws SQLException
     {
         DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
         PreparedStatement stmt = null;
-        
+
         Set<String> existingColumnNames = existingColumns.keySet();
-        
+
         try
         {
             for (String columnName : columnsToRemove.keySet())
             {
                 DbColumn columnToRemove = columnsToRemove.get(columnName);
-                
+
                 String newName = _getNewName(con, columnName, existingColumnNames);
-                
+
                 String sql = DbTypeHelper.getRenameColumnStatement(tableName, columnToRemove, newName, dbType);
-                
+
                 if (__logger.isDebugEnabled())
                 {
                     __logger.debug("Moving column: " + sql);
                 }
-                
+
                 stmt = con.prepareStatement(sql);
                 stmt.executeUpdate();
-                
+
                 // Add a column for the file name.
                 if (columnToRemove.getSqlType() == Types.BLOB)
                 {
                     // Release the previous statement.
                     ConnectionHelper.cleanup(stmt);
-                    
+
                     String fileNameColumn = columnName + FILE_NAME_COLUMN_SUFFIX;
                     String newFileNameColumn = _getNewName(con, fileNameColumn, existingColumnNames);
                     String varcharType = DbTypeHelper.getVarcharType(dbType);
-                    
+
                     sql = DbTypeHelper.getRenameColumnStatement(tableName, fileNameColumn, newFileNameColumn, varcharType, dbType);
-                    
+
                     if (__logger.isDebugEnabled())
                     {
                         __logger.debug("Altering table : " + sql.toString());
                     }
-                    
+
                     stmt = con.prepareStatement(sql.toString());
                     stmt.executeUpdate();
                 }
@@ -798,55 +840,55 @@
             throw e;
         }
     }
-    
+
     private void _addColumns(Connection con, Map<String, FieldValue> columnsToAdd, String tableName) throws SQLException
     {
         DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
         PreparedStatement stmt = null;
-        
+
         try
         {
             for (Entry<String, FieldValue> column : columnsToAdd.entrySet())
             {
                 StringBuilder sql = new StringBuilder();
-                
+
                 sql.append("ALTER TABLE ").append(DbTypeHelper.escape(dbType, tableName));
-                
+
                 int sqlType = column.getValue().getType();
-                
+
                 sql.append(" ADD ").append(DbTypeHelper.escape(dbType, column.getKey())).append(" ");
                 sql.append(_getColumnType(sqlType, dbType));
                 sql.append(" DEFAULT NULL");
-                
+
                 if (__logger.isDebugEnabled())
                 {
                     __logger.debug("Altering table : " + sql.toString());
                 }
-                
+
                 stmt = con.prepareStatement(sql.toString());
                 stmt.executeUpdate();
-                
+
                 // Add a column for the file name.
                 if (sqlType == Types.BLOB)
                 {
                     // Release the previous statement.
                     ConnectionHelper.cleanup(stmt);
-                    
+
                     sql.setLength(0);
                     sql.append("ALTER TABLE ").append(DbTypeHelper.escape(dbType, tableName));
-                    
+
                     String fileNameColumn = column.getKey() + FILE_NAME_COLUMN_SUFFIX;
                     String normalizedName = DbTypeHelper.normalizeName(dbType, fileNameColumn);
-                    
+
                     sql.append(" ADD ").append(DbTypeHelper.escape(dbType, normalizedName)).append(" ");
                     sql.append(DbTypeHelper.getVarcharType(dbType));
                     sql.append(" DEFAULT NULL");
-                    
+
                     if (__logger.isDebugEnabled())
                     {
                         __logger.debug("Adding column: " + sql.toString());
                     }
-                    
+
                     stmt = con.prepareStatement(sql.toString());
                     stmt.executeUpdate();
                 }
@@ -858,7 +900,7 @@
             throw e;
         }
     }
-    
+
     /**
      * Get the new name of a column to be moved.
      * @param con the connection.
@@ -869,21 +911,21 @@
     private String _getNewName(Connection con, String currentName, Set<String> existingColumnNames)
     {
         DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-        
+
         int i = 1;
         String newName = DbTypeHelper.normalizeName(dbType, currentName + "_old" + i);
         String filteredNewName = DbTypeHelper.filterName(dbType, newName);
-        
+
         while (existingColumnNames.contains(filteredNewName))
         {
             i++;
             newName = DbTypeHelper.normalizeName(dbType, currentName + "_old" + i);
             filteredNewName = DbTypeHelper.filterName(dbType, newName);
         }
-        
+
         return newName;
     }
-    
+
     /**
      * Get the SQL type corresponding to a field type.
      * @param fieldType the field
@@ -918,7 +960,6 @@
         }
         return sqlType;
     }
-    
 
     /**
      * Delete the submission from a form.
@@ -929,30 +970,30 @@
     public void deleteSubmission(Form form, Integer entryId) throws FormsException
     {
         final String tableName = TABLE_PREFIX + form.getId();
-        
+
         Connection con = null;
         PreparedStatement stmt = null;
-        
+
         try
         {
             // Connect to the database.
             con = ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
             DatabaseType dbType = ConnectionHelper.getDatabaseType(con);
-            
+
             String request = "DELETE FROM " + DbTypeHelper.escape(dbType, tableName);
-            
+
             if (entryId != null)
             {
                 request += " WHERE " + ID_FIELD + " = ?";
             }
-            
+
             stmt = con.prepareStatement(request);
-            
+
             if (entryId != null)
             {
                 stmt.setInt(1, entryId);
             }
-            
+
             // Execute the query.
             stmt.executeUpdate();
         }
@@ -963,25 +1004,24 @@
         }
         finally
         {
-            // Fermer les ressources de connexion
+            // Clean up connection resources
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(con);
         }
     }
-    
-    
+
     /**
      * Class storing modifications to do on columns.
      */
     class DbColumnModifications
     {
-        
+
         /** The columns to remove. */
         protected Map<String, DbColumn> _columnsToRemove;
-        
+
         /** The columns to remove. */
         protected Map<String, FieldValue> _columnsToAdd;
-        
+
         /**
          * Build a DbColumnModifications object.
          */
@@ -989,7 +1029,7 @@
         {
             this(new HashMap<String, DbColumn>(), new HashMap<String, FieldValue>());
         }
-        
+
         /**
          * Build a DbColumnModifications object.
          * @param columnsToRemove the columns to remove.
@@ -1000,7 +1040,7 @@
             this._columnsToRemove = columnsToRemove;
             this._columnsToAdd = columnsToAdd;
         }
-        
+
         /**
          * Get the columnsToRemove.
          * @return the columnsToRemove
@@ -1009,7 +1049,7 @@
         {
             return _columnsToRemove;
         }
-        
+
         /**
          * Set the columnsToRemove.
          * @param columnsToRemove the columnsToRemove to set
@@ -1018,7 +1058,7 @@
         {
             this._columnsToRemove = columnsToRemove;
         }
-        
+
         /**
          * Get the columnsToAdd.
          * @return the columnsToAdd
@@ -1027,7 +1067,7 @@
         {
             return _columnsToAdd;
         }
-        
+
         /**
          * Set the columnsToAdd.
          * @param columnsToAdd the columnsToAdd to set
@@ -1036,7 +1076,7 @@
         {
             this._columnsToAdd = columnsToAdd;
         }
-        
+
     }
 
     /**
@@ -1044,19 +1084,19 @@
      */
     class DbColumn
     {
-        
+
         /** The columns to remove. */
         protected String _name;
-        
+
         /** The columns to remove. */
         protected int _sqlType;
-        
+
         /** The columns to remove. */
         protected String _typeName;
-        
+
         /** The columns to remove. */
         protected int _columnSize;
-        
+
         /**
          * Build a DB column object.
          */
@@ -1064,7 +1104,7 @@
         {
             this("", 0, "", 0);
         }
-        
+
         /**
          * Build a DB column object.
          * @param name the column name.
@@ -1079,7 +1119,7 @@
             this._typeName = typeName;
             this._columnSize = columnSize;
         }
-        
+
         /**
          * Get the name.
          * @return the name
@@ -1088,7 +1128,7 @@
         {
             return _name;
         }
-        
+
         /**
          * Set the name.
          * @param name the name to set
@@ -1097,7 +1137,7 @@
         {
             this._name = name;
         }
-        
+
         /**
          * Get the sqlType.
          * @return the sqlType
@@ -1106,7 +1146,7 @@
         {
             return _sqlType;
         }
-        
+
         /**
          * Set the sqlType.
          * @param sqlType the sqlType to set
@@ -1115,7 +1155,7 @@
         {
             this._sqlType = sqlType;
         }
-        
+
         /**
          * Get the typeName.
          * @return the typeName
@@ -1124,7 +1164,7 @@
         {
             return _typeName;
         }
-        
+
         /**
          * Set the typeName.
          * @param typeName the typeName to set
@@ -1133,7 +1173,7 @@
         {
             this._typeName = typeName;
         }
-        
+
         /**
          * Get the columnSize.
          * @return the columnSize
@@ -1142,7 +1182,7 @@
         {
             return _columnSize;
         }
-        
+
         /**
          * Set the columnSize.
          * @param columnSize the columnSize to set
@@ -1151,7 +1191,7 @@
         {
             this._columnSize = columnSize;
         }
-        
+
         /**
          * Get a type identifier corresponding to the column (i.e. TEXT, VARCHAR(255), INT(1), and so on.)
          * @return a type identifier  corresponding to the column (i.e. TEXT, VARCHAR(255), INT(1), and so on.)
@@ -1159,16 +1199,16 @@
         public String getColumnTypeIdentifier()
         {
             StringBuilder buff = new StringBuilder();
-            
+
             buff.append(_typeName);
             if (_typeName.equals("VARCHAR") || _typeName.equals("INT") || _typeName.equals("NUMBER"))
             {
                 buff.append('(').append(_columnSize).append(')');
             }
-            
+
             return buff.toString();
         }
-        
+
     }
-    
+
 }
