3 This is the main module that binds everything together.
6 __copyright__
= "Copyright (c) 2002-2005 Free Software Foundation, Inc."
7 __license__
= """ GNU General Public License
9 This program is free software; you can redistribute it and/or modify it under the
10 terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with
19 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 Place - Suite 330, Boston, MA 02111-1307, USA. """
23 from xml
.sax
import saxutils
26 import gobject
, gtk
, gtk
.glade
33 import FeedCategoryList
36 from ItemView
import ItemView
37 from ItemList
import ItemListPresenter
, ItemListView
38 from FeedListView
import FeedsView
, FeedsPresenter
39 from OfflineToggle
import OfflineToggle
40 from MainloopManager
import MainloopManager
41 from FeedPropertiesDialog
import FeedPropertyView
, FeedPropertyPresenter
, show_feed_properties
as show_feed_properties_dialog
42 from PreferencesDialog
import PreferencesDialog
43 #from Find import FindPresenter, FindView
52 class StatusPresenter(MVP
.BasicPresenter
):
53 def _initialize(self
):
54 self
._mmgr
= MessageManager
.get_instance()
55 self
._mmgr
.signal_connect(Event
.StatusDisplaySignal
,
59 def _display(self
, signal
):
60 cid
= self
._view
.get_context_id("straw_main")
62 self
._view
.push(cid
, self
._mmgr
.read_message())
66 def __init__(self
, widget
):
68 self
._tooltips
= gtk
.Tooltips()
70 #self._curr_feed = None
71 #self._curr_category = None
72 #fclist = FeedCategoryList.get_instance()
73 #fclist.connect('category-changed', self._category_changed)
75 def feedlist_selection_changed(self
, selection
, column
):
77 (model
, pathlist
) = selection
.get_selected_rows()
78 iters
= [model
.get_iter(path
) for path
in pathlist
]
81 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
83 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
84 errortexts
= [feed
.error
for feed
in errorfeeds
]
87 ### XXX display OPML Category error too
91 text
.append(_("Error:"))
96 self
._tooltips
.set_tip(self
._widget
,t
,t
)
97 self
._tooltips
.enable()
100 self
._tooltips
.disable()
107 class MenuFeedPropsPresenter(MVP
.BasicPresenter
):
108 def set_sensitive(self
, s
):
109 self
._view
.set_sensitive(s
)
112 class ToolbarView(MVP
.WidgetView
):
113 """ Widget: gtk.Toolbar"""
114 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
116 def _initialize(self
):
117 client
= gconf
.client_get_default()
118 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
120 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
121 gconf
.CLIENT_PRELOAD_NONE
)
122 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
123 self
._toolbar
_style
_changed
)
124 self
._widget
.set_tooltips(True)
126 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
127 value
= entry
.value
.get_string()
128 self
._presenter
.style_changed(value
)
130 def set_style(self
, style
):
131 self
._widget
.set_style(style
)
134 client
= gconf
.client_get_default()
135 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
138 class ToolbarPresenter(MVP
.BasicPresenter
):
139 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
140 'text':gtk
.TOOLBAR_TEXT
,
141 'icons':gtk
.TOOLBAR_ICONS
,
142 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
144 def _initialize(self
):
145 style
= self
._view
.get_style()
146 if style
in self
.STYLES
.keys():
147 self
._view
.set_style(self
.STYLES
[style
])
150 def style_changed(self
, value
):
151 if value
in self
.STYLES
.keys():
152 self
._view
.set_style(self
.STYLES
[value
])
155 class ApplicationPresenter(MVP
.BasicPresenter
):
156 def _initialize(self
):
157 self
._curr
_category
= None
158 self
._curr
_feed
= None
159 self
._curr
_item
= None
161 self
._init
_presenters
()
162 self
._prefs
_dialog
= None
165 def _init_widgets(self
):
166 widget_tree
= self
._view
.get_widget_tree()
167 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
168 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
170 def _init_presenters(self
):
171 widget_tree
= self
._view
.get_widget_tree()
172 toolbar_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
173 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
175 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
177 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
178 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
179 view
.add_selection_changed_listener(self
._item
_view
)
181 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
182 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
183 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
184 view
.add_selection_changed_listener(self
._error
_presenter
)
186 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
188 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
189 self
._menufp
_presenter
= MenuFeedPropsPresenter( view
= widget_tree
.get_widget('menu_feed_properties'))
190 self
._menufp
_presenter
.set_sensitive(False)
191 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
194 def copy_itemview_text_selection(self
):
195 utils
.set_clipboard_text(self
._item
_view
.get_selected_text())
197 def check_allocation(self
, widget
, event
):
198 config
= Config
.get_instance()
199 def check_size((width
, height
, widget
)):
200 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
201 config
.main_window_size
= (width
, height
)
202 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
203 gobject
.timeout_add(1000, check_size
, (
204 (event
.width
, event
.height
, widget
)))
206 def check_main_pane_position(self
, widget
):
207 config
= Config
.get_instance()
208 def check_position((position
, widget
)):
209 if position
== widget
.get_position():
210 config
.main_pane_position
= position
211 pos
= widget
.get_position()
212 if pos
!= config
.main_pane_position
:
213 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
215 def check_sub_pane_position(self
, widget
):
216 config
= Config
.get_instance()
217 def check_position((position
, widget
)):
218 if position
== widget
.get_position():
219 config
.sub_pane_position
= position
220 pos
= widget
.get_position()
221 if pos
!= config
.sub_pane_position
:
222 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
225 return dialogs
.credits()
228 if self
._warn
_if
_offline
():
229 fclist
= FeedCategoryList
.get_instance()
230 self
._poll
_categories
(fclist
.all_categories
)
233 def poll_current_category(self
):
234 if self
._warn
_if
_offline
():
235 self
._poll
_categories
([self
._curr
_category
])
238 def poll_current_feed(self
):
239 if self
._warn
_if
_offline
():
240 pm
= PollManager
.get_instance()
241 pm
.poll([self
._curr
_feed
])
244 def mark_feed_as_read(self
):
245 self
._curr
_feed
.mark_all_read()
247 def mark_all_as_read(self
):
248 mmgr
= MainloopManager
.get_instance()
249 flist
= feeds
.get_instance().flatten_list()
253 if feed
is self
._curr
_feed
:
255 feed
.unload_contents()
258 def remove_selected_feed(self
):
259 # self._feed_list_presenter.remove_selected_feed()
262 def show_search(self
):
263 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
264 # self._item_view.item_selection_changed)
265 self
._item
_view
.display_empty_search()
266 self
._itemlist
_view
_notebook
.set_current_page(1)
267 self
._feedlist
_view
_notebook
.set_current_page(1)
268 self
._feedinfo
_presenter
.hide()
270 def hide_search(self
):
271 # self._find_presenter.clear()
272 self
._itemlist
_view
_notebook
.set_current_page(0)
273 self
._feedlist
_view
_notebook
.set_current_page(0)
274 self
._feedinfo
_presenter
.show()
275 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
276 # self._item_view.item_selection_changed)
279 def _poll_categories(self
, fclist
):
280 pm
= PollManager
.get_instance()
281 pm
.poll_categories(fclist
)
284 def _warn_if_offline(self
):
285 config
= Config
.get_instance()
288 response
= self
._view
.show_offline_dialog()
289 if response
== gtk
.RESPONSE_OK
:
290 config
.offline
= not config
.offline
296 def _get_next_category(self
, category
= None):
298 category
= self
._curr
_category
299 fclist
= FeedCategoryList
.get_instance()
300 allcats
= fclist
.user_categories
+ list(fclist
.pseudo_categories
)
302 category
= allcats
[0]
304 index
= allcats
.index(category
)
305 if index
< len(allcats
) - 1:
309 category
= allcats
[index
]
312 def _get_previous_category(self
, category
= None):
314 category
= self
._curr
_category
315 fclist
= FeedCategoryList
.get_instance()
316 allcats
= fclist
.user_categories
+ list(fclist
.pseudo_categories
)
318 category
= allcats
[-1]
320 index
= allcats
.index(category
)
324 index
= len(allcats
) - 1
325 category
= allcats
[index
]
328 def display_previous_category(self
, category
= None):
330 Displays the category before the current selected category
332 category
= self
._get
_previous
_category
(category
)
333 # self._category_selector.category_selected(category)
334 self
._display
_category
_feeds
(category
)
336 def display_next_category(self
, category
= None):
338 Display the category after the current selected category
340 category
= self
._get
_next
_category
(category
)
341 # self._category_selector.category_selected(category)
342 self
._display
_category
_feeds
(category
)
344 def display_previous_feed(self
, item
= None):
346 Displays the feed before the current selected feed
348 self
._feed
_list
_presenter
.select_previous_feed()
350 def display_next_feed(self
, item
=None):
352 Displays the feed after the current selected feed
354 self
._feed
_list
_presenter
.select_next_feed()
357 def display_next_unread_feed(self
):
359 Displays the next feed with an unread item
361 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
364 def display_previous_item(self
, item
=None):
366 Displays the item before the current selected item. If the item is the
367 first item, scrolls to the previous feed
369 is_prev
= self
._itemlist
_presenter
.select_previous_item()
371 # TODO HACK - implement select_previous_feed(select_last=True) ...
372 # ... to select previous feed's last item
373 self
._feed
_list
_presenter
.select_previous_feed()
374 self
._itemlist
_presenter
.select_last_item()
378 def display_next_item(self
, item
=None):
380 Displays the item after the current selected item. If the item is the
381 last item, selectes the next feed. If the current feed is the last
382 feed in the list, it goes back and selects the first feed
384 is_next
= self
._itemlist
_presenter
.select_next_item()
386 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
388 self
._feed
_list
_presenter
.select_firsteed_feed()
391 def scroll_or_display_next_unread_item(self
, item
=None):
392 has_unread_item
= False
393 if not self
._item
_view
.scroll_down():
394 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
395 if not has_unread_item
:
396 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
399 def show_preferences_dialog(self
, parent
):
400 if not self
._prefs
_dialog
:
401 xf
= utils
.find_glade_file()
402 xml
= gtk
.glade
.XML(xf
, "preferences_dialog", gettext
.textdomain())
403 self
._prefs
_dialog
= PreferencesDialog(xml
, parent
)
404 self
._prefs
_dialog
.show()
406 def show_feed_properties(self
, parent
):
407 fpd
= show_feed_properties_dialog(parent
, self
._curr
_feed
)
412 ItemStore
.get_instance().stop()
415 class ApplicationView(MVP
.WidgetView
):
419 def _initialize(self
):
420 self
._config
= Config
.get_instance()
421 self
._initialize
_dnd
()
422 self
._initialize
_window
_updater
()
423 self
._create
_unmodified
_accelerator
_group
()
424 self
._attach
_unmodified
_accelerator
_group
()
425 self
._initialize
_window
()
426 self
._find
_toggled
= False
428 def _initialize_window(self
):
429 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
430 if self
._config
.window_maximized
:
431 self
._widget
.maximize()
433 # we use resize here since configure-event seems to
434 # overwrite the default size if we use set_default_size.
435 self
._widget
.resize(*self
._config
.main_window_size
)
436 mmp
= widget_tree
.get_widget('main_main_pane')
437 msp
= widget_tree
.get_widget('main_sub_pane')
438 mmp
.set_position(self
._config
.main_pane_position
)
439 msp
.set_position(self
._config
.sub_pane_position
)
441 def _initialize_dnd(self
):
442 self
._widget
.drag_dest_set(
443 gtk
.DEST_DEFAULT_ALL
,
444 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
445 ('x-url/http', 0, 2)],
446 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
449 def _initialize_window_updater(self
):
450 feedlist
= feeds
.get_instance()
451 #feedlist.signal_connect(Event.AllItemsReadSignal,
452 # lambda signal: self._update_title(feedlist))
453 #feedlist.signal_connect(Event.ItemReadSignal,
454 # lambda signal: self._update_title(feedlist))
455 #feedlist.signal_connect(Event.ItemsAddedSignal,
456 # lambda signal: self._update_title(feedlist))
457 #feedlist.signal_connect(Event.FeedsChangedSignal,
458 # lambda signal: self._update_title(feedlist))
461 def _update_title(self
, flist
):
462 uritems
= urfeeds
= 0
464 listfeeds
= flist
.flatten_list()
465 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
470 urfeeds
= len(listfeeds
)
473 item_feed_map
= {'uritems': uritems
,
476 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
477 self
._widget
.set_title( title
+ " - %s" % constants
.APPNAME
)
480 # We have a separate accelerator group for the unmodified and
481 # shifted accelerators, that is, stuff like space, N, P, etc. This
482 # is so that we can have the find pane work correctly
483 def _create_unmodified_accelerator_group(self
):
484 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
485 agroup
= gtk
.AccelGroup()
486 accels
= (('menu_mark_feed_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
487 ('menu_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
488 ('menu_next', 'N', gtk
.gdk
.SHIFT_MASK
),
489 ('menu_next_unread', ' ', 0),
490 ('menu_previous', 'P', gtk
.gdk
.SHIFT_MASK
))
491 for widget_name
, key
, mask
in accels
:
492 widget
= xml
.get_widget(widget_name
)
493 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
495 self
._unmodified
_accelerator
_group
= agroup
497 def _attach_unmodified_accelerator_group(self
):
498 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
500 def _detach_unmodified_accelerator_group(self
):
501 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
503 def _on_straw_main_destroy_event(self
, *args
):
504 return self
._presenter
.quit()
506 def _on_straw_main_delete_event(self
, *args
):
507 return self
._presenter
.quit()
509 def _on_menu_quit_activate(self
, *args
):
510 return self
._presenter
.quit()
512 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
513 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
514 self
._config
.window_maximized
= False
515 self
._presenter
.check_allocation(widget
, event
)
517 self
._config
.window_maximized
= True
520 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
521 self
._presenter
.check_main_pane_position(widget
)
523 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
524 self
._presenter
.check_sub_pane_position(widget
)
526 def _on_menu_report_problem_activate(self
, menuitem
, *args
):
527 utils
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
529 def _on_menu_about_activate(self
, menuitem
, *args
):
530 widget
= self
._presenter
.credits()
533 def _on_menu_refresh_all_activate(self
, *args
):
534 self
._presenter
.poll_all()
536 def _on_menu_refresh_category_activate(self
, *args
):
537 self
._presenter
.poll_current_category()
539 def _on_menu_refresh_selected_activate(self
, *args
):
540 self
._presenter
.poll_current_feed()
542 def _on_toolbar_refresh_all_button_clicked(self
, *args
):
543 self
._presenter
.poll_all()
545 def _on_menu_add_activate(self
, *args
):
546 subscribe
.display_window(parent
=self
._widget
)
548 def _on_toolbar_subscribe_button_clicked(self
, *args
):
549 subscribe
.display_window(parent
=self
._widget
)
551 def _on_menu_import_subscriptions_activate(self
, *args
):
552 dialogs
.import_subscriptions(self
._widget
)
554 def _on_menu_export_subscriptions_activate(self
, *args
):
555 dialogs
.export_subscriptions(self
._widget
)
557 def _on_menu_copy_text_activate(self
, *args
):
558 self
._presenter
.copy_itemview_text_selection()
560 def _on_menu_mark_feed_as_read_activate(self
, *args
):
561 self
._presenter
.mark_feed_as_read()
563 def _on_menu_mark_all_as_read_activate(self
, *args
):
564 self
._presenter
.mark_all_as_read()
566 def _on_find_activate(self
, widget
, *args
):
567 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
568 menu_find
= xml
.get_widget('menu_find')
569 accel_label
= menu_find
.get_child()
571 if not self
._find
_toggled
:
572 self
._presenter
.show_search()
573 self
._detach
_unmodified
_accelerator
_group
()
574 self
._find
_toggled
= True
576 # save the "Find..." stock text for later recovery
577 self
._old
_label
_text
= accel_label
.get_text()
578 accel_label
.set_text(_('Return to feed list...'))
581 self
._presenter
.hide_search()
582 self
._attach
_unmodified
_accelerator
_group
()
583 self
._find
_toggled
= False
584 accel_label
.set_text(self
._old
_label
_text
)
586 def _on_menu_next_activate(self
, *args
):
587 self
._presenter
.display_next_item()
589 def _on_toolbar_scroll_or_next_button_clicked(self
, *args
):
590 self
._presenter
.scroll_or_display_next_unread_item()
592 def _on_menu_scroll_next_activate(self
, *args
):
593 self
._presenter
.scroll_or_display_next_unread_item()
595 def _on_menu_previous_activate(self
, *args
):
596 self
._presenter
.display_previous_item()
598 def _on_menu_next_feed_unread_activate(self
, *args
):
599 self
._presenter
.display_next_unread_feed()
601 def _on_menu_next_feed_activate(self
, *args
):
602 self
._presenter
.display_next_feed()
604 def _on_menu_previous_feed_activate(self
, *args
):
605 self
._presenter
.display_previous_feed()
607 def _on_menu_remove_selected_feed_activate(self
, *args
):
608 self
._presenter
.remove_selected_feed()
610 def _on_menu_next_category_activate(self
, *args
):
611 self
._presenter
.display_next_category()
613 def _on_menu_previous_category_activate(self
, *args
):
614 self
._presenter
.display_previous_category()
616 def _on_menu_next_category_activate(self
, *args
):
617 self
._presenter
.display_next_category()
619 def _on_menu_previous_category_activate(self
, *args
):
620 self
._presenter
.display_previous_category()
622 def _on_menu_preferences_activate(self
, *args
):
623 self
._presenter
.show_preferences_dialog(self
._widget
)
625 def _on_menu_feed_properties_activate(self
, *args
):
626 self
._presenter
.show_feed_properties(self
._widget
)
628 def _on_straw_main_drag_data_received(self
, w
, context
,
629 x
, y
, data
, info
, time
):
630 if data
and data
.format
== 8:
631 url
= data
.data
.split("\n")[0]
632 subscribe
.display_window("%s" % url
, self
._widget
)
633 context
.finish(True, False, time
)
635 context
.finish(False, False, time
)
637 def show_offline_dialog(self
):
638 return dialogs
.report_offline_status(self
._widget
)
640 def get_widget_tree(self
):
641 return gtk
.glade
.get_widget_tree(self
._widget
)
644 self
._widget
.present()
646 def should_present(self
):
647 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
650 self
._widget
.present()
660 gnome
.program_init(constants
.APPNAME
.lower(), constants
.VERSION
)
661 # initialize threading and environment
662 gobject
.threads_init()
663 config
= Config
.get_instance()
664 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
666 gtk
.window_set_auto_startup_notification(True)
667 self
._initialize
_gettext
()
669 config
= Config
.get_instance()
671 feedlist
= feeds
.get_instance()
672 feed_categories
= FeedCategoryList
.get_instance()
675 #xmlfile = utils.find_glade_file()
676 #xml = gtk.glade.XML(xmlfile, "straw_main", gettext.textdomain())
677 #window = xml.get_widget('straw_main')
678 #self._main_presenter = ApplicationPresenter(view =
679 # ApplicationView(window))
681 if config
.first_time
:
682 libdir
= utils
.find_data_dir()
683 filepath
= os
.path
.join(libdir
, "default_subscriptions.opml")
684 OPMLImport
.import_opml(filepath
)
687 feed_categories
.load_data()
690 itemstore
= ItemStore
.get_instance()
691 except ItemStore
.ConvertException
, ex
:
692 dialogs
.report_error(_("There was a problem while converting the database."),
693 _("Straw will not behave as expected. You should probably quit now. " +
694 "The exception has been saved to the file '%s'. Please see the Straw README for further instructions."
698 ImageCache
.initialize()
702 xmlfile
= utils
.find_glade_file()
703 xml
= gtk
.glade
.XML(xmlfile
, "straw_main", gettext
.textdomain())
704 window
= xml
.get_widget('straw_main')
705 self
._main
_presenter
= ApplicationPresenter(view
=
706 ApplicationView(window
))
707 self
._main
_presenter
.view
.present()
709 PollManager
.get_instance().start_polling_loop()
710 # set the default icon for the windows
711 iconfile
= os
.path
.join(utils
.find_image_dir(),"straw.png")
712 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
714 strawdbus
.start_services()
720 def _initialize_gettext(self
):
722 lname
= constants
.APPNAME
.lower()
724 localedir
= utils
.find_locale_dir()
725 gettext
.bindtextdomain(lname
, localedir
)
726 gettext
.textdomain(lname
)
727 gettext
.install(lname
, localedir
, unicode=1)
728 gtk
.glade
.bindtextdomain(lname
, localedir
)
730 def broken_gettext_workaround(s
):
732 __builtins__
.__dict
__['_'] = broken_gettext_workaround
733 locale
.setlocale(locale
.LC_ALL
, '')
737 from Tray
import Tray
739 tray
.connect('button_press_event', self
._tray
_clicked
)
741 def _tray_clicked(self
, signal
, event
):
742 if event
.button
== 1:
743 self
._main
_presenter
.view
.present()
744 self
._main
_presenter
.scroll_or_display_next_unread_item()
746 self
._main
_presenter
.view
.should_present()