SelectionTool.py 50.8 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
4
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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.
#
##############################################################################

"""\
30
ERP portal_selection tool.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
31 32
"""

33
from OFS.Traversable import NotFound
Jean-Paul Smets's avatar
Jean-Paul Smets committed
34 35 36
from OFS.SimpleItem import SimpleItem
from Products.CMFCore.utils import UniqueObject
from Globals import InitializeClass, DTMLFile, PersistentMapping, get_request
37
from ZTUtils import make_query
Jean-Paul Smets's avatar
Jean-Paul Smets committed
38 39 40
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions as ERP5Permissions
from Products.ERP5Form import _dtmldir
41
from Selection import Selection, DomainSelection
42
from ZPublisher.HTTPRequest import FileUpload
Sebastien Robin's avatar
Sebastien Robin committed
43 44
from email.MIMEBase import MIMEBase
from email import Encoders
Sebastien Robin's avatar
Sebastien Robin committed
45
from copy import copy
46
from DateTime import DateTime
Sebastien Robin's avatar
Sebastien Robin committed
47
import md5
Sebastien Robin's avatar
Sebastien Robin committed
48 49 50
import pickle
import hmac
import random
51
import re
52
import string
Jean-Paul Smets's avatar
Jean-Paul Smets committed
53
from zLOG import LOG
54
from Acquisition import Implicit, aq_base
55
from Products.ERP5Type.Message import Message
56

Jean-Paul Smets's avatar
Jean-Paul Smets committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
class SelectionError( Exception ):
    pass

class SelectionTool( UniqueObject, SimpleItem ):
    """
      The SelectionTool object is the place holder for all
      methods and algorithms related to persistent selections
      in ERP5.
    """

    id              = 'portal_selections'
    meta_type       = 'ERP5 Selections'

    security = ClassSecurityInfo()

    #
    #   ZMI methods
    #
    manage_options = ( ( { 'label'      : 'Overview'
                         , 'action'     : 'manage_overview'
77 78 79 80
                         },
                         { 'label'      : 'View Selections'
                         , 'action'     : 'manage_view_selections'
                         } ))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
81 82 83

    security.declareProtected( ERP5Permissions.ManagePortal
                             , 'manage_overview' )
84
    manage_overview = DTMLFile( 'explainSelectionTool', _dtmldir )
Jean-Paul Smets's avatar
Jean-Paul Smets committed
85

86 87 88
    security.declareProtected( ERP5Permissions.ManagePortal
                             , 'manage_view_selections' )
    manage_view_selections = DTMLFile( 'SelectionTool_manageViewSelections', _dtmldir )
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

    _query_string_reset_regexp = re.compile('\\breset(:int|)?=')
    _query_string_report_depth_regexp = re.compile('\\breport_depth(:int|)?=')
    def _redirectToOriginalForm(self, REQUEST=None, form_id=None, query_string=None,
                                no_reset=False, no_report_depth=False):
      """Redirect to the original form, using the information given as parameters.
         If no_reset is True, replace reset parameters with noreset.
         If no_report_depth is True, replace report_depth parameters with noreport_depth.
      """
      if REQUEST is None:
        return

      context = self.aq_parent
      if form_id is None:
        form_id = 'view'
      url = context.absolute_url() + '/' + form_id
      if query_string is not None:
        if no_reset:
          query_string = self._query_string_reset_regexp.sub('noreset\\1=',
                                                             query_string)
        if no_report_depth:
          query_string = self._query_string_report_depth_regexp.sub('noreport_depth\\1=',
                                                                    query_string)
        url = url + '?' + query_string
      return REQUEST.RESPONSE.redirect(url)

115 116 117 118 119 120 121 122 123 124 125
    security.declareProtected(ERP5Permissions.View, 'getSelectionNames')
    def getSelectionNames(self, context=None, REQUEST=None):
      if context is None: context = self
      if not REQUEST:
        REQUEST = get_request()
        if hasattr(self, 'selection_data'):
          user_id = self.portal_membership.getAuthenticatedMember().getUserName()
        if user_id is not None and self.selection_data.has_key(user_id):
          return self.selection_data[user_id].keys()
      return ()

126 127 128 129 130 131 132 133
    security.declareProtected(ERP5Permissions.View, 'callSelectionFor')
    def callSelectionFor(self, selection_name, context=None, REQUEST=None):
      if context is None: context = self
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is None:
        return None
      return selection(context=context)

Jean-Paul Smets's avatar
Jean-Paul Smets committed
134 135 136 137 138 139 140
    security.declareProtected(ERP5Permissions.View, 'getSelectionFor')
    def getSelectionFor(self, selection_name, REQUEST=None):
      """
        Returns the selection instance for a given selection_name
      """
      if not REQUEST:
        REQUEST = get_request()
141

142 143 144 145 146 147
      if not hasattr(self, 'selection_data'):
        self.selection_data = PersistentMapping()
      user_id = self.portal_membership.getAuthenticatedMember().getUserName()
      if user_id is not None:
        if not self.selection_data.has_key(user_id):
          self.selection_data[user_id] = PersistentMapping()
148 149
        if type(selection_name) is type(()) or type(selection_name) is type([]) :
          selection_name = selection_name[0]
150 151
        return self.selection_data[user_id].get(selection_name, None)
      else:
Jean-Paul Smets's avatar
Jean-Paul Smets committed
152
        return None
153

Jean-Paul Smets's avatar
Jean-Paul Smets committed
154 155 156 157 158
    security.declareProtected(ERP5Permissions.View, 'setSelectionFor')
    def setSelectionFor(self, selection_name, selection_object, REQUEST=None):
      """
        Sets the selection instance for a given selection_name
      """
159 160 161
      if selection_object != None:
        # Set the name so that this selection itself can get its own name.
        selection_object.edit(name = selection_name)
162

