[Zope-CVS] CVS: Products/CompositePage - utils.py:1.1 tool.py:1.8 transformers.py:1.8

Shane Hathaway shane at zope.com
Sat Dec 27 23:33:18 EST 2003


Update of /cvs-repository/Products/CompositePage
In directory cvs.zope.org:/tmp/cvs-serv16763

Modified Files:
	tool.py transformers.py 
Added Files:
	utils.py 
Log Message:
Implemented the clipboard using Zope's __cp cookie.

XXX need unit tests.


=== Added File Products/CompositePage/utils.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Utilities for handling ZODB objects.

(Copied from the Ape product.)

$Id: utils.py,v 1.1 2003/12/28 04:32:47 shane Exp $
"""

from cStringIO import StringIO
from cPickle import Pickler, Unpickler
from types import StringType


def copyOf(source):
    """Copies a ZODB object, loading subobjects as needed.

    Re-ghostifies objects along the way to save memory.
    """
    former_ghosts = []
    zclass_refs = {}

    def persistent_id(ob, former_ghosts=former_ghosts,
                      zclass_refs=zclass_refs):
        if getattr(ob, '_p_changed', 0) is None:
            # Load temporarily.
            former_ghosts.append(ob)
            ob._p_changed = 0
        if hasattr(ob, '__bases__'):
            m = getattr(ob, '__module__', None)
            if (m is not None
                and isinstance(m, StringType)
                and m.startswith('*')):
                n = getattr(ob, '__name__', None)
                if n is not None:
                    # Pickling a ZClass instance.  Store the reference to
                    # the ZClass class separately, so that the pickler
                    # and unpickler don't trip over the apparently
                    # missing module.
                    ref = (m, n)
                    zclass_refs[ref] = ob
                    return ref
        return None

    def persistent_load(ref, zclass_refs=zclass_refs):
        return zclass_refs[ref]

    stream = StringIO()
    p = Pickler(stream, 1)
    p.persistent_id = persistent_id
    p.dump(source)
    if former_ghosts:
        for g in former_ghosts:
            del g._p_changed
        del former_ghosts[:]
    stream.seek(0)
    u = Unpickler(stream)
    u.persistent_load = persistent_load
    return u.load()



=== Products/CompositePage/tool.py 1.7 => 1.8 ===
--- Products/CompositePage/tool.py:1.7	Sat Dec 27 17:56:43 2003
+++ Products/CompositePage/tool.py	Sat Dec 27 23:32:47 2003
@@ -20,12 +20,14 @@
 from Acquisition import aq_base, aq_parent, aq_inner
 from OFS.SimpleItem import SimpleItem
 from OFS.Folder import Folder
+from OFS.CopySupport import _cb_encode, _cb_decode, cookie_path
 from AccessControl import ClassSecurityInfo
 from AccessControl.ZopeGuards import guarded_getattr
 
 from interfaces import ISlot, ISlotDefinition, IRenderableInline
 from interfaces import CompositeError
 from render import adapt
+from utils import copyOf
 
 
 _transformers = {}
@@ -92,8 +94,8 @@
         self._reserved_names = ('slot_defs',)
 
     security.declarePublic("moveElements")
-    def moveElements(self, source_paths, target_path, target_index):
-        """Moves elements to a slot.
+    def moveElements(self, source_paths, target_path, target_index, copy=0):
+        """Moves or copies elements to a slot.
         """
         target_index = int(target_index)
         # Coerce the paths to sequences of path elements.
@@ -138,14 +140,17 @@
 
         changed_slots = {}  # id(aq_base(slot)) -> slot
         try:
-            # Replace items with nulls to avoid changing indexes while moving.
-            for source in sources:
-                slot = root.restrictedTraverse(source[:-1])
-                slot_id = id(aq_base(slot))
-                if not changed_slots.has_key(slot_id):
-                    changed_slots[slot_id] = slot
-                nullify = guarded_getattr(slot, "nullify")  # Check security
-                nullify(source[-1])
+            if not copy:
+                # Replace items with nulls to avoid changing indexes
+                # while moving.
+                for source in sources:
+                    slot = root.restrictedTraverse(source[:-1])
+                    slot_id = id(aq_base(slot))
+                    if not changed_slots.has_key(slot_id):
+                        changed_slots[slot_id] = slot
+                    # Check security
+                    nullify = guarded_getattr(slot, "nullify")
+                    nullify(source[-1])
 
             # Add the elements and reorder.
             for element in elements:
@@ -160,9 +165,12 @@
 
                 element = aq_base(element)
                 new_id = target._get_id(element.getId())
+                if copy:
+                    element = copyOf(element)
                 element._setId(new_id)
                 target._setObject(new_id, element)
-                reorder = guarded_getattr(target, "reorder")  # Check security
+                # Check security
+                reorder = guarded_getattr(target, "reorder")
                 reorder(new_id, target_index)
                 target_index += 1
         finally:
@@ -201,7 +209,7 @@
     def moveAndDelete(self, move_source_paths="", move_target_path="",
                       move_target_index="", delete_source_paths="",
                       REQUEST=None):
-        """Move and delete elements.
+        """Move and/or delete elements.
         """
         if move_source_paths:
             p = move_source_paths.split(':')
@@ -214,6 +222,34 @@
             REQUEST["RESPONSE"].redirect(REQUEST["HTTP_REFERER"])
 
 
+    security.declarePublic("useClipboard")
+    def useClipboard(self, func, REQUEST,
+                     source_paths=None, target_path=None, target_index=None):
+        """Clipboard interaction.
+        """
+        resp = REQUEST['RESPONSE']
+        if func in ("cut", "copy"):
+            assert source_paths
+            items = []  # list of path tuples
+            cut = (func == 'cut')
+            for p in str(source_paths).split(':'):
+                items.append(p.split('/'))
+            data = _cb_encode((cut, items))
+            resp.setCookie('__cp', data, path=cookie_path(REQUEST))
+        elif func == 'paste':
+            assert target_path
+            assert target_index
+            assert REQUEST is not None
+            data = REQUEST['__cp']
+            cut, items = _cb_decode(data)
+            self.moveElements(
+                items, target_path, int(target_index), not cut)
+            resp.expireCookie('__cp', path=cookie_path(REQUEST))
+        else:
+            raise ValueError("Clipboard function %s unknown" % func)
+        resp.redirect(REQUEST["HTTP_REFERER"])
+
+
     security.declarePublic("getRendererFor")
     def getRendererFor(self, ob):
         return adapt(ob, IRenderableInline)
@@ -228,5 +264,4 @@
     dispatcher._setObject(ob.getId(), ob)
     if REQUEST is not None:
         return dispatcher.manage_main(dispatcher, REQUEST)
-
 


=== Products/CompositePage/transformers.py 1.7 => 1.8 ===
--- Products/CompositePage/transformers.py:1.7	Sat Dec 27 17:56:43 2003
+++ Products/CompositePage/transformers.py	Sat Dec 27 23:32:47 2003
@@ -37,8 +37,7 @@
 start_of_body_search = re.compile("(<body[^>]*>)", re.IGNORECASE).search
 end_of_body_search = re.compile("(</body[^>]*>)", re.IGNORECASE).search
 
-default_html_page = """
-<html>
+default_html_page = """<html>
 <head>
 <title>Composite Page</title>
 </head>
@@ -48,8 +47,7 @@
 </html>
 """
 
-close_dialog_html = '''
-<html>
+close_dialog_html = '''<html>
 <script type="text/javascript">
 if (window.opener)
   window.opener.location.reload();
@@ -58,7 +56,6 @@
 </html>
 '''
 
-
 class CommonTransformer (SimpleItem):
     """Basic page transformer.
 
@@ -155,7 +152,7 @@
         from composite import Composite
 
         obj = self.getPhysicalRoot()
-        parts = path.split('/')
+        parts = str(path).split('/')
         for name in parts:
             obj = obj.restrictedTraverse(name)
             try:
@@ -178,7 +175,7 @@
         obs = []
         all_choices = None  # {view -> 1}
         current = None
-        for path in paths.split(':'):
+        for path in str(paths).split(':'):
             ob = root.restrictedTraverse(path)
             obs.append(ob)
             renderer = tool.getRendererFor(ob)




More information about the Zope-CVS mailing list