[REF] purchase: search view of purchase order and form view of merge order wizard
[odoo/odoo.git] / addons / document / nodes.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #    
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
19 #
20 ##############################################################################
21
22 import base64
23
24 from osv import osv, fields
25 from osv.orm import except_orm
26 import urlparse
27 import pooler
28 from tools.safe_eval import safe_eval
29
30 import os
31 import time
32
33 #
34 # An object that represent an uri
35 #   path: the uri of the object
36 #   content: the Content it belongs to (_print.pdf)
37 #   type: content or collection
38 #       content: objct = res.partner
39 #       collection: object = directory, object2 = res.partner
40 #       file: objct = ir.attachement
41 #   root: if we are at the first directory of a ressource
42 #
43
44 def get_node_context(cr, uid, context):
45     return node_context(cr,uid,context)
46
47 class node_context(object):
48     """ This is the root node, representing access to some particular
49         context """
50     cached_roots = {}
51
52     def __init__(self, cr, uid, context=None):        
53         self.dbname = cr.dbname
54         self.uid = uid
55         self.context = context
56         self._dirobj = pooler.get_pool(cr.dbname).get('document.directory')
57         assert self._dirobj
58         self.rootdir = False #self._dirobj._get_root_directory(cr,uid,context)
59
60     def get_uri(self, cr,  uri):
61         """ Although this fn passes back to doc.dir, it is needed since
62         it is a potential caching point """            
63         (ndir, duri) =  self._dirobj._locate_child(cr,self.uid, self.rootdir,uri, None, self)          
64         while duri:                    
65             ndir = ndir.child(cr, duri[0])            
66             if not ndir:
67                 return False            
68             duri = duri[1:] 
69         return ndir
70
71
72 class node_database():
73     """ A node representing the database directory
74         Useless?
75         """
76     def __init__(self,ncontext):
77         self.nctx = ncontext
78
79
80
81
82 class node_class(object):
83     """ this is a superclass for our inodes
84         It is an API for all code that wants to access the document files. 
85         Nodes have attributes which contain usual file properties
86         """
87     our_type = 'baseclass'
88     def __init__(self, path, parent, context):
89         assert isinstance(context,node_context)
90         assert (not parent ) or isinstance(parent,node_class)
91         self.path = path
92         self.context = context
93         self.type=self.our_type
94         self.parent = parent
95         self.mimetype = 'application/octet-stream'
96         self.create_date = None
97         self.write_date = None
98         self.content_length = 0
99         # dynamic context:
100         self.dctx = {}
101         if parent:
102             self.dctx = parent.dctx.copy()
103         self.displayname = 'Object'
104     
105     def full_path(self):
106         """ Return the components of the full path for some
107             node. 
108             The returned list only contains the names of nodes.
109         """
110         if self.parent:
111             s = self.parent.full_path()
112         else:
113             s = []
114         if isinstance(self.path,list):
115             s+=self.path
116         else:
117             s.append(self.path)
118         return s #map(lambda x: '/' +x, s)
119
120     def children(self, cr):
121         print "node_class.children()"
122         return [] #stub
123
124     def child(self,cr, name):
125         print "node_class.child()"
126         return None
127
128     def path_get(self):
129         print "node_class.path_get()"
130         return False
131     
132     def get_data(self,cr):
133         raise TypeError('no data for %s'% self.type)
134
135     def _get_storage(self,cr):
136         raise RuntimeError("no storage for base class")
137
138     def get_etag(self,cr):
139         """ Get a tag, unique per object + modification.
140     
141             see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
142         return self._get_ttag(cr) + ':' + self._get_wtag(cr)
143
144     def _get_wtag(self,cr):
145         """ Return the modification time as a unique, compact string """
146         if self.write_date:
147             wtime = time.mktime(time.strptime(self.write_date,'%Y-%m-%d %H:%M:%S'))
148         else: wtime = time.time()
149         return str(wtime)
150     
151     def _get_ttag(self,cr):
152         """ Get a unique tag for this type/id of object.
153             Must be overriden, so that each node is uniquely identified.
154         """
155         print "node_class.get_ttag()",self
156         raise RuntimeError("get_etag stub()")
157     
158     def get_dav_props(self, cr):
159         """ If this class has special behaviour for GroupDAV etc, export
160         its capabilities """
161         return {}
162
163     def get_dav_eprop(self,cr,ns,prop):
164         return None
165
166 class node_dir(node_class):
167     our_type = 'collection'
168     def __init__(self,path, parent, context, dirr, dctx=None):
169         super(node_dir,self).__init__(path, parent,context)
170         self.dir_id = dirr and dirr.id or False
171         #todo: more info from dirr
172         self.mimetype = 'application/x-directory'
173             # 'httpd/unix-directory'
174         self.create_date = dirr and dirr.create_date or False
175         self.domain = dirr and dirr.domain or []
176         self.res_model = dirr and dirr.ressource_type_id and dirr.ressource_type_id.model or False
177         # TODO: the write date should be MAX(file.write)..
178         self.write_date = dirr and (dirr.write_date or dirr.create_date) or False
179         self.content_length = 0
180         if dctx:
181             self.dctx.update(dctx)
182         dc2 = self.context.context
183         dc2.update(self.dctx)
184         dc2['dir_id'] = self.dir_id
185         self.displayname = dirr and dirr.name or False
186         if dirr and dirr.dctx_ids:
187             for dfld in dirr.dctx_ids:
188                 try:
189                     self.dctx['dctx_' + dfld.field] = safe_eval(dfld.expr,dc2)
190                 except Exception,e:
191                     print "Cannot eval %s" % dfld.expr
192                     print e
193                     pass
194
195     def children(self,cr):
196         return self._child_get(cr) + self._file_get(cr)
197
198     def child(self,cr, name):        
199         res = self._child_get(cr,name)
200         if res:
201             return res[0]
202         res = self._file_get(cr,name)
203         if res:
204             return res[0]
205         return None
206
207     def _file_get(self,cr, nodename=False):
208         res = []
209         cntobj = self.context._dirobj.pool.get('document.directory.content')
210         uid = self.context.uid
211         ctx = self.context.context.copy()
212         ctx.update(self.dctx)
213         where = [('directory_id','=',self.dir_id) ]
214         ids = cntobj.search(cr, uid, where, context=ctx)
215         for content in cntobj.browse(cr, uid, ids, context=ctx):
216             res3 = cntobj._file_get(cr, self, nodename, content)
217             if res3:
218                 res.extend(res3)
219
220         return res
221
222     def get_dav_props(self, cr):
223         res = {}
224         cntobj = self.context._dirobj.pool.get('document.directory.content')
225         uid = self.context.uid
226         ctx = self.context.context.copy()
227         ctx.update(self.dctx)
228         where = [('directory_id','=',self.dir_id) ]
229         ids = cntobj.search(cr,uid,where,context=ctx)
230         for content in cntobj.browse(cr,uid,ids,context=ctx):
231             if content.extension == '.ics': # FIXME: call the content class!
232                 res['http://groupdav.org/'] = ('resourcetype',)
233                 break
234         return res
235
236     def get_dav_eprop(self,cr,ns,prop):
237         if ns != 'http://groupdav.org/' or prop != 'resourcetype':
238             print "Who asked for %s:%s?" % (ns,prop)
239             return None
240         res = {}
241         cntobj = self.context._dirobj.pool.get('document.directory.content')
242         uid = self.context.uid
243         ctx = self.context.context.copy()
244         ctx.update(self.dctx)
245         where = [('directory_id','=',self.dir_id) ]
246         ids = cntobj.search(cr,uid,where,context=ctx)
247         for content in cntobj.browse(cr,uid,ids,context=ctx):
248             if content.extension == '.ics': # FIXME: call the content class!
249                 return ('vevent-collection','http://groupdav.org/')
250         return None
251
252     def _child_get(self,cr,name = None):
253         dirobj = self.context._dirobj
254         uid = self.context.uid
255         ctx = self.context.context.copy()
256         ctx.update(self.dctx)
257         where = [('parent_id','=',self.dir_id) ]
258         if name:
259             where.append(('name','=',name))               
260
261         ids = dirobj.search(cr, uid, where + [('ressource_parent_type_id','=',False)],context=ctx)
262         res = []
263         if ids:
264             for dirr in dirobj.browse(cr,uid,ids,context=ctx):
265                 if dirr.type == 'directory':
266                     res.append(node_dir(dirr.name,self,self.context,dirr))
267                 elif dirr.type == 'ressource':
268                     res.append(node_res_dir(dirr.name,self,self.context,dirr))
269         
270         fil_obj=dirobj.pool.get('ir.attachment')
271         #where2 = where # + [('res_model', '=', None)]
272         ids = fil_obj.search(cr,uid,where,context=ctx)
273         if ids:
274             for fil in fil_obj.browse(cr,uid,ids,context=ctx):
275                 res.append(node_file(fil.name,self,self.context,fil))
276     
277         return res
278     
279     def create_child(self,cr,path,data):
280         """ API function to create a child file object and node
281             Return the node_* created
282         """
283         dirobj = self.context._dirobj
284         uid = self.context.uid
285         ctx = self.context.context.copy()
286         ctx.update(self.dctx)
287         fil_obj=dirobj.pool.get('ir.attachment')
288         val = {
289             'name': path,
290             'datas_fname': path,
291             'parent_id': self.dir_id,
292             # Datas are not set here
293         }
294
295         fil_id = fil_obj.create(cr,uid, val, context=ctx)
296         fil = fil_obj.browse(cr,uid,fil_id,context=ctx)
297         fnode = node_file(path,self,self.context,fil)
298         fnode.set_data(cr,data,fil)
299         return fnode
300     
301     def _get_ttag(self,cr):
302         return 'dir-%d' % self.dir_id
303
304 class node_res_dir(node_class):
305     """ A special sibling to node_dir, which does only contain dynamically
306         created folders foreach resource in the foreign model.
307         All folders should be of type node_res_obj and merely behave like
308         node_dirs (with limited domain).
309     """
310     our_type = 'collection'
311     def __init__(self,path, parent, context, dirr, dctx=None ):
312         super(node_res_dir,self).__init__(path, parent,context)
313         self.dir_id = dirr.id
314         #todo: more info from dirr
315         self.mimetype = 'application/x-directory'
316                         # 'httpd/unix-directory'
317         self.create_date = dirr.create_date
318         # TODO: the write date should be MAX(file.write)..
319         self.write_date = dirr.write_date or dirr.create_date
320         self.content_length = 0
321         self.res_model = dirr.ressource_type_id and dirr.ressource_type_id.model or False
322         self.resm_id = dirr.ressource_id
323         self.namefield = dirr.resource_field or 'name'
324         self.displayname = dirr.name
325         # Important: the domain is evaluated using the *parent* dctx!        
326         self.domain = dirr.domain
327         self.ressource_tree = dirr.ressource_tree
328         # and then, we add our own vars in the dctx:
329         if dctx:
330             self.dctx.update(dctx)
331     
332         # and then, we prepare a dctx dict, for deferred evaluation:
333         self.dctx_dict = {}
334         for dfld in dirr.dctx_ids:
335             self.dctx_dict['dctx_' + dfld.field] = dfld.expr
336
337     def children(self,cr):
338         return self._child_get(cr)
339
340     def child(self,cr, name):        
341         res = self._child_get(cr,name)
342         if res:
343             return res[0]
344         return None
345
346     def _child_get(self,cr,name = None):
347         """ return virtual children of resource, based on the
348             foreign object.
349         
350             Note that many objects use NULL for a name, so we should
351             better call the name_search(),name_get() set of methods
352         """
353         obj = self.context._dirobj.pool.get(self.res_model)
354         if not obj:
355             print "couldn't find model", self.res_model
356             return []
357         dirobj = self.context._dirobj
358         uid = self.context.uid
359         ctx = self.context.context.copy()
360         ctx.update(self.dctx)
361         where = []
362         if self.domain:
363             where += safe_eval(self.domain, self.dctx)
364         if self.resm_id:
365             where.append(('id','=',self.resm_id))
366     
367         if name:
368             where.append((self.namefield,'=',name))
369         
370         # print "Where clause for %s" % self.res_model, where
371         if self.ressource_tree:
372             object2 = False
373             if self.resm_id:
374                 object2 = dirobj.pool.get(self.res_model).browse(cr, uid, self.resm_id) or False                
375             if obj._parent_name in obj.fields_get(cr, uid):                    
376                 where.append((obj._parent_name,'=',object2 and object2.id or False))
377                 
378         resids = obj.search(cr,uid, where, context=ctx)
379         res = []        
380         for bo in obj.browse(cr,uid,resids,context=ctx):
381             if not bo:
382                 continue
383             name = getattr(bo,self.namefield)
384             if not name:
385                 continue
386                 # Yes! we can't do better but skip nameless records.     
387              
388             res.append(node_res_obj(name, self.dir_id, self, self.context, self.res_model, bo))
389         return res
390
391     def _get_ttag(self,cr):
392         return 'rdir-%d' % self.dir_id
393
394 class node_res_obj(node_class):
395     """ A special sibling to node_dir, which does only contain dynamically
396         created folders foreach resource in the foreign model.
397         All folders should be of type node_res_obj and merely behave like
398         node_dirs (with limited domain).
399         """
400     our_type = 'collection'
401     def __init__(self, path, dir_id, parent, context, res_model, res_bo, res_id = None):
402         super(node_res_obj,self).__init__(path, parent,context)
403         assert parent
404         #todo: more info from dirr            
405         self.dir_id = dir_id
406         self.mimetype = 'application/x-directory'
407                         # 'httpd/unix-directory'
408         self.create_date = parent.create_date
409         # TODO: the write date should be MAX(file.write)..
410         self.write_date = parent.write_date
411         self.content_length = 0
412         self.res_model = res_model
413         self.domain = parent.domain
414         self.displayname = path  
415         self.dctx_dict = parent.dctx_dict      
416         if res_bo:            
417             self.res_id = res_bo.id            
418             dc2 = self.context.context
419             dc2.update(self.dctx)
420             dc2['res_model'] = res_model
421             dc2['res_id'] = res_bo.id
422             dc2['this'] = res_bo            
423             for fld,expr in self.dctx_dict.items():
424                 try:
425                     self.dctx[fld] = safe_eval(expr,dc2)
426                 except Exception,e:
427                     print "Cannot eval %s for %s" % (expr, fld)
428                     print e
429                     pass
430         else:
431             self.res_id = res_id
432
433     def children(self,cr):        
434         return self._child_get(cr) + self._file_get(cr)
435
436     def child(self,cr, name):            
437         res = self._child_get(cr,name)                
438         if res:
439             return res[0]
440         res = self._file_get(cr,name)
441         if res:
442             return res[0]
443         return None
444
445     def _file_get(self,cr, nodename=False):
446         res = []
447         cntobj = self.context._dirobj.pool.get('document.directory.content')
448         uid = self.context.uid
449         ctx = self.context.context.copy()
450         ctx.update(self.dctx)
451         where = [('directory_id','=',self.dir_id) ]
452         #if self.domain:
453         #    where.extend(self.domain)
454         # print "res_obj file_get clause", where
455         ids = cntobj.search(cr,uid,where,context=ctx)
456         for content in cntobj.browse(cr,uid,ids,context=ctx):
457             res3 = cntobj._file_get(cr,self,nodename,content, context=ctx)
458             if res3:
459                 res.extend(res3)
460
461         return res
462
463     def get_dav_props(self, cr):
464         res = {}
465         cntobj = self.context._dirobj.pool.get('document.directory.content')
466         uid = self.context.uid
467         ctx = self.context.context.copy()
468         ctx.update(self.dctx)
469         where = [('directory_id','=',self.dir_id) ]
470         ids = cntobj.search(cr,uid,where,context=ctx)
471         for content in cntobj.browse(cr,uid,ids,context=ctx):
472             if content.extension == '.ics': # FIXME: call the content class!
473                 res['http://groupdav.org/'] = ('resourcetype',)
474         return res
475
476     def get_dav_eprop(self,cr,ns,prop):
477         if ns != 'http://groupdav.org/' or prop != 'resourcetype':
478             print "Who asked for %s:%s?" % (ns,prop)
479             return None
480         res = {}
481         cntobj = self.context._dirobj.pool.get('document.directory.content')
482         uid = self.context.uid
483         ctx = self.context.context.copy()
484         ctx.update(self.dctx)
485         where = [('directory_id','=',self.dir_id) ]
486         ids = cntobj.search(cr,uid,where,context=ctx)
487         for content in cntobj.browse(cr,uid,ids,context=ctx):
488             if content.extension == '.ics': # FIXME: call the content class!
489                 return ('vevent-collection','http://groupdav.org/')
490         return None
491
492     def _child_get(self,cr,name = None):        
493         dirobj = self.context._dirobj
494         uid = self.context.uid
495         ctx = self.context.context.copy()
496         ctx.update(self.dctx)
497         directory = dirobj.browse(cr, uid, self.dir_id)
498         obj = dirobj.pool.get(self.res_model)
499         where = []
500         res = []        
501         if name:
502             where.append(('name','=',name))   
503        
504         # Directory Structure display in tree structure
505         if self.res_id and directory.ressource_tree:  
506             where1 = []                 
507             if obj._parent_name in obj.fields_get(cr, uid):                    
508                 where1 = where + [(obj._parent_name, '=', self.res_id)]
509             resids = obj.search(cr,uid, where1, context=ctx)                        
510             for bo in obj.browse(cr,uid,resids,context=ctx):
511                 namefield = directory.resource_field or 'name'
512                 if not bo:
513                     continue
514                 res_name = getattr(bo, namefield)
515                 if not res_name:
516                     continue                
517                 res.append(node_res_obj(res_name, self.dir_id, self, self.context, self.res_model, res_bo = bo))        
518         
519         
520         where2 = where + [('parent_id','=',self.dir_id) ]        
521         ids = dirobj.search(cr, uid, where2, context=ctx) 
522         for dirr in dirobj.browse(cr, uid, ids, context=ctx):
523             if dirr.type == 'directory':
524                 res.append(node_res_obj(dirr.name, dirr.id, self, self.context, self.res_model, res_bo = None, res_id = self.res_id))
525             elif dirr.type == 'ressource':
526                 # child resources can be controlled by properly set dctx
527                 res.append(node_res_dir(dirr.name,self,self.context, dirr, {'active_id': self.res_id}))
528         
529
530        
531         
532         fil_obj = dirobj.pool.get('ir.attachment')
533         where3 = where2  + [('res_model', '=', self.res_model), ('res_id','=',self.res_id)]
534         # print "where clause for dir_obj", where2
535         ids = fil_obj.search(cr, uid, where3, context=ctx)
536         if ids:
537             for fil in fil_obj.browse(cr, uid, ids, context=ctx):
538                 res.append(node_file(fil.name, self, self.context, fil))
539     
540         
541         # Get Child Ressource Directories                
542         if directory.ressource_type_id and directory.ressource_type_id.id:              
543             where4 = where + [('ressource_parent_type_id','=',directory.ressource_type_id.id)]            
544             where5 = where4 + [('ressource_id','=',0)]
545             dirids = dirobj.search(cr,uid, where5)            
546             where5 = where4 + [('ressource_id','=',self.res_id)]
547             dirids = dirids + dirobj.search(cr,uid, where5)            
548             for dirr in dirobj.browse(cr, uid, dirids, context=ctx):
549                 if dirr.type == 'directory' and not dirr.parent_id:
550                     res.append(node_res_obj(dirr.name, dirr.id, self, self.context, self.res_model, res_bo = None, res_id = self.res_id))
551                 if dirr.type == 'ressource':
552                     res.append(node_res_dir(dirr.name, self, self.context, dirr, {'active_id': self.res_id}))                
553         return res
554     
555     def create_child(self,cr,path,data):
556         """ API function to create a child file object and node
557             Return the node_* created
558         """
559         dirobj = self.context._dirobj
560         uid = self.context.uid
561         ctx = self.context.context.copy()
562         ctx.update(self.dctx)
563         fil_obj=dirobj.pool.get('ir.attachment')
564         val = {
565             'name': path,
566             'datas_fname': path,
567             'parent_id': self.dir_id,
568             'res_model': self.res_model,
569             'res_id': self.res_id,
570             # Datas are not set here
571         }
572
573         fil_id = fil_obj.create(cr,uid, val, context=ctx)
574         fil = fil_obj.browse(cr,uid,fil_id,context=ctx)
575         fnode = node_file(path,self,self.context,fil)
576         fnode.set_data(cr,data,fil)
577         return fnode
578
579     def _get_ttag(self,cr):
580         return 'rodir-%d-%d' % (self.dir_id,self.res_id)
581
582 class node_file(node_class):
583     our_type = 'file'
584     def __init__(self,path, parent, context, fil):
585         super(node_file,self).__init__(path, parent,context)
586         self.file_id = fil.id
587         #todo: more info from ir_attachment
588         if fil.file_type and '/' in fil.file_type:
589             self.mimetype = fil.file_type
590         self.create_date = fil.create_date
591         self.write_date = fil.write_date or fil.create_date
592         self.content_length = fil.file_size
593         self.displayname = fil.name
594         
595         # This only propagates the problem to get_data. Better
596         # fix those files to point to the root dir.
597         if fil.parent_id:
598             self.storage_id = fil.parent_id.storage_id.id
599         else:
600             self.storage_id = None                       
601             
602     
603     def get_data(self, cr, fil_obj = None):
604         """ Retrieve the data for some file. 
605             fil_obj may optionally be specified, and should be a browse object
606             for the file. This is useful when the caller has already initiated
607             the browse object. """
608         # this is where storage kicks in..
609         stor = self.storage_id
610         if not stor:
611             data_obj = self.context._dirobj.pool.get('ir.model.data')
612             data_id = data_obj._get_id(cr, self.context.uid, 'document', 'storage_db')
613             if data_id:
614                 stor = data_obj.browse(cr, self.context.uid, data_id, context=self.context.context).res_id 
615         assert stor
616         stobj = self.context._dirobj.pool.get('document.storage')
617         return stobj.get_data(cr,self.context.uid,stor, self,self.context.context, fil_obj)
618
619     def get_data_len(self, cr, fil_obj = None):
620         # TODO: verify with the storage object!
621         bin_size = self.context.context.get('bin_size', False)
622         if bin_size and not self.content_length:
623             self.content_length = fil_obj.db_datas
624         return self.content_length
625
626     def set_data(self, cr, data, fil_obj = None):
627         """ Store data at some file. 
628             fil_obj may optionally be specified, and should be a browse object
629             for the file. This is useful when the caller has already initiated
630             the browse object. """
631         # this is where storage kicks in..
632         stor = self.storage_id
633         assert stor
634         stobj = self.context._dirobj.pool.get('document.storage')
635         return stobj.set_data(cr,self.context.uid,stor, self, data, self.context.context, fil_obj)
636
637     def _get_ttag(self,cr):
638         return 'file-%d' % self.file_id
639
640 class node_content(node_class):
641     our_type = 'content'
642     def __init__(self,path, parent, context, cnt, dctx = None, act_id=None):
643         super(node_content,self).__init__(path, parent,context)
644         self.cnt_id = cnt.id
645         self.create_date = False
646         self.write_date = False
647         self.content_length = False
648         self.extension = cnt.extension
649         self.report_id = cnt.report_id and cnt.report_id.id
650         #self.mimetype = cnt.extension.
651         self.displayname = path
652         if dctx:
653            self.dctx.update(dctx)
654         self.act_id = act_id
655     
656     def fill_fields(self,cr,dctx = None):
657         """ Try to read the object and fill missing fields, like mimetype,
658             dates etc.
659             This function must be different from the constructor, because
660             it uses the db cursor.
661         """
662         
663         cr.execute('SELECT DISTINCT mimetype FROM document_directory_content_type WHERE active AND code = %s;',
664                 (self.extension,))
665         res = cr.fetchall()
666         if res and res[0][0]:
667             self.mimetype = res[0][0]
668
669
670     def get_data(self, cr, fil_obj = None):
671         cntobj = self.context._dirobj.pool.get('document.directory.content')
672         ctx = self.context.context.copy()
673         ctx.update(self.dctx)
674         data = cntobj.process_read(cr,self.context.uid,self,ctx)
675         if data:
676             self.content_length = len(data)
677         return data
678
679     def get_data_len(self, cr, fil_obj = None):
680         if not self.content_length:
681             self.get_data(cr,fil_obj)
682         return self.content_length
683
684     def set_data(self, cr, data, fil_obj = None):
685         cntobj = self.context._dirobj.pool.get('document.directory.content')
686         ctx = self.context.context.copy()
687         ctx.update(self.dctx)
688         return cntobj.process_write(cr,self.context.uid,self, data,ctx)
689
690     def _get_ttag(self,cr):
691         return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '')
692
693 class old_class():
694     # the old code, remove..
695     def __init__(self, cr, uid, path, object, object2=False, context={}, content=False, type='collection', root=False):
696         self.cr = cr
697     def _file_get(self, nodename=False):
698         if not self.object:
699             return []
700         pool = pooler.get_pool(self.cr.dbname)
701         fobj = pool.get('ir.attachment')
702         res2 = []
703         where = []
704         if self.object2:
705             where.append( ('res_model','=',self.object2._name) )
706             where.append( ('res_id','=',self.object2.id) )
707         else:
708             where.append( ('parent_id','=',self.object.id) )
709             where.append( ('res_id','=',False) )
710         if nodename:
711             where.append( (fobj._rec_name,'=',nodename) )
712         for content in self.object.content_ids:
713             res3 = content._table._file_get(self,nodename,content)
714             if res3:
715                 res2.extend(res3)
716
717         ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ])
718         if self.object and self.root and (self.object.type=='ressource'):
719             ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ])
720         res = fobj.browse(self.cr, self.uid, ids, context=self.context)
721         return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=False), res) + res2
722     
723     def get_translation(self,value,lang):
724         # Must go, it works on arbitrary models and could be ambiguous.
725         result = value
726         pool = pooler.get_pool(self.cr.dbname)        
727         translation_ids = pool.get('ir.translation').search(self.cr, self.uid, [('value','=',value),('lang','=',lang),('type','=','model')])
728         if len(translation_ids):
729             tran_id = translation_ids[0]
730             translation = pool.get('ir.translation').read(self.cr, self.uid, tran_id, ['res_id','name'])
731             res_model,field_name = tuple(translation['name'].split(','))  
732             res_id = translation['res_id']        
733             res = pool.get(res_model).read(self.cr, self.uid, res_id, [field_name])
734             if res:
735                 result = res[field_name]
736         return result 
737     
738     def directory_list_for_child(self,nodename,parent=False):
739         pool = pooler.get_pool(self.cr.dbname)
740         where = []
741         if nodename:
742             nodename = self.get_translation(nodename, self.context['lang'])
743             where.append(('name','=',nodename))
744         if (self.object and self.object.type=='directory') or not self.object2:
745             where.append(('parent_id','=',self.object and self.object.id or False))
746         else:
747             where.append(('parent_id','=',False))
748         if self.object:
749             where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id))
750         else:
751             where.append(('ressource_parent_type_id','=',False))
752
753         ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)])
754         if self.object2:
755             ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)])        
756         res = pool.get('document.directory').browse(self.cr, self.uid, ids, self.context)
757         return res
758
759     def _child_get(self, nodename=False):
760         if self.type not in ('collection','database'):
761             return []
762         res = self.directory_list_for_child(nodename)
763         result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, context=self.context, root=self.root), res)
764         if self.type=='database':
765             pool = pooler.get_pool(self.cr.dbname)
766             fobj = pool.get('ir.attachment')
767             vargs = [('parent_id','=',False),('res_id','=',False)]
768             if nodename:
769                 vargs.append((fobj._rec_name,'=',nodename))
770             file_ids=fobj.search(self.cr,self.uid,vargs)
771
772             res = fobj.browse(self.cr, self.uid, file_ids, context=self.context)
773             result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=self.root), res)
774         if self.type=='collection' and self.object.type=="ressource":
775             where = self.object.domain and eval(self.object.domain, {'active_id':self.root, 'uid':self.uid}) or []
776             pool = pooler.get_pool(self.cr.dbname)
777             obj = pool.get(self.object.ressource_type_id.model)
778             _dirname_field = obj._rec_name
779             if len(obj.fields_get(self.cr, self.uid, ['dirname'])):
780                 _dirname_field = 'dirname'
781
782             name_for = obj._name.split('.')[-1]
783             if nodename  and nodename.find(name_for) == 0  :
784                 id = int(nodename.replace(name_for,''))
785                 where.append(('id','=',id))
786             elif nodename:
787                 if nodename.find('__') :
788                     nodename=nodename.replace('__','/')
789                 for invalid in INVALID_CHARS:
790                     if nodename.find(INVALID_CHARS[invalid]) :
791                         nodename=nodename.replace(INVALID_CHARS[invalid],invalid)
792                 nodename = self.get_translation(nodename, self.context['lang'])
793                 where.append((_dirname_field,'=',nodename))
794
795             if self.object.ressource_tree:
796                 if obj._parent_name in obj.fields_get(self.cr,self.uid):
797                     where.append((obj._parent_name,'=',self.object2 and self.object2.id or False))
798                     ids = obj.search(self.cr, self.uid, where)
799                     res = obj.browse(self.cr, self.uid, ids,self.context)
800                     result+= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res)
801                     return result
802                 else :
803                     if self.object2:
804                         return result
805             else:
806                 if self.object2:
807                     return result
808
809             
810             ids = obj.search(self.cr, self.uid, where)
811             res = obj.browse(self.cr, self.uid, ids,self.context)
812             for r in res:
813                 if len(obj.fields_get(self.cr, self.uid, [_dirname_field])):
814                     r.name = eval('r.'+_dirname_field)
815                 else:
816                     r.name = False
817                 if not r.name:
818                     r.name = name_for + '%d'%r.id
819                 for invalid in INVALID_CHARS:
820                     if r.name.find(invalid) :
821                         r.name = r.name.replace(invalid,INVALID_CHARS[invalid])
822             result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res)
823             if result2:
824                 if self.object.ressource_tree:
825                     result += result2
826                 else:
827                     result = result2
828         return result
829
830
831     def path_get(self):
832         path = self.path
833         if self.path[0]=='/':
834             path = self.path[1:]
835         return path