[Zope3-checkins] CVS: Zope3/src/zope/app/browser/container - contents.pt:1.1 contents.py:1.21 main.pt:NONE rename.pt:NONE

Jim Fulton jim@zope.com
Thu, 12 Jun 2003 05:31:19 -0400


Update of /cvs-repository/Zope3/src/zope/app/browser/container
In directory cvs.zope.org:/tmp/cvs-serv26395/src/zope/app/browser/container

Modified Files:
	contents.py 
Added Files:
	contents.pt 
Removed Files:
	main.pt rename.pt 
Log Message:
Significantly refactored the contents view:

- Ported the basic template from the rotterdam skin.
  In-place add now works for all uses of this view.

- Added in-place rename.  When the rename button is selected, the
  contents are redisplated with the ids for the selected items
  displayed as text inputs.

  In addition, in the normal contents display, if you click just after
  a name, the contents will be redisplayed with than name editable.

- Added in-place title editing. Clicking on a title (or the locatioon
  where a title would be displayed), causes the contents to be
  redisplayed with a text field for editing the title.

- When performing an in-place operation, submit and cancel buttons are
  displayed rather than the normal buttons.

- The view is now a self-posting form with a single url.


=== Added File Zope3/src/zope/app/browser/container/contents.pt ===
<html metal:use-macro="views/standard_macros/page"  i18n:domain="zope">
<head>
<style metal:fill-slot="headers" type="text/css">
</style>
</head>
<body>
<div metal:fill-slot="body">
<div metal:define-macro="contents">

  <p tal:condition="view/error" tal:content="view/error">Error message</p>

  <form name="containerContentsForm" method="POST" action="."
        tal:attributes="action request/URL">

      <input type="hidden" name="type_name" value=""
             tal:attributes="value request/type_name"
             tal:condition="request/type_name|nothing"
             />
      <input type="hidden" name="retitle_id" value=""
             tal:attributes="value request/retitle_id"
             tal:condition="request/retitle_id|nothing"
             />

      <table id="sortable" class="listing" summary="Content listing"
             metal:define-macro="contents_table"
             tal:define="container_contents view/listContentInfo"
             >
    
        <thead> 
          <tr>
            <th>&nbsp;</th>
            <th>Name</th>
            <th>Title</th>
            <th>Size</th>
            <th>Created</th>
            <th>Modified</th>
          </tr>
        </thead>

        <tbody>

        <tr tal:condition="request/type_name|nothing">
          <td></td>
          <td><input name="new_value" id="focusid" value=""></td>
          <td></td>
          <td></td>
          <td></td>
        </tr>

        <metal:block tal:repeat="item container_contents">
          <tr tal:define="oddrow repeat/item/odd; url item/url"
              tal:attributes="class python:oddrow and 'even' or 'odd'" > 
            <td>
              <input type="checkbox" class="noborder" name="ids:list" id="#"
                     value="#"
                     tal:attributes="value item/id;
                                     id item/cb_id;
                                     checked request/ids_checked|nothing;"/>
            </td>
            <td><a href="#" 
                 tal:attributes="href 
                                 string:${url}/@@SelectedManagementView.html"
                 tal:content="structure item/icon|default">
                </a
                ><span tal:condition="item/rename"
                   ><input name="new_value:list" 
                     tal:attributes="value item/id"
                     /><input type="hidden" name="rename_ids:list" value=""
                              tal:attributes="value item/rename"
                     /></span
                ><span tal:condition="not:item/rename">
                  <a href="#" 
                     tal:attributes="href 
                                 string:${url}/@@SelectedManagementView.html"
                     tal:content="item/id"
                     >foo</a
                  ><a href="#" 
                     tal:attributes="href 
                         string:${request/URL}?rename_ids:list=${item/id}"
                     >&nbsp;&nbsp;</a
                ></span
               ></td>
            <td>
              <input name="new_value" id="focusid"
                     tal:attributes="value item/title|nothing"
                     tal:condition="item/retitle"
                     />
              <a href="#" 
                 tal:attributes="href 
                                 string:${request/URL}?retitle_id=${item/id}"
                 tal:condition="item/retitleable"
                 tal:content="item/title|default"
                 >&nbsp;&nbsp;&nbsp;&nbsp;</a> 
              <span 
                 tal:condition="item/plaintitle"
                 tal:content="item/title|default"
                 >&nbsp;&nbsp;&nbsp;&nbsp;</span> 
            </td>
            <td><span tal:attributes="size item/size/sizeForSorting"
                      tal:content="item/size/sizeForDisplay">&nbsp;</span></td>
            <td><span tal:define="created item/created|default"
                      tal:content="created">&nbsp;</span></td>
            <td><span tal:define="modified item/modified|default"
                      tal:content="modified">&nbsp;</span></td>
          </tr>
        </metal:block>

        </tbody> 
      </table>

      <div tal:condition="view/normalButtons">
        <input type="submit" name="container_rename_button" value="Rename"
               i18n:attributes="value container_rename_button" 
               tal:condition="view/supportsRename"
               />
        <input type="submit" name="container_cut_button" value="Cut"
               i18n:attributes="value container_cut_button" 
               tal:condition="view/supportsCut"
               />
        <input type="submit" name="container_copy_button" value="Copy"
               i18n:attributes="value container_copy_button" 
               tal:condition="view/supportsCopy"
               />
        <input type="submit" name="container_paste_button" value="Paste"
               tal:condition="view/hasClipboardContents" 
               i18n:attributes="value container_paste_button" 
               />
        <input type="submit" name="container_delete_button" value="Delete"
               i18n:attributes="value container_delete_button"
               i18n:domain="zope"
               />
      </div>

      <div tal:condition="view/specialButtons">
        <input type="submit" value="Applu"
               i18n:attributes="value container_apply_button" 
               />
        <input type="submit" name="container_cancel_button" value="Cancel"
               i18n:attributes="value container_cancel_button" 
               />
      </div>

  </form>

      <script ><!--
          prettydump('focus', LG_INFO);
          document.containerContentsForm.new_value.focus();
          //-->
      </script>


