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

zopefoundation / Zope / 6263629025

21 Sep 2023 03:12PM UTC coverage: 82.146% (-0.01%) from 82.159%
6263629025

Pull #1164

github

web-flow
[pre-commit.ci lite] apply automatic fixes
Pull Request #1164: Move all linters to pre-commit.

4353 of 6963 branches covered (0.0%)

Branch coverage included in aggregate %.

487 of 487 new or added lines in 186 files covered. (100.0%)

27394 of 31684 relevant lines covered (86.46%)

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

25

26
@implementer(IOrderedContainer)
1✔
27
class OrderSupport:
1✔
28
    """Ordered container mixin class.
29

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

37
    has_order_support = 1
1✔
38
    _default_sort_key = 'position'
1✔
39
    _default_sort_reverse = 0
1✔
40

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

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

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

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

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

114
    @security.protected(manage_properties)
1✔
115
    def manage_set_default_sorting(self, REQUEST, key, reverse):
1✔
116
        """Set default sorting key and direction."""
117
        self.setDefaultSorting(key, reverse)
×
118
        return self.manage_main(self, REQUEST)
×
119

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

144
        for id in ids:
1✔
145
            old_position = subset_ids.index(id)
1✔
146
            new_position = max(old_position - abs(delta), min_position)
1✔
147
            if new_position == min_position:
1✔
148
                min_position += 1
1✔
149
            if not old_position == new_position:
1✔
150
                subset_ids.remove(id)
1✔
151
                subset_ids.insert(new_position, id)
1✔
152
                counter += 1
1✔
153

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

171
        if not suppress_events:
1✔
172
            notifyContainerModified(self)
1✔
173

174
        return counter
1✔
175

176
    @security.protected(manage_properties)
1✔
177
    def moveObjectsUp(self, ids, delta=1, subset_ids=None):
1✔
178
        # Move specified sub-objects up by delta in container.
179
        return self.moveObjectsByDelta(ids, -delta, subset_ids)
1✔
180

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

186
    @security.protected(manage_properties)
1✔
187
    def moveObjectsToTop(self, ids, subset_ids=None):
1✔
188
        # Move specified sub-objects to top of container.
189
        return self.moveObjectsByDelta(ids, -len(self._objects), subset_ids)
1✔
190

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

196
    @security.protected(manage_properties)
1✔
197
    def orderObjects(self, key, reverse=None):
1✔
198
        # Order sub-objects by key and direction.
199
        ids = [id for id, obj in sort(
1✔
200
            self.objectItems(), ((key, 'cmp', 'asc'), ))]
201
        if reverse:
1✔
202
            ids.reverse()
1✔
203
        return self.moveObjectsByDelta(ids, -len(self._objects))
1✔
204

205
    @security.protected(access_contents_information)
1✔
206
    def getObjectPosition(self, id):
1✔
207
        # Get the position of an object by its id.
208
        ids = self.objectIds()
1✔
209
        if id in ids:
1✔
210
            return ids.index(id)
1✔
211
        raise ValueError('The object with the id "%s" does not exist.' % id)
1✔
212

213
    @security.protected(manage_properties)
1✔
214
    def moveObjectToPosition(self, id, position, suppress_events=False):
1✔
215
        # Move specified object to absolute position.
216
        delta = position - self.getObjectPosition(id)
1✔
217
        return self.moveObjectsByDelta(
1✔
218
            id,
219
            delta,
220
            suppress_events=suppress_events,
221
        )
222

223
    @security.protected(access_contents_information)
1✔
224
    def getDefaultSorting(self):
1✔
225
        # Get default sorting key and direction.
226
        return self._default_sort_key, self._default_sort_reverse
×
227

228
    @security.protected(manage_properties)
1✔
229
    def setDefaultSorting(self, key, reverse):
1✔
230
        # Set default sorting key and direction.
231
        self._default_sort_key = key
1✔
232
        self._default_sort_reverse = reverse and 1 or 0
1✔
233

234
    def manage_renameObject(self, id, new_id, REQUEST=None):
1✔
235
        """Rename a particular sub-object without changing its position."""
236
        old_position = self.getObjectPosition(id)
1✔
237
        result = super().manage_renameObject(id, new_id, REQUEST)
1✔
238
        self.moveObjectToPosition(
1✔
239
            new_id,
240
            old_position,
241
            suppress_events=True
242
        )
243
        return result
1✔
244

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

268
    def getIdsSubset(self, objects):
1✔
269
        return [obj['id'] for obj in objects]
1✔
270

271

272
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