Jean-Paul Smets's avatar
Jean-Paul Smets committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
      if not REQUEST:
        REQUEST = get_request()
      # New system: store directly - bypass session
      if 0:
        user_id = self.portal_membership.getAuthenticatedMember().getUserName()
        if user_id is not None:
          self.selection_data.set((user_id, selection_name), selection_object)
        return

      # Another method: local dict
      if 0:
        if not hasattr(self, 'selection_data'):
          self.selection_data = PersistentMapping()
        user_id = self.portal_membership.getAuthenticatedMember().getUserName()
        if user_id is not None:
          self.selection_data[(user_id, selection_name)] = selection_object
        return

      # Another method: local dict but 2 stage to prevent user conflict
      if 1:
        if not hasattr(self, 'selection_data'):
          self.selection_data = PersistentMapping()
        user_id = self.portal_membership.getAuthenticatedMember().getUserName()
        if user_id is not None:
          if not self.selection_data.has_key(user_id):
            self.selection_data[user_id] = PersistentMapping()
          self.selection_data[user_id][selection_name] = selection_object
        return

      #try: CAUSES PROBLEMS WHY ??
      if 1:
        session = REQUEST.SESSION
        selection_name = selection_name + '_selection_object'
        session[selection_name] = selection_object
      #except:
      #  LOG('WARNING ERP5Form SelectionTool',0,'Could not set Selection')

200 201
    security.declareProtected(ERP5Permissions.View, 'getSelectionParamsFor')
    def getSelectionParamsFor(self, selection_name, params=None, REQUEST=None):
202 203 204
      """
        Returns the params in the selection
      """
205
      if params is None: params = {}
206 207
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
208 209
        if len(selection.params) > 0:
          return selection.getParams()
210 211 212 213
        else:
          return params
      else:
        return params
214 215 216 217 218
    
    # backward compatibility 
    security.declareProtected(ERP5Permissions.View, 'getSelectionParams')
    getSelectionParams = getSelectionParamsFor
    
Jean-Paul Smets's avatar
Jean-Paul Smets committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    security.declareProtected(ERP5Permissions.View, 'setSelectionParamsFor')
    def setSelectionParamsFor(self, selection_name, params, REQUEST=None):
      """
        Sets the selection params for a given selection_name
      """
      selection_object = self.getSelectionFor(selection_name, REQUEST)
      if selection_object:
        selection_object.edit(params=params)
      else:
        selection_object = Selection(params=params)
      self.setSelectionFor(selection_name, selection_object, REQUEST)

    security.declareProtected(ERP5Permissions.View, 'setSelectionCheckedUidsFor')
    def setSelectionCheckedUidsFor(self, selection_name, checked_uids, REQUEST=None):
      """
        Sets the selection params for a given selection_name
      """
      selection_object = self.getSelectionFor(selection_name, REQUEST)
      if selection_object:
        selection_object.edit(checked_uids=checked_uids)
      else:
        selection_object = Selection(checked_uids=checked_uids)
      self.setSelectionFor(selection_name, selection_object, REQUEST)

243 244 245 246 247 248 249 250 251 252 253
    def updateSelectionCheckedUidList(self, selection_name, listbox_uid, uids, REQUEST=None):
      """
        Sets the selection params for a given selection_name
      """
      if listbox_uid is None:
        listbox_uid = []
      if uids is None:
        uids = []
      self.uncheckAll(selection_name,listbox_uid,REQUEST=REQUEST)
      self.checkAll(selection_name,uids,REQUEST=REQUEST)

254 255 256 257 258 259 260
    security.declareProtected(ERP5Permissions.View, 'getSelectionCheckedUidsFor')
    def getSelectionCheckedUidsFor(self, selection_name, REQUEST=None):
      """
        Sets the selection params for a given selection_name
      """
      selection_object = self.getSelectionFor(selection_name, REQUEST)
      if selection_object:
261
        #return selection_object.selection_checked_uids
262
        return selection_object.getCheckedUids()
263 264 265
      return []

    security.declareProtected(ERP5Permissions.View, 'checkAll')
266 267
    def checkAll(self, selection_name, listbox_uid=[], REQUEST=None,
                 query_string=None, form_id=None):
268 269 270 271 272 273
      """
        Sets the selection params for a given selection_name
      """
      selection_object = self.getSelectionFor(selection_name, REQUEST)
      if selection_object:
        selection_uid_dict = {}
274
        for uid in selection_object.checked_uids:
275 276
          selection_uid_dict[uid] = 1
        for uid in listbox_uid:
277 278
          try:
            selection_uid_dict[int(uid)] = 1
279
          except ValueError:
280
            pass # this can happen in report
281
        self.setSelectionCheckedUidsFor(selection_name, selection_uid_dict.keys(), REQUEST=REQUEST)
282 283 284
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string, no_reset=True)
285 286

    security.declareProtected(ERP5Permissions.View, 'uncheckAll')
287 288
    def uncheckAll(self, selection_name, listbox_uid=[], REQUEST=None,
                   query_string=None, form_id=None):
289 290 291 292 293 294
      """
        Sets the selection params for a given selection_name
      """
      selection_object = self.getSelectionFor(selection_name, REQUEST)
      if selection_object:
        selection_uid_dict = {}
295
        for uid in selection_object.checked_uids:
296 297
          selection_uid_dict[uid] = 1
        for uid in listbox_uid:
298 299 300
          try:
            if selection_uid_dict.has_key(int(uid)): del selection_uid_dict[int(uid)]
          except ValueError:
301
            pass # This happens in report mode
302
        self.setSelectionCheckedUidsFor(selection_name, selection_uid_dict.keys(), REQUEST=REQUEST)
303 304 305
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string, no_reset=True)
306

Jean-Paul Smets's avatar
Jean-Paul Smets committed
307 308 309 310 311 312 313
    security.declareProtected(ERP5Permissions.View, 'getSelectionListUrlFor')
    def getSelectionListUrlFor(self, selection_name, REQUEST=None):
      """
        Returns the URL of the list mode of selection instance
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection:
314
        return selection.getListUrl()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
315 316 317 318 319 320 321 322 323 324
      else:
        return None

    security.declareProtected(ERP5Permissions.View, 'setSelectionToIds')
    def setSelectionToIds(self, selection_name, selection_uids, REQUEST=None):
      """
        Sets the selection to a small list of uids of documents
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
325
        selection.edit(invert_mode=1, uids=selection_uids, checked_uids=selection_uids)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
326 327

    security.declareProtected(ERP5Permissions.View, 'setSelectionToAll')
328 329
    def setSelectionToAll(self, selection_name, REQUEST=None,
                          reset_domain_tree=False, reset_report_tree=False):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
330 331 332 333 334
      """
        Resets the selection
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
335 336
        selection.edit(invert_mode=0, params={}, checked_uids=[])
        if reset_domain_tree:
337
          selection.edit(domain=None, domain_path=None, domain_list=None)
338
        if reset_report_tree:
339
          selection.edit(report=None, report_path=None, report_list=None)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
340 341 342 343 344 345 346 347 348 349 350

    security.declareProtected(ERP5Permissions.View, 'setSelectionSortOrder')
    def setSelectionSortOrder(self, selection_name, sort_on, REQUEST=None):
      """
        Defines the sort order of the selection
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
        selection.edit(sort_on=sort_on)

    security.declareProtected(ERP5Permissions.View, 'setSelectionQuickSortOrder')
