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
36 import FeedCategoryList
39 from ItemView
import ItemView
40 from ItemList
import ItemListPresenter
, ItemListView
41 from FeedListView
import FeedsView
, FeedsPresenter
42 from OfflineToggle
import OfflineToggle
43 from CategorySelector
import CategoryPresenter
, CategoryView
44 from MainloopManager
import MainloopManager
45 from FeedPropertiesDialog
import FeedPropertyView
, FeedPropertyPresenter
, show_feed_properties
as show_feed_properties_dialog
46 from PreferencesDialog
import PreferencesDialog
47 from Find
import FindPresenter
, FindView
56 class StatusPresenter(MVP
.BasicPresenter
):
57 def _initialize(self
):
58 self
._mmgr
= MessageManager
.get_instance()
59 self
._mmgr
.signal_connect(Event
.StatusDisplaySignal
,
63 def _display(self
, signal
):
64 cid
= self
._view
.get_context_id("straw_main")
66 self
._view
.push(cid
, self
._mmgr
.read_message())
70 def __init__(self
, widget
):
72 self
._tooltips
= gtk
.Tooltips()
74 self
._curr
_feed
= None
75 self
._curr
_category
= None
76 fclist
= FeedCategoryList
.get_instance()
77 fclist
.signal_connect(Event
.FeedCategoryChangedSignal
,
78 self
._category
_changed
)
80 def display_feed_error(self
, feed
):
81 if self
._curr
_feed
is not None:
82 self
._curr
_feed
.signal_disconnect(Event
.FeedErrorStatusChangedSignal
,
83 self
._error
_status
_changed
)
84 self
._curr
_feed
= feed
85 self
._curr
_feed
.signal_connect(Event
.FeedErrorStatusChangedSignal
,
86 self
._error
_status
_changed
)
90 def display_category_error(self
, category
):
92 self
._curr
_category
= category
96 def _update_view(self
):
98 if self
._curr
_category
and self
._curr
_category
.subscription
and self
._curr
_category
.subscription
.error
:
99 text
.append(_("Category error:"))
100 text
.append(self
._curr
_category
.subscription
.error
)
101 if self
._curr
_feed
and self
._curr
_feed
.error
:
102 text
.append(_("Feed Error:"))
103 text
.append(self
._curr
_feed
.error
)
106 self
._tooltips
.set_tip(self
._widget
,t
,t
)
107 self
._tooltips
.enable()
110 self
._tooltips
.disable()
114 def _category_changed(self
, signal
):
115 if signal
.sender
is self
._curr
_category
:
116 self
.display_category_error(self
._curr
_category
)
118 def _error_status_changed(self
, signal
):
119 if signal
.sender
is self
._curr
_feed
:
120 self
.display_feed_error(signal
.sender
)
126 class FeedInfoView(MVP
.WidgetView
):
127 def _initialize(self
):
128 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
129 self
._title
= widget_tree
.get_widget('feed_item_label')
130 self
._refresh
= widget_tree
.get_widget('feed_refresh_label')
132 def set_title(self
, title
):
133 self
._title
.set_label(title
)
136 def set_refresh(self
, refresh
):
137 self
._refresh
.set_label(refresh
)
149 class FeedInfoPresenter(MVP
.BasicPresenter
):
150 def display(self
, feed
):
151 next
= feed
.next_refresh
153 text
= _("Next Refresh: %s") % utils
.format_date(time
.gmtime(next
))
154 self
._view
.set_refresh(text
)
155 self
._view
.set_title(_("%s") % saxutils
.escape(feed
.title
))
162 self
._view
.set_title("")
163 self
._view
.set_refresh("")
165 def show(self
): self
._view
.show()
167 class MenuFeedPropsPresenter(MVP
.BasicPresenter
):
168 def set_sensitive(self
, s
):
169 self
._view
.set_sensitive(s
)
172 class ToolbarView(MVP
.WidgetView
):
173 """ Widget: gtk.Toolbar"""
174 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
176 def _initialize(self
):
177 client
= gconf
.client_get_default()
178 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
180 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
181 gconf
.CLIENT_PRELOAD_NONE
)
182 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
183 self
._toolbar
_style
_changed
)
184 self
._widget
.set_tooltips(True)
186 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
187 value
= entry
.value
.get_string()
188 self
._presenter
.style_changed(value
)
190 def set_style(self
, style
):
191 self
._widget
.set_style(style
)
194 client
= gconf
.client_get_default()
195 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
198 class ToolbarPresenter(MVP
.BasicPresenter
):
199 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
200 'text':gtk
.TOOLBAR_TEXT
,
201 'icons':gtk
.TOOLBAR_ICONS
,
202 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
204 def _initialize(self
):
205 style
= self
._view
.get_style()
206 if style
in self
.STYLES
.keys():
207 self
._view
.set_style(self
.STYLES
[style
])
210 def style_changed(self
, value
):
211 if value
in self
.STYLES
.keys():
212 self
._view
.set_style(self
.STYLES
[value
])
215 class ApplicationPresenter(MVP
.BasicPresenter
):
216 def _initialize(self
):
217 self
._curr
_category
= None
218 self
._curr
_feed
= None
219 self
._curr
_item
= None
221 self
._init
_presenters
()
223 self
._prefs
_dialog
= None
226 def _init_widgets(self
):
227 widget_tree
= self
._view
.get_widget_tree()
228 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
229 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
231 def _init_presenters(self
):
232 widget_tree
= self
._view
.get_widget_tree()
233 toolbar_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
234 self
._feed
_list
_presenter
= FeedsPresenter(view
=FeedsView(widget_tree
.get_widget('feed_selection_treeview')))
235 self
._category
_selector
= CategoryPresenter(view
=CategoryView(widget_tree
.get_widget('category_combo')))
236 self
._error
_presenter
= ErrorPresenter(
237 widget_tree
.get_widget('statusbar_error_indicator'))
238 self
._offline
_presenter
= OfflineToggle(
239 widget_tree
.get_widget('offline_toggle'))
240 self
._itemlist
_presenter
= ItemListPresenter(view
= ItemListView(widget_tree
.get_widget('item_selection_treeview')))
241 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
242 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
243 self
._menufp
_presenter
= MenuFeedPropsPresenter( view
= widget_tree
.get_widget('menu_feed_properties'))
244 self
._menufp
_presenter
.set_sensitive(False)
245 self
._feedinfo
_presenter
= FeedInfoPresenter(view
= FeedInfoView(widget_tree
.get_widget('article_refresh_hbox')))
246 self
._find
_presenter
= FindPresenter(view
=FindView(widget_tree
.get_widget("find_vbox")))
249 def _init_signals(self
):
250 self
._feed
_list
_presenter
.signal_connect(Event
.FeedSelectionChangedSignal
,
251 self
._feed
_selection
_changed
)
252 self
._feed
_list
_presenter
.signal_connect(Event
.FeedsEmptySignal
,
253 self
._feeds
_empty
_cb
)
254 self
._itemlist
_presenter
.signal_connect(Event
.ItemSelectionChangedSignal
,
255 self
._item
_view
.item_selection_changed
)
256 self
._category
_selector
.signal_connect(Event
.CategorySelectionChangedSignal
,
257 self
._category
_selection
_changed
)
260 def _feed_selection_changed(self
, signal
):
261 if signal
.old
and self
._curr
_feed
:
262 self
._curr
_feed
.unload_contents()
265 self
._curr
_feed
.signal_disconnect(Event
.FeedPolledSignal
,
267 self
._curr
_feed
.signal_disconnect(Event
.ItemsAddedSignal
,
268 self
._feed
_items
_added
)
269 self
._curr
_feed
= signal
.new
270 self
._curr
_feed
.signal_connect(Event
.FeedPolledSignal
,
272 self
._curr
_feed
.signal_connect(Event
.ItemsAddedSignal
,
273 self
._feed
_items
_added
)
274 self
._display
_feed
(self
._curr
_feed
)
277 def _feed_polled(self
, signal
):
278 self
._feedinfo
_presenter
.display(signal
.sender
)
281 def _feed_items_added(self
, signal
):
282 self
._itemlist
_presenter
.display_feed_items(self
._curr
_feed
, False)
284 def _category_selection_changed(self
, signal
):
285 self
._display
_category
_feeds
(signal
.current
)
288 def _display_category_feeds(self
, category
, *args
):
289 self
._curr
_category
= category
291 self
._feed
_list
_presenter
.display_category_feeds(category
)
292 self
._error
_presenter
.display_category_error(category
)
294 self
._feed
_list
_presenter
.display_empty_category()
295 self
._menufp
_presenter
.set_sensitive(False)
296 self
._itemlist
_presenter
.display_empty_feed()
297 self
._item
_view
.display_empty_feed()
300 def _display_feed(self
, feed
, select_first
= 1):
301 if feed
and feed
.number_of_items
< 1:
302 self
._item
_view
.display_empty_feed()
303 self
._error
_presenter
.display_feed_error(feed
)
304 self
._feedinfo
_presenter
.display(feed
)
305 self
._itemlist
_presenter
.display_feed_items(feed
, select_first
)
306 self
._menufp
_presenter
.set_sensitive(True)
309 def _feeds_empty_cb(self
, signal
):
310 self
._itemlist
_presenter
.display_empty_feed()
311 self
._item
_view
.display_empty_feed()
312 self
._feedinfo
_presenter
.hide()
313 self
._error
_presenter
.hide()
314 self
._menufp
_presenter
.set_sensitive(False)
317 def copy_itemview_text_selection(self
):
318 utils
.set_clipboard_text(self
._item
_view
.get_selected_text())
320 def check_allocation(self
, widget
, event
):
321 config
= Config
.get_instance()
322 def check_size((width
, height
, widget
)):
323 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
324 config
.main_window_size
= (width
, height
)
325 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
326 gobject
.timeout_add(1000, check_size
, (
327 (event
.width
, event
.height
, widget
)))
329 def check_main_pane_position(self
, widget
):
330 config
= Config
.get_instance()
331 def check_position((position
, widget
)):
332 if position
== widget
.get_position():
333 config
.main_pane_position
= position
334 pos
= widget
.get_position()
335 if pos
!= config
.main_pane_position
:
336 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
338 def check_sub_pane_position(self
, widget
):
339 config
= Config
.get_instance()
340 def check_position((position
, widget
)):
341 if position
== widget
.get_position():
342 config
.sub_pane_position
= position
343 pos
= widget
.get_position()
344 if pos
!= config
.sub_pane_position
:
345 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
348 return dialogs
.credits()
351 if self
._warn
_if
_offline
():
352 fclist
= FeedCategoryList
.get_instance()
353 self
._poll
_categories
(fclist
.all_categories
)
356 def poll_current_category(self
):
357 if self
._warn
_if
_offline
():
358 self
._poll
_categories
([self
._curr
_category
])
361 def poll_current_feed(self
):
362 if self
._warn
_if
_offline
():
363 pm
= PollManager
.get_instance()
364 pm
.poll([self
._curr
_feed
])
367 def mark_feed_as_read(self
):
368 self
._curr
_feed
.mark_all_read()
370 def mark_all_as_read(self
):
371 mmgr
= MainloopManager
.get_instance()
372 flist
= FeedList
.get_instance().flatten_list()
376 if feed
is self
._curr
_feed
:
378 feed
.unload_contents()
381 def remove_selected_feed(self
):
382 self
._feed
_list
_presenter
.remove_selected_feed()
384 def show_search(self
):
385 self
._itemlist
_presenter
.signal_disconnect(Event
.ItemSelectionChangedSignal
,
386 self
._item
_view
.item_selection_changed
)
387 self
._find
_presenter
.item_list
.signal_connect(Event
.ItemSelectionChangedSignal
,
388 self
._item
_view
.item_selection_changed
)
389 self
._item
_view
.display_empty_search()
390 self
._itemlist
_view
_notebook
.set_current_page(1)
391 self
._feedlist
_view
_notebook
.set_current_page(1)
392 self
._feedinfo
_presenter
.hide()
394 def hide_search(self
):
395 self
._find
_presenter
.clear()
396 self
._itemlist
_view
_notebook
.set_current_page(0)
397 self
._feedlist
_view
_notebook
.set_current_page(0)
398 self
._feedinfo
_presenter
.show()
399 self
._find
_presenter
.item_list
.signal_disconnect(Event
.ItemSelectionChangedSignal
,
400 self
._item
_view
.item_selection_changed
)
401 self
._itemlist
_presenter
.signal_connect(Event
.ItemSelectionChangedSignal
,
402 self
._item
_view
.item_selection_changed
)
404 def _poll_categories(self
, fclist
):
405 pm
= PollManager
.get_instance()
406 pm
.poll_categories(fclist
)
409 def _warn_if_offline(self
):
410 config
= Config
.get_instance()
413 response
= self
._view
.show_offline_dialog()
414 if response
== gtk
.RESPONSE_OK
:
415 config
.offline
= not config
.offline
421 def _get_next_category(self
, category
= None):
423 category
= self
._curr
_category
424 fclist
= FeedCategoryList
.get_instance()
425 allcats
= fclist
.user_categories
+ list(fclist
.pseudo_categories
)
427 category
= allcats
[0]
429 index
= allcats
.index(category
)
430 if index
< len(allcats
) - 1:
434 category
= allcats
[index
]
437 def _get_previous_category(self
, category
= None):
439 category
= self
._curr
_category
440 fclist
= FeedCategoryList
.get_instance()
441 allcats
= fclist
.user_categories
+ list(fclist
.pseudo_categories
)
443 category
= allcats
[-1]
445 index
= allcats
.index(category
)
449 index
= len(allcats
) - 1
450 category
= allcats
[index
]
453 def display_previous_category(self
, category
= None):
455 Displays the category before the current selected category
457 category
= self
._get
_previous
_category
(category
)
458 self
._category
_selector
.category_selected(category
)
459 self
._display
_category
_feeds
(category
)
461 def display_next_category(self
, category
= None):
463 Display the category after the current selected category
465 category
= self
._get
_next
_category
(category
)
466 self
._category
_selector
.category_selected(category
)
467 self
._display
_category
_feeds
(category
)
469 def display_previous_feed(self
, item
= None):
471 Displays the feed before the current selected feed
473 self
._feed
_list
_presenter
.select_previous_feed()
475 def display_next_feed(self
, item
=None):
477 Displays the feed after the current selected feed
479 is_next
= self
._feed
_list
_presenter
.select_next_feed()
481 self
._feed
_list
_presenter
.select_first_feed()
484 def display_next_unread_feed(self
):
486 Displays the next feed with an unread item
488 self
._feed
_list
_presenter
.select_next_unread_feed()
490 def display_previous_item(self
, item
=None):
492 Displays the item before the current selected item. If the item is the
493 first item, scrolls to the previous feed
495 is_prev
= self
._itemlist
_presenter
.select_previous_item()
497 # TODO HACK - implement select_previous_feed(select_last=True) ...
498 # ... to select previous feed's last item
499 self
._feed
_list
_presenter
.select_previous_feed()
500 self
._itemlist
_presenter
.select_last_item()
503 def display_next_item(self
, item
=None):
505 Displays the item after the current selected item. If the item is the
506 last item, selectes the next feed. If the current feed is the last
507 feed in the list, it goes back and selects the first feed
509 is_next
= self
._itemlist
_presenter
.select_next_item()
511 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
513 self
._feed
_list
_presenter
.select_first_feed()
516 def scroll_or_display_next_unread_item(self
, item
=None):
517 has_unread_item
= False
518 if not self
._item
_view
.scroll_down():
519 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
520 if not has_unread_item
:
521 self
._feed
_list
_presenter
.select_next_unread_feed()
524 def show_preferences_dialog(self
, parent
):
525 if not self
._prefs
_dialog
:
526 xf
= utils
.find_glade_file()
527 xml
= gtk
.glade
.XML(xf
, "preferences_dialog", gettext
.textdomain())
528 self
._prefs
_dialog
= PreferencesDialog(xml
, parent
)
529 self
._prefs
_dialog
.show()
531 def show_feed_properties(self
, parent
):
532 fpd
= show_feed_properties_dialog(parent
, self
._curr
_feed
)
537 ItemStore
.get_instance().stop()
540 class ApplicationView(MVP
.WidgetView
):
544 def _initialize(self
):
545 self
._config
= Config
.get_instance()
546 self
._initialize
_dnd
()
547 self
._initialize
_window
_updater
()
548 self
._create
_unmodified
_accelerator
_group
()
549 self
._attach
_unmodified
_accelerator
_group
()
550 self
._initialize
_window
()
551 self
._find
_toggled
= False
553 def _initialize_window(self
):
554 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
555 if self
._config
.window_maximized
:
556 self
._widget
.maximize()
558 # we use resize here since configure-event seems to
559 # overwrite the default size if we use set_default_size.
560 self
._widget
.resize(*self
._config
.main_window_size
)
561 mmp
= widget_tree
.get_widget('main_main_pane')
562 msp
= widget_tree
.get_widget('main_sub_pane')
563 mmp
.set_position(self
._config
.main_pane_position
)
564 msp
.set_position(self
._config
.sub_pane_position
)
566 def _initialize_dnd(self
):
567 self
._widget
.drag_dest_set(
568 gtk
.DEST_DEFAULT_ALL
,
569 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
570 ('x-url/http', 0, 2)],
571 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
574 def _initialize_window_updater(self
):
575 feedlist
= FeedList
.get_instance()
576 feedlist
.signal_connect(Event
.AllItemsReadSignal
,
577 lambda signal
: self
._update
_title
(feedlist
))
578 feedlist
.signal_connect(Event
.ItemReadSignal
,
579 lambda signal
: self
._update
_title
(feedlist
))
580 feedlist
.signal_connect(Event
.ItemsAddedSignal
,
581 lambda signal
: self
._update
_title
(feedlist
))
582 feedlist
.signal_connect(Event
.FeedsChangedSignal
,
583 lambda signal
: self
._update
_title
(feedlist
))
586 def _update_title(self
, flist
):
587 uritems
= urfeeds
= 0
589 listfeeds
= flist
.flatten_list()
590 for ur
in [f
.n_items_unread
for f
in listfeeds
]:
595 urfeeds
= len(listfeeds
)
598 item_feed_map
= {'uritems': uritems
,
601 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
602 self
._widget
.set_title( title
+ " - %s" % constants
.APPNAME
)
605 # We have a separate accelerator group for the unmodified and
606 # shifted accelerators, that is, stuff like space, N, P, etc. This
607 # is so that we can have the find pane work correctly
608 def _create_unmodified_accelerator_group(self
):
609 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
610 agroup
= gtk
.AccelGroup()
611 accels
= (('menu_mark_feed_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
612 ('menu_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
613 ('menu_next', 'N', gtk
.gdk
.SHIFT_MASK
),
614 ('menu_next_unread', ' ', 0),
615 ('menu_previous', 'P', gtk
.gdk
.SHIFT_MASK
))
616 for widget_name
, key
, mask
in accels
:
617 widget
= xml
.get_widget(widget_name
)
618 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
620 self
._unmodified
_accelerator
_group
= agroup
622 def _attach_unmodified_accelerator_group(self
):
623 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
625 def _detach_unmodified_accelerator_group(self
):
626 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
628 def _on_straw_main_destroy_event(self
, *args
):
629 return self
._presenter
.quit()
631 def _on_straw_main_delete_event(self
, *args
):
632 return self
._presenter
.quit()
634 def _on_menu_quit_activate(self
, *args
):
635 return self
._presenter
.quit()
637 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
638 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
639 self
._config
.window_maximized
= False
640 self
._presenter
.check_allocation(widget
, event
)
642 self
._config
.window_maximized
= True
645 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
646 self
._presenter
.check_main_pane_position(widget
)
648 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
649 self
._presenter
.check_sub_pane_position(widget
)
651 def _on_menu_report_problem_activate(self
, menuitem
, *args
):
652 utils
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
654 def _on_menu_about_activate(self
, menuitem
, *args
):
655 widget
= self
._presenter
.credits()
658 def _on_menu_refresh_all_activate(self
, *args
):
659 self
._presenter
.poll_all()
661 def _on_menu_refresh_category_activate(self
, *args
):
662 self
._presenter
.poll_current_category()
664 def _on_menu_refresh_selected_activate(self
, *args
):
665 self
._presenter
.poll_current_feed()
667 def _on_toolbar_refresh_all_button_clicked(self
, *args
):
668 self
._presenter
.poll_all()
670 def _on_menu_add_activate(self
, *args
):
671 subscribe
.display_window(parent
=self
._widget
)
673 def _on_toolbar_subscribe_button_clicked(self
, *args
):
674 subscribe
.display_window(parent
=self
._widget
)
676 def _on_menu_import_subscriptions_activate(self
, *args
):
677 dialogs
.import_subscriptions(self
._widget
)
679 def _on_menu_export_subscriptions_activate(self
, *args
):
680 dialogs
.export_subscriptions(self
._widget
)
682 def _on_menu_copy_text_activate(self
, *args
):
683 self
._presenter
.copy_itemview_text_selection()
685 def _on_menu_mark_feed_as_read_activate(self
, *args
):
686 self
._presenter
.mark_feed_as_read()
688 def _on_menu_mark_all_as_read_activate(self
, *args
):
689 self
._presenter
.mark_all_as_read()
691 def _on_find_activate(self
, widget
, *args
):
692 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
693 menu_find
= xml
.get_widget('menu_find')
694 accel_label
= menu_find
.get_child()
696 if not self
._find
_toggled
:
697 self
._presenter
.show_search()
698 self
._detach
_unmodified
_accelerator
_group
()
699 self
._find
_toggled
= True
701 # save the "Find..." stock text for later recovery
702 self
._old
_label
_text
= accel_label
.get_text()
703 accel_label
.set_text(_('Return to feed list...'))
706 self
._presenter
.hide_search()
707 self
._attach
_unmodified
_accelerator
_group
()
708 self
._find
_toggled
= False
709 accel_label
.set_text(self
._old
_label
_text
)
711 def _on_menu_next_activate(self
, *args
):
712 self
._presenter
.display_next_item()
714 def _on_toolbar_scroll_or_next_button_clicked(self
, *args
):
715 self
._presenter
.scroll_or_display_next_unread_item()
717 def _on_menu_scroll_next_activate(self
, *args
):
718 self
._presenter
.scroll_or_display_next_unread_item()
720 def _on_menu_previous_activate(self
, *args
):
721 self
._presenter
.display_previous_item()
723 def _on_menu_next_feed_unread_activate(self
, *args
):
724 self
._presenter
.display_next_unread_feed()
726 def _on_menu_next_feed_activate(self
, *args
):
727 self
._presenter
.display_next_feed()
729 def _on_menu_previous_feed_activate(self
, *args
):
730 self
._presenter
.display_previous_feed()
732 def _on_menu_remove_selected_feed_activate(self
, *args
):
733 self
._presenter
.remove_selected_feed()
735 def _on_menu_next_category_activate(self
, *args
):
736 self
._presenter
.display_next_category()
738 def _on_menu_previous_category_activate(self
, *args
):
739 self
._presenter
.display_previous_category()
741 def _on_menu_next_category_activate(self
, *args
):
742 self
._presenter
.display_next_category()
744 def _on_menu_previous_category_activate(self
, *args
):
745 self
._presenter
.display_previous_category()
747 def _on_menu_preferences_activate(self
, *args
):
748 self
._presenter
.show_preferences_dialog(self
._widget
)
750 def _on_menu_feed_properties_activate(self
, *args
):
751 self
._presenter
.show_feed_properties(self
._widget
)
753 def _on_straw_main_drag_data_received(self
, w
, context
,
754 x
, y
, data
, info
, time
):
755 if data
and data
.format
== 8:
756 url
= data
.data
.split("\n")[0]
757 subscribe
.display_window("%s" % url
, self
._widget
)
758 context
.finish(True, False, time
)
760 context
.finish(False, False, time
)
762 def show_offline_dialog(self
):
763 return dialogs
.report_offline_status(self
._widget
)
765 def get_widget_tree(self
):
766 return gtk
.glade
.get_widget_tree(self
._widget
)
769 self
._widget
.present()
771 def should_present(self
):
772 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
775 self
._widget
.present()
785 gnome
.program_init(constants
.APPNAME
.lower(), constants
.VERSION
)
786 # initialize threading and environment
787 gobject
.threads_init()
788 config
= Config
.get_instance()
789 config
.use_threads
= True
790 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
791 config
.no_etags
= os
.getenv('STRAW_NO_ETAGS') is not None
793 gtk
.window_set_auto_startup_notification(True)
794 self
._initialize
_gettext
()
796 config
= Config
.get_instance()
798 feedlist
= FeedList
.get_instance()
799 feed_categories
= FeedCategoryList
.get_instance()
802 xmlfile
= utils
.find_glade_file()
803 xml
= gtk
.glade
.XML(xmlfile
, "straw_main", gettext
.textdomain())
804 window
= xml
.get_widget('straw_main')
805 self
._main
_presenter
= ApplicationPresenter(view
=
806 ApplicationView(window
))
808 if config
.first_time
:
809 libdir
= utils
.find_data_dir()
810 filepath
= os
.path
.join(libdir
, "default_subscriptions.opml")
811 OPMLImport
.import_opml(filepath
)
814 feed_categories
.load_data()
817 itemstore
= ItemStore
.get_instance(config
.straw_dir
)
818 except ItemStore
.ConvertException
, ex
:
819 dialogs
.report_error(_("There was a problem while converting the database."),
820 _("Straw will not behave as expected. You should probably quit now. " +
821 "The exception has been saved to the file '%s'. Please see the Straw README for further instructions."
825 ImageCache
.initialize()
828 self
._main
_presenter
.view
.present()
829 PollManager
.get_instance().start_polling_loop()
831 # set the default icon for the windows
832 iconfile
= os
.path
.join(utils
.find_image_dir(),"straw.png")
833 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
835 strawdbus
.start_services()
841 def _initialize_gettext(self
):
843 lname
= constants
.APPNAME
.lower()
845 localedir
= utils
.find_locale_dir()
846 gettext
.bindtextdomain(lname
, localedir
)
847 gettext
.textdomain(lname
)
848 gettext
.install(lname
, localedir
, unicode=1)
849 gtk
.glade
.bindtextdomain(lname
, localedir
)
851 def broken_gettext_workaround(s
):
853 __builtins__
.__dict
__['_'] = broken_gettext_workaround
854 locale
.setlocale(locale
.LC_ALL
, '')
858 from Tray
import Tray
860 tray
.connect('button_press_event', self
._tray
_clicked
)
862 def _tray_clicked(self
, signal
, event
):
863 if event
.button
== 1:
864 self
._main
_presenter
.view
.present()
865 self
._main
_presenter
.scroll_or_display_next_unread_item()
867 self
._main
_presenter
.view
.should_present()