~azzar1/unity/add-show-desktop-key

1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
1
# IVLE - Informatics Virtual Learning Environment
2
# Copyright (C) 2007-2009 The University of Melbourne
3
#
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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18
# Author: Nick Chadwick
19
20
import inspect
21
import os.path
1099.1.120 by William Grant
Move the login machinery to the new framework.
22
import urllib
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
23
24
import genshi.template
25
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
26
from ivle.webapp.media import media_url
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
27
from ivle.webapp.core import Plugin as CorePlugin
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
28
from ivle.webapp.base.views import BaseView
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
29
from ivle.webapp.base.plugins import ViewPlugin, OverlayPlugin
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
30
from ivle.webapp.errors import HTTPError, Unauthorized
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
31
32
class XHTMLView(BaseView):
33
    """
34
    A view which provides a base class for views which need to return XHTML
35
    It is expected that apps which use this view will be written using Genshi
36
    templates.
37
    """
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
38
39
    template = 'template.html'
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
40
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
41
    plugin_scripts = {}
42
    plugin_styles = {}
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
43
    scripts_init = []
44
1099.1.129 by William Grant
Allow XHTML views to specify that they cannot have overlays.
45
    allow_overlays = True
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
46
    overlay_blacklist = []
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
47
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
48
    def __init__(self, req, **kwargs):
49
        for key in kwargs:
1099.1.46 by Nick Chadwick
Fixed a slight issue in the indentation of xhtml.py
50
            setattr(self, key, kwargs[key])
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
51
1148 by William Grant
Allow XHTMLView subclasses to apply filters to the generated app XML stream.
52
    def filter(self, stream, ctx):
53
        return stream
54
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
55
    def render(self, req):
56
        req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
57
58
        # View template
59
        viewctx = genshi.template.Context()
60
        self.populate(req, viewctx)
61
62
        # The template is found in the directory of the module containing the
63
        # view.
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
64
        app_template = os.path.join(os.path.dirname(
1099.1.35 by William Grant
ivle.webapp.base.xhtml#XHTMLView: Rename app_template to template (the things
65
                        inspect.getmodule(self).__file__), self.template) 
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
66
        loader = genshi.template.TemplateLoader(".", auto_reload=True)
67
        tmpl = loader.load(app_template)
1148 by William Grant
Allow XHTMLView subclasses to apply filters to the generated app XML stream.
68
        app = self.filter(tmpl.generate(viewctx), viewctx)
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
69
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
70
        view_scripts = []
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
71
        for plugin in self.plugin_scripts:
72
            for path in self.plugin_scripts[plugin]:
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
73
                view_scripts.append(media_url(req, plugin, path))
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
74
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
75
        view_styles = []
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
76
        for plugin in self.plugin_styles:
77
            for path in self.plugin_styles[plugin]:
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
78
                view_styles.append(media_url(req, plugin, path))
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
79
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
80
        # Global template
81
        ctx = genshi.template.Context()
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
82
83
        overlay_bits = self.render_overlays(req) if req.user else [[]]*4
84
        ctx['overlays'] = overlay_bits[0]
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
85
86
        ctx['styles'] = [media_url(req, CorePlugin, 'ivle.css')]
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
87
        ctx['styles'] += view_styles
88
        ctx['styles'] += overlay_bits[1]
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
89
90
        ctx['scripts'] = [media_url(req, CorePlugin, path) for path in
1092.1.28 by William Grant
Only load tos.js on /+tos.
91
                           ('util.js', 'json2.js', 'md5.js')]
1160 by William Grant
Swap the version and +external in media URLs, and use media_url for jQuery.
92
        ctx['scripts'].append(media_url(req, '+external/jquery', 'jquery.js'))
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
93
        ctx['scripts'] += view_scripts
94
        ctx['scripts'] += overlay_bits[2]
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
95
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
96
        ctx['scripts_init'] = self.scripts_init + overlay_bits[3]
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
97
        ctx['app_template'] = app
1100.1.9 by Matt Giuca
The IVLE logo is now an <img> element, rather than a CSS background.
98
        ctx['title_img'] = media_url(req, CorePlugin,
99
                                     "images/chrome/title.png")
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
100
        self.populate_headings(req, ctx)
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
101
        tmpl = loader.load(os.path.join(os.path.dirname(__file__), 
102
                                                        'ivle-headings.html'))
103
        req.write(tmpl.generate(ctx).render('xhtml', doctype='xhtml'))
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
104
        
105
    def populate(self, req, ctx):
106
        raise NotImplementedError()
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
107
108
    def populate_headings(self, req, ctx):
109
        ctx['favicon'] = None
1202 by William Grant
XHTMLView no longer uses ivle.conf.
110
        ctx['root_dir'] = req.config['urls']['root']
111
        ctx['public_host'] = req.config['urls']['public_host']
112
        ctx['svn_base'] = req.config['urls']['svn_addr']
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
113
        ctx['write_javascript_settings'] = req.write_javascript_settings
114
        if req.user:
115
            ctx['login'] = req.user.login
116
            ctx['logged_in'] = True
117
            ctx['nick'] = req.user.nick
118
        else:
119
            ctx['login'] = None
1099.1.92 by William Grant
Fix the XHTML base template to not crash when not logged in.
120
            ctx['logged_in'] = False
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
121
        ctx['publicmode'] = req.publicmode
1099.1.100 by Nick Chadwick
Created a new help system.
122
        if hasattr(self, 'help'):
123
            ctx['help_path'] = self.help
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
124
125
        ctx['apps_in_tabs'] = []
1092.1.59 by William Grant
Move the plugin loading/indexing logic into ivle.config.Config.
126
        for plugin in req.config.plugin_index[ViewPlugin]:
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
127
            if not hasattr(plugin, 'tabs'):
128
                continue
129
130
            for tab in plugin.tabs:
131
                # tab is a tuple: name, title, desc, icon, path
132
                new_app = {}
1116 by William Grant
Move the old tutorial views into the 'subjects' tab, so they get the right
133
                new_app['this_app'] = hasattr(self, 'tab') \
134
                                      and tab[0] == self.tab
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
135
136
                # Icon name
137
                if tab[3] is not None:
138
                    new_app['has_icon'] = True
139
                    icon_url = media_url(req, plugin, tab[3])
140
                    new_app['icon_url'] = icon_url
141
                    if new_app['this_app']:
142
                        ctx['favicon'] = icon_url
143
                else:
144
                    new_app['has_icon'] = False
1210 by William Grant
Use Request.make_path everywhere.
145
                new_app['path'] = req.make_path(tab[4])
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
146
                new_app['desc'] = tab[2]
147
                new_app['name'] = tab[1]
148
                new_app['weight'] = tab[5]
149
                ctx['apps_in_tabs'].append(new_app)
150
151
        ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
152
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
153
    def render_overlays(self, req):
154
        """Generate XML streams for the overlays.
155
        
156
        Returns a list of streams. Populates the scripts, styles, and 
157
        scripts_init.
158
        """
159
        overlays = []
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
160
        styles = []
161
        scripts = []
162
        scripts_init = []
1099.1.129 by William Grant
Allow XHTML views to specify that they cannot have overlays.
163
        if not self.allow_overlays:
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
164
            return (overlays, styles, scripts, scripts_init)
1099.1.129 by William Grant
Allow XHTML views to specify that they cannot have overlays.
165
1092.1.59 by William Grant
Move the plugin loading/indexing logic into ivle.config.Config.
166
        for plugin in req.config.plugin_index[OverlayPlugin]:
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
167
            for overclass in plugin.overlays:
168
                if overclass in self.overlay_blacklist:
169
                    continue
170
                overlay = overclass(req)
171
                #TODO: Re-factor this to look nicer
172
                for mplugin in overlay.plugin_scripts:
173
                    for path in overlay.plugin_scripts[mplugin]:
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
174
                        scripts.append(media_url(req, mplugin, path))
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
175
176
                for mplugin in overlay.plugin_styles:
177
                    for path in overlay.plugin_styles[mplugin]:
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
178
                        styles.append(media_url(req, mplugin, path))
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
179
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
180
                scripts_init += overlay.plugin_scripts_init
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
181
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
182
                overlays.append(overlay.render(req))
1282.1.2 by William Grant
Remove use of req.{styles,scripts{,_init}} from XHTMLView.
183
        return (overlays, styles, scripts, scripts_init)
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
184
1099.1.95 by William Grant
Error views are now retrieved from a class method of the view, not the plugin
185
    @classmethod
186
    def get_error_view(cls, e):
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
187
        view_map = {HTTPError:    XHTMLErrorView,
188
                    Unauthorized: XHTMLUnauthorizedView}
1099.1.95 by William Grant
Error views are now retrieved from a class method of the view, not the plugin
189
        for exccls in inspect.getmro(type(e)):
190
            if exccls in view_map:
191
                return view_map[exccls]
192
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
193
class XHTMLErrorView(XHTMLView):
194
    template = 'xhtmlerror.html'
195
196
    def __init__(self, req, exception):
197
        self.context = exception
198
199
    def populate(self, req, ctx):
200
        ctx['exception'] = self.context
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
201
202
class XHTMLUnauthorizedView(XHTMLErrorView):
203
    template = 'xhtmlunauthorized.html'
204
205
    def __init__(self, req, exception):
206
        super(XHTMLUnauthorizedView, self).__init__(req, exception)
1099.1.120 by William Grant
Move the login machinery to the new framework.
207
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
208
        if req.user is None:
209
            # Not logged in. Redirect to login page.
1099.1.209 by William Grant
Don't escape / in paths when they are in +login/+tos URLs.
210
            if req.uri == '/':
211
                query_string = ''
212
            else:
213
                query_string = '?url=' + urllib.quote(req.uri, safe="/~")
214
            req.throw_redirect('/+login' + query_string)
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
215
216
        req.status = 403