351 352
    def setSelectionQuickSortOrder(self, selection_name, sort_on, REQUEST=None,
                                   query_string=None, form_id=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
      """
        Defines the sort order of the selection directly from the listbox
        In this method, sort_on is just a string that comes from url
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
        current_sort_on = self.getSelectionSortOrder(selection_name)
        # We must first switch from asc to desc and vice-versa if sort_order exists
        # in selection
        n = 0
        for current in current_sort_on:
          if current[0] == sort_on:
            n = 1
            if current[1] == 'ascending':
              new_sort_on = [(sort_on, 'descending')]
              break
            else:
              new_sort_on = [(sort_on,'ascending')]
              break
        # And if no one exists, we just set ascending sort
        if n == 0:
          new_sort_on = [(sort_on,'ascending')]
        selection.edit(sort_on=new_sort_on)

377 378 379
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string, no_reset=True)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
380 381 382 383 384 385 386 387

    security.declareProtected(ERP5Permissions.View, 'getSelectionSortOrder')
    def getSelectionSortOrder(self, selection_name, REQUEST=None):
      """
        Returns the sort order of the selection
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is None: return ()
388
      return selection.sort_on
Jean-Paul Smets's avatar
Jean-Paul Smets committed
389 390 391 392 393 394 395 396 397 398

    security.declareProtected(ERP5Permissions.View, 'setSelectionColumns')
    def setSelectionColumns(self, selection_name, columns, REQUEST=None):
      """
        Defines the columns in the selection
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      selection.edit(columns=columns)

    security.declareProtected(ERP5Permissions.View, 'getSelectionColumns')
399
    def getSelectionColumns(self, selection_name, columns=None, REQUEST=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
400 401 402
      """
        Returns the columns in the selection
      """
403
      if columns is None: columns = []
Jean-Paul Smets's avatar
Jean-Paul Smets committed
404 405
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
406 407
        if len(selection.columns) > 0:
          return selection.columns
408
      return columns
Jean-Paul Smets's avatar
Jean-Paul Smets committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426


    security.declareProtected(ERP5Permissions.View, 'setSelectionStats')
    def setSelectionStats(self, selection_name, stats, REQUEST=None):
      """
        Defines the stats in the selection
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      selection.edit(stats=stats)

    security.declareProtected(ERP5Permissions.View, 'getSelectionStats')
    def getSelectionStats(self, selection_name, stats=[' ',' ',' ',' ',' ',' '], REQUEST=None):
      """
        Returns the stats in the selection
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
        try:
427
          return selection.stats
Yoshinori Okuji's avatar
Yoshinori Okuji committed
428
        except AttributeError:
429
          return stats # That is really bad programming XXX
Jean-Paul Smets's avatar
Jean-Paul Smets committed
430 431 432 433 434 435 436 437 438 439 440 441 442
      else:
        return stats


    security.declareProtected(ERP5Permissions.View, 'viewFirst')
    def viewFirst(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
      """
        Access first item in a selection
      """
      if not REQUEST:
        REQUEST = get_request()
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection:
443
        method = self.unrestrictedTraverse(selection.method_path)
444 445
        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
        o = selection_list[0]
Jean-Paul Smets's avatar
Jean-Paul Smets committed
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
        url = o.absolute_url()
      else:
        url = REQUEST.url
      url = '%s/%s?selection_index=%s&selection_name=%s' % (url, form_id, 0, selection_name)
      REQUEST.RESPONSE.redirect(url)

    security.declareProtected(ERP5Permissions.View, 'viewLast')
    def viewLast(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
      """
        Access first item in a selection
      """
      if not REQUEST:
        REQUEST = get_request()
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection:
461
        method = self.unrestrictedTraverse(selection.method_path)
462 463
        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
        o = selection_list[-1]
Jean-Paul Smets's avatar
Jean-Paul Smets committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
        url = o.absolute_url()
      else:
        url = REQUEST.url
      url = '%s/%s?selection_index=%s&selection_name=%s' % (url, form_id, -1, selection_name)
      REQUEST.RESPONSE.redirect(url)

    security.declareProtected(ERP5Permissions.View, 'viewNext')
    def viewNext(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
      """
        Access next item in a selection
      """
      if not REQUEST:
        REQUEST = get_request()
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection:
479
        method = self.unrestrictedTraverse(selection.method_path)
480 481
        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
        o = selection_list[(int(selection_index) + 1) % len(selection_list)]
Jean-Paul Smets's avatar
Jean-Paul Smets committed
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
        url = o.absolute_url()
      else:
        url = REQUEST.url
      url = '%s/%s?selection_index=%s&selection_name=%s' % (url, form_id, int(selection_index) + 1, selection_name)
      REQUEST.RESPONSE.redirect(url)

    security.declareProtected(ERP5Permissions.View, 'viewPrevious')
    def viewPrevious(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
      """
        Access previous item in a selection
      """
      if not REQUEST:
        REQUEST = get_request()
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection:
497
        method = self.unrestrictedTraverse(selection.method_path)
498 499
        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
        o = selection_list[(int(selection_index) - 1) % len(selection_list)]
Jean-Paul Smets's avatar
Jean-Paul Smets committed
500 501 502 503 504 505 506 507 508
        url = o.absolute_url()
      else:
        url = REQUEST.url
      url = '%s/%s?selection_index=%s&selection_name=%s' % (url, form_id, int(selection_index) - 1, selection_name)
      REQUEST.RESPONSE.redirect(url)


    # ListBox related methods
    security.declareProtected(ERP5Permissions.View, 'nextPage')
509
    def nextPage(self, listbox_uid, uids=None, REQUEST=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
510 511 512
      """
        Access the next page of a list
      """
513
      if uids is None: uids = []
Jean-Paul Smets's avatar
Jean-Paul Smets committed
514
      request = REQUEST
515
      #form_id = request.form_id
Jean-Paul Smets's avatar
Jean-Paul Smets committed
516 517
      selection_name = request.list_selection_name
      selection = self.getSelectionFor(selection_name, REQUEST)
518
      params = selection.getParams()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
519 520 521 522 523
      lines = params.get('list_lines',0)
      start = params.get('list_start', 0)
      params['list_start'] = int(start) + int(lines)
      selection.edit(params= params)

524 525
      self.uncheckAll(selection_name, listbox_uid)
      return self.checkAll(selection_name, uids, REQUEST=REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
526 527

    security.declareProtected(ERP5Permissions.View, 'previousPage')
528
    def previousPage(self, listbox_uid, uids=None, REQUEST=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
529 530 531
      """
        Access the previous page of a list
      """
532
      if uids is None: uids = []
Jean-Paul Smets's avatar
Jean-Paul Smets committed
533
      request = REQUEST
534
      #form_id = request.form_id
Jean-Paul Smets's avatar
Jean-Paul Smets committed
535 536
      selection_name = request.list_selection_name
      selection = self.getSelectionFor(selection_name, REQUEST)
537
      params = selection.getParams()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
538 539 540
      lines = params.get('list_lines',0)
      start = params.get('list_start', 0)
      params['list_start'] = max(int(start) - int(lines), 0)
541
      selection.edit(params= selection.params)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
542

543 544
      self.uncheckAll(selection_name, listbox_uid)
      return self.checkAll(selection_name, uids, REQUEST=REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
545 546

    security.declareProtected(ERP5Permissions.View, 'setPage')
547
    def setPage(self, listbox_uid, query_string=None, uids=None, REQUEST=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
548 549 550
      """
        Access the previous page of a list
      """
551
      if uids is None: uids = []
Jean-Paul Smets's avatar
Jean-Paul Smets committed
552
      request = REQUEST
553
      #form_id = request.form_id
Jean-Paul Smets's avatar
Jean-Paul Smets committed
554
      selection_name = request.list_selection_name
555

Jean-Paul Smets's avatar
Jean-Paul Smets committed
556 557
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
558
        params = selection.getParams()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
559 560 561 562
        lines = params.get('list_lines',0)
        start = request.form.get('list_start',0)

        params['list_start'] = start
563
        selection.edit(params= selection.params)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
564

565
      self.uncheckAll(selection_name, listbox_uid)
566 567
      return self.checkAll(selection_name, uids, REQUEST=REQUEST, query_string=query_string)

Jean-Paul Smets's avatar
Jean-Paul Smets committed
568

569
    security.declareProtected(ERP5Permissions.View, 'setZoom')
570
    def setZoom(self, uids=None, REQUEST=None, form_id=None, query_string=None):
571 572
      """
      Set graphic zoom in PlanningBox
573
      """
574
      if uids is None: uids = []
575
      zoom=REQUEST.get('zoom')
576 577 578 579 580 581
      selection_name=request.list_selection_name
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
      if selection is not None:
        params = selection.getParams()
        params['zoom'] = zoom
        selection.edit(params= params)
582 583 584 585
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string)

Jean-Paul Smets's avatar
Jean-Paul Smets committed
586
    security.declareProtected(ERP5Permissions.View, 'setDomainRoot')
587
    def setDomainRoot(self, REQUEST, form_id=None, query_string=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
588 589 590
      """
        Sets the root domain for the current selection
      """
591
      selection_name = REQUEST.list_selection_name
Jean-Paul Smets's avatar
Jean-Paul Smets committed
592
      selection = self.getSelectionFor(selection_name, REQUEST)
593
      root_url = REQUEST.form.get('domain_root_url','portal_categories')
594
      selection.edit(domain_path=root_url, domain_list=())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
595

596 597 598
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
599

600
    security.declareProtected(ERP5Permissions.View, 'unfoldDomain')
601
    def unfoldDomain(self, REQUEST, form_id=None, query_string=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
602 603 604
      """
        Sets the root domain for the current selection
      """
605
      selection_name = REQUEST.list_selection_name
Jean-Paul Smets's avatar
Jean-Paul Smets committed
606
      selection = self.getSelectionFor(selection_name, REQUEST)
607 608
      domain_url = REQUEST.form.get('domain_url',None)
      domain_depth = REQUEST.form.get('domain_depth',0)
609 610
      domain_list = list(selection.getDomainList())
      domain_list = domain_list[0:min(domain_depth, len(domain_list))]
611
      if isinstance(domain_url, str):
612
        selection.edit(domain_list = domain_list + [domain_url])
Jean-Paul Smets's avatar
Jean-Paul Smets committed
613

614 615 616
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
617

618
    security.declareProtected(ERP5Permissions.View, 'foldDomain')
619
    def foldDomain(self, REQUEST, form_id=None, query_string=None):
620 621 622
      """
        Sets the root domain for the current selection
      """
623
      selection_name = REQUEST.list_selection_name
624
      selection = self.getSelectionFor(selection_name, REQUEST)
625 626
      domain_url = REQUEST.form.get('domain_url',None)
      domain_depth = REQUEST.form.get('domain_depth',0)
627 628
      domain_list = list(selection.getDomainList())
      domain_list = domain_list[0:min(domain_depth, len(domain_list))]
629
      selection.edit(domain_list=[x for x in domain_list if x != domain_url])
630

631 632 633
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string)
634

635

Jean-Paul Smets's avatar
Jean-Paul Smets committed
636
    security.declareProtected(ERP5Permissions.View, 'setReportRoot')
637
    def setReportRoot(self, REQUEST, form_id=None, query_string=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
638 639 640
      """
        Sets the root domain for the current selection
      """
641
      selection_name = REQUEST.list_selection_name
Jean-Paul Smets's avatar
Jean-Paul Smets committed
642
      selection = self.getSelectionFor(selection_name, REQUEST)
643
      root_url = REQUEST.form.get('report_root_url','portal_categories')
644
      selection.edit(report_path=root_url, report_list=())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
645

646 647 648
      if REQUEST is not None:
        return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                            query_string=query_string)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
649 650

    security.declareProtected(ERP5Permissions.View, 'unfoldReport')
651
    def unfoldReport(self, REQUEST, form_id=None, query_string=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
652 653
      """
        Sets the root domain for the current selection
654

655
        report_list is a list of relative_url of category, domain, etc.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
656
      """
657
      selection_name = REQUEST.list_selection_name
Jean-Paul Smets's avatar
Jean-Paul Smets committed
658
      selection = self.getSelectionFor(selection_name, REQUEST)
659
      report_url = REQUEST.form.get('report_url',None)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
660
      if type(report_url) == type('a'):
661
        selection.edit(report_list=list(selection.getReportList()) + [report_url])
Jean-Paul Smets's avatar
Jean-Paul Smets committed
662

663 664 665
      return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                          query_string=query_string,
                                          no_report_depth=True)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
666 667

    security.declareProtected(ERP5Permissions.View, 'foldReport')
668
    def foldReport(self, REQUEST, form_id=None, query_string=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
669 670 671
      """
        Sets the root domain for the current selection
      """
672
      selection_name = REQUEST.list_selection_name
Jean-Paul Smets's avatar
Jean-Paul Smets committed
673
      selection = self.getSelectionFor(selection_name, REQUEST)
674
      report_url = REQUEST.form.get('report_url',None)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
675
      if type(report_url) == type('a'):
676
        report_list = selection.getReportList()
677
        selection.edit(report_list=[x for x in report_list if x != report_url])
Jean-Paul Smets's avatar
Jean-Paul Smets committed
678

679 680 681
      return self._redirectToOriginalForm(REQUEST=REQUEST, form_id=form_id,
                                          query_string=query_string,
                                          no_report_depth=True)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
682

683 684 685 686
    security.declareProtected(ERP5Permissions.View, 'getListboxDisplayMode')
    def getListboxDisplayMode(self, selection_name, REQUEST=None):
      if REQUEST is None:
        REQUEST = get_request()
687
      selection = self.getSelectionFor(selection_name, REQUEST)
688

689 690 691 692 693
      if getattr(selection, 'report_tree_mode', 0):
        return 'ReportTreeMode'
      elif getattr(selection, 'domain_tree_mode', 0):
        return 'DomainTreeMode'
      return 'FlatListMode'
694

Jean-Paul Smets's avatar
Jean-Paul Smets committed
695
    security.declareProtected(ERP5Permissions.View, 'setListboxDisplayMode')
696
    def setListboxDisplayMode(self, REQUEST, listbox_display_mode, 
697 698
                              selection_name=None, redirect=0,
                              form_id=None, query_string=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
699 700 701 702
      """
        Toogle display of the listbox
      """
      request = REQUEST
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
      # XXX FIXME
      # Dirty fix: we must be able to change the display mode of a listbox
      # in form_view
      # But, form can have multiple listbox...
      # This need to be cleaned
      # Beware, this fix may break the report system...
      # and we don't have test for this
      # Possible fix: currently, display mode icon are implemented as 
      # method. It could be easier to generate them as link (where we 
      # can define explicitely parameters through the url).
      try:
        list_selection_name = request.list_selection_name
      except AttributeError:
        pass
      else:
        if list_selection_name is not None:
          selection_name = request.list_selection_name
      # Get the selection
Jean-Paul Smets's avatar
Jean-Paul Smets committed
721
      selection = self.getSelectionFor(selection_name, REQUEST)
722 723
      if selection is None:
        selection = Selection()
724
        self.setSelectionFor(selection_name, selection, REQUEST=REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
725 726 727 728 729 730 731 732 733 734 735 736 737

      if listbox_display_mode == 'FlatListMode':
        flat_list_mode = 1
        domain_tree_mode = 0
        report_tree_mode = 0
      elif listbox_display_mode == 'DomainTreeMode':
        flat_list_mode = 0
        domain_tree_mode = 1
        report_tree_mode = 0
      elif listbox_display_mode == 'ReportTreeMode':
        flat_list_mode = 0
        domain_tree_mode = 0
        report_tree_mode = 1
738 739 740 741
      else:
        flat_list_mode = 0
        domain_tree_mode = 0
        report_tree_mode = 0      
742

743 744 745
      selection.edit(flat_list_mode=flat_list_mode,
                     domain_tree_mode=domain_tree_mode,
                     report_tree_mode=report_tree_mode)
746
      # It is better to reset the query when changing the display mode.
747 748
      params = selection.getParams()
      if 'where_expression' in params: del params['where_expression']
749 750
      selection.edit(params = params)

751
      if redirect:
752 753 754
        return self._redirectToOriginalForm(REQUEST=request, form_id=form_id,
                                            query_string=query_string,
                                            no_reset=True)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
755 756

    security.declareProtected(ERP5Permissions.View, 'setFlatListMode')
757
    def setFlatListMode(self, REQUEST, selection_name=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
758 759 760
      """
        Set display of the listbox to FlatList mode
      """
761 762 763
      return self.setListboxDisplayMode(
                       REQUEST=REQUEST, listbox_display_mode='FlatListMode', 
                       selection_name=selection_name, redirect=1)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
764 765

    security.declareProtected(ERP5Permissions.View, 'setDomainTreeMode')
766
    def setDomainTreeMode(self, REQUEST, selection_name=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
767 768 769
      """
         Set display of the listbox to DomainTree mode
      """
770 771 772
      return self.setListboxDisplayMode(
                       REQUEST=REQUEST, listbox_display_mode='DomainTreeMode', 
                       selection_name=selection_name, redirect=1)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
773 774

    security.declareProtected(ERP5Permissions.View, 'setReportTreeMode')
775
    def setReportTreeMode(self, REQUEST, selection_name=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
776 777 778
      """
        Set display of the listbox to ReportTree mode
      """
779 780 781
      return self.setListboxDisplayMode(
                       REQUEST=REQUEST, listbox_display_mode='ReportTreeMode',
                       selection_name=selection_name, redirect=1)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
782

783 784 785 786 787 788
    security.declareProtected(ERP5Permissions.View, 'getSelectionSelectedValueList')
    def getSelectionSelectedValueList(self, selection_name, REQUEST=None, selection_method=None, context=None):
      """
        Get the list of values selected for 'selection_name'
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
789 790
      if selection is None:
        return []
791
      return selection(method=selection_method, context=context, REQUEST=REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
792

793 794 795 796 797 798
    security.declareProtected(ERP5Permissions.View, 'getSelectionCheckedValueList')
    def getSelectionCheckedValueList(self, selection_name, REQUEST=None):
      """
        Get the list of values checked for 'selection_name'
      """
      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
799 800
      if selection is None:
        return []
801
      uid_list = selection.getCheckedUids()
802 803 804 805 806 807 808 809 810 811
      value_list = self.portal_catalog.getObjectList(uid_list)
      return value_list

    security.declareProtected(ERP5Permissions.View, 'getSelectionValueList')
    def getSelectionValueList(self, selection_name, REQUEST=None, selection_method=None, context=None):
      """
        Get the list of values checked or selected for 'selection_name'
      """
      value_list = self.getSelectionCheckedValueList(selection_name, REQUEST=REQUEST)
      if len(value_list) == 0:
812 813 814 815 816
        value_list = self.getSelectionSelectedValueList(
                                            selection_name,
                                            REQUEST=REQUEST, 
                                            selection_method=selection_method, 
                                            context=context)
817
      return value_list
Jean-Paul Smets's avatar
Jean-Paul Smets committed
818

Jean-Paul Smets's avatar
Jean-Paul Smets committed
819 820 821 822 823 824 825
    security.declareProtected(ERP5Permissions.View, 'getSelectionUidList')
    def getSelectionUidList(self, selection_name, REQUEST=None, selection_method=None, context=None):
      """
        Get the list of values checked or selected for 'selection_name'
      """
      return map(lambda x:x.getObject().getUid(), self.getSelectionValueList(selection_name, REQUEST=REQUEST, selection_method=selection_method, context=context))

Sebastien Robin's avatar
Sebastien Robin committed
826 827 828 829 830
    security.declareProtected(ERP5Permissions.View, 'selectionHasChanged')
    def selectionHasChanged(self, md5_string, object_uid_list):
      """
        We want to be sure that the selection did not change
      """
831 832 833 834 835 836
      # XXX To avoid the difference of the string representations of int and long,
      # convert each element to a string. 
      object_uid_list = [str(x) for x in object_uid_list]
      object_uid_list.sort()
      new_md5_string = md5.new(str(object_uid_list)).hexdigest()
      return md5_string != new_md5_string
Sebastien Robin's avatar
Sebastien Robin committed
837

838 839
    security.declareProtected(ERP5Permissions.View, 'getPickle')
    def getPickle(self,**kw):
Sebastien Robin's avatar
Sebastien Robin committed
840 841 842 843
      """
      we give many keywords and we will get the corresponding
      pickle string and signature
      """
Yoshinori Okuji's avatar
Yoshinori Okuji committed
844
      #LOG('getPickle kw',0,kw)
845 846 847
      # XXX Remove DateTime, This is really bad, only use for zope 2.6
      # XXX This has to be removed as quickly as possible
      for k,v in kw.items():
Sebastien Robin's avatar
Sebastien Robin committed
848
        if isinstance(v,DateTime):
849 850
          del kw[k]
      # XXX End of the part to remove
851
      #LOG('SelectionTool.getPickle, kw',0,kw)
Sebastien Robin's avatar
Sebastien Robin committed
852 853 854 855 856 857
      pickle_string = pickle.dumps(kw)
      msg = MIMEBase('application','octet-stream')
      msg.set_payload(pickle_string)
      Encoders.encode_base64(msg)
      pickle_string = msg.get_payload()
      pickle_string = pickle_string.replace('\n','@@@')
858 859 860 861 862 863 864 865
      return pickle_string

    security.declareProtected(ERP5Permissions.View, 'getPickleAndSignature')
    def getPickleAndSignature(self,**kw):
      """
      we give many keywords and we will get the corresponding
      pickle string and signature
      """
866
      cookie_password = self._getCookiePassword()
867
      pickle_string = self.getPickle(**kw)
Sebastien Robin's avatar
Sebastien Robin committed
868 869 870
      signature = hmac.new(cookie_password,pickle_string).hexdigest()
      return (pickle_string,signature)

871 872 873 874 875 876 877 878 879 880 881 882 883 884
    security.declareProtected(ERP5Permissions.View, 'getObjectFromPickle')
    def getObjectFromPickle(self,pickle_string):
      """
      we give a pickle string and a signature
      """
      object = None
      pickle_string = pickle_string.replace('@@@','\n')
      msg = MIMEBase('application','octet-stream')
      Encoders.encode_base64(msg)
      msg.set_payload(pickle_string)
      pickle_string = msg.get_payload(decode=1)
      object = pickle.loads(pickle_string)
      return object

Sebastien Robin's avatar
Sebastien Robin committed
885 886 887 888 889 890 891 892 893
    security.declareProtected(ERP5Permissions.View, 'getObjectFromPickleAndSignature')
    def getObjectFromPickleAndSignature(self,pickle_string,signature):
      """
      we give a pickle string and a signature
      """
      cookie_password = self._getCookiePassword()
      object = None
      new_signature = hmac.new(cookie_password,pickle_string).hexdigest()
      if new_signature==signature:
894
        object = self.getObjectFromPickle(pickle_string)
Sebastien Robin's avatar
Sebastien Robin committed
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
      return object

    security.declarePrivate('_getCookiePassword')
    def _getCookiePassword(self):
      """
      get the password used for encryption
      """
      cookie_password = getattr(self,'cookie_password',None)
      if cookie_password is None:
        cookie_password = str(random.randrange(1,2147483600))
        self.cookie_password = cookie_password
      return cookie_password

    security.declareProtected(ERP5Permissions.View, 'registerCookieInfo')
    def setCookieInfo(self,request,cookie_name,**kw):
      """
      regiter info directly in cookie
      """
      cookie_name = cookie_name + '_cookie'
      (pickle_string,signature) = self.getPickleAndSignature(**kw)
      request.RESPONSE.setCookie(cookie_name,pickle_string,max_age=15*60)
      signature_cookie_name = cookie_name + '_signature'
      request.RESPONSE.setCookie(signature_cookie_name,signature,max_age=15*60)

    security.declareProtected(ERP5Permissions.View, 'registerCookieInfo')
    def getCookieInfo(self,request,cookie_name):
      """
      regiter info directly in cookie
      """
      cookie_name = cookie_name + '_cookie'
      object = None
      if getattr(request,cookie_name,None) is not None:
        pickle_string = request.get(cookie_name)
        signature_cookie_name = cookie_name + '_signature'
        signature = request.get(signature_cookie_name)
        object = self.getObjectFromPickleAndSignature(pickle_string,signature)
      if object is None:
        object = {}
      return object

935
    # Related document searching
936
    def viewSearchRelatedDocumentDialog(self, index, form_id, REQUEST=None,
937
                                        sub_index=None, **kw):
938
      """
939 940
      Returns a search related document dialog
      A set of forwarders us defined to circumvent limitations of HTML
941
      """
Romain Courteaud's avatar
Romain Courteaud committed
942 943
      if sub_index != None:
        REQUEST.form['sub_index'] = sub_index
944
      # Find the object which needs to be updated
945
      object_uid = REQUEST.get('object_uid', None)
946
      object_path = REQUEST.get('object_path', None)
947
      if object_uid is not None:
948 949
        try :
          o = self.portal_catalog.getObject(object_uid)
950
        except (NotFound, KeyError), err :
951
          o = None
952 953 954
      if o is None:
        # we first try to reindex the object, thanks to the object_path
        if object_path is not None:
955
          o = self.getPortalObject().restrictedTraverse(object_path)
956
        if o is not None:
957
          # XXX
958
          o.immediateReindexObject()
959
          object_uid = o.getUid()
960
        else:
961 962 963
          raise SelectionError, \
                "Sorrry, Error, the calling object was not catalogued. " \
                "Do not know how to do ?"
964
      # Find the field which was clicked on
965
      # Important to get from the object instead of self
966
      form = getattr(o, form_id)
967
      field = None
968 969
      # Search the correct field
      relation_field_found = 0
970
      relation_index = 0
971
      # XXX may be should support another parameter,
972
      for field in form.get_fields(include_disabled=0):
973 974
        if field.get_value('editable', REQUEST=REQUEST):
          try:
975 976
           field.get_value('is_relation_field')
          except KeyError:
977
            pass
978
          else:
979 980 981 982 983
            if index == relation_index:
              relation_field_found = 1
              break
            else:
              relation_index += 1
984
      if not relation_field_found:
985
        # We didn't find the field...
986
        raise SelectionError, "SelectionTool: can not find the relation" \
987
                              " field %s" % index
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
      else:
        # Field found
        field_key = field.generate_field_key()
        field_value = REQUEST.form[field_key]
        # XXX Hardcoded form name
        redirect_form_id = 'Base_viewRelatedObjectList'
        redirect_form = getattr(o, redirect_form_id)
        # XXX Hardcoded listbox field
        selection_name = redirect_form.listbox.get_value('selection_name')
        # Reset current selection
        self.portal_selections.setSelectionFor(selection_name, None)


        if (field.get_value('is_multi_relation_field')) and \
           (sub_index is None):
1003 1004 1005 1006
          # user click on the wheel, not on the validation button
          # we need to facilitate user search

          # first: store current field value in the selection
1007
          base_category = field.get_value('base_category')
1008

1009 1010 1011 1012 1013 1014
          property_get_related_uid_method_name = \
            "get%sUidList" % ''.join(['%s%s' % (x[0].upper(), x[1:]) \
                                      for x in base_category.split('_')])
          current_uid_list = getattr(o, property_get_related_uid_method_name)\
                               (portal_type=[x[0] for x in \
                                  field.get_value('portal_type')])
Romain Courteaud's avatar
Romain Courteaud committed
1015 1016 1017
          # Checked current uid
          kw ={}
          kw[field.get_value('catalog_index')] = field_value
1018 1019 1020 1021 1022
          self.portal_selections.setSelectionParamsFor(selection_name, 
                                                       kw.copy())
          self.portal_selections.setSelectionCheckedUidsFor(
                                             selection_name, 
                                             current_uid_list)
1023 1024 1025 1026 1027 1028 1029 1030
          field_value = str(field_value).splitlines()
          REQUEST.form[field_key] = field_value
          portal_status_message = Message(
                          domain='erp5_ui',
                          message="Please select one (or more) object.")
        else:
          portal_status_message = Message(domain='erp5_ui',
                                          message="Please select one object.")
1031 1032


1033 1034 1035 1036 1037 1038
        # Save the current REQUEST form
        # We can't put FileUpload instances because we can't pickle them
        pickle_kw = {}
        for key in REQUEST.form.keys():
          if not isinstance(REQUEST.form[key],FileUpload):
            pickle_kw[key] = REQUEST.form[key]
1039
        form_pickle, form_signature = self.getPickleAndSignature(**pickle_kw)
1040

1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
        base_category = None
        kw = {}
        kw['object_uid'] = object_uid
        kw['form_id'] = redirect_form_id
        kw['selection_name'] = selection_name
        kw['selection_index'] = 0 # We start on the first page
        kw['field_id'] = field.id
        kw['portal_type'] = [x[0] for x in field.get_value('portal_type')]
        parameter_list = field.get_value('parameter_list')
        if len(parameter_list) > 0:
          for k,v in parameter_list:
            kw[k] = v
        kw['reset'] = 0
        kw['base_category'] = field.get_value( 'base_category')
        kw['cancel_url'] = REQUEST.get('HTTP_REFERER')
        kw['previous_form_id'] = form_id
        kw[field.get_value('catalog_index')] = field_value
        kw['portal_status_message'] = portal_status_message
1059 1060 1061 1062 1063 1064
        kw['form_pickle'] = form_pickle   
        kw['form_signature'] = form_signature

         # Empty the selection (uid)
        REQUEST.form = kw # New request form
        # Define new HTTP_REFERER
Romain Courteaud's avatar
Romain Courteaud committed
1065 1066
        REQUEST.HTTP_REFERER = '%s/%s' % (o.absolute_url(),
                                          redirect_form_id)
1067 1068
        # Return the search dialog
        return getattr(o, redirect_form_id)(REQUEST=REQUEST)
1069

1070 1071
    def _aq_dynamic(self, name):
      """
1072 1073
        Generate viewSearchRelatedDocumentDialog0, 
                 viewSearchRelatedDocumentDialog1,... if necessary
1074 1075 1076
      """
      aq_base_name = getattr(aq_base(self), name, None)
      if aq_base_name == None:
1077 1078 1079
        DYNAMIC_METHOD_NAME = 'viewSearchRelatedDocumentDialog'
        method_name_length = len(DYNAMIC_METHOD_NAME)

1080
        zope_security = '__roles__'
1081
        if (name[:method_name_length] == DYNAMIC_METHOD_NAME) and \
1082
           (name[-len(zope_security):] != zope_security):
1083
          method_count_string_list = name[method_name_length:].split('_')
1084 1085 1086 1087
          method_count_string = method_count_string_list[0]
          # be sure that method name is correct
          try:
            method_count = string.atoi(method_count_string)
Yoshinori Okuji's avatar
Yoshinori Okuji committed
1088
          except TypeError:
1089
            return aq_base_name
1090
          else:
1091 1092 1093
            if len(method_count_string_list) > 1:
              # be sure that method name is correct
              try:
Romain Courteaud's avatar
Romain Courteaud committed
1094
                sub_index = string.atoi(method_count_string_list[1])
Yoshinori Okuji's avatar
Yoshinori Okuji committed
1095
              except TypeError:
1096 1097
                return aq_base_name
            else:
Romain Courteaud's avatar
Romain Courteaud committed
1098
              sub_index = None
1099

1100
            # generate dynamicaly needed forwarder methods
1101 1102
            def viewSearchRelatedDocumentDialogWrapper(self, form_id, 
                                                       REQUEST=None, **kw):
1103 1104 1105
              """
                viewSearchRelatedDocumentDialog Wrapper
              """
1106 1107
              LOG('SelectionTool.viewSearchRelatedDocumentDialogWrapper, kw', 
                  0, kw)
1108
              return self.viewSearchRelatedDocumentDialog(
1109 1110 1111 1112
                                   method_count, form_id, 
                                   REQUEST=REQUEST, sub_index=sub_index, **kw)
            setattr(self.__class__, name, 
                    viewSearchRelatedDocumentDialogWrapper)
1113 1114 1115 1116 1117 1118 1119

            klass = aq_base(self).__class__
            if hasattr(klass, 'security'):
              from Products.ERP5Type import Permissions as ERP5Permissions
              klass.security.declareProtected(ERP5Permissions.View, name)
            else:
              # XXX security declaration always failed....
1120 1121
              LOG('WARNING ERP5Form SelectionTool, security not defined on',
                  0, klass.__name__)
1122 1123 1124 1125
            return getattr(self, name)
        else:
          return aq_base_name
      return aq_base_name
1126

Jean-Paul Smets's avatar
Jean-Paul Smets committed
1127
InitializeClass( SelectionTool )
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245

class TreeListLine:
  def __init__(self,object,is_pure_summary,depth, is_open,select_domain_dict,exception_uid_list):
    self.object=object
    self.is_pure_summary=is_pure_summary
    self.depth=depth
    self.is_open=is_open
    self.select_domain_dict=select_domain_dict
    self.exception_uid_list=exception_uid_list
  def getObject(self):
    return self.object
    
  def getIsPureSummary(self):
    return self.is_pure_summary
    
  def getDepth(self):
    return self.depth
    
  def getIsOpen(self):
    return self.is_open
  
  def getSelectDomainDict(self): 
    return self.select_domain_dict
    
  def getExceptionUidList(self):
    return self.exception_uid_list
  

def makeTreeList(here, form, root_dict, report_path, base_category, depth, unfolded_list, form_id, selection_name, report_depth, is_report_opened=1, sort_on = (('id', 'ASC'),)):
  """
    (object, is_pure_summary, depth, is_open, select_domain_dict)

    select_domain_dict is a dictionary of  associative list of (id, domain)
  """
  if type(report_path) is type('a'): report_path = report_path.split('/')

  portal_categories = getattr(form, 'portal_categories', None)
  portal_domains = getattr(form, 'portal_domains', None)
  portal_object = form.portal_url.getPortalObject()
  if len(report_path):
    base_category = report_path[0]

  if root_dict is None:
    root_dict = {}

  is_empty_level = 1
  while is_empty_level:
    if not root_dict.has_key(base_category):
      root = None
      if portal_categories is not None:
        if base_category in portal_categories.objectIds():
          if base_category == 'parent':
            # parent has a special treatment
            root = root_dict[base_category] = root_dict[None] = here
            report_path = report_path[1:]
          else:          
            root = root_dict[base_category] = root_dict[None] = portal_categories[base_category]
            report_path = report_path[1:]
      if root is None and portal_domains is not None:
        if base_category in portal_domains.objectIds():
          root = root_dict[base_category] = root_dict[None] = portal_domains[base_category]
          report_path = report_path[1:]
      if root is None:
        try:
          root = root_dict[None] = portal_object.unrestrictedTraverse(report_path)
        except KeyError:
          root = None
        report_path = ()
    else:
      root = root_dict[None] = root_dict[base_category]
      report_path = report_path[1:]
    is_empty_level = (root.objectCount() == 0) and (len(report_path) != 0)
    if is_empty_level: base_category = report_path[0]

  tree_list = []
  if root is None: return tree_list

  if base_category == 'parent':
    if hasattr(aq_base(root), 'objectValues'):
      # If this is a folder, try to browse the hierarchy
      for zo in root.searchFolder(sort_on=sort_on):
        o = zo.getObject()
        if o is not None:
          new_root_dict = root_dict.copy()
          new_root_dict[None] = new_root_dict[base_category] = o
          
          selection_domain = DomainSelection(domain_dict = new_root_dict)
          if (report_depth is not None and depth <= (report_depth - 1)) or o.getRelativeUrl() in unfolded_list:
            exception_uid_list = [] # Object we do not want to display
            
            for sub_zo in o.searchFolder(sort_on=sort_on):
              sub_o = sub_zo.getObject()
              if sub_o is not None and hasattr(aq_base(root), 'objectValues'):
                exception_uid_list.append(sub_o.getUid())          
            tree_list += [TreeListLine(o, 1, depth, 1, selection_domain, exception_uid_list)] # Summary (open)
            if is_report_opened :
              tree_list += [TreeListLine(o, 0, depth, 0, selection_domain, exception_uid_list)] # List (contents, closed, must be strict selection)
            tree_list += makeTreeList(here, form, new_root_dict, report_path, base_category, depth + 1, unfolded_list, form_id, selection_name, report_depth, is_report_opened=is_report_opened, sort_on=sort_on)
          else:
            tree_list += [TreeListLine(o, 1, depth, 0, selection_domain, ())] # Summary (closed)
  else:
    for o in root.objectValues():
      new_root_dict = root_dict.copy()
      new_root_dict[None] = new_root_dict[base_category] = o
      selection_domain = DomainSelection(domain_dict = new_root_dict)
      if (report_depth is not None and depth <= (report_depth - 1)) or o.getRelativeUrl() in unfolded_list:
        tree_list += [TreeListLine(o, 1, depth, 1, selection_domain, None)] # Summary (open)
        if is_report_opened :
          tree_list += [TreeListLine(o, 0, depth, 0, selection_domain, None)] # List (contents, closed, must be strict selection)
        tree_list += makeTreeList(here, form, new_root_dict, report_path, base_category, depth + 1, 
            unfolded_list, form_id, selection_name, report_depth, 
            is_report_opened=is_report_opened, sort_on=sort_on)
      else:

        tree_list += [TreeListLine(o, 1, depth, 0, selection_domain, None)] # Summary (closed)
   
  return tree_list