Merge lp:~jsjgruber/lernid/lernid-proposed into lp:lernid

Proposed by John S. Gruber
Status: Merged
Merged at revision: 226
Proposed branch: lp:~jsjgruber/lernid/lernid-proposed
Merge into: lp:lernid
Diff against target: 2406 lines (+904/-466)
21 files modified
Copyright (+1/-0)
bin/lernid (+56/-6)
data/ui/ChatWidget.ui (+34/-9)
data/ui/ConnectDialog.ui (+95/-54)
data/ui/LernidWindow.ui (+385/-322)
debian/changelog (+69/-0)
debian/control (+1/-2)
debian/copyright (+2/-1)
lernid/AboutLernidDialog.py (+1/-1)
lernid/EventManager.py (+67/-16)
lernid/IrcBackend.py (+29/-4)
lernid/Sessions.py (+60/-13)
lernid/lernidconfig.py (+4/-1)
lernid/widgets/Browser.py (+7/-0)
lernid/widgets/Classroom.py (+7/-5)
lernid/widgets/IrcWidget.py (+17/-4)
lernid/widgets/NativeChatroom.py (+26/-15)
lernid/widgets/Schedule.py (+29/-3)
lernid/widgets/Slide.py (+7/-3)
lernid/widgets/WebChatroom.py (+4/-4)
setup.py (+3/-3)
To merge this branch: bzr merge lp:~jsjgruber/lernid/lernid-proposed
Reviewer Review Type Date Requested Status
John S. Gruber Pending
Review via email: mp+66229@code.launchpad.net

Description of the change

Changes to make lernid more robust, addressing fifteen bugs. A couple of minor enhancements are included.

Built by recipe in https://launchpad.net/~jsjgruber/+archive/lernid-proposed. Use add-apt-repository ppa:jsjgruber/lernid-proposed - and use a package manager's force version to test.

To post a comment you must log in.
lp:~jsjgruber/lernid/lernid-proposed updated
226. By John S. Gruber

Set for release
Add John S Gruber to AUTHOR file
Correct classroom and chatroom labels if lernid was invoked with the
   the --chatroom or --classroom option.
Fix traceback where appindicator is turned off by preference.
Correct handling of unusual case where a calendar start or stop time is
    missing.
Change maintainer to John S Gruber and add copyrights. Set new version.
In the schedule add italicized event names to the titles of sessions.
Use checkbox rather than a button to allow the user to prepend "Question:"
    to their contribution to the chatroom.

Let the user know about Question: in the session notification.
    Fixes: LP: #793029
When classroom and chatroom are joined change their widgets from inactive to
    active so it is more obvious. Fixes LP: #604658
Switch to the session tab at the beginning of the event. Suggest in session
    notification that the user keep the tab selected to see all visual
    materials. Use an eyecatcher, with color, to point out that additional
    slides or web material are in the session tab. Add a status
    message suggesting the user switch to the session tab. LP: #793788
Warn in the connection dialog that connecting can take a minute.
    LP: #604773
See that only an instructor or helper can change what the browser displays.
    LP: #530185. Add option to override this for testing.
    (--unsafe-override).

Emphasize messages from an instructor, helper, or classbot. LP: #794126

Add a --chatroom option so that the user can specify both the classroom and
    chatroom they want.

Remove nicknames saying <???> by rechecking with telepathy when a nickname
    is unknown. LP: #793048

Fix mispelling of "event" in in lernid/Sessions.py code.
Change format of slide progress message to ease translation.
    LP: #792364
Delay setting pane positions until the system has resized the
    window. Sort of hackish. LP: #801547
Don't specify that "lernid" should be translated in LernidWindow.ui
    and other locations. Addresses LP: #682807
Add classroom and chatroom names to their widgets.
Address LP: #493316 adding extensions to make Lernid more robust when a
    connection doesn't exist, the config site, calendar, or irc server
    cannot be reached, or the connection is dropped. Also addresses
    LP: #528935, LP: #603248, LP: #795339 Supplies default configs or
    calendar as needed. Session entries without complete information are
    noted in the schedule.
Merge Chris Coulson's changes to remove the dependency on gtkmozembed.
    LP: #799211.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Copyright'
