3 This is the main module that binds everything together.
7 __copyright__
= "Copyright (c) 2002-2005 Free Software Foundation, Inc."
8 __license__
= """ GNU General Public License
10 This program is free software; you can redistribute it and/or modify it under the
11 terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA. """
23 from FeedListView
import FeedsView
, FeedsPresenter
24 from ItemList
import ItemListPresenter
, ItemListView
25 from ItemView
import ItemView
26 from MainloopManager
import MainloopManager
27 from OfflineToggle
import OfflineToggle
28 from xml
.sax
import saxutils
37 import gobject
, gtk
, gtk
.glade
39 import os
, gettext
, getopt
, sys
45 #from Find import FindPresenter, FindView
48 class StatusPresenter(MVP
.BasicPresenter
):
49 def _initialize(self
):
50 self
._mmgr
= straw
.get_status_manager()
51 self
._mmgr
.connect('changed', self
._display
)
53 def _display(self
, *args
):
54 cid
= self
._view
.get_context_id("straw_main")
56 self
._view
.push(cid
, self
._mmgr
.read_message())
60 def __init__(self
, widget
):
62 self
._tooltips
= gtk
.Tooltips()
64 #self._curr_feed = None
65 #self._curr_category = None
66 #fclist = FeedCategoryList.get_instance()
67 #fclist.connect('category-changed', self._category_changed)
69 def feedlist_selection_changed(self
, selection
, column
):
72 (model
, pathlist
) = selection
.get_selected_rows()
73 iters
= [model
.get_iter(path
) for path
in pathlist
]
76 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
78 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
79 errortexts
= [feed
.error
for feed
in errorfeeds
]
82 ### XXX display OPML Category error too
86 text
.append(_("Error:"))
91 self
._tooltips
.set_tip(self
._widget
,t
,t
)
92 self
._tooltips
.enable()
95 self
._tooltips
.disable()
102 class MenuFeedPropsPresenter(MVP
.BasicPresenter
):
104 def set_sensitive(self
, s
):
105 self
._view
.set_sensitive(s
)
108 class ToolbarView(MVP
.WidgetView
):
109 """ Widget: gtk.Toolbar"""
110 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
112 def _initialize(self
):
113 client
= gconf
.client_get_default()
114 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
116 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
117 gconf
.CLIENT_PRELOAD_NONE
)
118 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
119 self
._toolbar
_style
_changed
)
120 self
._widget
.set_tooltips(True)
122 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
123 value
= entry
.value
.get_string()
124 self
._presenter
.style_changed(value
)
126 def set_style(self
, style
):
127 self
._widget
.set_style(style
)
130 client
= gconf
.client_get_default()
131 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
134 class ToolbarPresenter(MVP
.BasicPresenter
):
135 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
136 'text':gtk
.TOOLBAR_TEXT
,
137 'icons':gtk
.TOOLBAR_ICONS
,
138 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
140 def _initialize(self
):
141 style
= self
._view
.get_style()
143 if style
in self
.STYLES
.keys():
144 self
._view
.set_style(self
.STYLES
[style
])
146 widget_tree
= gtk
.glade
.get_widget_tree(self
._view
._widget
)
147 self
.change_read_state_button
= widget_tree
.get_widget("toolbar_change_read_state_button")
149 def style_changed(self
, value
):
150 if value
in self
.STYLES
.keys():
151 self
._view
.set_style(self
.STYLES
[value
])
153 def set_change_read_button_state(self
, new_state
):
154 self
.change_read_state_button
.set_active(new_state
)
156 class ApplicationPresenter(MVP
.BasicPresenter
):
157 def _initialize(self
):
158 FeedManager
._get
_instance
().connect("update-all-done", self
._on
_update
_all
_done
)
160 self
._current
_item
= None
163 self
._init
_presenters
()
166 def _init_widgets(self
):
167 widget_tree
= self
._view
.get_widget_tree()
169 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
170 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
172 item_view_container
= widget_tree
.get_widget('item_view_container')
173 item_list_container
= widget_tree
.get_widget('item_list_container')
175 self
.update_all_button
= widget_tree
.get_widget("toolbar_refresh_all_button")
177 parent_paned
= item_view_container
.get_parent()
178 parent_parent_widget
= parent_paned
.get_parent()
180 config
= Config
.get_instance()
183 layout
= config
.pane_layout
184 if layout
== 'vertical':
185 new_paned
= gtk
.VPaned()
186 child_list
.append(item_list_container
)
187 child_list
.append(item_view_container
)
188 elif layout
== 'horizontal':
189 new_paned
= gtk
.HPaned()
190 child_list
.append(item_view_container
)
191 child_list
.append(item_list_container
)
192 else: # Use vertical layout as default
193 new_paned
= gtk
.VPaned()
194 child_list
.append(item_list_container
)
195 child_list
.append(item_view_container
)
197 for child
in child_list
:
198 child
.reparent(new_paned
)
200 parent_parent_widget
.remove(parent_paned
)
201 parent_parent_widget
.add(new_paned
)
205 def _init_presenters(self
):
206 widget_tree
= self
._view
.get_widget_tree()
207 self
._toolbar
_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
208 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
210 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
212 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
213 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
215 view
.add_selection_changed_listener(self
._item
_view
)
216 view
.add_selection_changed_listener(self
)
218 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
219 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
220 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
221 view
.add_selection_changed_listener(self
._error
_presenter
)
223 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
225 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
226 self
._menufp
_presenter
= MenuFeedPropsPresenter( view
= widget_tree
.get_widget('feed_information'))
227 self
._menufp
_presenter
.set_sensitive(False)
228 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
230 def set_current_item(self
, item
):
231 self
._current
_item
= item
232 self
._current
_item
_connect
_id
= item
.connect("is-read-changed", self
._on
_current
_item
_is
_read
_changed
)
234 def clear_current_item(self
):
235 if self
._current
_item
:
236 self
._current
_item
.disconnect(self
._current
_item
_connect
_id
)
237 self
._current
_item
= None
239 def set_current_item_is_read(self
, is_read
):
240 if self
._current
_item
:
241 self
._current
_item
.props
.is_read
= is_read
243 def _on_current_item_is_read_changed(self
, obj
, is_read
):
244 self
._toolbar
_presenter
.set_change_read_button_state(is_read
)
246 def itemlist_selection_changed(self
, selection
, column
):
247 self
.clear_current_item()
249 (model
, treeiter
) = selection
.get_selected()
250 if not treeiter
: return
251 item
= model
.get_value(treeiter
, column
)
252 self
._toolbar
_presenter
.set_change_read_button_state(item
.is_read
)
253 self
.set_current_item(item
)
255 def add_category(self
):
256 self
._feed
_list
_presenter
.add_category()
258 def copy_itemview_text_selection(self
):
259 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
261 def check_allocation(self
, widget
, event
):
262 config
= Config
.get_instance()
263 def check_size((width
, height
, widget
)):
264 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
265 config
.main_window_size
= (width
, height
)
266 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
267 gobject
.timeout_add(1000, check_size
, (
268 (event
.width
, event
.height
, widget
)))
270 def check_main_pane_position(self
, widget
):
271 config
= Config
.get_instance()
272 def check_position((position
, widget
)):
273 if position
== widget
.get_position():
274 config
.main_pane_position
= position
275 pos
= widget
.get_position()
276 if pos
!= config
.main_pane_position
:
277 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
279 def check_sub_pane_position(self
, widget
):
280 config
= Config
.get_instance()
281 def check_position((position
, widget
)):
282 if position
== widget
.get_position():
283 config
.sub_pane_position
= position
284 pos
= widget
.get_position()
285 if pos
!= config
.sub_pane_position
:
286 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
289 return helpers
.credits()
292 if not self
._warn
_if
_offline
():
295 if not FeedManager
.is_update_all_running():
296 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
297 "task-done": [ self
._on
_feed
_poll
_done
] })
298 self
.update_all_button
.set_sensitive(True)
299 self
.update_all_button
.set_stock_id(gtk
.STOCK_STOP
)
301 self
.update_all_button
.set_sensitive(False)
302 JobManager
.stop_jobs()
304 def _on_feed_poll_started(self
, handler
, feed
):
307 def _on_feed_poll_done(self
, handler
, data
):
310 def _on_update_all_done(self
, obj
):
311 self
.update_all_button
.set_sensitive(True)
312 self
.update_all_button
.set_stock_id(gtk
.STOCK_REFRESH
)
314 def poll_current_category(self
):
315 if self
._warn
_if
_offline
():
316 self
._poll
_categories
([self
._curr
_category
])
318 def poll_current_feed(self
):
319 if self
._warn
_if
_offline
():
320 print self
._curr
_feed
321 pm
= PollManager
.get_instance()
322 pm
.poll([self
._curr
_feed
])
324 def mark_feed_as_read(self
):
325 self
._curr
_feed
.mark_all_read()
327 def mark_all_as_read(self
):
328 print "TODO mark_all_as_read"
330 def remove_selected_feed(self
):
331 # self._feed_list_presenter.remove_selected_feed()
334 def show_search(self
):
335 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
336 # self._item_view.item_selection_changed)
337 self
._item
_view
.display_empty_search()
338 self
._itemlist
_view
_notebook
.set_current_page(1)
339 self
._feedlist
_view
_notebook
.set_current_page(1)
340 self
._feedinfo
_presenter
.hide()
342 def hide_search(self
):
343 # self._find_presenter.clear()
344 self
._itemlist
_view
_notebook
.set_current_page(0)
345 self
._feedlist
_view
_notebook
.set_current_page(0)
346 self
._feedinfo
_presenter
.show()
347 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
348 # self._item_view.item_selection_changed)
350 def _poll_categories(self
, fclist
):
351 pm
= PollManager
.get_instance()
352 pm
.poll_categories(fclist
)
354 def _warn_if_offline(self
):
355 config
= Config
.get_instance()
358 response
= self
._view
.show_offline_dialog()
359 if response
== gtk
.RESPONSE_OK
:
360 config
.offline
= not config
.offline
366 def display_previous_feed(self
, item
= None):
368 Displays the feed before the current selected feed
370 self
._feed
_list
_presenter
.select_previous_feed()
372 def display_next_feed(self
, item
=None):
374 Displays the feed after the current selected feed
376 self
._feed
_list
_presenter
.select_next_feed()
379 def display_next_unread_feed(self
):
381 Displays the next feed with an unread item
383 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
386 def display_previous_item(self
, item
=None):
388 Displays the item before the current selected item. If the item is the
389 first item, scrolls to the previous feed
391 is_prev
= self
._itemlist
_presenter
.select_previous_item()
393 # TODO HACK - implement select_previous_feed(select_last=True) ...
394 # ... to select previous feed's last item
395 self
._feed
_list
_presenter
.select_previous_feed()
396 self
._itemlist
_presenter
.select_last_item()
400 def display_next_item(self
, item
=None):
402 Displays the item after the current selected item. If the item is the
403 last item, selectes the next feed. If the current feed is the last
404 feed in the list, it goes back and selects the first feed
406 is_next
= self
._itemlist
_presenter
.select_next_item()
408 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
410 self
._feed
_list
_presenter
.select_firsteed_feed()
413 def scroll_or_display_next_unread_item(self
, item
=None):
414 has_unread_item
= False
415 if not self
._item
_view
.scroll_down():
416 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
417 if not has_unread_item
:
418 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
421 def show_preferences_dialog(self
, parent
):
422 straw
.preferences_show()
424 def show_feed_properties(self
, parent
):
425 straw
.feed_properties_show(self
._curr
_feed
)
430 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
432 Setup the file chooser dialog. This includes an extra widget (a combobox)
433 to include the categories to import or export
435 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
436 buttons
=(gtk
.STOCK_CANCEL
,
438 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
441 for category
in FeedManager
.categories():
442 category_list
.append(category
)
444 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
445 combobox
= gtk
.ComboBox(model
)
446 celltitle
= gtk
.CellRendererText()
447 combobox
.pack_start(celltitle
,False)
448 combobox
.add_attribute(celltitle
, 'text', 0)
450 for category
in category_list
:
452 model
.set(it
, 0, category
.name
, 1, category
)
454 combobox
.set_active(0)
455 label
= gtk
.Label(extra_widget_title
)
456 label
.set_alignment(1.0,0.5)
457 hbox
= gtk
.HBox(spacing
=6)
458 hbox
.pack_start(label
,True,True,0)
459 hbox
.pack_end(combobox
,False,False,0)
462 dialog
.set_extra_widget(hbox
)
463 return (dialog
, combobox
)
465 def import_subscriptions(self
, parent
):
466 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
467 gtk
.FILE_CHOOSER_ACTION_OPEN
,
468 _("Add new subscriptions in:"))
469 ffilter
= gtk
.FileFilter()
470 ffilter
.set_name(_("OPML Files Only"))
471 ffilter
.add_pattern("*.xml")
472 ffilter
.add_pattern("*.opml")
473 dialog
.add_filter(ffilter
)
474 dialog
.set_transient_for(parent
)
475 response
= dialog
.run()
476 if response
== gtk
.RESPONSE_OK
:
477 filename
= dialog
.get_filename()
478 model
= combobox
.get_model()
479 category
= model
[combobox
.get_active()][1]
481 FeedManager
.import_opml(filename
, category
)
484 def export_subscriptions(self
, parent
):
485 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Export Subscriptions"),
486 gtk
.FILE_CHOOSER_ACTION_SAVE
,
487 _("Select category to export:"))
488 def selection_changed(widget
, dialog
):
489 model
= widget
.get_model()
490 category
= model
[widget
.get_active()][1]
491 dialog
.set_current_name("Straw-%s.xml" % category
.name
)
493 combobox
.connect('changed', selection_changed
, dialog
)
494 selection_changed(combobox
, dialog
)
495 dialog
.set_transient_for(parent
)
496 response
= dialog
.run()
498 if response
== gtk
.RESPONSE_OK
:
499 filename
= dialog
.get_filename()
500 model
= combobox
.get_model()
501 root_category
= model
[combobox
.get_active()][1]
502 FeedManager
.export_opml(root_category
.id, filename
)
507 straw
.subscribe_show(parent
=self
.view
._widget
)
509 class ApplicationView(MVP
.WidgetView
):
513 def _initialize(self
):
514 self
._config
= Config
.get_instance()
515 self
._initialize
_dnd
()
516 self
._initialize
_window
_updater
()
517 self
._create
_unmodified
_accelerator
_group
()
518 self
._attach
_unmodified
_accelerator
_group
()
519 self
._initialize
_window
()
520 self
._find
_toggled
= False
522 def _initialize_window(self
):
523 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
524 if self
._config
.window_maximized
:
525 self
._widget
.maximize()
527 # we use resize here since configure-event seems to
528 # overwrite the default size if we use set_default_size.
529 self
._widget
.resize(*self
._config
.main_window_size
)
530 mmp
= widget_tree
.get_widget('main_main_pane')
531 msp
= widget_tree
.get_widget('main_sub_pane')
532 mmp
.set_position(self
._config
.main_pane_position
)
533 msp
.set_position(self
._config
.sub_pane_position
)
535 def _initialize_dnd(self
):
536 self
._widget
.drag_dest_set(
537 gtk
.DEST_DEFAULT_ALL
,
538 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
539 ('x-url/http', 0, 2)],
540 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
543 def _initialize_window_updater(self
):
544 #feedlist.signal_connect(Event.AllItemsReadSignal,
545 # lambda signal: self._update_title(feedlist))
546 #feedlist.signal_connect(Event.ItemReadSignal,
547 # lambda signal: self._update_title(feedlist))
548 #feedlist.signal_connect(Event.ItemsAddedSignal,
549 # lambda signal: self._update_title(feedlist))
550 #feedlist.signal_connect(Event.FeedsChangedSignal,
551 # lambda signal: self._update_title(feedlist))
554 def _update_title(self
, flist
):
555 uritems
= urfeeds
= 0
557 listfeeds
= flist
.flatten_list()
558 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
563 urfeeds
= len(listfeeds
)
566 item_feed_map
= {'uritems': uritems
,
569 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
570 self
._widget
.set_title( title
+ " - %s" % straw
.PACKAGE
)
572 # We have a separate accelerator group for the unmodified and
573 # shifted accelerators, that is, stuff like space, N, P, etc. This
574 # is so that we can have the find pane work correctly
575 def _create_unmodified_accelerator_group(self
):
576 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
577 agroup
= gtk
.AccelGroup()
578 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
579 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
580 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
581 ('next_unread_feed', ' ', 0),
582 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
583 for widget_name
, key
, mask
in accels
:
584 widget
= xml
.get_widget(widget_name
)
585 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
587 self
._unmodified
_accelerator
_group
= agroup
589 def _on_category_add_activate(self
, *args
):
590 self
._presenter
.add_category()
592 def _on_toolbar_change_read_state_button_toggled(self
, button
):
593 self
._presenter
.set_current_item_is_read(button
.get_active())
595 def _attach_unmodified_accelerator_group(self
):
596 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
598 def _detach_unmodified_accelerator_group(self
):
599 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
601 def _on_straw_main_destroy_event(self
, *args
):
602 return self
._presenter
.quit()
604 def _on_straw_main_delete_event(self
, *args
):
605 return self
._presenter
.quit()
607 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
608 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
609 self
._config
.window_maximized
= False
610 self
._presenter
.check_allocation(widget
, event
)
612 self
._config
.window_maximized
= True
615 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
616 self
._presenter
.check_main_pane_position(widget
)
618 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
619 self
._presenter
.check_sub_pane_position(widget
)
622 def _on_feed_subscribe_activate(self
, *args
):
623 self
._presenter
.subscribe()
625 def _on_feed_unsubscribe_activate(self
, *args
):
626 self
._presenter
.remove_selected_feed()
628 def _on_subscription_import_activate(self
, *args
):
629 self
._presenter
.import_subscriptions(self
._widget
)
631 def _on_subscription_export_activate(self
, *args
):
632 self
._presenter
.export_subscriptions(self
._widget
)
634 def _on_feed_mark_as_read_activate(self
, *args
):
635 self
._presenter
.mark_feed_as_read()
637 def _on_feed_mark_all_as_read_activate(self
, *args
):
638 self
._presenter
.mark_all_as_read()
640 def _on_feed_refresh_selected_activate(self
, *args
):
641 self
._presenter
.poll_current_feed()
643 def _on_subscription_refresh_activate(self
, *args
):
644 #print self._widget.get_children()[0].set_stock_id(gtk.STOCK_STOP)
645 self
._presenter
.poll_all()
647 def _on_quit_activate(self
, *args
):
648 return self
._presenter
.quit()
651 def _on_copy_activate(self
, *args
):
652 self
._presenter
.copy_itemview_text_selection()
655 def _on_find_activate(self
, widget
, *args
):
656 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
657 menu_find
= xml
.get_widget('menu_find')
658 accel_label
= menu_find
.get_child()
660 if not self
._find
_toggled
:
661 self
._presenter
.show_search()
662 self
._detach
_unmodified
_accelerator
_group
()
663 self
._find
_toggled
= True
665 # save the "Find..." stock text for later recovery
666 self
._old
_label
_text
= accel_label
.get_text()
667 accel_label
.set_text(_('Return to feed list...'))
670 self
._presenter
.hide_search()
671 self
._attach
_unmodified
_accelerator
_group
()
672 self
._find
_toggled
= False
673 accel_label
.set_text(self
._old
_label
_text
)
675 def _on_preferences_activate(self
, *args
):
676 self
._presenter
.show_preferences_dialog(self
._widget
)
678 def _on_feed_information_activate(self
, *args
):
679 self
._presenter
.show_feed_properties(self
._widget
)
682 def _on_previous_item_activate(self
, *args
):
683 self
._presenter
.display_previous_item()
685 def _on_next_item_activate(self
, *args
):
686 self
._presenter
.display_next_item()
688 def _on_next_feed_activate(self
, *args
):
689 self
._presenter
.display_next_feed()
691 def _on_previous_feed_activate(self
, *args
):
692 self
._presenter
.display_previous_feed()
694 def _on_next_unread_feed_activate(self
, *args
):
695 self
._presenter
.display_next_unread_feed()
697 def _on_scroll_unread_items_activate(self
, *args
):
698 self
._presenter
.scroll_or_display_next_unread_item()
702 def _on_report_problem_activate(self
, menuitem
, *args
):
703 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
705 def _on_about_activate(self
, menuitem
, *args
):
706 widget
= self
._presenter
.credits()
709 def _on_straw_main_drag_data_received(self
, w
, context
,
710 x
, y
, data
, info
, time
):
711 if data
and data
.format
== 8:
712 url
= data
.data
.split("\n")[0]
713 straw
.subscribe_show("%s" % url
, self
._widget
)
714 context
.finish(True, False, time
)
716 context
.finish(False, False, time
)
719 def show_offline_dialog(self
):
720 return helpers
.report_offline_status(self
._widget
)
722 def get_widget_tree(self
):
723 return gtk
.glade
.get_widget_tree(self
._widget
)
726 self
._widget
.present()
728 def should_present(self
):
729 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
732 self
._widget
.present()
737 gnome
.program_init(straw
.PACKAGE
, straw
.VERSION
)
740 # initialize threading and environment
741 gobject
.threads_init()
742 config
= Config
.get_instance()
743 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
745 # build tray status icon
747 iconfile
= os
.path
.normpath(straw
.STRAW_DATA_DIR
+ "/straw.png")
748 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
749 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
750 image
.set_from_pixbuf(scaled_buf
)
752 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
753 self
.tray
.connect('activate', self
._tray
_clicked
)
754 except AttributeError:
757 self
.tray
= egg
.trayicon
.TrayIcon(straw
.PACKAGE
);
758 self
._eventbox
= gtk
.EventBox()
759 self
.tray
.add(self
._eventbox
)
760 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
761 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
762 self
._eventbox
.drag_dest_set(
763 gtk
.DEST_DEFAULT_ALL
,
764 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
765 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
766 self
._eventbox
.add(image
)
769 self
._tooltip
= gtk
.Tooltips()
770 self
.unread_count
= 0
771 # end build tray status icon
773 FeedManager
.setup(storage_path
= "test.db")
776 ItemManager
.setup(storage_path
= "test.db")
779 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
781 #if config.first_time:
782 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
783 # feeds.import_opml(filepath)
785 #ImageCache.initialize()
788 #print feedfinder.feeds("http://eclipse.org", True)
790 xml
= gtk
.glade
.XML(os
.path
.join(straw
.STRAW_DATA_DIR
,'straw.glade'), "straw_main", gettext
.textdomain())
791 window
= xml
.get_widget('straw_main')
792 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
793 self
._main
_presenter
.view
.present()
795 #PollManager.get_instance().start_polling_loop()
796 # set the default icon for the windows
797 iconfile
= os
.path
.join(straw
.STRAW_DATA_DIR
,"straw.png")
798 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
800 straw
.start_services()
803 gtk
.gdk
.threads_init()
804 gtk
.gdk
.threads_enter()
806 gtk
.gdk
.threads_leave()
808 def _update(self
,flist
):
809 uritems
= urfeeds
= 0
810 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
814 if uritems
== self
.unread_count
:
816 self
.unread_count
= uritems
818 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
824 def _tray_clicked(self
, widget
, event
=None):
825 self
._main
_presenter
.view
.should_present()
826 if event
and not (event
.button
== 1):
828 self
._main
_presenter
.scroll_or_display_next_unread_item()
830 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
831 if data
and data
.format
== 8:
832 url
= data
.data
.split("\n")[0]
833 straw
.subscribe_show(url
="%s" % url
)
834 context
.finish(True, False, timestamp
)
836 context
.finish(False, False, timestamp
)