</div>
</div>
</body>
</html>


=== Zope3/src/zope/app/browser/container/contents.py 1.20 => 1.21 ===
--- Zope3/src/zope/app/browser/container/contents.py:1.20	Thu Jun  5 16:56:17 2003
+++ Zope3/src/zope/app/browser/container/contents.py	Thu Jun 12 05:30:48 2003
@@ -15,38 +15,134 @@
 
 Revision information: $Id$
 """
+
+from zope.app import zapi
 from zope.app.interfaces.container import IContainer, IZopeContainer
 from zope.app.interfaces.dublincore import IZopeDublinCore
 from zope.app.interfaces.size import ISized
 from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
-
-from zope.component import queryView, queryAdapter, getAdapter, getService
 from zope.publisher.browser import BrowserView
-from zope.app.traversing import traverse, getPath, joinPath
 from zope.app.interfaces.copypastemove import IPrincipalClipboard
 from zope.app.interfaces.copypastemove import IObjectCopier
 from zope.app.interfaces.copypastemove import IObjectMover
+from zope.app.interfaces.container import IPasteTarget
+from zope.app.interfaces.container import ICopySource, IMoveSource
+from zope.app.interfaces.dublincore import IDCDescriptiveProperties
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+from zope.app.browser.container.adding import BasicAdding
+
 
 class Contents(BrowserView):
 
     __used_for__ = IContainer
 
+    error = ''
+    message = ''
+    normalButtons = False
+    specialButtons = False
+
+    def listContentInfo(self):
+        request = self.request
+
+        if  "container_cancel_button" in request:
+            if "type_name" in request:
+                del request.form['type_name']
+            if "rename_ids" in request and "new_value" in request:
+                del request.form['rename_ids']
+            if "retitle_id" in request and "new_value" in request:
+                del request.form['retitle_id']
+
+            return self._normalListContentsInfo()
+
+        elif "type_name" in request and "new_value" in request:
+            self.addObject()
+        elif "rename_ids" in request and "new_value" in request:
+            self.renameObjects()
+        elif "retitle_id" in request and "new_value" in request:
+            self.changeTitle()
+        elif "container_cut_button" in request:
+            self.cutObjects()
+        elif "container_copy_button" in request:
+            self.copyObjects()
+        elif "container_paste_button" in request:
+            self.pasteObjects()
+        elif "container_delete_button" in request:
+            self.removeObjects()
+        else:
+            return self._normalListContentsInfo()
+
+        if self.error:
+            return self._normalListContentsInfo()
+
+        status = request.response.getStatus()
+        if status not in (302, 303):
+            # Only redirect if nothing else has
+            request.response.redirect(request.URL)
+        return ()
+
+    def _normalListContentsInfo(self):
+        request = self.request
+
+        self.specialButtons = (
+                 'type_name' in request or
+                 'rename_ids' in request or
+                 'container_rename_button' in request or
+                 'retitle_id' in request
+                 )
+        self.normalButtons = not self.specialButtons
+
+        info = map(self._extractContentInfo,
+                   zapi.getAdapter(self.context, IZopeContainer).items())
+
+        self.supportsCut = (
+            info and zapi.queryAdapter(self.context, IMoveSource) is not None)
+        self.supportsCopy = (
+            info and zapi.queryAdapter(self.context, ICopySource) is not None)
+        self.supportsPaste = (
+            zapi.queryAdapter(self.context, IPasteTarget) is not None)
+
+        self.supportsRename = self.supportsCut and self.supportsPaste
+
+        return info
+        
+
     def _extractContentInfo(self, item):
+        request = self.request
+
+
+        rename_ids = {}
+        if "container_rename_button" in request:
+            for rename_id in request.get('ids', ()):
+                rename_ids[rename_id] = rename_id
+        elif "rename_ids" in request:
+            for rename_id in request.get('rename_ids', ()):
+                rename_ids[rename_id] = rename_id
+                
+        
+        retitle_id = request.get('retitle_id')
+        
         id, obj = item
         info = {}
-        info['id'] = id
+        info['id'] = info['cb_id'] = id
         info['object'] = obj
 
         info['url'] = id
+        info['rename'] = rename_ids.get(id)
+        info['retitle'] = id == retitle_id
+        
 
-        zmi_icon = queryView(obj, 'zmi_icon', self.request)
+        zmi_icon = zapi.queryView(obj, 'zmi_icon', self.request)
         if zmi_icon is None:
             info['icon'] = None
         else:
             info['icon'] = zmi_icon()
 
-        dc = queryAdapter(obj, IZopeDublinCore)
+        dc = zapi.queryAdapter(obj, IZopeDublinCore)
         if dc is not None:
+            info['retitleable'] = id != retitle_id
+            info['plaintitle'] = 0
+            
             title = dc.title
             if title:
                 info['title'] = title
@@ -59,107 +155,149 @@
             modified = dc.modified
             if modified is not None:
                 info['modified'] = formatter.format(modified)
+        else:
+            info['retitleable'] = 0
+            info['plaintitle'] = 1
+
 
-        sized_adapter = queryAdapter(obj, ISized)
+        sized_adapter = zapi.queryAdapter(obj, ISized)
         if sized_adapter is not None:
             info['size'] = sized_adapter
         return info
 
-    def renameObjects(self, ids, newids):
+    def renameObjects(self):
         """Given a sequence of tuples of old, new ids we rename"""
-        container = getAdapter(self.context, IZopeContainer)
-        for id, newid in zip(ids, newids):
+        request = self.request
+        ids = request.get("rename_ids")
+        newids = request.get("new_value")
+
+        for id, newid in map(None, ids, newids):
             if newid != id:
+                container = zapi.getAdapter(self.context, IZopeContainer)
                 container.rename(id, newid)
-        self.request.response.redirect('@@contents.html')
 
-    def removeObjects(self, ids):
+    def changeTitle(self):
+        """Given a sequence of tuples of old, new ids we rename"""
+        request = self.request
+        id = request.get("retitle_id")
+        new = request.get("new_value")
+
+        item = self.context[id]
+        dc = zapi.getAdapter(item, IDCDescriptiveProperties)
+        dc.title = new
+
+    def addObject(self):
+        request = self.request
+        new = request["new_value"]
+        if new:
+            adding = zapi.queryView(self.context, "+", request)
+            if adding is None:
+                adding = BasicAdding(self.context, request)
+            else:
+                # Set up context so that the adding can build a url
+                # if the type name names a view.
+                # Note that we can't so this for the "adding is None" case
+                # above, because there is no "+" view.
+                adding = zapi.ContextWrapper(adding, self.context, name="+")
+
+            adding.action(request['type_name'], new)
+
+            
+
+            
+    def removeObjects(self):
         """Remove objects specified in a list of object ids"""
-        container = getAdapter(self.context, IZopeContainer)
+        request = self.request
+        ids = request.get('ids')
+        if not ids:
+            self.error = _("You didn't specify any ids to rename.")
+            return
+                 
+        container = zapi.getAdapter(self.context, IZopeContainer)
         for id in ids:
             container.__delitem__(id)
 
-        self.request.response.redirect('@@contents.html')
-
-    def copyObjects(self, ids):
+    def copyObjects(self):
         """Copy objects specified in a list of object ids"""
-        container_path = getPath(self.context)
+        request = self.request
+        ids = request.get('ids')
+        if not ids:
+            self.error = _("You didn't specify any ids to copy.")
+            return
+                 
+        container_path = zapi.getPath(self.context)
 
         user = self.request.user
-        annotationsvc = getService(self.context, 'PrincipalAnnotation')
+        annotationsvc = zapi.getService(self.context, 'PrincipalAnnotation')
         annotations = annotationsvc.getAnnotations(user)
-        clipboard = getAdapter(annotations, IPrincipalClipboard)
+        clipboard = zapi.getAdapter(annotations, IPrincipalClipboard)
         clipboard.clearContents()
         items = []
         for id in ids:
-            items.append(joinPath(container_path, id))
+            items.append(zapi.joinPath(container_path, id))
         clipboard.addItems('copy', items)
 
-        self.request.response.redirect('@@contents.html')
-
-    def cutObjects(self, ids):
+    def cutObjects(self):
         """move objects specified in a list of object ids"""
-        container_path = getPath(self.context)
+        request = self.request
+        ids = request.get('ids')
+        if not ids:
+            self.error = _("You didn't specify any ids to cut.")
+            return
+
+        container_path = zapi.getPath(self.context)
 
         user = self.request.user
-        annotationsvc = getService(self.context, 'PrincipalAnnotation')
+        annotationsvc = zapi.getService(self.context, 'PrincipalAnnotation')
         annotations = annotationsvc.getAnnotations(user)
-        clipboard = getAdapter(annotations, IPrincipalClipboard)
+        clipboard = zapi.getAdapter(annotations, IPrincipalClipboard)
         clipboard.clearContents()
         items = []
         for id in ids:
-            items.append(joinPath(container_path, id))
+            items.append(zapi.joinPath(container_path, id))
         clipboard.addItems('cut', items)
 
-        self.request.response.redirect('@@contents.html')
-
     def pasteObjects(self):
         """Iterate over clipboard contents and perform the
            move/copy operations"""
         target = self.context
 
         user = self.request.user
-        annotationsvc = getService(self.context, 'PrincipalAnnotation')
+        annotationsvc = zapi.getService(self.context, 'PrincipalAnnotation')
         annotations = annotationsvc.getAnnotations(user)
-        clipboard = getAdapter(annotations, IPrincipalClipboard)
+        clipboard = zapi.getAdapter(annotations, IPrincipalClipboard)
         items = clipboard.getContents()
         for item in items:
-            obj = traverse(target, item['target'])
+            obj = zapi.traverse(target, item['target'])
             if item['action'] == 'cut':
-                getAdapter(obj, IObjectMover).moveTo(target)
-                # XXX need to remove the item from the clipboard here
-                # as it will not be available anymore from the old location
+                zapi.getAdapter(obj, IObjectMover).moveTo(target)
+                clipboard.clearContents()
             elif item['action'] == 'copy':
-                getAdapter(obj, IObjectCopier).copyTo(target)
+                zapi.getAdapter(obj, IObjectCopier).copyTo(target)
             else:
                 raise
 
-        self.request.response.redirect('@@contents.html')
-
     def hasClipboardContents(self):
         """ interogates the PrinicipalAnnotation to see if
            clipboard contents exist """
 
+        if not self.supportsPaste:
+            return False
+
         user = self.request.user
 
-        annotationsvc = getService(self.context, 'PrincipalAnnotation')
+        annotationsvc = zapi.getService(self.context, 'PrincipalAnnotation')
         annotations = annotationsvc.getAnnotations(user)
         
-        clipboard = getAdapter(annotations, IPrincipalClipboard)
+        clipboard = zapi.getAdapter(annotations, IPrincipalClipboard)
 
         if clipboard.getContents():
             return True
 
         return False
 
-    def listContentInfo(self):
-        return map(self._extractContentInfo,
-                   getAdapter(self.context, IZopeContainer).items())
-
-    contents = ViewPageTemplateFile('main.pt')
+    contents = ViewPageTemplateFile('contents.pt')
     contentsMacros = contents
-
-    rename = ViewPageTemplateFile('rename.pt')
 
     _index = ViewPageTemplateFile('index.pt')
 

=== Removed File Zope3/src/zope/app/browser/container/main.pt ===

=== Removed File Zope3/src/zope/app/browser/container/rename.pt ===