2--- Copyright 2010-02-08 16:49:55 +0000
3+++ Copyright 2011-06-29 01:07:28 +0000
4@@ -1,5 +1,6 @@
5 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
6 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
7+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
8 #
9 #This program is free software: you can redistribute it and/or modify it
10 #under the terms of the GNU General Public License version 3, as published
11
12=== modified file 'bin/lernid'
13--- bin/lernid 2011-04-27 21:32:46 +0000
14+++ bin/lernid 2011-06-29 01:07:28 +0000
15@@ -3,6 +3,7 @@
16 ### BEGIN LICENSE
17 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
18 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
19+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
20 #
21 #This program is free software: you can redistribute it and/or modify it
22 #under the terms of the GNU General Public License version 3, as published
23@@ -126,9 +127,9 @@
24 self._terminal = Terminal.Terminal()
25
26 def update_title(schedule, session):
27- self.set_title('{0} - {1}'.format(_('Lernid'), session.title))
28+ self.set_title('{0} - {1}'.format('Lernid', session.title))
29 def reset_title(schedule):
30- self.set_title(_('Lernid'))
31+ self.set_title('Lernid')
32 self._schedule.connect('session-changed', update_title)
33 self._schedule.connect('session-ended', reset_title)
34
35@@ -139,7 +140,9 @@
36
37 def highlight_session_tab(w, url=None):
38 if self._tabs.get_current_page() != self.TAB_SESSION:
39- self._session_label.set_label('<b>%s</b>' % _('_Session'))
40+ eye_catcher = u"<span color='red'>●</span><span color='yellow'>●</span><span color='blue'>●</span>"
41+ self._session_label.set_label(eye_catcher + ' %s' % _('_Session'))
42+ Statusbar.push_message(_('Select the Session tab to see classroom learning material'), duration=20)
43 def unhighlight_session_tab(w, p, page_num):
44 if page_num == self.TAB_SESSION:
45 self._session_label.set_label(_('_Session'))
46@@ -148,6 +151,14 @@
47 self.main_window_size['width'] = event.width
48 self.main_window_size['height'] = event.height
49
50+ def event_interrupted(self, event):
51+ logging.error("event interrupted")
52+ n=pynotify.Notification(_('Event Connection Interrupted'), _('Please reestablish your Internet connection\nand reconnect to the event'), 'lernid')
53+ n.show()
54+ Statusbar.push_message(_('Event Connection Interrupted -- '
55+ 'Please reestablish your Internet connection and reconnect to the event'))
56+ self.emit('event-disconnect', event)
57+
58 self._browser.connect('page-changed', highlight_session_tab)
59 self._slide.connect('slide-changed', highlight_session_tab)
60 self._main_window.connect('configure-event', configure_event_mainwindow)
61@@ -178,8 +189,13 @@
62 if pos['sub'] > self.main_window_size['height']-160:
63 pos['sub'] = self.main_window_size['height']-160
64
65- self._mainpane.set_position(pos['main'])
66- self._subpane.set_position(pos['sub'])
67+ def setpos(pos):
68+ self._mainpane.set_position(pos['main'])
69+ self._subpane.set_position(pos['sub'])
70+ return False
71+ # Wait for window resize to complete before we
72+ # set the pane positions
73+ glib.timeout_add_seconds(2, setpos,pos)
74
75 menu_tweet = builder.get_object('menu_tweet')
76 if HAVE_GWIBBER:
77@@ -188,6 +204,21 @@
78 self._schedule.connect('session-ended', lambda s: menu_tweet.set_sensitive(False))
79 self._eventman.connect('event-disconnect', lambda em, e: menu_tweet.set_sensitive(False))
80
81+ self._eventman.connect('event-interrupted', event_interrupted)
82+ def event_connected(self, ignore):
83+ glib.timeout_add_seconds( 12, event_message)
84+ return False
85+
86+ def event_message():
87+ message1 = _('You can interact with classes held in the classroom')
88+ message2 = _(
89+ 'Add "Question:" to the beginning of your query '
90+ 'to direct it to the classroom instructor.')
91+ notification = pynotify.Notification(message1, message2, 'lernid')
92+ notification.show()
93+
94+ self._eventman.connect('event-connect', event_connected)
95+
96 conn_menu_item = builder.get_object('menu_connect')
97 disconn_menu_item = builder.get_object('menu_disconnect')
98 open_url_menu_item = builder.get_object('menu_open_url')
99@@ -195,11 +226,13 @@
100 conn_menu_item.set_sensitive(not connecting)
101 disconn_menu_item.set_sensitive(connecting)
102 open_url_menu_item.set_sensitive(connecting)
103- if HAVE_APPINDICATOR:
104+ if hasattr(self, 'ind'):
105 self.indmenu['menu_connect'].set_sensitive(not connecting)
106 self.indmenu['menu_disconnect'].set_sensitive(connecting)
107 self._eventman.connect('event-connect', toggle_menu_items, True)
108 self._eventman.connect('event-disconnect', toggle_menu_items, False)
109+ self._eventman.connect('event-connect',
110+ lambda x,y,z: self._tabs.set_current_page(z), self.TAB_SESSION)
111
112 self.connect_dialog(None)
113
114@@ -252,6 +285,19 @@
115 statusbar = Statusbar.get_instance()
116 main_vbox.pack_start(statusbar, expand=False)
117
118+ classroom_label = self.builder.get_object(prefix+'classroom_label')
119+ chatroom_label = self.builder.get_object(prefix+'chatroom_label')
120+ def set_room_label(em, event):
121+ classroom_name = Options.get('classroom', event.classroom)
122+ chatroom_name = Options.get('chatroom', event.chat)
123+ classroom_label.set_label(_('Classroom')+' - '+ classroom_name)
124+ chatroom_label.set_label(_('_Chatroom')+' - '+ chatroom_name)
125+ def clear_room_label(em, event):
126+ classroom_label.set_label(_('Classroom'))
127+ chatroom_label.set_label(_('_Chatroom'))
128+ self._eventman.connect('event-connect' , set_room_label)
129+ self._eventman.connect('event-disconnect', clear_room_label)
130+
131 def connect_dialog(self, widget):
132 self._eventman.connect_dialog(parent=self._main_window)
133
134@@ -440,10 +486,14 @@
135 Options.add_option('-v', '--verbose', action='store_true', dest='verbose', help=_('Show debug messages'))
136 Options.add_option('--classroom', action='store', dest='classroom',
137 help=_('Override classroom channel'))
138+ Options.add_option('--chatroom', action='store', dest='chatroom',
139+ help=_('Override chatroom channel'))
140 Options.add_option('--config', action='store', default=None,
141 help=_('Filename or URL to Lernid config file'))
142 Options.add_option('--web-chat', action='store_true', default=False,
143 help=_('Use web chat widget instead of the native one'))
144+ Options.add_option('--unsafe-override', action='store_true', default=False,
145+ help=_('Unsafe testing option'))
146 Options.parse_args()
147
148 # Set the logging level to show debug messages
149
150=== modified file 'data/ui/ChatWidget.ui'
151--- data/ui/ChatWidget.ui 2010-02-24 21:37:04 +0000
152+++ data/ui/ChatWidget.ui 2011-06-29 01:07:28 +0000
153@@ -1,14 +1,15 @@
154-<?xml version="1.0"?>
155+<?xml version="1.0" encoding="UTF-8"?>
156 <interface>
157 <requires lib="gtk+" version="2.16"/>
158 <!-- interface-naming-policy project-wide -->
159 <object class="GtkVBox" id="vbox1">
160 <property name="visible">True</property>
161- <property name="orientation">vertical</property>
162+ <property name="can_focus">False</property>
163 <property name="spacing">4</property>
164 <child>
165 <object class="GtkViewport" id="viewport1">
166 <property name="visible">True</property>
167+ <property name="can_focus">False</property>
168 <property name="resize_mode">queue</property>
169 <child>
170 <object class="GtkScrolledWindow" id="scroll">
171@@ -31,44 +32,68 @@
172 </child>
173 </object>
174 <packing>
175+ <property name="expand">True</property>
176+ <property name="fill">True</property>
177 <property name="position">0</property>
178 </packing>
179 </child>
180 <child>
181 <object class="GtkHBox" id="hbox1">
182 <property name="visible">True</property>
183+ <property name="can_focus">False</property>
184 <property name="spacing">4</property>
185 <child>
186- <object class="GtkToggleButton" id="questionbutton">
187- <property name="label">gtk-dialog-question</property>
188+ <object class="GtkCheckButton" id="questioncheckbox">
189 <property name="visible">True</property>
190- <property name="sensitive">False</property>
191- <property name="can_focus">True</property>
192+ <property name="can_focus">False</property>
193 <property name="receives_default">False</property>
194- <property name="use_stock">True</property>
195+ <property name="use_action_appearance">False</property>
196+ <property name="focus_on_click">False</property>
197+ <property name="xalign">0</property>
198+ <property name="draw_indicator">True</property>
199 </object>
200 <packing>
201 <property name="expand">False</property>
202+ <property name="fill">True</property>
203 <property name="position">0</property>
204 </packing>
205 </child>
206 <child>
207+ <object class="GtkLabel" id="questionlabel">
208+ <property name="visible">True</property>
209+ <property name="can_focus">False</property>
210+ <property name="tooltip_text" translatable="yes">"Question:" directs your question to the classroom for an answer from the instructor</property>
211+ <property name="label" translatable="yes">Question:</property>
212+ <property name="selectable">True</property>
213+ </object>
214+ <packing>
215+ <property name="expand">False</property>
216+ <property name="fill">False</property>
217+ <property name="position">1</property>
218+ </packing>
219+ </child>
220+ <child>
221 <object class="GtkEntry" id="input">
222 <property name="visible">True</property>
223 <property name="sensitive">False</property>
224 <property name="can_focus">True</property>
225- <property name="invisible_char">&#x25CF;</property>
226+ <property name="invisible_char">●</property>
227 <property name="secondary_icon_stock">gtk-go-forward</property>
228+ <property name="primary_icon_activatable">False</property>
229 <property name="secondary_icon_activatable">True</property>
230+ <property name="primary_icon_sensitive">True</property>
231 <property name="secondary_icon_sensitive">True</property>
232 </object>
233 <packing>
234- <property name="position">1</property>
235+ <property name="expand">True</property>
236+ <property name="fill">True</property>
237+ <property name="position">2</property>
238 </packing>
239 </child>
240 </object>
241 <packing>
242 <property name="expand">False</property>
243+ <property name="fill">True</property>
244 <property name="position">1</property>
245 </packing>
246 </child>
247
248=== modified file 'data/ui/ConnectDialog.ui'
249--- data/ui/ConnectDialog.ui 2010-02-13 15:43:30 +0000
250+++ data/ui/ConnectDialog.ui 2011-06-29 01:07:28 +0000
251@@ -1,9 +1,10 @@
252-<?xml version="1.0"?>
253+<?xml version="1.0" encoding="UTF-8"?>
254 <interface>
255 <requires lib="gtk+" version="2.16"/>
256 <!-- interface-requires connect_dialog 1.0 -->
257 <!-- interface-naming-policy project-wide -->
258 <object class="ConnectDialog" id="connect_dialog">
259+ <property name="can_focus">False</property>
260 <property name="border_width">6</property>
261 <property name="title" translatable="yes">Choose an event</property>
262 <property name="resizable">False</property>
263@@ -13,26 +14,75 @@
264 <property name="icon_name">lernid</property>
265 <property name="type_hint">dialog</property>
266 <property name="skip_taskbar_hint">True</property>
267- <property name="has_separator">False</property>
268- <signal name="close" handler="cancel"/>
269- <signal name="delete_event" handler="cancel"/>
270+ <signal name="close" handler="cancel" swapped="no"/>
271+ <signal name="delete-event" handler="cancel" swapped="no"/>
272 <child internal-child="vbox">
273 <object class="GtkVBox" id="dialog-vbox1">
274 <property name="visible">True</property>
275- <property name="orientation">vertical</property>
276+ <property name="can_focus">False</property>
277+ <child internal-child="action_area">
278+ <object class="GtkHButtonBox" id="dialog-action_area1">
279+ <property name="visible">True</property>
280+ <property name="can_focus">False</property>
281+ <property name="layout_style">end</property>
282+ <child>
283+ <object class="GtkButton" id="button_cancel">
284+ <property name="label">gtk-cancel</property>
285+ <property name="visible">True</property>
286+ <property name="can_focus">True</property>
287+ <property name="receives_default">True</property>
288+ <property name="use_action_appearance">False</property>
289+ <property name="use_stock">True</property>
290+ <signal name="clicked" handler="cancel" swapped="no"/>
291+ </object>
292+ <packing>
293+ <property name="expand">False</property>
294+ <property name="fill">False</property>
295+ <property name="position">0</property>
296+ </packing>
297+ </child>
298+ <child>
299+ <object class="GtkButton" id="button_connect">
300+ <property name="label">gtk-connect</property>
301+ <property name="visible">True</property>
302+ <property name="sensitive">False</property>
303+ <property name="can_focus">True</property>
304+ <property name="can_default">True</property>
305+ <property name="has_default">True</property>
306+ <property name="receives_default">True</property>
307+ <property name="use_action_appearance">False</property>
308+ <property name="use_stock">True</property>
309+ <signal name="clicked" handler="ok" swapped="no"/>
310+ </object>
311+ <packing>
312+ <property name="expand">False</property>
313+ <property name="fill">False</property>
314+ <property name="position">1</property>
315+ </packing>
316+ </child>
317+ </object>
318+ <packing>
319+ <property name="expand">False</property>
320+ <property name="fill">True</property>
321+ <property name="pack_type">end</property>
322+ <property name="position">0</property>
323+ </packing>
324+ </child>
325 <child>
326 <object class="GtkVBox" id="vbox1">
327 <property name="visible">True</property>
328+ <property name="can_focus">False</property>
329 <property name="border_width">6</property>
330- <property name="orientation">vertical</property>
331 <property name="spacing">12</property>
332 <child>
333 <object class="GtkAlignment" id="alignment1">
334 <property name="visible">True</property>
335+ <property name="can_focus">False</property>
336 <property name="left_padding">3</property>
337 <child>
338 <object class="GtkTable" id="table1">
339 <property name="visible">True</property>
340+ <property name="can_focus">False</property>
341 <property name="n_rows">2</property>
342 <property name="n_columns">2</property>
343 <property name="column_spacing">12</property>
344@@ -40,6 +90,7 @@
345 <child>
346 <object class="GtkLabel" id="label1">
347 <property name="visible">True</property>
348+ <property name="can_focus">False</property>
349 <property name="xalign">0</property>
350 <property name="label" translatable="yes">Event:</property>
351 </object>
352@@ -51,6 +102,7 @@
353 <child>
354 <object class="GtkLabel" id="label2">
355 <property name="visible">True</property>
356+ <property name="can_focus">False</property>
357 <property name="xalign">0</property>
358 <property name="label" translatable="yes">Nickname:</property>
359 </object>
360@@ -64,7 +116,8 @@
361 <child>
362 <object class="GtkComboBox" id="event_combo">
363 <property name="visible">True</property>
364- <signal name="changed" handler="check_ready_to_connect"/>
365+ <property name="can_focus">False</property>
366+ <signal name="changed" handler="check_ready_to_connect" swapped="no"/>
367 </object>
368 <packing>
369 <property name="left_attach">1</property>
370@@ -76,9 +129,13 @@
371 <object class="GtkEntry" id="nick_textentry">
372 <property name="visible">True</property>
373 <property name="can_focus">True</property>
374- <property name="invisible_char">&#x25CF;</property>
375+ <property name="invisible_char">●</property>
376 <property name="activates_default">True</property>
377- <signal name="changed" handler="check_ready_to_connect"/>
378+ <property name="primary_icon_activatable">False</property>
379+ <property name="secondary_icon_activatable">False</property>
380+ <property name="primary_icon_sensitive">True</property>
381+ <property name="secondary_icon_sensitive">True</property>
382+ <signal name="changed" handler="check_ready_to_connect" swapped="no"/>
383 </object>
384 <packing>
385 <property name="left_attach">1</property>
386@@ -93,6 +150,7 @@
387 </object>
388 <packing>
389 <property name="expand">False</property>
390+ <property name="fill">True</property>
391 <property name="position">0</property>
392 </packing>
393 </child>
394@@ -103,18 +161,22 @@
395 <child>
396 <object class="GtkAlignment" id="alignment2">
397 <property name="visible">True</property>
398+ <property name="can_focus">False</property>
399 <property name="left_padding">3</property>
400 <child>
401 <object class="GtkHBox" id="hbox1">
402 <property name="visible">True</property>
403+ <property name="can_focus">False</property>
404 <property name="spacing">12</property>
405 <child>
406 <object class="GtkLabel" id="label4">
407 <property name="visible">True</property>
408+ <property name="can_focus">False</property>
409 <property name="label" translatable="yes">NickServ password:</property>
410 </object>
411 <packing>
412 <property name="expand">False</property>
413+ <property name="fill">True</property>
414 <property name="position">0</property>
415 </packing>
416 </child>
417@@ -123,10 +185,16 @@
418 <property name="visible">True</property>
419 <property name="can_focus">True</property>
420 <property name="visibility">False</property>
421- <property name="invisible_char">&#x25CF;</property>
422+ <property name="invisible_char">●</property>
423 <property name="activates_default">True</property>
424+ <property name="primary_icon_activatable">False</property>
425+ <property name="secondary_icon_activatable">False</property>
426+ <property name="primary_icon_sensitive">True</property>
427+ <property name="secondary_icon_sensitive">True</property>
428 </object>
429 <packing>
430+ <property name="expand">True</property>
431+ <property name="fill">True</property>
432 <property name="position">1</property>
433 </packing>
434 </child>
435@@ -137,64 +205,37 @@
436 <child type="label">
437 <object class="GtkLabel" id="label3">
438 <property name="visible">True</property>
439+ <property name="can_focus">False</property>
440 <property name="label" translatable="yes">Advanced options</property>
441 </object>
442 </child>
443 </object>
444 <packing>
445 <property name="expand">False</property>
446+ <property name="fill">True</property>
447 <property name="position">1</property>
448 </packing>
449 </child>
450+ <child>
451+ <object class="GtkLabel" id="label5">
452+ <property name="visible">True</property>
453+ <property name="can_focus">False</property>
454+ <property name="label" translatable="yes">Connecting to the classroom may take up to one minute</property>
455+ </object>
456+ <packing>
457+ <property name="expand">True</property>
458+ <property name="fill">True</property>
459+ <property name="pack_type">end</property>
460+ <property name="position">2</property>
461+ </packing>
462+ </child>
463 </object>
464 <packing>
465+ <property name="expand">True</property>
466+ <property name="fill">True</property>
467 <property name="position">1</property>
468 </packing>
469 </child>
470- <child internal-child="action_area">
471- <object class="GtkHButtonBox" id="dialog-action_area1">
472- <property name="visible">True</property>
473- <property name="layout_style">end</property>
474- <child>
475- <object class="GtkButton" id="button_cancel">
476- <property name="label">gtk-cancel</property>
477- <property name="visible">True</property>
478- <property name="can_focus">True</property>
479- <property name="receives_default">True</property>
480- <property name="use_stock">True</property>
481- <signal name="clicked" handler="cancel"/>
482- </object>
483- <packing>
484- <property name="expand">False</property>
485- <property name="fill">False</property>
486- <property name="position">0</property>
487- </packing>
488- </child>
489- <child>
490- <object class="GtkButton" id="button_connect">
491- <property name="label">gtk-connect</property>
492- <property name="visible">True</property>
493- <property name="sensitive">False</property>
494- <property name="can_focus">True</property>
495- <property name="can_default">True</property>
496- <property name="has_default">True</property>
497- <property name="receives_default">True</property>
498- <property name="use_stock">True</property>
499- <signal name="clicked" handler="ok"/>
500- </object>
501- <packing>
502- <property name="expand">False</property>
503- <property name="fill">False</property>
504- <property name="position">1</property>
505- </packing>
506- </child>
507- </object>
508- <packing>
509- <property name="expand">False</property>
510- <property name="pack_type">end</property>
511- <property name="position">0</property>
512- </packing>
513- </child>
514 </object>
515 </child>
516 <action-widgets>
517
518=== modified file 'data/ui/LernidWindow.ui'
519--- data/ui/LernidWindow.ui 2011-04-19 02:05:14 +0000
520+++ data/ui/LernidWindow.ui 2011-06-29 01:07:28 +0000
521@@ -1,40 +1,192 @@
522-<?xml version="1.0"?>
523+<?xml version="1.0" encoding="UTF-8"?>
524 <interface>
525 <requires lib="gtk+" version="2.16"/>
526 <!-- interface-requires lernid_window 1.0 -->
527 <!-- interface-naming-policy project-wide -->
528 <!-- interface-local-resource-path ../media -->
529+ <object class="GtkAdjustment" id="adjustment1">
530+ <property name="upper">100</property>
531+ <property name="step_increment">1</property>
532+ <property name="page_increment">10</property>
533+ <property name="page_size">10</property>
534+ </object>
535+ <object class="GtkAlignment" id="halignment">
536+ <property name="visible">True</property>
537+ <property name="can_focus">False</property>
538+ <property name="top_padding">6</property>
539+ <property name="bottom_padding">6</property>
540+ <property name="left_padding">6</property>
541+ <property name="right_padding">6</property>
542+ <child>
543+ <object class="GtkVPaned" id="hmainpaned">
544+ <property name="visible">True</property>
545+ <property name="can_focus">True</property>
546+ <child>
547+ <object class="GtkNotebook" id="htabs">
548+ <property name="visible">True</property>
549+ <property name="can_focus">True</property>
550+ <child>
551+ <placeholder/>
552+ </child>
553+ <child type="tab">
554+ <placeholder/>
555+ </child>
556+ <child>
557+ <placeholder/>
558+ </child>
559+ <child type="tab">
560+ <placeholder/>
561+ </child>
562+ <child>
563+ <placeholder/>
564+ </child>
565+ <child type="tab">
566+ <placeholder/>
567+ </child>
568+ </object>
569+ <packing>
570+ <property name="resize">True</property>
571+ <property name="shrink">False</property>
572+ </packing>
573+ </child>
574+ <child>
575+ <object class="GtkHPaned" id="hsubpaned">
576+ <property name="visible">True</property>
577+ <property name="can_focus">True</property>
578+ <child>
579+ <object class="GtkVBox" id="hclassroom_vbox">
580+ <property name="visible">True</property>
581+ <property name="can_focus">False</property>
582+ <child>
583+ <object class="GtkLabel" id="hclassroom_label">
584+ <property name="visible">True</property>
585+ <property name="can_focus">False</property>
586+ <property name="xalign">0</property>
587+ <property name="xpad">6</property>
588+ <property name="ypad">3</property>
589+ <property name="label" translatable="yes">Classroom</property>
590+ <property name="justify">fill</property>
591+ <attributes>
592+ <attribute name="weight" value="bold"/>
593+ </attributes>
594+ </object>
595+ <packing>
596+ <property name="expand">False</property>
597+ <property name="fill">True</property>
598+ <property name="position">0</property>
599+ </packing>
600+ </child>
601+ <child>
602+ <placeholder/>
603+ </child>
604+ </object>
605+ <packing>
606+ <property name="resize">False</property>
607+ <property name="shrink">True</property>
608+ </packing>
609+ </child>
610+ <child>
611+ <object class="GtkVBox" id="hchatroom_vbox">
612+ <property name="visible">True</property>
613+ <property name="can_focus">False</property>
614+ <child>
615+ <object class="GtkHBox" id="hbox1">
616+ <property name="visible">True</property>
617+ <property name="can_focus">False</property>
618+ <property name="spacing">6</property>
619+ <child>
620+ <object class="GtkLabel" id="hchatroom_label">
621+ <property name="visible">True</property>
622+ <property name="can_focus">False</property>
623+ <property name="xalign">0</property>
624+ <property name="xpad">6</property>
625+ <property name="ypad">3</property>
626+ <property name="label" translatable="yes">_Chatroom</property>
627+ <property name="use_underline">True</property>
628+ <property name="justify">fill</property>
629+ <attributes>
630+ <attribute name="weight" value="bold"/>
631+ </attributes>
632+ </object>
633+ <packing>
634+ <property name="expand">False</property>
635+ <property name="fill">True</property>
636+ <property name="position">0</property>
637+ </packing>
638+ </child>
639+ <child>
640+ <object class="GtkLabel" id="hchatroom_mcount">
641+ <property name="visible">True</property>
642+ <property name="can_focus">False</property>
643+ <property name="xalign">0</property>
644+ </object>
645+ <packing>
646+ <property name="expand">True</property>
647+ <property name="fill">True</property>
648+ <property name="position">1</property>
649+ </packing>
650+ </child>
651+ </object>
652+ <packing>
653+ <property name="expand">False</property>
654+ <property name="fill">True</property>
655+ <property name="position">0</property>
656+ </packing>
657+ </child>
658+ <child>
659+ <placeholder/>
660+ </child>
661+ </object>
662+ <packing>
663+ <property name="resize">False</property>
664+ <property name="shrink">True</property>
665+ </packing>
666+ </child>
667+ </object>
668+ <packing>
669+ <property name="resize">True</property>
670+ <property name="shrink">True</property>
671+ </packing>
672+ </child>
673+ </object>
674+ </child>
675+ </object>
676 <object class="LernidWindow" id="lernid_window">
677 <property name="width_request">800</property>
678 <property name="height_request">550</property>
679- <property name="title" translatable="yes">Lernid</property>
680- <!--property name="window_position">center</property-->
681+ <property name="can_focus">False</property>
682+ <property name="title" translatable="no">Lernid</property>
683 <property name="icon_name">lernid</property>
684- <signal name="destroy" handler="quit"/>
685+ <signal name="destroy" handler="quit" swapped="no"/>
686 <child>
687 <object class="GtkVBox" id="main_vbox">
688 <property name="visible">True</property>
689- <property name="orientation">vertical</property>
690+ <property name="can_focus">False</property>
691 <child>
692 <object class="GtkMenuBar" id="menubar1">
693 <property name="visible">True</property>
694+ <property name="can_focus">False</property>
695 <child>
696 <object class="GtkMenuItem" id="event_menuitem">
697 <property name="visible">True</property>
698+ <property name="can_focus">False</property>
699+ <property name="use_action_appearance">False</property>
700 <property name="label" translatable="yes">Eve_nt</property>
701 <property name="use_underline">True</property>
702 <child type="submenu">
703 <object class="GtkMenu" id="menu1">
704 <property name="visible">True</property>
705+ <property name="can_focus">False</property>
706 <child>
707 <object class="GtkImageMenuItem" id="menu_connect">
708 <property name="label">gtk-connect</property>
709 <property name="visible">True</property>
710- <property name="use_action_appearance">True</property>
711+ <property name="can_focus">False</property>
712+ <property name="use_action_appearance">False</property>
713 <property name="use_underline">True</property>
714 <property name="use_stock">True</property>
715 <accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/>
716- <signal name="activate" handler="connect_dialog"/>
717+ <signal name="activate" handler="connect_dialog" swapped="no"/>
718 </object>
719 </child>
720 <child>
721@@ -42,41 +194,50 @@
722 <property name="label">gtk-disconnect</property>
723 <property name="visible">True</property>
724 <property name="sensitive">False</property>
725+ <property name="can_focus">False</property>
726+ <property name="use_action_appearance">False</property>
727 <property name="use_underline">True</property>
728 <property name="use_stock">True</property>
729- <signal name="activate" handler="disconnect_from_event"/>
730+ <signal name="activate" handler="disconnect_from_event" swapped="no"/>
731 </object>
732 </child>
733 <child>
734 <object class="GtkMenuItem" id="menu_open_url">
735 <property name="visible">True</property>
736 <property name="sensitive">False</property>
737+ <property name="can_focus">False</property>
738+ <property name="use_action_appearance">False</property>
739 <property name="label" translatable="yes">Open _URL...</property>
740 <property name="use_underline">True</property>
741- <signal name="activate" handler="open_url"/>
742+ <signal name="activate" handler="open_url" swapped="no"/>
743 </object>
744 </child>
745 <child>
746 <object class="GtkMenuItem" id="menu_tweet">
747 <property name="sensitive">False</property>
748+ <property name="can_focus">False</property>
749 <property name="no_show_all">True</property>
750+ <property name="use_action_appearance">False</property>
751 <property name="label" translatable="yes">Tweet current session</property>
752 <property name="use_underline">True</property>
753- <signal name="activate" handler="tweet_session"/>
754+ <signal name="activate" handler="tweet_session" swapped="no"/>
755 </object>
756 </child>
757 <child>
758 <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
759 <property name="visible">True</property>
760+ <property name="can_focus">False</property>
761 </object>
762 </child>
763 <child>
764 <object class="GtkImageMenuItem" id="menu_quit">
765 <property name="label">gtk-quit</property>
766 <property name="visible">True</property>
767+ <property name="can_focus">False</property>
768+ <property name="use_action_appearance">False</property>
769 <property name="use_underline">True</property>
770 <property name="use_stock">True</property>
771- <signal name="activate" handler="quit"/>
772+ <signal name="activate" handler="quit" swapped="no"/>
773 </object>
774 </child>
775 </object>
776@@ -86,18 +247,23 @@
777 <child>
778 <object class="GtkMenuItem" id="edit_menuitem">
779 <property name="visible">True</property>
780+ <property name="can_focus">False</property>
781+ <property name="use_action_appearance">False</property>
782 <property name="label" translatable="yes">_Edit</property>
783 <property name="use_underline">True</property>
784 <child type="submenu">
785 <object class="GtkMenu" id="menu4">
786 <property name="visible">True</property>
787+ <property name="can_focus">False</property>
788 <child>
789 <object class="GtkImageMenuItem" id="menu_prefs">
790 <property name="label">gtk-preferences</property>
791 <property name="visible">True</property>
792+ <property name="can_focus">False</property>
793+ <property name="use_action_appearance">False</property>
794 <property name="use_underline">True</property>
795 <property name="use_stock">True</property>
796- <signal name="activate" handler="preferences"/>
797+ <signal name="activate" handler="preferences" swapped="no"/>
798 </object>
799 </child>
800 </object>
801@@ -107,27 +273,34 @@
802 <child>
803 <object class="GtkMenuItem" id="view_menuitem">
804 <property name="visible">True</property>
805+ <property name="can_focus">False</property>
806+ <property name="use_action_appearance">False</property>
807 <property name="label" translatable="yes">_View</property>
808 <property name="use_underline">True</property>
809 <child type="submenu">
810 <object class="GtkMenu" id="menu2">
811 <property name="visible">True</property>
812+ <property name="can_focus">False</property>
813 <child>
814 <object class="GtkCheckMenuItem" id="menu_fullscreen">
815 <property name="visible">True</property>
816+ <property name="can_focus">False</property>
817+ <property name="use_action_appearance">False</property>
818 <property name="label" translatable="yes">_Fullscreen</property>
819 <property name="use_underline">True</property>
820 <accelerator key="F11" signal="activate"/>
821- <signal name="toggled" handler="toggle_fullscreen"/>
822+ <signal name="toggled" handler="toggle_fullscreen" swapped="no"/>
823 </object>
824 </child>
825 <child>
826 <object class="GtkCheckMenuItem" id="menu_statusbar">
827 <property name="visible">True</property>
828+ <property name="can_focus">False</property>
829+ <property name="use_action_appearance">False</property>
830 <property name="label" translatable="yes">_Statusbar</property>
831 <property name="use_underline">True</property>
832 <property name="active">True</property>
833- <signal name="toggled" handler="toggle_statusbar"/>
834+ <signal name="toggled" handler="toggle_statusbar" swapped="no"/>
835 </object>
836 </child>
837 </object>
838@@ -137,18 +310,23 @@
839 <child>
840 <object class="GtkMenuItem" id="help_menuitem">
841 <property name="visible">True</property>
842+ <property name="can_focus">False</property>
843+ <property name="use_action_appearance">False</property>
844 <property name="label" translatable="yes">_Help</property>
845 <property name="use_underline">True</property>
846 <child type="submenu">
847 <object class="GtkMenu" id="menu3">
848 <property name="visible">True</property>
849+ <property name="can_focus">False</property>
850 <child>
851 <object class="GtkImageMenuItem" id="menu_about">
852 <property name="label">gtk-about</property>
853 <property name="visible">True</property>
854+ <property name="can_focus">False</property>
855+ <property name="use_action_appearance">False</property>
856 <property name="use_underline">True</property>
857 <property name="use_stock">True</property>
858- <signal name="activate" handler="about"/>
859+ <signal name="activate" handler="about" swapped="no"/>
860 </object>
861 </child>
862 </object>
863@@ -158,6 +336,7 @@
864 </object>
865 <packing>
866 <property name="expand">False</property>
867+ <property name="fill">True</property>
868 <property name="position">0</property>
869 </packing>
870 </child>
871@@ -170,325 +349,21 @@
872 </object>
873 </child>
874 </object>
875- <object class="GtkAdjustment" id="adjustment1">
876- <property name="upper">100</property>
877- <property name="step_increment">1</property>
878- <property name="page_increment">10</property>
879- <property name="page_size">10</property>
880- </object>
881- <object class="GtkAlignment" id="valignment">
882- <property name="visible">True</property>
883- <property name="top_padding">6</property>
884- <property name="bottom_padding">6</property>
885- <property name="left_padding">6</property>
886- <property name="right_padding">6</property>
887- <child>
888- <object class="GtkHPaned" id="vmainpaned">
889- <property name="visible">True</property>
890- <property name="can_focus">True</property>
891- <child>
892- <object class="GtkNotebook" id="vtabs">
893- <property name="visible">True</property>
894- <property name="can_focus">True</property>
895- <child>
896- <placeholder/>
897- </child>
898- <child type="tab">
899- <placeholder/>
900- </child>
901- <child>
902- <placeholder/>
903- </child>
904- <child type="tab">
905- <placeholder/>
906- </child>
907- <child>
908- <placeholder/>
909- </child>
910- <child type="tab">
911- <placeholder/>
912- </child>
913- </object>
914- <packing>
915- <property name="resize">True</property>
916- <property name="shrink">False</property>
917- </packing>
918- </child>
919- <child>
920- <object class="GtkVPaned" id="vsubpaned">
921- <property name="visible">True</property>
922- <property name="can_focus">True</property>
923- <property name="orientation">vertical</property>
924- <child>
925- <object class="GtkVBox" id="vclassroom_vbox">
926- <property name="visible">True</property>
927- <property name="orientation">vertical</property>
928- <child>
929- <object class="GtkLabel" id="label1">
930- <property name="visible">True</property>
931- <property name="xalign">0</property>
932- <property name="xpad">6</property>
933- <property name="ypad">3</property>
934- <property name="label" translatable="yes">Classroom</property>
935- <property name="justify">fill</property>
936- <attributes>
937- <attribute name="weight" value="bold"/>
938- </attributes>
939- </object>
940- <packing>
941- <property name="expand">False</property>
942- <property name="position">0</property>
943- </packing>
944- </child>
945- <child>
946- <placeholder/>
947- </child>
948- </object>
949- <packing>
950- <property name="resize">False</property>
951- <property name="shrink">True</property>
952- </packing>
953- </child>
954- <child>
955- <object class="GtkVBox" id="vchatroom_vbox">
956- <property name="visible">True</property>
957- <property name="orientation">vertical</property>
958- <child>
959- <object class="GtkHBox" id="hbox2">
960- <property name="visible">True</property>
961- <property name="spacing">6</property>
962- <child>
963- <object class="GtkLabel" id="vchatroom_label">
964- <property name="visible">True</property>
965- <property name="xalign">0</property>
966- <property name="xpad">6</property>
967- <property name="ypad">3</property>
968- <property name="label" translatable="yes">_Chatroom</property>
969- <property name="use_underline">True</property>
970- <property name="justify">fill</property>
971- <attributes>
972- <attribute name="weight" value="bold"/>
973- </attributes>
974- </object>
975- <packing>
976- <property name="expand">False</property>
977- <property name="position">0</property>
978- </packing>
979- </child>
980- <child>
981- <object class="GtkLabel" id="vchatroom_mcount">
982- <property name="visible">True</property>
983- <property name="xalign">0</property>
984- </object>
985- <packing>
986- <property name="position">1</property>
987- </packing>
988- </child>
989- </object>
990- <packing>
991- <property name="expand">False</property>
992- <property name="position">0</property>
993- </packing>
994- </child>
995- <child>
996- <placeholder/>
997- </child>
998- </object>
999- <packing>
1000- <property name="resize">True</property>
1001- <property name="shrink">True</property>
1002- </packing>
1003- </child>
1004- </object>
1005- <packing>
1006- <property name="resize">True</property>
1007- <property name="shrink">True</property>
1008- </packing>
1009- </child>
1010- </object>
1011- </child>
1012- </object>
1013- <object class="GtkAlignment" id="halignment">
1014- <property name="visible">True</property>
1015- <property name="top_padding">6</property>
1016- <property name="bottom_padding">6</property>
1017- <property name="left_padding">6</property>
1018- <property name="right_padding">6</property>
1019- <child>
1020- <object class="GtkVPaned" id="hmainpaned">
1021- <property name="visible">True</property>
1022- <property name="can_focus">True</property>
1023- <property name="orientation">vertical</property>
1024- <child>
1025- <object class="GtkNotebook" id="htabs">
1026- <property name="visible">True</property>
1027- <property name="can_focus">True</property>
1028- <child>
1029- <placeholder/>
1030- </child>
1031- <child type="tab">
1032- <placeholder/>
1033- </child>
1034- <child>
1035- <placeholder/>
1036- </child>
1037- <child type="tab">
1038- <placeholder/>
1039- </child>
1040- <child>
1041- <placeholder/>
1042- </child>
1043- <child type="tab">
1044- <placeholder/>
1045- </child>
1046- </object>
1047- <packing>
1048- <property name="resize">True</property>
1049- <property name="shrink">False</property>
1050- </packing>
1051- </child>
1052- <child>
1053- <object class="GtkHPaned" id="hsubpaned">
1054- <property name="visible">True</property>
1055- <property name="can_focus">True</property>
1056- <child>
1057- <object class="GtkVBox" id="hclassroom_vbox">
1058- <property name="visible">True</property>
1059- <property name="orientation">vertical</property>
1060- <child>
1061- <object class="GtkLabel" id="label4">
1062- <property name="visible">True</property>
1063- <property name="xalign">0</property>
1064- <property name="xpad">6</property>
1065- <property name="ypad">3</property>
1066- <property name="label" translatable="yes">Classroom</property>
1067- <property name="justify">fill</property>
1068- <attributes>
1069- <attribute name="weight" value="bold"/>
1070- </attributes>
1071- </object>
1072- <packing>
1073- <property name="expand">False</property>
1074- <property name="position">0</property>
1075- </packing>
1076- </child>
1077- <child>
1078- <placeholder/>
1079- </child>
1080- </object>
1081- <packing>
1082- <property name="resize">False</property>
1083- <property name="shrink">True</property>
1084- </packing>
1085- </child>
1086- <child>
1087- <object class="GtkVBox" id="hchatroom_vbox">
1088- <property name="visible">True</property>
1089- <property name="orientation">vertical</property>
1090- <child>
1091- <object class="GtkHBox" id="hbox1">
1092- <property name="visible">True</property>
1093- <property name="spacing">6</property>
1094- <child>
1095- <object class="GtkLabel" id="hchatroom_label">
1096- <property name="visible">True</property>
1097- <property name="xalign">0</property>
1098- <property name="xpad">6</property>
1099- <property name="ypad">3</property>
1100- <property name="label" translatable="yes">_Chatroom</property>
1101- <property name="use_underline">True</property>
1102- <property name="justify">fill</property>
1103- <attributes>
1104- <attribute name="weight" value="bold"/>
1105- </attributes>
1106- </object>
1107- <packing>
1108- <property name="expand">False</property>
1109- <property name="position">0</property>
1110- </packing>
1111- </child>
1112- <child>
1113- <object class="GtkLabel" id="hchatroom_mcount">
1114- <property name="visible">True</property>
1115- <property name="xalign">0</property>
1116- </object>
1117- <packing>
1118- <property name="position">1</property>
1119- </packing>
1120- </child>
1121- </object>
1122- <packing>
1123- <property name="expand">False</property>
1124- <property name="position">0</property>
1125- </packing>
1126- </child>
1127- <child>
1128- <placeholder/>
1129- </child>
1130- </object>
1131- <packing>
1132- <property name="resize">False</property>
1133- <property name="shrink">True</property>
1134- </packing>
1135- </child>
1136- </object>
1137- <packing>
1138- <property name="resize">True</property>
1139- <property name="shrink">True</property>
1140- </packing>
1141- </child>
1142- </object>
1143- </child>
1144- </object>
1145 <object class="GtkDialog" id="open_url_dialog">
1146+ <property name="can_focus">False</property>
1147 <property name="border_width">5</property>
1148 <property name="window_position">center</property>
1149 <property name="icon_name">lernid</property>
1150 <property name="type_hint">dialog</property>
1151- <property name="has_separator">False</property>
1152 <child internal-child="vbox">
1153 <object class="GtkVBox" id="dialog-vbox1">
1154 <property name="visible">True</property>
1155- <property name="orientation">vertical</property>
1156+ <property name="can_focus">False</property>
1157 <property name="spacing">2</property>
1158- <child>
1159- <object class="GtkVBox" id="vbox1">
1160- <property name="visible">True</property>
1161- <property name="border_width">6</property>
1162- <property name="orientation">vertical</property>
1163- <property name="spacing">6</property>
1164- <child>
1165- <object class="GtkLabel" id="label2">
1166- <property name="visible">True</property>
1167- <property name="xalign">0</property>
1168- <property name="xpad">4</property>
1169- <property name="label" translatable="yes">Enter the address you would like to open in the browser:</property>
1170- </object>
1171- <packing>
1172- <property name="expand">False</property>
1173- <property name="position">0</property>
1174- </packing>
1175- </child>
1176- <child>
1177- <object class="GtkEntry" id="url_entry">
1178- <property name="visible">True</property>
1179- <property name="can_focus">True</property>
1180- <property name="invisible_char">&#x25CF;</property>
1181- <property name="activates_default">True</property>
1182- </object>
1183- <packing>
1184- <property name="expand">False</property>
1185- <property name="position">1</property>
1186- </packing>
1187- </child>
1188- </object>
1189- <packing>
1190- <property name="position">1</property>
1191- </packing>
1192- </child>
1193 <child internal-child="action_area">
1194 <object class="GtkHButtonBox" id="dialog-action_area1">
1195 <property name="visible">True</property>
1196+ <property name="can_focus">False</property>
1197 <property name="layout_style">end</property>
1198 <child>
1199 <object class="GtkButton" id="button2">
1200@@ -496,6 +371,7 @@
1201 <property name="visible">True</property>
1202 <property name="can_focus">True</property>
1203 <property name="receives_default">True</property>
1204+ <property name="use_action_appearance">False</property>
1205 <property name="use_stock">True</property>
1206 </object>
1207 <packing>
1208@@ -512,6 +388,7 @@
1209 <property name="can_default">True</property>
1210 <property name="has_default">True</property>
1211 <property name="receives_default">True</property>
1212+ <property name="use_action_appearance">False</property>
1213 <property name="relief">half</property>
1214 <property name="use_stock">True</property>
1215 </object>
1216@@ -524,10 +401,55 @@
1217 </object>
1218 <packing>
1219 <property name="expand">False</property>
1220+ <property name="fill">True</property>
1221 <property name="pack_type">end</property>
1222 <property name="position">0</property>
1223 </packing>
1224 </child>
1225+ <child>
1226+ <object class="GtkVBox" id="vbox1">
1227+ <property name="visible">True</property>
1228+ <property name="can_focus">False</property>
1229+ <property name="border_width">6</property>
1230+ <property name="spacing">6</property>
1231+ <child>
1232+ <object class="GtkLabel" id="label2">
1233+ <property name="visible">True</property>
1234+ <property name="can_focus">False</property>
1235+ <property name="xalign">0</property>
1236+ <property name="xpad">4</property>
1237+ <property name="label" translatable="yes">Enter the address you would like to open in the browser:</property>
1238+ </object>
1239+ <packing>
1240+ <property name="expand">False</property>
1241+ <property name="fill">True</property>
1242+ <property name="position">0</property>
1243+ </packing>
1244+ </child>
1245+ <child>
1246+ <object class="GtkEntry" id="url_entry">
1247+ <property name="visible">True</property>
1248+ <property name="can_focus">True</property>
1249+ <property name="invisible_char">●</property>
1250+ <property name="activates_default">True</property>
1251+ <property name="primary_icon_activatable">False</property>
1252+ <property name="secondary_icon_activatable">False</property>
1253+ <property name="primary_icon_sensitive">True</property>
1254+ <property name="secondary_icon_sensitive">True</property>
1255+ </object>
1256+ <packing>
1257+ <property name="expand">False</property>
1258+ <property name="fill">True</property>
1259+ <property name="position">1</property>
1260+ </packing>
1261+ </child>
1262+ </object>
1263+ <packing>
1264+ <property name="expand">True</property>
1265+ <property name="fill">True</property>
1266+ <property name="position">1</property>
1267+ </packing>
1268+ </child>
1269 </object>
1270 </child>
1271 <action-widgets>
1272@@ -535,4 +457,145 @@
1273 <action-widget response="-5">button1</action-widget>
1274 </action-widgets>
1275 </object>
1276+ <object class="GtkAlignment" id="valignment">
1277+ <property name="visible">True</property>
1278+ <property name="can_focus">False</property>
1279+ <property name="top_padding">6</property>
1280+ <property name="bottom_padding">6</property>
1281+ <property name="left_padding">6</property>
1282+ <property name="right_padding">6</property>
1283+ <child>
1284+ <object class="GtkHPaned" id="vmainpaned">
1285+ <property name="visible">True</property>
1286+ <property name="can_focus">True</property>
1287+ <child>
1288+ <object class="GtkNotebook" id="vtabs">
1289+ <property name="visible">True</property>
1290+ <property name="can_focus">True</property>
1291+ <child>
1292+ <placeholder/>
1293+ </child>
1294+ <child type="tab">
1295+ <placeholder/>
1296+ </child>
1297+ <child>
1298+ <placeholder/>
1299+ </child>
1300+ <child type="tab">
1301+ <placeholder/>
1302+ </child>
1303+ <child>
1304+ <placeholder/>
1305+ </child>
1306+ <child type="tab">
1307+ <placeholder/>
1308+ </child>
1309+ </object>
1310+ <packing>
1311+ <property name="resize">True</property>
1312+ <property name="shrink">False</property>
1313+ </packing>
1314+ </child>
1315+ <child>
1316+ <object class="GtkVPaned" id="vsubpaned">
1317+ <property name="visible">True</property>
1318+ <property name="can_focus">True</property>
1319+ <child>
1320+ <object class="GtkVBox" id="vclassroom_vbox">
1321+ <property name="visible">True</property>
1322+ <property name="can_focus">False</property>
1323+ <child>
1324+ <object class="GtkLabel" id="vclassroom_label">
1325+ <property name="visible">True</property>
1326+ <property name="can_focus">False</property>
1327+ <property name="xalign">0</property>
1328+ <property name="xpad">6</property>
1329+ <property name="ypad">3</property>
1330+ <property name="label" translatable="yes">Classroom</property>
1331+ <property name="justify">fill</property>
1332+ <attributes>
1333+ <attribute name="weight" value="bold"/>
1334+ </attributes>
1335+ </object>
1336+ <packing>
1337+ <property name="expand">False</property>
1338+ <property name="fill">True</property>
1339+ <property name="position">0</property>
1340+ </packing>
1341+ </child>
1342+ <child>
1343+ <placeholder/>
1344+ </child>
1345+ </object>
1346+ <packing>
1347+ <property name="resize">False</property>
1348+ <property name="shrink">True</property>
1349+ </packing>
1350+ </child>
1351+ <child>
1352+ <object class="GtkVBox" id="vchatroom_vbox">
1353+ <property name="visible">True</property>
1354+ <property name="can_focus">False</property>
1355+ <child>
1356+ <object class="GtkHBox" id="hbox2">
1357+ <property name="visible">True</property>
1358+ <property name="can_focus">False</property>
1359+ <property name="spacing">6</property>
1360+ <child>
1361+ <object class="GtkLabel" id="vchatroom_label">
1362+ <property name="visible">True</property>
1363+ <property name="can_focus">False</property>
1364+ <property name="xalign">0</property>
1365+ <property name="xpad">6</property>
1366+ <property name="ypad">3</property>
1367+ <property name="label" translatable="yes">_Chatroom</property>
1368+ <property name="use_underline">True</property>
1369+ <property name="justify">fill</property>
1370+ <attributes>
1371+ <attribute name="weight" value="bold"/>
1372+ </attributes>
1373+ </object>
1374+ <packing>
1375+ <property name="expand">False</property>
1376+ <property name="fill">True</property>
1377+ <property name="position">0</property>
1378+ </packing>
1379+ </child>
1380+ <child>
1381+ <object class="GtkLabel" id="vchatroom_mcount">
1382+ <property name="visible">True</property>
1383+ <property name="can_focus">False</property>
1384+ <property name="xalign">0</property>
1385+ </object>
1386+ <packing>
1387+ <property name="expand">True</property>
1388+ <property name="fill">True</property>
1389+ <property name="position">1</property>
1390+ </packing>
1391+ </child>
1392+ </object>
1393+ <packing>
1394+ <property name="expand">False</property>
1395+ <property name="fill">True</property>
1396+ <property name="position">0</property>
1397+ </packing>
1398+ </child>
1399+ <child>
1400+ <placeholder/>
1401+ </child>
1402+ </object>
1403+ <packing>
1404+ <property name="resize">True</property>
1405+ <property name="shrink">True</property>
1406+ </packing>
1407+ </child>
1408+ </object>
1409+ <packing>
1410+ <property name="resize">True</property>
1411+ <property name="shrink">True</property>
1412+ </packing>
1413+ </child>
1414+ </object>
1415+ </child>
1416+ </object>
1417 </interface>
1418
1419=== modified file 'debian/changelog'
1420--- debian/changelog 2011-05-17 20:10:30 +0000
1421+++ debian/changelog 2011-06-29 01:07:28 +0000
1422@@ -1,3 +1,72 @@
1423+lernid (0.8.1.4) natty; urgency=low
1424+
1425+ Correct classroom and chatroom labels if lernid was invoked with the
1426+ the --chatroom or --classroom option.
1427+
1428+ Fix traceback where appindicator is turned off by preference.
1429+
1430+ Correct handling of unusual case where a calendar start or stop time is
1431+ missing.
1432+
1433+ Change maintainer to John S Gruber and add copyrights. Set new version.
1434+
1435+ In the schedule add italicized event names to the titles of sessions.
1436+
1437+ Use checkbox rather than a button to allow the user to prepend "Question:"
1438+ to their contribution to the chatroom.
1439+
1440+ Let the user know about Question: in the session notification.
1441+ Fixes: LP: #793029
1442+
1443+ When classroom and chatroom are joined change their widgets from inactive to
1444+ active so it is more obvious. Fixes LP: #604658
1445+
1446+ Switch to the session tab at the beginning of the event. Suggest in session
1447+ notification that the user keep the tab selected to see all visual
1448+ materials. Use an eyecatcher, with color, to point out that additional
1449+ slides or web material are in the session tab. Add a status
1450+ message suggesting the user switch to the session tab. LP: #793788
1451+
1452+ Warn in the connection dialog that connecting can take a minute.
1453+ LP: #604773
1454+
1455+ See that only an instructor or helper can change what the browser displays.
1456+ LP: #530185. Add option to override this for testing.
1457+ (--unsafe-override).
1458+
1459+ Emphasize messages from an instructor, helper, or classbot. LP: #794126
1460+
1461+ Add a --chatroom option so that the user can specify both the classroom and
1462+ chatroom they want.
1463+
1464+ Remove nicknames saying <???> by rechecking with telepathy when a nickname
1465+ is unknown. LP: #793048
1466+
1467+ Fix mispelling of "event" in in lernid/Sessions.py code.
1468+
1469+ Change format of slide progress message to ease translation.
1470+ LP: #792364
1471+
1472+ Delay setting pane positions until the system has resized the
1473+ window. Sort of hackish. LP: #801547
1474+
1475+ Don't specify that "lernid" should be translated in LernidWindow.ui
1476+ and other locations. Addresses LP: #682807
1477+
1478+ Add classroom and chatroom names to their widgets.
1479+
1480+ Address LP: #493316 adding extensions to make Lernid more robust when a
1481+ connection doesn't exist, the config site, calendar, or irc server
1482+ cannot be reached, or the connection is dropped. Also addresses
1483+ LP: #528935, LP: #603248, LP: #795339 Supplies default configs or
1484+ calendar as needed. Session entries without complete information are
1485+ noted in the schedule.
1486+
1487+ Merge Chris Coulson's changes to remove the dependency on gtkmozembed.
1488+ LP: #799211.
1489+
1490+ -- John S Gruber <JohnSGruber@gmail.com> Mon, 27 Jun 2011 10:54:55 -0400
1491+
1492 lernid (0.8.1) natty; urgency=low
1493
1494 * Prepare next release
1495
1496=== modified file 'debian/control'
1497--- debian/control 2011-03-14 03:20:05 +0000
1498+++ debian/control 2011-06-29 01:07:28 +0000
1499@@ -6,7 +6,7 @@
1500 python,
1501 python-central (>= 0.6.11),
1502 Build-Depends-Indep: python-distutils-extra (>= 2.10)
1503-Maintainer: Michael Budde <mbudde@gmail.com>
1504+Maintainer: John S Gruber <johnsgruber@gmail.com>
1505 Standards-Version: 3.9.1
1506 XS-Python-Version: current
1507
1508@@ -17,7 +17,6 @@
1509 ${python:Depends},
1510 telepathy-idle,
1511 python-xdg,
1512- python-gtkmozembed,
1513 python-telepathy,
1514 python-webkit,
1515 python-dbus,
1516
1517=== modified file 'debian/copyright'
1518--- debian/copyright 2010-09-16 14:08:50 +0000
1519+++ debian/copyright 2011-06-29 01:07:28 +0000
1520@@ -1,11 +1,12 @@
1521 Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
1522 Upstream-Name: lernid
1523-Upstream-Maintainer: Michael Budde <mbudde@gmail.com>
1524+Upstream-Maintainer: John S Gruber <johnsgruber@gmail.com>
1525 Upstream-Source: https://launchpad.net/lernid
1526
1527 Files: *
1528 Copyright: (C) 2009 <Jono Bacon> <jono@ubuntu.com>
1529 Copyright: (C) 2010 Michael Budde <mbudde@gmail.com>
1530+Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
1531 License: GPL-3+
1532 This program is free software; you can redistribute it
1533 and/or modify it under the terms of the GNU General Public
1534
1535=== modified file 'lernid/AboutLernidDialog.py'
1536--- lernid/AboutLernidDialog.py 2010-02-08 16:49:55 +0000
1537+++ lernid/AboutLernidDialog.py 2011-06-29 01:07:28 +0000
1538@@ -47,7 +47,7 @@
1539 self.builder = builder
1540 self.builder.connect_signals(self)
1541
1542- self.set_comments(DESCRIPTION)
1543+ self.set_comments(_(DESCRIPTION))
1544 self.set_version(VERSION)
1545 self.set_website(WEBSITE)
1546 self.set_authors(CONTRIBUTORS)
1547
1548=== modified file 'lernid/EventManager.py'
1549--- lernid/EventManager.py 2010-09-15 14:28:54 +0000
1550+++ lernid/EventManager.py 2011-06-29 01:07:28 +0000
1551@@ -3,6 +3,7 @@
1552 ### BEGIN LICENSE
1553 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
1554 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
1555+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
1556 #
1557 #This program is free software: you can redistribute it and/or modify it
1558 #under the terms of the GNU General Public License version 3, as published
1559@@ -21,7 +22,8 @@
1560 import gtk
1561 import gobject
1562 import ConfigParser
1563-import urllib
1564+import urllib2
1565+import io
1566 import logging
1567
1568 from lernid import ConnectDialog
1569@@ -48,6 +50,9 @@
1570 'event-disconnect': (
1571 gobject.SIGNAL_RUN_LAST, None, (gobject.TYPE_PYOBJECT,)
1572 ),
1573+ 'event-interrupted': (
1574+ gobject.SIGNAL_RUN_LAST, None, (gobject.TYPE_PYOBJECT,)
1575+ ),
1576 }
1577
1578 def __init__(self):
1579@@ -58,8 +63,27 @@
1580 self._connectdialog = None
1581 self._passworddialog = None
1582 self._widgets = {}
1583- self._read_config()
1584+ self._config = ConfigParser.ConfigParser()
1585+ self._defaultconfig = u"""[All Ubuntu Classroom Sessions]
1586+homepage: https://wiki.ubuntu.com/Classroom
1587+classroom: ubuntu-classroom
1588+chat: ubuntu-classroom-chat
1589+icalurl: http://www.google.com/calendar/ical/canonical.com_qg6t4s8i7mg8d4lgfu9f93qid4@group.calendar.google.com/public/basic.ics
1590
1591+[Ubuntu Classes in Spanish]
1592+homepage: https://wiki.ubuntu.com/Classroom
1593+classroom: ubuntu-classroom-es
1594+Chat: ubuntu-classroom-chat-es
1595+icalurl: http://www.google.com/calendar/ical/canonical.com_qg6t4s8i7mg8d4lgfu9f93qid4@group.calendar.google.com/public/basic.ics
1596+"""
1597+ self.classbotnames = ['classbot', 'classroombot']
1598+ try:
1599+ self._configtext = self._read_config()
1600+ except IOError:
1601+ Statusbar.push_message(_('Cannot retrieve configuration'))
1602+ self._configtext = self._defaultconfig
1603+ self._config.readfp(io.StringIO(unicode(self._configtext)))
1604+
1605 @classmethod
1606 def get_instance(cls):
1607 global _instance_object
1608@@ -71,26 +95,53 @@
1609 if Options.get('config'):
1610 uri = Options.get('config')
1611 if uri.startswith('http://') or uri.startswith('https://'):
1612- configfile = urllib.urlopen(uri)
1613+ return urllib2.urlopen(uri,None,30).read()
1614 else:
1615- configfile = open(uri)
1616+ try:
1617+ return open(uri).read()
1618+ except IOError:
1619+ logging.critical("Unable to read configuration file "+uri)
1620+ raise
1621 else:
1622- configfile = urllib.urlopen('http://ubuntu-owl.org/lernid/ubuntu.lernid')
1623- self._config = ConfigParser.ConfigParser()
1624- self._config.readfp(configfile)
1625+ return urllib2.urlopen('http://ubuntu-owl.org/lernid/ubuntu.lernid',None,30).read()
1626
1627 def _connect_event(self, event, nick):
1628 if self.is_connected():
1629 self.disconnect()
1630+ if not self._config.has_option(event, 'eventstart'):
1631+ eventstart = '2011-01-01 00:00:00'
1632+ else:
1633+ eventstart = self._config.get(event, 'eventstart')
1634+ if not self._config.has_option(event, 'eventend'):
1635+ eventend = '2029-01-01 23:59:59'
1636+ else:
1637+ eventend = self._config.get(event, 'eventend')
1638+ try:
1639+ homepage = self._config(event, 'homepage')
1640+ except:
1641+ homepage = "https://wiki.ubuntu.com/Classroom"
1642+ try:
1643+ icalurl = self._config.get(event, 'icalurl')
1644+ except:
1645+ icalurl = "http://www.google.com/calendar/ical/canonical.com_qg6t4s8i7mg8d4lgfu9f93qid4@group.calendar.google.com/public/basic.ics"
1646+ try:
1647+ classroom = self._config.get(event, 'classroom')
1648+ except:
1649+ classroom = "ubuntu-classroom"
1650+ try:
1651+ chat = self._config.get(event, 'chat')
1652+ except:
1653+ chat = "ubuntu-classroom-chat"
1654+
1655 self._event = Event(
1656- name=event,
1657- nick=nick,
1658- homepage=self._config.get(event, 'homepage'),
1659- icalurl=self._config.get(event, 'icalurl'),
1660- classroom=self._config.get(event, 'classroom'),
1661- chat=self._config.get(event, 'chat'),
1662- eventstart=self._config.get(event, 'eventstart'),
1663- eventend=self._config.get(event, 'eventend')
1664+ name = event,
1665+ nick = nick,
1666+ homepage = homepage,
1667+ icalurl = icalurl,
1668+ classroom = classroom,
1669+ chat = chat,
1670+ eventstart=eventstart,
1671+ eventend=eventend
1672 )
1673 logging.debug('connecting to event {0}'.format(event))
1674 Statusbar.push_message(_('Connecting to event'), duration=10)
1675@@ -98,7 +149,7 @@
1676 self.emit('event-connect', self._event)
1677
1678 def _identify_nick(self, nick, password):
1679- server = Server.get_server('irc.freenode.net', nick)
1680+ server = Server.get_server('irc.freenode.net', nick, self)
1681 identifier = server.identify_nick(password)
1682 def update_statusbar(obj):
1683 Statusbar.push_message(_('Your nickname is now identified'), duration=60)
1684
1685=== modified file 'lernid/IrcBackend.py'
1686--- lernid/IrcBackend.py 2011-05-17 03:28:31 +0000
1687+++ lernid/IrcBackend.py 2011-06-29 01:07:28 +0000
1688@@ -3,6 +3,7 @@
1689 ### BEGIN LICENSE
1690 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
1691 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
1692+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
1693 #
1694 #This program is free software: you can redistribute it and/or modify it
1695 #under the terms of the GNU General Public License version 3, as published
1696@@ -17,6 +18,7 @@
1697 #with this program. If not, see <http://www.gnu.org/licenses/>.
1698 ### END LICENSE
1699
1700+import glib
1701 import os
1702 import gobject
1703 import random
1704@@ -52,8 +54,9 @@
1705
1706 DISCONNECTED, CONNECTING, CONNECTED = range(3)
1707
1708- def __init__(self, server, nick):
1709+ def __init__(self, server, nick, eventman):
1710 gobject.GObject.__init__(self)
1711+ self._eventman = eventman
1712 self._nick = nick
1713 self._server = server
1714 self._channels = {}
1715@@ -65,6 +68,7 @@
1716 self._nickidentifier = None
1717 self._load_manager()
1718 self._request_connection(server, nick)
1719+ self._conn_timeout = None
1720
1721 @property
1722 def nick(self):
1723@@ -75,7 +79,7 @@
1724 self._nick = val
1725
1726 @classmethod
1727- def get_server(cls, server, nick):
1728+ def get_server(cls, server, nick, eventman):
1729 logging.debug('getting server')
1730 global _server_instances
1731 if server in _server_instances:
1732@@ -84,7 +88,7 @@
1733 server_obj._request_connection(server, nick)
1734 return server_obj
1735 else:
1736- obj = cls(server, nick)
1737+ obj = cls(server, nick, eventman)
1738 _server_instances[server] = obj
1739 return obj
1740
1741@@ -109,6 +113,12 @@
1742 self._connect_private_channel(self._nickidentifier)
1743 return self._nickidentifier
1744
1745+ def connection_ready_timeout(self):
1746+ logging.debug('Connection timed out')
1747+ self.disconnect()
1748+ self._eventman.emit('event-interrupted', self._eventman._event)
1749+ return False
1750+
1751 def _load_manager(self):
1752 logging.debug('loading manager')
1753 reg = telepathy.client.ManagerRegistry()
1754@@ -135,10 +145,15 @@
1755 self._status_changed)
1756 self._conn[CONNECTION].Connect(reply_handler=ignore,
1757 error_handler=self.error)
1758+ if self._conn_timeout:
1759+ glib.source_remove(self._conn_timeout)
1760+ self._conn_timeout = glib.timeout_add_seconds(90,self.connection_ready_timeout)
1761
1762 def _ready(self, connection):
1763 logging.debug('server ready')
1764 self._state = self.CONNECTED
1765+ glib.source_remove(self._conn_timeout)
1766+ self._conn_timeout = None
1767 for channel in self._unconnected_channels.keys():
1768 self._connect_channel(channel)
1769 self._unconnected_channels = {}
1770@@ -194,6 +209,11 @@
1771 if reason == CONNECTION_STATUS_REASON_NAME_IN_USE:
1772 self._nick = '{0}{1}'.format(self._nick, random.randint(10, 99))
1773 self._request_connection(self._server, self._nick)
1774+ if reason == CONNECTION_STATUS_REASON_NETWORK_ERROR:
1775+ if self._conn_timeout:
1776+ glib.source_remove(self._conn_timeout)
1777+ self._conn_timeout = None
1778+ self._eventman.emit('event-interrupted', self._eventman._event)
1779
1780 def disconnect(self):
1781 if not self._conn:
1782@@ -303,11 +323,16 @@
1783
1784 def _received_message(self, id, timestamp, sender_handle, msgtype, flags, text):
1785 logging.debug('message received in %s' % self.name)
1786- sender = self._members.get(sender_handle, "???")
1787 if msgtype == CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
1788 msgtype = self.TYPE_ACTION
1789 else:
1790 msgtype = self.TYPE_NORMAL
1791+ if not sender_handle in self._members:
1792+ sender = self._conn[CONNECTION_INTERFACE_ALIASING].RequestAliases(
1793+ [sender_handle])[0] # Need to backstop other alias mechanisms
1794+ self._members[sender_handle] = sender
1795+ else:
1796+ sender = self._members[sender_handle]
1797 self.emit('message-received', sender, text, msgtype)
1798
1799
1800
1801=== modified file 'lernid/Sessions.py'
1802--- lernid/Sessions.py 2010-03-03 10:51:26 +0000
1803+++ lernid/Sessions.py 2011-06-29 01:07:28 +0000
1804@@ -3,6 +3,7 @@
1805 ### BEGIN LICENSE
1806 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
1807 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
1808+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
1809 #
1810 #This program is free software: you can redistribute it and/or modify it
1811 #under the terms of the GNU General Public License version 3, as published
1812@@ -19,9 +20,11 @@
1813
1814 import re
1815 import vobject
1816-import urllib
1817+import urllib2
1818+import logging
1819
1820 import lernid.DateTime as dt
1821+import io
1822
1823 class Session(object):
1824
1825@@ -29,7 +32,7 @@
1826
1827 def __init__(self, **kwargs):
1828 for k, v in kwargs.iteritems():
1829- if k in ('title', 'description', 'instructors', 'local_start', 'local_end', 'slides', 'event'):
1830+ if k in ('title', 'description', 'instructors', 'helpers', 'local_start', 'local_end', 'slides', 'event'):
1831 setattr(self, '_'+k, v)
1832
1833 @property
1834@@ -42,7 +45,11 @@
1835
1836 @property
1837 def instructors(self):
1838- return self._instructors
1839+ return getattr(self, '_instructors', [])
1840+
1841+ @property
1842+ def helpers(self):
1843+ return getattr(self, '_helpers', [])
1844
1845 @property
1846 def start_local_date(self):
1847@@ -72,8 +79,8 @@
1848 return getattr(self, '_slides', None)
1849
1850 @property
1851- def evenet(self):
1852- return self._event
1853+ def event(self):
1854+ return getattr(self, '_event', None)
1855
1856 @property
1857 def state(self):
1858@@ -88,9 +95,34 @@
1859
1860 def parse_ical(event):
1861 """Parse iCal schedule for event and generate a list of Session objects"""
1862-
1863- ical = urllib.urlopen(event.icalurl)
1864- cal = vobject.readOne(ical)
1865+ default_cal_error = (
1866+u"""BEGIN:VCALENDAR
1867+BEGIN:VEVENT
1868+DTSTART:20100101T000000Z
1869+DTEND:20100101T000000Z
1870+DESCRIPTION:CalendarError
1871+SUMMARY: """ + _('Unable to load calendar %s\n') +
1872+u"""END:VEVENT
1873+END:VCALENDAR""") % event.icalurl
1874+ default_cal_error2 = (
1875+u"""BEGIN:VCALENDAR
1876+BEGIN:VEVENT
1877+DTSTART:20100101T000000Z
1878+DTEND:20100101T000000Z
1879+DESCRIPTION:CalendarError
1880+SUMMARY: """ + _('Unable to parse calendar %s\n') +
1881+u"""END:VEVENT
1882+END:VCALENDAR""") % event.icalurl
1883+ try:
1884+ ical = urllib2.urlopen(event.icalurl, None, 30)
1885+ except IOError:
1886+ logging.error('Unable to open calendar %s' % event.icalurl)
1887+ ical = io.StringIO(default_cal_error)
1888+ try:
1889+ cal = vobject.readOne(ical)
1890+ except:
1891+ logging.critical('Error parsing calendar at %s' % event.icalurl)
1892+ cal = vobject.readOne(io.StringIO(default_cal_error2))
1893
1894 sessions = []
1895
1896@@ -98,14 +130,26 @@
1897 eventend_local = dt.parse_time(event.eventend, '%Y-%m-%d %H:%M:%S')
1898
1899 for session in cal.vevent_list:
1900- local_start = dt.as_local(session.dtstart.value)
1901- local_end = dt.as_local(session.dtend.value)
1902-
1903- if eventstart_local < local_start < eventend_local:
1904+ session_data = {}
1905+ if not hasattr(session, "dtstart") or not hasattr(session, "dtend"):
1906+ logging.debug("Missing or invalid time for event")
1907+ local_start = eventend_local
1908+ local_end = eventend_local
1909+ else:
1910+ local_start = dt.as_local(session.dtstart.value)
1911+ local_end = dt.as_local(session.dtend.value)
1912 if hasattr(session, "description"):
1913+ if session.description.value == "CalendarError":
1914+ local_start = eventend_local
1915+ local_end = eventend_local
1916 session_data = parse_ical_description(session.description.value)
1917+ if hasattr(session, "summary"):
1918+ summary = session.summary.value
1919+ else:
1920+ summary = _('Missing Session Name')
1921+ if eventstart_local <= local_start <= eventend_local:
1922 sessions.append(Session(
1923- title = session.summary.value,
1924+ title = summary,
1925 local_start = local_start,
1926 local_end = local_end,
1927 **session_data))
1928@@ -127,4 +171,7 @@
1929 elif key == 'instructor' or key == 'instructors':
1930 instructors = [s.strip() for s in value.split(',')]
1931 session['instructors'] = instructors
1932+ elif key == 'helper' or key == 'helpers':
1933+ helpers = [s.strip() for s in value.split(',')]
1934+ session['helpers'] = helpers
1935 return session
1936
1937=== modified file 'lernid/lernidconfig.py'
1938--- lernid/lernidconfig.py 2011-06-02 04:43:14 +0000
1939+++ lernid/lernidconfig.py 2011-06-29 01:07:28 +0000
1940@@ -29,7 +29,9 @@
1941 import os
1942 import xdg.BaseDirectory
1943
1944-VERSION = '0.8.1'
1945+def _(message): return message
1946+
1947+VERSION = '0.8.1.4'
1948 DESCRIPTION = _('Connect to a world of online tutorials quickly and easily.')
1949 WEBSITE = 'http://wiki.ubuntu.com/Lernid'
1950 CONTRIBUTORS = [
1951@@ -44,6 +46,7 @@
1952 "Peeyoosh Sangolekar <piyush_sangolekar@hotmail.com>",
1953 "Sanne Wouda <sanne@gruttepier.net>",
1954 "Sense Hofstede <sense@qense.nl>",
1955+ "John S Gruber <johnsgruber@gmail.com>",
1956 ]
1957 ARTISTS = [
1958 'K.Vishnoo Charan Reddy <foo.mac.v@gmail.com>'
1959
1960=== modified file 'lernid/widgets/Browser.py'
1961--- lernid/widgets/Browser.py 2011-04-19 02:12:34 +0000
1962+++ lernid/widgets/Browser.py 2011-06-29 01:07:28 +0000
1963@@ -24,6 +24,7 @@
1964 import re
1965
1966 from lernid.widgets.Widget import Widget
1967+from lernid.LernidOptions import Options
1968
1969 class Browser(Widget):
1970
1971@@ -89,6 +90,8 @@
1972 # FIXME: why does the button not follow sensitive state of the toolbar?
1973 self._pause_button.set_sensitive(True)
1974 self.set_location(event.homepage)
1975+ schedule = eventman.get_widget_by_name('schedule')
1976+ self._on_faculty = schedule.on_faculty # retrieve method
1977
1978 def do_event_disconnect(self, eventman, event):
1979 self._url_combo.handler_block_by_func(self._change_page)
1980@@ -138,6 +141,8 @@
1981 def _update_url_combo(self, browser, *args):
1982 """Update the browser url combo box with the new title."""
1983 url = browser.get_property('uri')
1984+ if url == None:
1985+ url = ''
1986 logging.debug('update url combo: {0}'.format(url))
1987 if url == 'about:blank':
1988 return
1989@@ -177,6 +182,8 @@
1990 self.set_location(url)
1991
1992 def _classroom_msg_received(self, classroom, chan, sender, text):
1993+ if not Options.get('unsafe-override') and not self._on_faculty(sender):
1994+ return
1995 load, ignore = self._parse_urls(text)
1996 if load and not self._paused:
1997 self.set_location(load)
1998
1999=== modified file 'lernid/widgets/Classroom.py'
2000--- lernid/widgets/Classroom.py 2011-03-14 03:19:11 +0000
2001+++ lernid/widgets/Classroom.py 2011-06-29 01:07:28 +0000
2002@@ -3,6 +3,7 @@
2003 ### BEGIN LICENSE
2004 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
2005 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
2006+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
2007 #
2008 #This program is free software: you can redistribute it and/or modify it
2009 #under the terms of the GNU General Public License version 3, as published
2010@@ -19,7 +20,6 @@
2011
2012 import gtk
2013 import gobject
2014-import gtkmozembed
2015 import pango
2016 import time
2017
2018@@ -56,6 +56,7 @@
2019 self._textview.set_left_margin(6)
2020 self._textview.set_right_margin(6)
2021 self._textview.modify_font(pango.FontDescription('Monospace'))
2022+ self._textview.set_sensitive(False)
2023 self._textview.connect('size-allocate', self._scroll)
2024 self._at_bottom = None
2025 scroll.add(self._textview)
2026@@ -63,24 +64,25 @@
2027 self._buffer = self._textview.get_buffer()
2028 text_color = self._textview.get_style().text[gtk.STATE_INSENSITIVE]
2029 self._buffer.create_tag('gray', foreground_gdk=text_color)
2030- highlight = self._textview.get_style().bg[gtk.STATE_SELECTED]
2031- self._buffer.create_tag('highlight', foreground_gdk=highlight)
2032+ self._buffer.create_tag('highlight', weight=700)
2033 self._init_hyperlinks()
2034
2035 self.show_all()
2036
2037 def do_event_connect(self, event_man, event):
2038 IrcWidget.do_event_connect(self, event_man, event)
2039- self._server = IrcBackend.Server.get_server('irc.freenode.net', event.nick)
2040+ self._server = IrcBackend.Server.get_server('irc.freenode.net', event.nick, event_man)
2041 self._nick = event.nick
2042 classchan = self._server.get_channel(Options.get('classroom', event.classroom))
2043 def joined(server):
2044- Statusbar.push_message(_('Joined classroom'), duration=10)
2045+ Statusbar.push_message(_('Joined classroom'))
2046+ self._textview.set_sensitive(True)
2047 self.event_connect_signal(classchan, 'joined', joined)
2048 self.event_connect_signal(classchan, 'message-received', self._message_received)
2049 self._browser = event_man.get_widget_by_name('browser')
2050
2051 def do_event_disconnect(self, event_man, event):
2052+ self._textview.set_sensitive(False)
2053 istart, iend = self._buffer.get_bounds()
2054 self._buffer.delete(istart, iend)
2055 classchan = self._server.get_channel(
2056
2057=== modified file 'lernid/widgets/IrcWidget.py'
2058--- lernid/widgets/IrcWidget.py 2010-03-05 00:45:41 +0000
2059+++ lernid/widgets/IrcWidget.py 2011-06-29 01:07:28 +0000
2060@@ -30,12 +30,23 @@
2061
2062 class IrcWidget(Widget):
2063
2064- hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
2065- regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
2066+ def get_hand_cursor(self):
2067+ if not hasattr(self, "_hand_cursor"):
2068+ self._hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
2069+ return self._hand_cursor
2070+
2071+ def get_regular_cursor(self):
2072+ if not hasattr(self, "_regular_cursor"):
2073+ self._regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
2074+ return self._regular_cursor
2075
2076 def do_event_connect(self, event_man, event):
2077 self._browser = event_man.get_widget_by_name('browser')
2078 self.get_toplevel().connect('focus-out-event', self._focus_out)
2079+ schedule = event_man.get_widget_by_name('schedule')
2080+ self._on_faculty = schedule.on_faculty # retrieve method
2081+ self._classbotnames = event_man.classbotnames
2082+
2083
2084 def _init_hyperlinks(self):
2085 hyperlink_tag = self._buffer.create_tag('hyperlink', foreground='#0000ff',
2086@@ -69,6 +80,8 @@
2087 start_pos = iend.get_offset()
2088 if self._nick in text and sender != self._nick:
2089 self._buffer.insert_with_tags_by_name(iend, text, 'highlight')
2090+ elif self._on_faculty(sender) or sender in self._classbotnames:
2091+ self._buffer.insert_with_tags_by_name(iend, text, 'highlight')
2092 else:
2093 self._buffer.insert(iend, text)
2094
2095@@ -92,9 +105,9 @@
2096 int(event.x), int(event.y))
2097 iter = text_view.get_iter_at_location(x, y)
2098 if (iter.has_tag(tag)):
2099- text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.hand_cursor)
2100+ text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.get_hand_cursor())
2101 else:
2102- text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.regular_cursor)
2103+ text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.get_regular_cursor())
2104 return False
2105
2106 def _focus_out(self, widget, event):
2107
2108=== modified file 'lernid/widgets/NativeChatroom.py'
2109--- lernid/widgets/NativeChatroom.py 2011-03-14 03:19:11 +0000
2110+++ lernid/widgets/NativeChatroom.py 2011-06-29 01:07:28 +0000
2111@@ -1,9 +1,9 @@
2112-
2113 #!/usr/bin/python
2114 # -*- coding: utf-8 -*-
2115 ### BEGIN LICENSE
2116 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
2117 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
2118+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
2119 #
2120 #This program is free software: you can redistribute it and/or modify it
2121 #under the terms of the GNU General Public License version 3, as published
2122@@ -20,7 +20,6 @@
2123
2124 import gtk
2125 import gobject
2126-import gtkmozembed
2127 import urlparse
2128 import logging
2129 import pango
2130@@ -30,6 +29,7 @@
2131 from lernid.widgets.IrcWidget import IrcWidget
2132
2133 from lernid import IrcBackend
2134+from lernid.LernidOptions import Options
2135
2136 class Chatroom(IrcWidget):
2137
2138@@ -53,14 +53,18 @@
2139 self.add(builder.get_object('vbox1'))
2140 self._textview = builder.get_object('textview')
2141 self._textview.modify_font(pango.FontDescription('Monospace'))
2142+ self._textview.set_sensitive(False)
2143 self._textview.connect('size-allocate', self._scroll)
2144 self._at_bottom = None
2145
2146 self._buffer = self._textview.get_buffer()
2147 text_color = self._textview.get_style().text[gtk.STATE_INSENSITIVE]
2148 self._buffer.create_tag('gray', foreground_gdk=text_color)
2149- highlight = self._textview.get_style().bg[gtk.STATE_SELECTED]
2150- self._buffer.create_tag('highlight', foreground_gdk=highlight)
2151+ self._buffer.create_tag('highlight', weight=700)
2152+ self._bold = pango.FontDescription()
2153+ self._bold.set_weight(700)
2154+ self._light = pango.FontDescription()
2155+ self._light.set_weight(300)
2156
2157 self._input = builder.get_object('input')
2158 self._input.connect('icon-press', self._send_text)
2159@@ -68,20 +72,23 @@
2160 self._input.connect('key-press-event', self._key_pressed)
2161 self._input.modify_font(pango.FontDescription('Monospace'))
2162
2163- self._questionbutton = builder.get_object('questionbutton')
2164- self._questionbutton.connect('toggled', self._questionbutton_toggled)
2165+ self._questioncheckbox = builder.get_object('questioncheckbox')
2166+ self._questioncheckbox.connect('toggled', self._questioncheckbox_toggled)
2167+ self._questionlabel = builder.get_object('questionlabel')
2168+ self._questionlabel.modify_font(self._light)
2169
2170 self._init_hyperlinks()
2171
2172 def do_event_connect(self, eventman, event):
2173 IrcWidget.do_event_connect(self, eventman, event)
2174- self._server = IrcBackend.Server.get_server('irc.freenode.net', event.nick)
2175+ self._server = IrcBackend.Server.get_server('irc.freenode.net', event.nick, eventman)
2176 self._nick = event.nick
2177- self._chatchan = self._server.get_channel(event.chat)
2178+ self._chatchan = self._server.get_channel(Options.get('chatroom', event.chat))
2179 def joined(server):
2180 logging.debug('connected to chatroom')
2181 self._input.set_sensitive(True)
2182- self._questionbutton.set_sensitive(True)
2183+ self._questioncheckbox.set_sensitive(True)
2184+ self._textview.set_sensitive(True)
2185 self.event_connect_signal(self._chatchan, 'joined', joined)
2186 self.event_connect_signal(self._chatchan, 'message-received', self._message_received)
2187 self.event_connect_signal(self._chatchan, 'message-sent', self._message_sent)
2188@@ -91,7 +98,8 @@
2189
2190 def do_event_disconnect(self, eventman, event):
2191 self._input.set_sensitive(False)
2192- self._questionbutton.set_sensitive(False)
2193+ self._questioncheckbox.set_sensitive(False)
2194+ self._textview.set_sensitive(False)
2195 istart, iend = self._buffer.get_bounds()
2196 self._buffer.delete(istart, iend)
2197 self._server.disconnect()
2198@@ -162,9 +170,9 @@
2199 return
2200 if text.startswith('/'):
2201 self._append_to_buffer(_('IRC commands are not yet supported.'))
2202- elif self._questionbutton.get_active():
2203- self._questionbutton.set_active(False)
2204- self._chatchan.send_message('QUESTION:' + ' ' + text)
2205+ elif self._questioncheckbox.get_active():
2206+ self._questioncheckbox.set_active(False)
2207+ self._chatchan.send_message(_('QUESTION:') + ' ' + text)
2208 else:
2209 self._chatchan.send_message(text)
2210 self._input.set_text('')
2211@@ -182,6 +190,9 @@
2212 if self._at_bottom:
2213 self._adjust.value = self._adjust.upper - self._adjust.page_size
2214
2215- def _questionbutton_toggled(self, *args):
2216+ def _questioncheckbox_toggled(self, *args):
2217 self._input.grab_focus()
2218-
2219+ if self._questioncheckbox.get_active():
2220+ self._questionlabel.modify_font(self._bold)
2221+ else:
2222+ self._questionlabel.modify_font(self._light)
2223
2224=== modified file 'lernid/widgets/Schedule.py'
2225--- lernid/widgets/Schedule.py 2010-02-24 20:12:48 +0000
2226+++ lernid/widgets/Schedule.py 2011-06-29 01:07:28 +0000
2227@@ -3,6 +3,7 @@
2228 ### BEGIN LICENSE
2229 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
2230 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
2231+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
2232 #
2233 #This program is free software: you can redistribute it and/or modify it
2234 #under the terms of the GNU General Public License version 3, as published
2235@@ -105,7 +106,7 @@
2236 cell = gtk.CellRendererText()
2237 cell.set_property('xpad', 6)
2238 column.pack_start(cell, True)
2239- column.set_attributes(cell, text=self.COL_TITLE)
2240+ column.set_attributes(cell, markup=self.COL_TITLE)
2241 label = gtk.Label(_('Title'))
2242 label.set_padding(6, 0)
2243 label.show()
2244@@ -119,6 +120,19 @@
2245 self.show_all()
2246
2247 def do_event_connect(self, event_man, event):
2248+ def quote(text):
2249+ quote_table = {
2250+ '<' : '&lt;',
2251+ '>' : '&gt;',
2252+ "'" : '&apos;',
2253+ '"' : '&quot;',
2254+ '&' : '&amp;'
2255+ }
2256+ return_value = ''
2257+ for l in text:
2258+ return_value= return_value + quote_table.get(l,l)
2259+ return return_value
2260+
2261 self._schedule = parse_ical(event)
2262 self._model.clear()
2263 for session in self._schedule:
2264@@ -127,7 +141,11 @@
2265 sessionrow.append(session.start_local_date)
2266 sessionrow.append(session.start_local_time)
2267 sessionrow.append(session.end_local_time)
2268- sessionrow.append(session.title)
2269+ title = quote(session.title)
2270+ if session.event:
2271+ sessionrow.append(title +' <i>' + quote(session.event) +'</i>')
2272+ else:
2273+ sessionrow.append(title)
2274 sessionrow.append(session)
2275 self._model.append(sessionrow)
2276
2277@@ -143,6 +161,7 @@
2278
2279 def do_event_disconnect(self, event_man, event):
2280 self._schedule = []
2281+ self._current_session = None
2282 self._model.clear()
2283 if self._update_handle:
2284 glib.source_remove(self._update_handle)
2285@@ -159,9 +178,13 @@
2286 row[self.COL_ICON] = gtk.STOCK_GO_FORWARD
2287 if session != self._current_session:
2288 if self._current_session == None:
2289+ session_message = _("Please keep the Session "
2290+ "tab selected to see session"
2291+ " learning materials.")
2292 self.show_notification(
2293 _('Session started'),
2294- _('The session "{0}" has started.').format(session.title)
2295+ _('The session "{0}" has started. ').format(session.title) +
2296+ session_message
2297 )
2298 self._current_session = session
2299 logging.debug('session changed')
2300@@ -183,6 +206,9 @@
2301 def get_current_session(self):
2302 return self._current_session
2303
2304+ def on_faculty(self,name):
2305+ return self._current_session and name in self._current_session.instructors + self._current_session.helpers
2306+
2307 def show_notification(self, summary, body):
2308 n = pynotify.Notification(summary, body, 'lernid')
2309 n.show()
2310
2311=== modified file 'lernid/widgets/Slide.py'
2312--- lernid/widgets/Slide.py 2011-04-27 21:31:17 +0000
2313+++ lernid/widgets/Slide.py 2011-06-29 01:07:28 +0000
2314@@ -3,6 +3,7 @@
2315 ### BEGIN LICENSE
2316 # Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
2317 # Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
2318+# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
2319 #
2320 #This program is free software: you can redistribute it and/or modify it
2321 #under the terms of the GNU General Public License version 3, as published
2322@@ -76,6 +77,8 @@
2323
2324 def do_event_connect(self, eventman, event):
2325 classroom = eventman.get_widget_by_name('classroom')
2326+ schedule = eventman.get_widget_by_name('schedule')
2327+ self._on_faculty = schedule.on_faculty # retrieve method
2328 self.event_connect_signal(classroom, 'message-received', self._classroom_msg_received)
2329 schedule = eventman.get_widget_by_name('schedule')
2330 self.event_connect_signal(schedule, 'session-changed', self._session_changed)
2331@@ -88,9 +91,10 @@
2332 self.event_disconnect_signals()
2333
2334 def _classroom_msg_received(self, classroom, chan, sender, text):
2335- matches = re.search(r'\[SLIDE (\d+)\]', text)
2336+ matches = re.search(r'\[SLIDE (\d+)\]', text.upper())
2337 if matches and self._session_slide_downloaded:
2338- self._change_slide_page(int(matches.groups()[0]))
2339+ if self._on_faculty(sender):
2340+ self._change_slide_page(int(matches.groups()[0]))
2341
2342 def _change_slide_page(self, pagenumber):
2343 logging.debug('changing slide to page %d' % pagenumber)
2344@@ -144,7 +148,7 @@
2345 logging.debug('downloading slides from %s' % session.slides)
2346 def reporthook(blocks, bs, size):
2347 Statusbar.pop_message('slidesession')
2348- msg = _('Downloading session slides ({0} % of {1:.1} MB)...').format(100*blocks*bs/size, float(size)/float(1024*1024))
2349+ msg = _('Downloading session slides (%i%% of %i MB)...') % (100*blocks*bs/size, float(size)/float(1024*1024))
2350 Statusbar.push_message(msg, 'slidesession')
2351 urllib.urlretrieve(session.slides, path, reporthook)
2352 Statusbar.push_message(_('Slides have been downloaded'), 'slidesession')
2353
2354=== modified file 'lernid/widgets/WebChatroom.py'
2355--- lernid/widgets/WebChatroom.py 2010-02-08 16:49:55 +0000
2356+++ lernid/widgets/WebChatroom.py 2011-06-29 01:07:28 +0000
2357@@ -19,7 +19,7 @@
2358
2359 import gtk
2360 import gobject
2361-import gtkmozembed
2362+import webkit
2363
2364 from lernid.widgets.Widget import Widget
2365
2366@@ -37,7 +37,7 @@
2367 Widget.__init__(self, 'chatroom')
2368 scroll = gtk.ScrolledWindow()
2369 scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
2370- self._chat = gtkmozembed.MozEmbed()
2371+ self._chat = webkit.WebView()
2372 scroll.add_with_viewport(self._chat)
2373 self.add(scroll)
2374
2375@@ -50,11 +50,11 @@
2376 def do_event_connect(self, event_man, event):
2377 chatirc = 'http://webchat.freenode.net/?nick={nick}&channels={chans}'.format(
2378 nick=event.nick, chans=event.chat)
2379- self._chat.load_url(chatirc)
2380+ self._chat.load_uri(chatirc)
2381 self._chat.show()
2382
2383 def do_event_disconnect(self, event_man, event):
2384- self._chat.load_url('about:blank')
2385+ self._chat.load_uri('about:blank')
2386 self._chat.hide()
2387
2388 def get_input_widget(self):
2389
2390=== modified file 'setup.py'
2391--- setup.py 2011-05-17 20:10:30 +0000
2392+++ setup.py 2011-06-29 01:07:28 +0000
2393@@ -68,10 +68,10 @@
2394
2395 setup(
2396 name = 'lernid',
2397- version = '0.8.1',
2398+ version = '0.8.1.4',
2399 license = 'GPL-3',
2400- author = 'Michael Budde',
2401- author_email = 'mbudde@gmail.com',
2402+ author = 'John S Gruber',
2403+ author_email = 'johnsgruber@gmail.com',
2404 description = 'Connect to Ubuntu learning events.',
2405 long_description = 'Lernid provides an interface for joining in Ubuntu learning events such as Ubuntu Open Week and Ubuntu Developer Week.',
2406 url = 'https://launchpad.net/lernid',

Subscribers

People subscribed via source and target branches