[7195] | 1 | ## $Id: breadcrumbs.py 9166 2012-09-06 16:50:17Z uli $ |
---|
| 2 | ## |
---|
| 3 | ## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann |
---|
| 4 | ## This program is free software; you can redistribute it and/or modify |
---|
| 5 | ## it under the terms of the GNU General Public License as published by |
---|
| 6 | ## the Free Software Foundation; either version 2 of the License, or |
---|
| 7 | ## (at your option) any later version. |
---|
| 8 | ## |
---|
| 9 | ## This program is distributed in the hope that it will be useful, |
---|
| 10 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 11 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 12 | ## GNU General Public License for more details. |
---|
| 13 | ## |
---|
| 14 | ## You should have received a copy of the GNU General Public License |
---|
| 15 | ## along with this program; if not, write to the Free Software |
---|
| 16 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 17 | ## |
---|
[4698] | 18 | """ Components to get breadcrumbs for any object. |
---|
| 19 | """ |
---|
| 20 | import grok |
---|
| 21 | from grokcore.view.interfaces import IGrokView |
---|
| 22 | from zope.component import getAdapter |
---|
| 23 | from zope.publisher.browser import TestRequest |
---|
| 24 | |
---|
[7811] | 25 | from waeup.kofa.interfaces import ( |
---|
[6918] | 26 | IConfigurationContainer, ISessionConfiguration) |
---|
[7811] | 27 | from waeup.kofa.interfaces import MessageFactory as _ |
---|
[9166] | 28 | from waeup.kofa.browser.interfaces import ( |
---|
| 29 | IBreadcrumb, IBreadcrumbIgnorable, IBreadcrumbContainer, IKofaObject, |
---|
| 30 | IUniversity, IFacultiesContainer, IUsersContainer, IDataCenter, IFaculty, |
---|
| 31 | IDepartment, ICourse, ICertificate, ICoursesContainer, ICertificateCourse, |
---|
| 32 | ICertificatesContainer, |
---|
| 33 | ) |
---|
[7811] | 34 | |
---|
[4698] | 35 | class Breadcrumb(grok.Adapter): |
---|
| 36 | """A most general breadcrumb generator. |
---|
| 37 | """ |
---|
| 38 | grok.provides(IBreadcrumb) |
---|
[9166] | 39 | grok.context(IKofaObject) |
---|
[4698] | 40 | grok.name('index') |
---|
| 41 | |
---|
| 42 | _title = None |
---|
| 43 | _parent = 0 |
---|
| 44 | _request = None |
---|
| 45 | parent_viewname = 'index' |
---|
| 46 | viewname = 'index' |
---|
[7811] | 47 | |
---|
[4698] | 48 | def __init__(self, context): |
---|
| 49 | """Turn a context into a breadcrumb. |
---|
| 50 | """ |
---|
| 51 | self.context = context |
---|
| 52 | |
---|
| 53 | @property |
---|
| 54 | def title(self): |
---|
| 55 | """Get a title for a context. |
---|
| 56 | """ |
---|
| 57 | if self._title is not None: |
---|
| 58 | return self._title |
---|
[4704] | 59 | if hasattr(self.context, 'title'): |
---|
| 60 | return self.context.title |
---|
[5864] | 61 | if hasattr(self.context, 'name'): |
---|
[7811] | 62 | return self.context.name |
---|
[4698] | 63 | return None |
---|
| 64 | |
---|
| 65 | @property |
---|
| 66 | def parent(self): |
---|
| 67 | """Get the contexts parent object and viewname or None. |
---|
| 68 | """ |
---|
| 69 | if self._parent is None: |
---|
| 70 | return None |
---|
| 71 | if self._parent is not 0: |
---|
| 72 | return (self._parent, self.parent_viewname) |
---|
[7008] | 73 | |
---|
[4698] | 74 | if self.viewname != 'index': |
---|
| 75 | self._parent = self.context |
---|
| 76 | else: |
---|
| 77 | site = grok.getSite() |
---|
| 78 | if self.context is not site: |
---|
| 79 | self._parent = getattr(self.context, '__parent__', None) |
---|
| 80 | |
---|
| 81 | if self._parent is not None: |
---|
| 82 | return (self._parent, self.parent_viewname) |
---|
| 83 | return None |
---|
| 84 | |
---|
[7008] | 85 | @property |
---|
| 86 | def target(self): |
---|
| 87 | return self.viewname |
---|
| 88 | |
---|
[4698] | 89 | class UniversityBreadcrumb(Breadcrumb): |
---|
| 90 | """A breadcrumb for university index pages. |
---|
| 91 | """ |
---|
[9166] | 92 | grok.context(IUniversity) |
---|
[7700] | 93 | title = _(u'Home') |
---|
[4698] | 94 | parent = None |
---|
| 95 | |
---|
[5393] | 96 | class PortalSettingsBreadcrumb(Breadcrumb): |
---|
| 97 | """A breadcrumb for the manage view of universities. |
---|
| 98 | |
---|
| 99 | Here we need a special `parent()` implementation, because the |
---|
| 100 | parent object is not a real parent (the University object has no |
---|
| 101 | valid parent in terms of breadcrumbs). Instead it is the |
---|
| 102 | ``administration`` view of the same context the ``manage`` page |
---|
| 103 | itself is bound to. |
---|
| 104 | """ |
---|
[9166] | 105 | grok.context(IUniversity) |
---|
[5393] | 106 | grok.name('manage') |
---|
[7700] | 107 | title = _(u'Portal Settings') |
---|
[5393] | 108 | |
---|
| 109 | @property |
---|
| 110 | def parent(self): |
---|
| 111 | """Return the 'administration' view of our context as parent. |
---|
| 112 | """ |
---|
| 113 | return (self.context, 'administration') |
---|
| 114 | |
---|
[7333] | 115 | class FacultiesContainerBreadcrumb(Breadcrumb): |
---|
[4698] | 116 | """A breadcrumb for faculty containers. |
---|
| 117 | """ |
---|
[9166] | 118 | grok.context(IFacultiesContainer) |
---|
[7700] | 119 | title = _(u'Academics') |
---|
[4698] | 120 | |
---|
| 121 | class AdministrationBreadcrumb(Breadcrumb): |
---|
| 122 | """A breadcrumb for administration areas of University instances. |
---|
| 123 | """ |
---|
[9166] | 124 | grok.context(IUniversity) |
---|
[4698] | 125 | grok.name('administration') |
---|
[7700] | 126 | title = _(u'Administration') |
---|
[4698] | 127 | viewname = 'administration' |
---|
| 128 | |
---|
[6907] | 129 | class ConfigurationContainerBreadcrumb(Breadcrumb): |
---|
| 130 | """A breadcrumb for the configuration container. |
---|
| 131 | """ |
---|
| 132 | grok.context(IConfigurationContainer) |
---|
[7700] | 133 | title = _(u'Portal Configuration') |
---|
[6907] | 134 | parent_viewname = 'administration' |
---|
| 135 | |
---|
[6918] | 136 | class SessionConfigurationBreadcrumb(Breadcrumb): |
---|
| 137 | """A breadcrumb for the configuration container. |
---|
| 138 | """ |
---|
| 139 | grok.context(ISessionConfiguration) |
---|
| 140 | title = u'Portal Session Configuration' |
---|
| 141 | |
---|
| 142 | @property |
---|
| 143 | def title(self): |
---|
| 144 | session_string = self.context.getSessionString() |
---|
| 145 | return 'Session %s' % session_string |
---|
| 146 | |
---|
[7172] | 147 | class UsersContainerBreadcrumb(Breadcrumb): |
---|
[4698] | 148 | """A breadcrumb for user containers. |
---|
| 149 | """ |
---|
[9166] | 150 | grok.context(IUsersContainer) |
---|
[7700] | 151 | title = _(u'Portal Users') |
---|
[4698] | 152 | parent_viewname = 'administration' |
---|
| 153 | |
---|
| 154 | class DataCenterBreadcrumb(Breadcrumb): |
---|
| 155 | """A breadcrumb for data centers. |
---|
[7811] | 156 | """ |
---|
[9166] | 157 | grok.context(IDataCenter) |
---|
[7700] | 158 | title = _(u'Data Center') |
---|
[4698] | 159 | parent_viewname = 'administration' |
---|
| 160 | |
---|
| 161 | class FacultyBreadcrumb(Breadcrumb): |
---|
| 162 | """A breadcrumb for faculties. |
---|
| 163 | """ |
---|
[9166] | 164 | grok.context(IFaculty) |
---|
[7811] | 165 | |
---|
[4698] | 166 | @property |
---|
| 167 | def title(self): |
---|
[5988] | 168 | return self.context.longtitle() |
---|
[4698] | 169 | |
---|
| 170 | class DepartmentBreadcrumb(FacultyBreadcrumb): |
---|
| 171 | """A breadcrumb for departments. |
---|
| 172 | """ |
---|
[9166] | 173 | grok.context(IDepartment) |
---|
[7811] | 174 | |
---|
[6008] | 175 | class CourseBreadcrumb(FacultyBreadcrumb): |
---|
| 176 | """A breadcrumb for courses. |
---|
| 177 | """ |
---|
[9166] | 178 | grok.context(ICourse) |
---|
[7811] | 179 | |
---|
[6008] | 180 | class CertificateBreadcrumb(FacultyBreadcrumb): |
---|
| 181 | """A breadcrumb for certificates. |
---|
| 182 | """ |
---|
[9166] | 183 | grok.context(ICertificate) |
---|
[4698] | 184 | |
---|
[7333] | 185 | class CoursesContainerBreadcrumb(Breadcrumb): |
---|
[4725] | 186 | """ We don't want course container breadcrumbs. |
---|
| 187 | """ |
---|
[9166] | 188 | grok.context(ICoursesContainer) |
---|
[4725] | 189 | grok.implements(IBreadcrumbIgnorable) |
---|
[4698] | 190 | |
---|
[7333] | 191 | class CertificatesContainerBreadcrumb(Breadcrumb): |
---|
[4725] | 192 | """ We don't want course container breadcrumbs. |
---|
| 193 | """ |
---|
[9166] | 194 | grok.context(ICertificatesContainer) |
---|
[4725] | 195 | grok.implements(IBreadcrumbIgnorable) |
---|
| 196 | |
---|
[4732] | 197 | class CertificateCourseBreadcrumb(Breadcrumb): |
---|
| 198 | """ We don't want course container breadcrumbs. |
---|
| 199 | """ |
---|
[9166] | 200 | grok.context(ICertificateCourse) |
---|
[4732] | 201 | @property |
---|
| 202 | def title(self): |
---|
[6008] | 203 | return self.context.longtitle() |
---|
[4732] | 204 | |
---|
[4698] | 205 | def getBreadcrumb(obj, viewname=None): |
---|
| 206 | """ Get a breadcrumb for an object and a viewname. |
---|
| 207 | |
---|
| 208 | If there is no breadcrumb defined for such a combination, a |
---|
| 209 | breadcrumb for the ``index`` view will be looked up. |
---|
| 210 | """ |
---|
| 211 | try: |
---|
| 212 | return getAdapter(obj, IBreadcrumb, name=viewname) |
---|
| 213 | except: |
---|
| 214 | pass |
---|
| 215 | return getAdapter(obj, IBreadcrumb, name='index') |
---|
| 216 | |
---|
| 217 | def getBreadcrumbList(obj, viewname): |
---|
| 218 | """Get an ordered list of breadcrumbs for an object and a viewname. |
---|
| 219 | |
---|
| 220 | Ignorables are excluded from the result. |
---|
| 221 | """ |
---|
| 222 | current = getBreadcrumb(obj, viewname) |
---|
| 223 | result = [current] |
---|
| 224 | while current.parent is not None: |
---|
| 225 | context, viewname = current.parent |
---|
| 226 | current = getBreadcrumb(context, viewname) |
---|
| 227 | if IBreadcrumbIgnorable.providedBy(current): |
---|
| 228 | # Ignore empty breadcrumbs... |
---|
| 229 | continue |
---|
| 230 | result.append(current) |
---|
| 231 | result.reverse() |
---|
| 232 | return result |
---|
| 233 | |
---|
| 234 | def getBreadcrumbListForView(view): |
---|
| 235 | """Get an ordered list of breadcrumbs a certain view. |
---|
| 236 | |
---|
| 237 | Ignorables are excluded from the result. |
---|
| 238 | """ |
---|
| 239 | context = getattr(view, 'context') |
---|
| 240 | viewname = getattr(view, '__name__') |
---|
| 241 | return getBreadcrumbList(context, viewname) |
---|
| 242 | |
---|
| 243 | class BreadcrumbContainer(grok.Adapter): |
---|
| 244 | """An adapter to adapt grok views to list of breadcrumbs. |
---|
| 245 | """ |
---|
| 246 | grok.context(IGrokView) |
---|
| 247 | grok.provides(IBreadcrumbContainer) |
---|
| 248 | |
---|
| 249 | _breadcrumbs = None |
---|
[7811] | 250 | |
---|
[4698] | 251 | def __init__(self, context): |
---|
| 252 | self.context = context |
---|
| 253 | self._breadcrumbs = getBreadcrumbListForView(self.context) |
---|
| 254 | |
---|
| 255 | def __iter__(self): |
---|
| 256 | """Allow iteration. |
---|
| 257 | """ |
---|
| 258 | return self._breadcrumbs.__iter__() |
---|
| 259 | |
---|
| 260 | def getList(self): |
---|
| 261 | """Get the (ordered) list of breadcrumbs liked to the context view. |
---|
| 262 | """ |
---|
| 263 | return self._breadcrumbs |
---|