• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / Zope / 3956162881

pending completion
3956162881

push

github

Michael Howitz
Update to deprecation warning free releases.

4401 of 7036 branches covered (62.55%)

Branch coverage included in aggregate %.

27161 of 31488 relevant lines covered (86.26%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.97
/src/OFS/OrderSupport.py
1
##############################################################################
2
#
3
# Copyright (c) 2003 Zope Foundation and Contributors.
4
#
5
# This software is subject to the provisions of the Zope Public License,
6
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
7
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10
# FOR A PARTICULAR PURPOSE.
11
#
12
##############################################################################
13
""" Order support for 'Object Manager'.
1✔
14
"""
15

16
from AccessControl.class_init import InitializeClass
1✔
17
from AccessControl.Permissions import access_contents_information
1✔
18
from AccessControl.Permissions import manage_properties
1✔
19
from AccessControl.SecurityInfo import ClassSecurityInfo
1✔
20
from Acquisition import aq_base
1✔
21
from OFS.interfaces import IOrderedContainer as IOrderedContainer
1✔
22
from zope.container.contained import notifyContainerModified
1✔
23
from zope.interface import implementer
1✔
24
from zope.sequencesort.ssort import sort
1✔
25

26

27
@implementer(IOrderedContainer)
1✔
28
class OrderSupport:
1✔
29

30
    """ Ordered container mixin class.
31

32
    This is an extension to the regular ObjectManager. It saves the objects in
33
    order and lets you change the order of the contained objects. This is
34
    particular helpful, if the order does not depend on object attributes, but
35
    is totally user-specific.
36
    """
37
    security = ClassSecurityInfo()
1✔
38

39
    has_order_support = 1
1✔
40
    _default_sort_key = 'position'
1✔
41
    _default_sort_reverse = 0
1✔
42

43
    manage_options = (
1✔
44
        {
45
            'label': 'Contents',
46
            'action': 'manage_main',
47
        },
48
    )
49

50
    @security.protected(manage_properties)
1✔
51
    def manage_move_objects_up(self, REQUEST, ids=None, delta=1):
1✔
52
        """ Move specified sub-objects up by delta in container.
53
        """
54
        if ids:
×
55
            try:
×
56
                attempt = self.moveObjectsUp(ids, delta)
×
57
                message = '%d item%s moved up.' % (
×
58
                    attempt, ((attempt != 1) and 's' or ''))
59
            except ValueError as errmsg:
×
60
                message = 'Error: %s' % (errmsg)
×
61
        else:
62
            message = 'Error: No items were specified!'
×
63
        return self.manage_main(
×
64
            self,
65
            REQUEST,
66
            manage_tabs_message=message
67
        )
68

69
    @security.protected(manage_properties)
1✔
70
    def manage_move_objects_down(self, REQUEST, ids=None, delta=1):
1✔
71
        """ Move specified sub-objects down by delta in container.
72
        """
73
        if ids:
×
74
            try:
×
75
                attempt = self.moveObjectsDown(ids, delta)
×
76
                message = '%d item%s moved down.' % (
×
77
                    attempt, ((attempt != 1) and 's' or ''))
78
            except ValueError as errmsg:
×
79
                message = 'Error: %s' % (errmsg)
×
80
        else:
81
            message = 'Error: No items were specified!'
×
82
        return self.manage_main(
×
83
            self,
84
            REQUEST,
85
            manage_tabs_message=message
86
        )
87

88
    @security.protected(manage_properties)
1✔
89
    def manage_move_objects_to_top(self, REQUEST, ids=None):
1✔
90
        """ Move specified sub-objects to top of container.
91
        """
92
        if ids:
×
93
            try:
×
94
                attempt = self.moveObjectsToTop(ids)
×
95
                message = '%d item%s moved to top.' % (
×
96
                    attempt, ((attempt != 1) and 's' or ''))
97
            except ValueError as errmsg:
×
98
                message = 'Error: %s' % (errmsg)
×
99
        else:
100
            message = 'Error: No items were specified!'
×
101
        return self.manage_main(self, REQUEST,
×
102
                                manage_tabs_message=message)
103

104
    @security.protected(manage_properties)
1✔
105
    def manage_move_objects_to_bottom(self, REQUEST, ids=None):
1✔
106
        """ Move specified sub-objects to bottom of container.
107
        """
108
        if ids:
×
109
            try:
×
110
                attempt = self.moveObjectsToBottom(ids)
×
111
                message = '%d item%s moved to bottom.' % (
×
112
                    attempt, ((attempt != 1) and 's' or ''))
113
            except ValueError as errmsg:
×
114
                message = 'Error: %s' % (errmsg)
×
115
        else:
116
            message = 'Error: No items were specified!'
×
117
        return self.manage_main(self, REQUEST,
×
118
                                manage_tabs_message=message)
119

120
    @security.protected(manage_properties)
1✔
121
    def manage_set_default_sorting(self, REQUEST, key, reverse):
1✔
122
        """ Set default sorting key and direction."""
123
        self.setDefaultSorting(key, reverse)
×
124
        return self.manage_main(self, REQUEST)
×
125

126
    @security.protected(manage_properties)
1✔
127
    def moveObjectsByDelta(
1✔
128
        self,
129
        ids,
130
        delta,
131
        subset_ids=None,
132
        suppress_events=False
133
    ):
134
        """Move specified sub-objects by delta."""
135
        if isinstance(ids, str):
1✔
136
            ids = (ids,)
1✔
137
        min_position = 0
1✔
138
        objects = list(self._objects)
1✔
139
        if subset_ids is None:
1✔
140
            subset_ids = self.getIdsSubset(objects)
1✔
141
        else:
142
            subset_ids = list(subset_ids)
1✔
143
        # unify moving direction
144
        if delta > 0:
1✔
145
            ids = list(ids)
1✔
146
            ids.reverse()
1✔
147
            subset_ids.reverse()
1✔
148
        counter = 0
1✔
149

150
        for id in ids:
1✔
151
            old_position = subset_ids.index(id)
1✔
152
            new_position = max(old_position - abs(delta), min_position)
1✔
153
            if new_position == min_position:
1✔
154
                min_position += 1
1✔
155
            if not old_position == new_position:
1✔
156
                subset_ids.remove(id)
1✔
157
                subset_ids.insert(new_position, id)
1✔
158
                counter += 1
1✔
159

160
        if counter > 0:
1✔
161
            if delta > 0:
1✔
162
                subset_ids.reverse()
1✔
163
            obj_dict = {}
1✔
164
            for obj in objects:
1✔
165
                obj_dict[obj['id']] = obj
1✔
166
            pos = 0
1✔
167
            for i in range(len(objects)):
1✔
168
                if objects[i]['id'] in subset_ids:
1!
169
                    try:
1✔
170
                        objects[i] = obj_dict[subset_ids[pos]]
1✔
171
                        pos += 1
1✔
172
                    except KeyError:
×
173
                        raise ValueError('The object with the id "%s" does '
×
174
                                         'not exist.' % subset_ids[pos])
175
            self._objects = tuple(objects)
1✔
176

177
        if not suppress_events:
1✔
178
            notifyContainerModified(self)
1✔
179

180
        return counter
1✔
181

182
    @security.protected(manage_properties)
1✔
183
    def moveObjectsUp(self, ids, delta=1, subset_ids=None):
1✔
184
        # Move specified sub-objects up by delta in container.
185
        return self.moveObjectsByDelta(ids, -delta, subset_ids)
1✔
186

187
    @security.protected(manage_properties)
1✔
188
    def moveObjectsDown(self, ids, delta=1, subset_ids=None):
1✔
189
        # Move specified sub-objects down by delta in container.
190
        return self.moveObjectsByDelta(ids, delta, subset_ids)
1✔
191

192
    @security.protected(manage_properties)
1✔
193
    def moveObjectsToTop(self, ids, subset_ids=None):
1✔
194
        # Move specified sub-objects to top of container.
195
        return self.moveObjectsByDelta(ids, -len(self._objects), subset_ids)
1✔
196

197
    @security.protected(manage_properties)
1✔
198
    def moveObjectsToBottom(self, ids, subset_ids=None):
1✔
199
        # Move specified sub-objects to bottom of container.
200
        return self.moveObjectsByDelta(ids, len(self._objects), subset_ids)
1✔
201

202
    @security.protected(manage_properties)
1✔
203
    def orderObjects(self, key, reverse=None):
1✔
204
        # Order sub-objects by key and direction.
205
        ids = [id for id, obj in sort(
1✔
206
            self.objectItems(), ((key, 'cmp', 'asc'), ))]
207
        if reverse:
1✔
208
            ids.reverse()
1✔
209
        return self.moveObjectsByDelta(ids, -len(self._objects))
1✔
210

211
    @security.protected(access_contents_information)
1✔
212
    def getObjectPosition(self, id):
1✔
213
        # Get the position of an object by its id.
214
        ids = self.objectIds()
1✔
215
        if id in ids:
1✔
216
            return ids.index(id)
1✔
217
        raise ValueError('The object with the id "%s" does not exist.' % id)
1✔
218

219
    @security.protected(manage_properties)
1✔
220
    def moveObjectToPosition(self, id, position, suppress_events=False):
1✔
221
        # Move specified object to absolute position.
222
        delta = position - self.getObjectPosition(id)
1✔
223
        return self.moveObjectsByDelta(
1✔
224
            id,
225
            delta,
226
            suppress_events=suppress_events,
227
        )
228

229
    @security.protected(access_contents_information)
1✔
230
    def getDefaultSorting(self):
1✔
231
        # Get default sorting key and direction.
232
        return self._default_sort_key, self._default_sort_reverse
×
233

234
    @security.protected(manage_properties)
1✔
235
    def setDefaultSorting(self, key, reverse):
1✔
236
        # Set default sorting key and direction.
237
        self._default_sort_key = key
1✔
238
        self._default_sort_reverse = reverse and 1 or 0
1✔
239

240
    def manage_renameObject(self, id, new_id, REQUEST=None):
1✔
241
        """ Rename a particular sub-object without changing its position.
242
        """
243
        old_position = self.getObjectPosition(id)
1✔
244
        result = super().manage_renameObject(id, new_id, REQUEST)
1✔
245
        self.moveObjectToPosition(
1✔
246
            new_id,
247
            old_position,
248
            suppress_events=True
249
        )
250
        return result
1✔
251

252
    def tpValues(self):
1✔
253
        # Return a list of subobjects, used by tree tag.
254
        r = []
1✔
255
        if hasattr(aq_base(self), 'tree_ids'):
1!
256
            tree_ids = self.tree_ids
×
257
            try:
×
258
                tree_ids = list(tree_ids)
×
259
            except TypeError:
×
260
                pass
×
261
            if hasattr(tree_ids, 'sort'):
×
262
                tree_ids.sort()
×
263
            for id in tree_ids:
×
264
                if hasattr(self, id):
×
265
                    r.append(self._getOb(id))
×
266
        else:
267
            # this part is different from the ObjectManager code
268
            r = [obj for obj in self.objectValues()
1✔
269
                 if getattr(obj, 'isPrincipiaFolderish', False)]
270
            r = sort(r, ((self._default_sort_key, 'cmp', 'asc'), ))
1✔
271
            if self._default_sort_reverse:
1✔
272
                r.reverse()
1✔
273
        return r
1✔
274

275
    def getIdsSubset(self, objects):
1✔
276
        return [obj['id'] for obj in objects]
1✔
277

278

279
InitializeClass(OrderSupport)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc