Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser.py	(revision 12206)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser.py	(revision 12206)
@@ -0,0 +1,192 @@
+## $Id$
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""UI components for documents offered for download by the company.
+"""
+
+import sys
+import grok
+import pytz
+from urllib import urlencode
+from datetime import datetime
+from zope.event import notify
+from zope.i18n import translate
+from zope.catalog.interfaces import ICatalog
+from zope.component import queryUtility, getUtility, createObject
+from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing
+from zope.formlib.textwidgets import BytesDisplayWidget
+from zope.security import checkPermission
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.interfaces import (
+    IContactForm, IObjectHistory, IIkobaObject, IIkobaUtils)
+from waeup.ikoba.browser.layout import (
+    IkobaPage, IkobaEditFormPage, IkobaAddFormPage, IkobaDisplayFormPage,
+    IkobaForm, NullValidator, jsaction, action, UtilityView)
+from waeup.ikoba.widgets.datewidget import (
+    FriendlyDateWidget, FriendlyDateDisplayWidget,
+    FriendlyDatetimeDisplayWidget)
+from waeup.ikoba.browser.breadcrumbs import Breadcrumb
+from waeup.ikoba.browser.pages import (
+    delSubobjects, add_local_role, del_local_roles, msave,
+    LocalRoleAssignmentUtilityView)
+
+from waeup.ikoba.documents.interfaces import (
+    IDocumentsContainer, IDocument)
+
+grok.context(IIkobaObject) # Make IKofaObject the default context
+grok.templatedir('browser_templates')
+
+
+class DocumentsBreadcrumb(Breadcrumb):
+    """A breadcrumb for the customers container.
+    """
+    grok.context(IDocumentsContainer)
+    title = _('Documents')
+
+
+class DocumentBreadcrumb(Breadcrumb):
+    """A breadcrumb for the customer container.
+    """
+    grok.context(IDocument)
+
+    def title(self):
+        return self.context.title
+
+
+class DocumentsContainerPage(IkobaDisplayFormPage):
+    """The standard view for document containers.
+    """
+    grok.context(IDocumentsContainer)
+    grok.name('index')
+    grok.require('waeup.viewDocuments')
+    grok.template('containerpage')
+    pnav = 2
+    label = _('Documents')
+
+
+class DocumentsContainerManageFormPage(IkobaEditFormPage,
+                                      LocalRoleAssignmentUtilityView):
+    """The manage page for customer containers.
+    """
+    grok.context(IDocumentsContainer)
+    grok.name('manage')
+    grok.require('waeup.manageDocuments')
+    grok.template('containermanagepage')
+    pnav = 2
+    label = _('Manage document section')
+
+    taboneactions = [_('Save'),_('Cancel')]
+    tabtwoactions = [_('Add document'), _('Remove selected'),_('Cancel')]
+
+    @jsaction(_('Remove selected'))
+    def delDocuments(self, **data):
+        delSubobjects(self, redirect='manage', tab='2')
+        return
+
+    @action(_('Save'), style='primary')
+    def save(self, **data):
+        return msave(self, **data)
+
+    @action(_('Cancel'), validator=NullValidator)
+    def cancel(self, **data):
+        self.redirect(self.url(self.context))
+        return
+
+    @action(_('Add document'), validator=NullValidator)
+    def addSubunit(self, **data):
+        self.redirect(self.url(self.context, 'adddocument'))
+        return
+
+
+class DocumentAddFormPage(IkobaAddFormPage):
+    """Add-form to add a customer.
+    """
+    grok.context(IDocumentsContainer)
+    grok.require('waeup.manageDocuments')
+    grok.name('adddocument')
+    form_fields = grok.AutoFields(IDocument).omit('document_id')
+    label = _('Add document')
+    pnav = 2
+
+    @action(_('Create document'), style='primary')
+    def addDocument(self, **data):
+        document = createObject(u'waeup.Document')
+        self.applyData(document, **data)
+        try:
+            self.context.addDocument(document)
+        except KeyError:
+            self.flash(_('The Id chosen already exists.'),
+                       type='danger')
+            return
+        self.flash(
+            _("Document ${a} added.", mapping = {'a':document.document_id}))
+        ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
+        self.context.__parent__.logger.info(
+            '%s - added: %s' % (ob_class, document.document_id))
+        self.redirect(self.url(self.context, u'manage')+'#tab2')
+        return
+
+
+class DocumentDisplayFormPage(IkobaDisplayFormPage):
+    """ Page to display document data
+    """
+    grok.context(IDocument)
+    grok.name('index')
+    grok.require('waeup.viewDocuments')
+    #grok.template('basepage')
+    form_fields = grok.AutoFields(IDocument)
+    pnav = 2
+
+    @property
+    def label(self):
+        return self.context.title
+
+
+class DocumentManageFormPage(IkobaEditFormPage,
+                            LocalRoleAssignmentUtilityView):
+    """ View to manage document data
+    """
+    grok.context(IDocument)
+    grok.name('manage')
+    grok.require('waeup.manageDocuments')
+    form_fields = grok.AutoFields(IDocument).omit('document_id')
+    grok.template('documentmanagepage')
+    pnav = 2
+
+    taboneactions = [_('Save'),_('Cancel')]
+    tabtwoactions1 = [_('Remove selected local roles')]
+    tabtwoactions2 = [_('Add local role')]
+
+    def label(self):
+        return _('Manage document ') + self.context.document_id
+
+    @action(_('Save'), style='primary')
+    def save(self, **data):
+        return msave(self, **data)
+
+    @action(_('Cancel'), validator=NullValidator)
+    def cancel(self, **data):
+        self.redirect(self.url(self.context))
+        return
+
+    @action(_('Add local role'), validator=NullValidator)
+    def addLocalRole(self, **data):
+        return add_local_role(self,2,**data)
+
+    @action(_('Remove selected local roles'))
+    def delLocalRoles(self, **data):
+        return del_local_roles(self,2,**data)
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/containermanagepage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/containermanagepage.pt	(revision 12206)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/containermanagepage.pt	(revision 12206)
@@ -0,0 +1,61 @@
+<form action="." tal:attributes="action request/URL"
+  i18n:domain="waeup.ikoba" method="POST" enctype="multipart/form-data">
+  <ul class="tabs nav nav-tabs" data-tabs="tabs">
+    <li class="active">
+    <a href="#tab1" data-toggle="tab">
+      <span i18n:translate="">Settings
+      </span></a>
+    </li>
+    <li>
+    <a href="#tab2" data-toggle="tab">
+      <span i18n:translate="">Documents
+      </span> </a>
+    </li>
+  </ul>
+  <div class="tab-content">
+    <div id="tab1" class="active tab-pane">
+      <table class="form-table">
+        <tbody>
+          <tal:widgets content="structure provider:widgets" />
+        </tbody>
+      </table>
+      <div tal:condition="view/availableActions">
+        <span tal:repeat="action view/actions" tal:omit-tag="">
+          <input tal:condition="python:action.label in view.taboneactions"
+                 tal:replace="structure action/render"/>
+        </span>
+      </div>
+    </div>
+    <div id="tab2" class="tab-pane">
+      <h3 i18n:translate="">Documents</h3>
+      <table class="ikoba-data-table dataTableManage">
+        <thead>
+          <tr>
+            <th>&nbsp;
+            </th>
+            <th i18n:translate="">Document Id
+            </th>
+            <th i18n:translate="">Title
+            </th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr tal:repeat="doc context/values"> <td>
+              <input type="checkbox" name="val_id"
+                     tal:attributes="value doc/document_id" /> </td> <td>
+              <a tal:attributes="href python: view.url(doc)"
+                 tal:content="doc/__name__"> ID</a> </td> <td>
+              <span tal:content="doc/title">TITLE
+              </span> </td>
+          </tr>
+        </tbody>
+      </table>
+      <div tal:condition="view/availableActions">
+        <span tal:repeat="action view/actions" tal:omit-tag="">
+          <input tal:condition="python:action.label in view.tabtwoactions"
+                 tal:replace="structure action/render"/>
+        </span>
+      </div>
+    </div>
+  </div>
+</form>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/containerpage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/containerpage.pt	(revision 12206)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/containerpage.pt	(revision 12206)
@@ -0,0 +1,19 @@
+<div i18n:domain="waeup.ikoba" i18n:translate="" tal:condition="python: not len(context.keys())">
+There are no subobjects registered yet.
+</div>
+
+<table class="ikoba-data-table dataTable" i18n:domain="waeup.ikoba">
+  <thead>
+    <tr>
+      <th i18n:translate="">Document Id</th>
+      <th i18n:translate="">Title</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr tal:repeat="value context/values">
+      <td> <a tal:attributes="href python: view.url(value)">
+          <span tal:content="value/document_id">ID</span></a></td>
+      <td tal:content="value/title">TITLE</td>
+    </tr>
+  </tbody>
+</table>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/documentmanagepage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/documentmanagepage.pt	(revision 12206)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/browser_templates/documentmanagepage.pt	(revision 12206)
@@ -0,0 +1,90 @@
+<form action="." tal:attributes="action request/URL" method="POST"
+      enctype="multipart/form-data" i18n:domain="waeup.ikoba">
+
+  <ul class="tabs nav nav-tabs" data-tabs="tabs">
+    <li class="active">
+      <a href="#tab1" data-toggle="tab" i18n:translate="">Settings</a>
+    </li>
+    <li>
+      <a href="#tab2" data-toggle="tab" i18n:translate="">Local Roles</a>
+    </li>
+  </ul>
+
+  <div class="tab-content">
+    <div id="tab1" class="tab-pane active">
+      <table class="form-table">
+        <tbody>
+          <tal:widgets content="structure provider:widgets" />
+        </tbody>
+      </table>
+      <div tal:condition="view/availableActions">
+        <span tal:repeat="action view/actions"
+              tal:omit-tag="">
+          <input tal:condition="python:action.label in view.taboneactions"
+                 tal:replace="structure action/render"/>
+        </span>
+      </div>
+    </div>
+    <div id="tab2" class="tab-pane">
+      <br />
+      <table class="ikoba-data-table dataTableManage">
+        <thead>
+          <tr>
+            <th>&nbsp;
+            </th>
+            <th i18n:translate="">User Id
+            </th>
+            <th i18n:translate="">Name
+            </th>
+            <th i18n:translate="">Local Role
+            </th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr tal:repeat="entry view/getUsersWithLocalRoles"> <td>
+            <input type="checkbox" name="role_id"
+                   tal:attributes="value python: entry['user_name']+'|'+entry['local_role']" /> </td>
+            <td tal:content="entry/user_name"> USERNAME </td>
+            <td tal:content="entry/user_title"> USERTITLE </td>
+            <td tal:content="entry/local_role_title"> LOCAL ROLE </td>
+          </tr>
+        </tbody>
+      </table>
+      <div tal:condition="view/availableActions">
+        <span tal:repeat="action view/actions" tal:omit-tag="">
+          <input tal:condition="python:action.label in view.tabtwoactions1"
+                 tal:replace="structure action/render"/>
+        </span>
+      </div><br /><br />
+      <div class="form-inline">
+        <br />
+        <div class="form-group">
+          <select id="user" name="user" class="form-control">
+            <option tal:repeat="user view/getUsers"
+                    tal:attributes="value user/name">
+            <span tal:replace="user/val/title">USERTITLE
+            </span>
+            </option>
+          </select>
+        </div>
+        <div class="form-group">
+          <select id="local_role" name="local_role" class="form-control">
+            <option tal:repeat="localrole view/getLocalRoles"
+                    tal:attributes="value localrole/name">
+            <span tal:replace="localrole/title">LOCALROLETITLE
+            </span>
+            </option>
+          </select>
+        </div>
+        <div class="form-group">
+          <div tal:condition="view/availableActions">
+                <span tal:repeat="action view/actions" tal:omit-tag="">
+                  <input tal:condition="python:action.label in view.tabtwoactions2"
+                         tal:replace="structure action/render"/>
+                </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</form>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/permissions.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/permissions.py	(revision 12206)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/permissions.py	(revision 12206)
@@ -0,0 +1,51 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+
+# Permissions
+
+class ViewDocuments(grok.Permission):
+    grok.name('waeup.viewDocuments')
+
+
+class ManageDocuments(grok.Permission):
+    grok.name('waeup.manageDocuments')
+
+
+# Local Roles
+
+class DocumentManager(grok.Role):
+    grok.name('waeup.local.DocumentManager')
+    grok.title(u'Document Manager')
+    grok.permissions('waeup.manageDocuments',
+                     'waeup.viewDocuments',
+                     'waeup.exportData')
+
+
+# Site Roles
+class DocumentsOfficer(grok.Role):
+    grok.name('waeup.DocumentsOfficer')
+    grok.title(u'Documents Officer (view only)')
+    grok.permissions('waeup.viewDocuments')
+
+
+class DocumentsManager(grok.Role):
+    grok.name('waeup.DocumentsManager')
+    grok.title(u'Documents Manager')
+    grok.permissions('waeup.viewDocuments',
+                     'waeup.manageDocuments')
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/viewlets.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/viewlets.py	(revision 12206)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/viewlets.py	(revision 12206)
@@ -0,0 +1,80 @@
+## $Id$
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Viewlet components for documents offered for download by the company.
+"""
+
+import grok
+from waeup.ikoba.browser.viewlets import (
+    PrimaryNavTab, ManageActionButton, AddActionButton)
+from waeup.ikoba.interfaces import IIkobaObject
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.browser.viewlets import PrimaryNavTab
+
+from waeup.ikoba.documents.interfaces import (
+    IDocumentsContainer, IDocument)
+from waeup.ikoba.documents.browser import (
+    DocumentsContainerManageFormPage, DocumentsContainerPage,
+    DocumentManageFormPage, DocumentDisplayFormPage)
+
+
+grok.context(IIkobaObject)  # Make IIkobaObject the default context
+grok.templatedir('browser_templates')
+
+
+class DocumentsTab(PrimaryNavTab):
+    """Documents tab in primary navigation.
+    """
+
+    grok.context(IIkobaObject)
+    grok.order(1)
+    grok.require('waeup.viewDocuments')
+    grok.name('documentstab')
+
+    pnav = 2
+    tab_title = _(u'Documents')
+
+    @property
+    def link_target(self):
+        return self.view.application_url('documents')
+
+class DocumentsContainerManageActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IDocumentsContainer)
+    grok.view(DocumentsContainerPage)
+    grok.require('waeup.manageDocuments')
+    text = _('Manage')
+    target = 'manage'
+
+
+class DocumentViewActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IDocument)
+    grok.view(DocumentManageFormPage)
+    grok.require('waeup.manageDocuments')
+    text = _('View')
+    target = 'index'
+    icon = 'actionicon_view.png'
+
+
+class DocumentManageActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IDocument)
+    grok.view(DocumentDisplayFormPage)
+    grok.require('waeup.manageDocuments')
+    text = _('Manage')
+    target = 'manage'
