source: products/quintagroup.referencedatagridfield/branches/plone4/quintagroup/referencedatagridfield/_field.py @ 2347

Last change on this file since 2347 was 2347, checked in by mylan, 14 years ago

Remove records with links to unexistent objects on getting data from the field

  • Property svn:eol-style set to native
File size: 6.9 KB
Line 
1#from Products.Archetypes import atapi
2import re
3import logging
4import urlparse
5from urllib import quote
6from types import ListType, TupleType
7
8from AccessControl import ClassSecurityInfo
9
10from Products.CMFCore.utils import getToolByName
11from Products.validation import validation #validators import baseValidators
12from Products.Archetypes.Field import encode, ReferenceField
13from Products.Archetypes.Registry import registerField, registerWidget
14
15from archetypes.referencebrowserwidget.widget import ReferenceBrowserWidget
16
17from Products.DataGridField.Column import Column
18from Products.DataGridField.DataGridField import DataGridField
19from Products.DataGridField.DataGridWidget import DataGridWidget
20
21from quintagroup.referencedatagridfield.columns import BlockColumn
22from quintagroup.referencedatagridfield.columns import HiddenColumn
23from quintagroup.referencedatagridfield.columns import StyledColumn
24
25# Logger object
26#logger = logging.getLogger('ReferenceDataGridField')
27#logger.debug("ReferenceDataGrid loading")
28
29class ReferenceDataGridWidget(DataGridWidget, ReferenceBrowserWidget):
30    _properties = ReferenceBrowserWidget._properties.copy()
31    _properties.update(DataGridWidget._properties.copy())
32    _properties.update({
33        'macro': "referencedatagridwidget",
34        'helper_css': ('datagridwidget.css','referencedatagridwidget.css'),
35        'helper_js': ('referencebrowser.js', 'datagridwidget.js', 'referencedatagridwidget.js'),
36        'force_close_on_insert': True,
37        'popup_name': 'datagridref_popup',
38        'columns': {
39            'title': StyledColumn("Title", trigger_key="default_title",
40                                  blur_handler="triggerTitleClass",
41                                  focus_handler="triggerOnFocusStyles",
42                                  class_no=None,
43                                  class_changed="changed-title-field",
44                                  class_not_changed="not-changed-title-field"),
45            'link': BlockColumn("Link", column_on_class="hidden-field",
46                                columns=['link','uid'], read_only=True),
47            'uid': HiddenColumn("UID", visible=False)},
48        })
49
50isURL = validation.validatorFor('isURL')
51
52class ReferenceDataGridField(DataGridField, ReferenceField):
53    _properties = ReferenceField._properties.copy()
54    _properties.update(DataGridField._properties.copy())
55    _properties.update({
56        'columns': ('title', 'link', 'uid'),
57        'widget': ReferenceDataGridWidget,
58        'multiValued' : True,
59        })
60
61    security = ClassSecurityInfo()
62
63    security.declarePrivate('isRemoteURL')
64    def isRemoteURL(self, url):
65        return isURL(url) == 1 and True or False
66
67    security.declarePrivate('set')
68    def set(self, instance, value, **kwargs):
69        """
70        The passed in object should be a records object, or a sequence of dictionaries
71        About link data:
72          * interpretations:
73            * if data not starts with standard protocol names (http://, ftp://) than
74              *uid* field data will be used as reference
75          * record removed if:
76            * no data;
77            * data contains UID of not existent object
78        About title:
79          * if there is UID of existent object and record has same title to the original
80            object - title will not be saved.
81        """
82        catalog = getToolByName(instance, "uid_catalog")
83
84        if value is None:
85            value = ()
86
87        if not isinstance(value, (ListType, TupleType)):
88            value = value,
89
90        result = []
91        for row in value:
92            data = {"title":"", "link":"", "uid":""}
93
94            uid = str(row.get("uid", "")).strip()
95            link = str(row.get("link", "")).strip()
96            title = str(row.get('title', ""))
97
98            if not title == "":
99                data["title"] = title
100
101            if link == "":
102                continue
103            elif self.isRemoteURL(link):
104                data["link"] = urlparse.urlunparse(urlparse.urlparse(link))
105            else:
106                if uid == '':
107                    continue
108
109                brains = catalog(UID=uid)
110                if len(brains) == 0:
111                    continue
112                # Found objects with pointed UID
113                brain = brains[0]
114                data["uid"] = uid
115                # Fix title for uid
116                if data['title'] == getattr(brain, "Title", ""):
117                    data['title'] = ""
118            result.append(data)
119
120        DataGridField.set(self, instance, result, **kwargs)
121
122        uids = [r['uid'] for r in result if r['uid']!=""]
123        ReferenceField.set(self, instance, uids, **kwargs)
124       
125    security.declarePrivate('get')
126    def get(self, instance, **kwargs):
127        """ Return DataGridField value
128
129        Value is a list object of rows.
130        Row id dictionary object with standard 'link', 'uid' and 'title' keys
131        plus extra informal *url* and *url_title* keys
132        """
133        purl = getToolByName(instance, "portal_url")
134        # use portal_catalog to hide protected object for the logged in user.
135        catalog = getToolByName(instance, "portal_catalog")
136
137        result = []
138        uids = {}
139        rows = DataGridField.get(self, instance, **kwargs)
140        for row in rows:
141            uid = row.get("uid","")
142            link = row.get("link","")
143            title = row.get("title","")
144            result.append({
145                # DataGridField row data
146                "uid": uid, "link": link, "title": title,
147                # View data
148                "url": "", "default_title": None})
149            data = result[-1]
150            # Process remote URL and collect UIDs
151            if link:
152                data["url"] = quote(link, safe='?$#@/:=+;$,&%')
153                data["default_title"] = link
154                # if title not set for remote url - set it equals to url
155                if not data["title"]:
156                    data["title"] = data["default_title"]
157            else:
158                uids[uid] = data
159        # Process UIDs
160        if uids:
161            brains = catalog(UID=uids.keys())
162            for b in brains:
163                data = uids[b.UID]
164                data["url"] = b.getURL()
165                data["link"] = b.getPath()
166                data["default_title"] = self._brains_title_or_id(b, instance)
167                # If title not set - get it from the brain
168                if not data["title"]:
169                    data["title"] = data["default_title"]
170            # Remove records with links to unexistent objects
171            del_uids = set(uids.keys()) - set([b.UID for b in brains])
172            result = filter(lambda r: not r["uid"] in del_uids, result)
173
174        return result
175
176
177registerWidget(
178    ReferenceDataGridWidget,
179    title='DataGrid Reference',
180    used_for=('quintagroup.referencedatagridfield.ReferenceDataGridField',)
181    )
182
183registerField(
184    ReferenceDataGridField,
185    title="DataGrid Reference Field",
186    description=("Reference DataGrid field.")
187    )
Note: See TracBrowser for help on using the repository browser.