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. """
22 from FeedListView
import FeedsView
, FeedsPresenter
23 from ItemList
import ItemListPresenter
, ItemListView
24 from ItemView
import ItemView
25 from MainloopManager
import MainloopManager
26 from OfflineToggle
import OfflineToggle
27 from xml
.sax
import saxutils
34 import gobject
, gtk
, gtk
.glade
36 import os
, gettext
, getopt
, sys
42 #from Find import FindPresenter, FindView
45 class StatusPresenter(MVP
.BasicPresenter
):
46 def _initialize(self
):
47 self
._mmgr
= straw
.get_status_manager()
48 self
._mmgr
.connect('changed', self
._display
)
50 def _display(self
, *args
):
51 cid
= self
._view
.get_context_id("straw_main")
53 self
._view
.push(cid
, self
._mmgr
.read_message())
57 def __init__(self
, widget
):
59 self
._tooltips
= gtk
.Tooltips()
61 #self._curr_feed = None
62 #self._curr_category = None
63 #fclist = FeedCategoryList.get_instance()
64 #fclist.connect('category-changed', self._category_changed)
66 def feedlist_selection_changed(self
, selection
, column
):
69 (model
, pathlist
) = selection
.get_selected_rows()
70 iters
= [model
.get_iter(path
) for path
in pathlist
]
73 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
75 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
76 errortexts
= [feed
.error
for feed
in errorfeeds
]
79 ### XXX display OPML Category error too
83 text
.append(_("Error:"))
88 self
._tooltips
.set_tip(self
._widget
,t
,t
)
89 self
._tooltips
.enable()
92 self
._tooltips
.disable()
99 class MenuFeedPropsPresenter(MVP
.BasicPresenter
):
101 def set_sensitive(self
, s
):
102 self
._view
.set_sensitive(s
)
105 class ToolbarView(MVP
.WidgetView
):
106 """ Widget: gtk.Toolbar"""
107 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
109 def _initialize(self
):
110 client
= gconf
.client_get_default()
111 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
113 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
114 gconf
.CLIENT_PRELOAD_NONE
)
115 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
116 self
._toolbar
_style
_changed
)
117 self
._widget
.set_tooltips(True)
119 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
120 value
= entry
.value
.get_string()
121 self
._presenter
.style_changed(value
)
123 def set_style(self
, style
):
124 self
._widget
.set_style(style
)
127 client
= gconf
.client_get_default()
128 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
131 class ToolbarPresenter(MVP
.BasicPresenter
):
132 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
133 'text':gtk
.TOOLBAR_TEXT
,
134 'icons':gtk
.TOOLBAR_ICONS
,
135 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
137 def _initialize(self
):
138 style
= self
._view
.get_style()
139 if style
in self
.STYLES
.keys():
140 self
._view
.set_style(self
.STYLES
[style
])
143 def style_changed(self
, value
):
144 if value
in self
.STYLES
.keys():
145 self
._view
.set_style(self
.STYLES
[value
])
148 class ApplicationPresenter(MVP
.BasicPresenter
):
149 def _initialize(self
):
150 self
._curr
_category
= None
151 self
._curr
_feed
= None
152 self
._curr
_item
= None
154 self
._init
_presenters
()
157 def _init_widgets(self
):
158 widget_tree
= self
._view
.get_widget_tree()
159 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
160 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
162 item_view_container
= widget_tree
.get_widget('item_view_container')
163 item_list_container
= widget_tree
.get_widget('item_list_container')
165 parent_paned
= item_view_container
.get_parent()
166 parent_parent_widget
= parent_paned
.get_parent()
168 config
= Config
.get_instance()
171 layout
= config
.pane_layout
172 if layout
== 'vertical':
173 new_paned
= gtk
.VPaned()
174 child_list
.append(item_list_container
)
175 child_list
.append(item_view_container
)
176 elif layout
== 'horizontal':
177 new_paned
= gtk
.HPaned()
178 child_list
.append(item_view_container
)
179 child_list
.append(item_list_container
)
180 else: # Use vertical layout as default
181 new_paned
= gtk
.VPaned()
182 child_list
.append(item_list_container
)
183 child_list
.append(item_view_container
)
185 for child
in child_list
:
186 child
.reparent(new_paned
)
188 parent_parent_widget
.remove(parent_paned
)
189 parent_parent_widget
.add(new_paned
)
193 def _init_presenters(self
):
194 widget_tree
= self
._view
.get_widget_tree()
195 toolbar_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
196 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
198 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
200 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
201 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
202 view
.add_selection_changed_listener(self
._item
_view
)
204 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
205 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
206 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
207 view
.add_selection_changed_listener(self
._error
_presenter
)
209 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
211 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
212 self
._menufp
_presenter
= MenuFeedPropsPresenter( view
= widget_tree
.get_widget('feed_information'))
213 self
._menufp
_presenter
.set_sensitive(False)
214 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
217 def copy_itemview_text_selection(self
):
218 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
220 def check_allocation(self
, widget
, event
):
221 config
= Config
.get_instance()
222 def check_size((width
, height
, widget
)):
223 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
224 config
.main_window_size
= (width
, height
)
225 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
226 gobject
.timeout_add(1000, check_size
, (
227 (event
.width
, event
.height
, widget
)))
229 def check_main_pane_position(self
, widget
):
230 config
= Config
.get_instance()
231 def check_position((position
, widget
)):
232 if position
== widget
.get_position():
233 config
.main_pane_position
= position
234 pos
= widget
.get_position()
235 if pos
!= config
.main_pane_position
:
236 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
238 def check_sub_pane_position(self
, widget
):
239 config
= Config
.get_instance()
240 def check_position((position
, widget
)):
241 if position
== widget
.get_position():
242 config
.sub_pane_position
= position
243 pos
= widget
.get_position()
244 if pos
!= config
.sub_pane_position
:
245 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
248 return helpers
.credits()
251 if self
._warn
_if
_offline
():
252 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
253 "task-done": [ self
._on
_feed
_poll
_done
] })
255 def _on_feed_poll_started(self
, handler
, feed
):
258 def _on_feed_poll_done(self
, handler
, data
):
261 def poll_current_category(self
):
262 if self
._warn
_if
_offline
():
263 self
._poll
_categories
([self
._curr
_category
])
265 def poll_current_feed(self
):
266 if self
._warn
_if
_offline
():
267 print self
._curr
_feed
268 pm
= PollManager
.get_instance()
269 pm
.poll([self
._curr
_feed
])
271 def mark_feed_as_read(self
):
272 self
._curr
_feed
.mark_all_read()
274 def mark_all_as_read(self
):
275 print "TODO mark_all_as_read"
277 def remove_selected_feed(self
):
278 # self._feed_list_presenter.remove_selected_feed()
281 def show_search(self
):
282 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
283 # self._item_view.item_selection_changed)
284 self
._item
_view
.display_empty_search()
285 self
._itemlist
_view
_notebook
.set_current_page(1)
286 self
._feedlist
_view
_notebook
.set_current_page(1)
287 self
._feedinfo
_presenter
.hide()
289 def hide_search(self
):
290 # self._find_presenter.clear()
291 self
._itemlist
_view
_notebook
.set_current_page(0)
292 self
._feedlist
_view
_notebook
.set_current_page(0)
293 self
._feedinfo
_presenter
.show()
294 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
295 # self._item_view.item_selection_changed)
298 def _poll_categories(self
, fclist
):
299 pm
= PollManager
.get_instance()
300 pm
.poll_categories(fclist
)
303 def _warn_if_offline(self
):
304 config
= Config
.get_instance()
307 response
= self
._view
.show_offline_dialog()
308 if response
== gtk
.RESPONSE_OK
:
309 config
.offline
= not config
.offline
315 def display_previous_feed(self
, item
= None):
317 Displays the feed before the current selected feed
319 self
._feed
_list
_presenter
.select_previous_feed()
321 def display_next_feed(self
, item
=None):
323 Displays the feed after the current selected feed
325 self
._feed
_list
_presenter
.select_next_feed()
328 def display_next_unread_feed(self
):
330 Displays the next feed with an unread item
332 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
335 def display_previous_item(self
, item
=None):
337 Displays the item before the current selected item. If the item is the
338 first item, scrolls to the previous feed
340 is_prev
= self
._itemlist
_presenter
.select_previous_item()
342 # TODO HACK - implement select_previous_feed(select_last=True) ...
343 # ... to select previous feed's last item
344 self
._feed
_list
_presenter
.select_previous_feed()
345 self
._itemlist
_presenter
.select_last_item()
349 def display_next_item(self
, item
=None):
351 Displays the item after the current selected item. If the item is the
352 last item, selectes the next feed. If the current feed is the last
353 feed in the list, it goes back and selects the first feed
355 is_next
= self
._itemlist
_presenter
.select_next_item()
357 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
359 self
._feed
_list
_presenter
.select_firsteed_feed()
362 def scroll_or_display_next_unread_item(self
, item
=None):
363 has_unread_item
= False
364 if not self
._item
_view
.scroll_down():
365 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
366 if not has_unread_item
:
367 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
370 def show_preferences_dialog(self
, parent
):
371 straw
.preferences_show()
373 def show_feed_properties(self
, parent
):
374 straw
.feed_properties_show(self
._curr
_feed
)
379 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
381 Setup the file chooser dialog. This includes an extra widget (a combobox)
382 to include the categories to import or export
384 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
385 buttons
=(gtk
.STOCK_CANCEL
,
387 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
390 for category
in FeedManager
.categories():
391 category_list
.append(category
)
395 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
396 combobox
= gtk
.ComboBox(model
)
397 celltitle
= gtk
.CellRendererText()
398 combobox
.pack_start(celltitle
,False)
399 combobox
.add_attribute(celltitle
, 'text', 0)
401 for category
in category_list
:
403 model
.set(it
, 0, category
.name
, 1, category
)
405 combobox
.set_active(0)
406 label
= gtk
.Label(extra_widget_title
)
407 label
.set_alignment(1.0,0.5)
408 hbox
= gtk
.HBox(spacing
=6)
409 hbox
.pack_start(label
,True,True,0)
410 hbox
.pack_end(combobox
,False,False,0)
413 dialog
.set_extra_widget(hbox
)
414 return (dialog
, combobox
)
416 def import_subscriptions(self
, parent
):
417 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
418 gtk
.FILE_CHOOSER_ACTION_OPEN
,
419 _("Add new subscriptions in:"))
420 ffilter
= gtk
.FileFilter()
421 ffilter
.set_name(_("OPML Files Only"))
422 ffilter
.add_pattern("*.xml")
423 ffilter
.add_pattern("*.opml")
424 dialog
.add_filter(ffilter
)
425 dialog
.set_transient_for(parent
)
426 response
= dialog
.run()
427 if response
== gtk
.RESPONSE_OK
:
428 filename
= dialog
.get_filename()
429 model
= combobox
.get_model()
430 category
= model
[combobox
.get_active()][1]
432 FeedManager
.import_opml(filename
, category
)
435 def export_subscriptions(parent
):
436 (dialog
,combobox
) = _setup_filechooser_dialog(_("Export Subscriptions"),
437 gtk
.FILE_CHOOSER_ACTION_SAVE
,
438 _("Select category to export:"))
439 def selection_changed(widget
, dialog
):
440 model
= widget
.get_model()
441 category
= model
[widget
.get_active()][1]
442 dialog
.set_current_name("Straw-%s.xml" % category
.title
)
444 combobox
.connect('changed',
447 selection_changed(combobox
, dialog
)
448 dialog
.set_transient_for(parent
)
449 response
= dialog
.run()
450 if response
== gtk
.RESPONSE_OK
:
451 filename
= dialog
.get_filename()
452 model
= combobox
.get_model()
453 cat
= model
[combobox
.get_active()][1]
454 opml
.export(cat
.title
, cat
.feeds
, filename
)
458 straw
.subscribe_show(parent
=self
.view
._widget
)
461 class ApplicationView(MVP
.WidgetView
):
465 def _initialize(self
):
466 self
._config
= Config
.get_instance()
467 self
._initialize
_dnd
()
468 self
._initialize
_window
_updater
()
469 self
._create
_unmodified
_accelerator
_group
()
470 self
._attach
_unmodified
_accelerator
_group
()
471 self
._initialize
_window
()
472 self
._find
_toggled
= False
474 def _initialize_window(self
):
475 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
476 if self
._config
.window_maximized
:
477 self
._widget
.maximize()
479 # we use resize here since configure-event seems to
480 # overwrite the default size if we use set_default_size.
481 self
._widget
.resize(*self
._config
.main_window_size
)
482 mmp
= widget_tree
.get_widget('main_main_pane')
483 msp
= widget_tree
.get_widget('main_sub_pane')
484 mmp
.set_position(self
._config
.main_pane_position
)
485 msp
.set_position(self
._config
.sub_pane_position
)
487 def _initialize_dnd(self
):
488 self
._widget
.drag_dest_set(
489 gtk
.DEST_DEFAULT_ALL
,
490 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
491 ('x-url/http', 0, 2)],
492 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
495 def _initialize_window_updater(self
):
496 #feedlist.signal_connect(Event.AllItemsReadSignal,
497 # lambda signal: self._update_title(feedlist))
498 #feedlist.signal_connect(Event.ItemReadSignal,
499 # lambda signal: self._update_title(feedlist))
500 #feedlist.signal_connect(Event.ItemsAddedSignal,
501 # lambda signal: self._update_title(feedlist))
502 #feedlist.signal_connect(Event.FeedsChangedSignal,
503 # lambda signal: self._update_title(feedlist))
506 def _update_title(self
, flist
):
507 uritems
= urfeeds
= 0
509 listfeeds
= flist
.flatten_list()
510 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
515 urfeeds
= len(listfeeds
)
518 item_feed_map
= {'uritems': uritems
,
521 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
522 self
._widget
.set_title( title
+ " - %s" % straw
.PACKAGE
)
525 # We have a separate accelerator group for the unmodified and
526 # shifted accelerators, that is, stuff like space, N, P, etc. This
527 # is so that we can have the find pane work correctly
528 def _create_unmodified_accelerator_group(self
):
529 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
530 agroup
= gtk
.AccelGroup()
531 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
532 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
533 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
534 ('next_unread_feed', ' ', 0),
535 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
536 for widget_name
, key
, mask
in accels
:
537 widget
= xml
.get_widget(widget_name
)
538 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
540 self
._unmodified
_accelerator
_group
= agroup
542 def _on_category_add_activate(self
, *args
):
545 def _attach_unmodified_accelerator_group(self
):
546 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
548 def _detach_unmodified_accelerator_group(self
):
549 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
551 def _on_straw_main_destroy_event(self
, *args
):
552 return self
._presenter
.quit()
554 def _on_straw_main_delete_event(self
, *args
):
555 return self
._presenter
.quit()
557 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
558 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
559 self
._config
.window_maximized
= False
560 self
._presenter
.check_allocation(widget
, event
)
562 self
._config
.window_maximized
= True
565 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
566 self
._presenter
.check_main_pane_position(widget
)
568 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
569 self
._presenter
.check_sub_pane_position(widget
)
572 def _on_feed_subscribe_activate(self
, *args
):
573 self
._presenter
.subscribe()
575 def _on_feed_unsubscribe_activate(self
, *args
):
576 self
._presenter
.remove_selected_feed()
578 def _on_subscription_import_activate(self
, *args
):
579 self
._presenter
.import_subscriptions(self
._widget
)
581 def _on_subscription_export_activate(self
, *args
):
582 self
._presenter
.export_subscriptions(self
._widget
)
584 def _on_feed_mark_as_read_activate(self
, *args
):
585 self
._presenter
.mark_feed_as_read()
587 def _on_feed_mark_all_as_read_activate(self
, *args
):
588 self
._presenter
.mark_all_as_read()
590 def _on_feed_refresh_selected_activate(self
, *args
):
591 self
._presenter
.poll_current_feed()
593 def _on_subscription_refresh_activate(self
, *args
):
594 #print self._widget.get_children()[0].set_stock_id(gtk.STOCK_STOP)
595 self
._presenter
.poll_all()
597 def _on_quit_activate(self
, *args
):
598 return self
._presenter
.quit()
601 def _on_copy_activate(self
, *args
):
602 self
._presenter
.copy_itemview_text_selection()
605 def _on_find_activate(self
, widget
, *args
):
606 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
607 menu_find
= xml
.get_widget('menu_find')
608 accel_label
= menu_find
.get_child()
610 if not self
._find
_toggled
:
611 self
._presenter
.show_search()
612 self
._detach
_unmodified
_accelerator
_group
()
613 self
._find
_toggled
= True
615 # save the "Find..." stock text for later recovery
616 self
._old
_label
_text
= accel_label
.get_text()
617 accel_label
.set_text(_('Return to feed list...'))
620 self
._presenter
.hide_search()
621 self
._attach
_unmodified
_accelerator
_group
()
622 self
._find
_toggled
= False
623 accel_label
.set_text(self
._old
_label
_text
)
625 def _on_preferences_activate(self
, *args
):
626 self
._presenter
.show_preferences_dialog(self
._widget
)
628 def _on_feed_information_activate(self
, *args
):
629 self
._presenter
.show_feed_properties(self
._widget
)
632 def _on_previous_item_activate(self
, *args
):
633 self
._presenter
.display_previous_item()
635 def _on_next_item_activate(self
, *args
):
636 self
._presenter
.display_next_item()
638 def _on_next_feed_activate(self
, *args
):
639 self
._presenter
.display_next_feed()
641 def _on_previous_feed_activate(self
, *args
):
642 self
._presenter
.display_previous_feed()
644 def _on_next_unread_feed_activate(self
, *args
):
645 self
._presenter
.display_next_unread_feed()
647 def _on_scroll_unread_items_activate(self
, *args
):
648 self
._presenter
.scroll_or_display_next_unread_item()
652 def _on_report_problem_activate(self
, menuitem
, *args
):
653 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
655 def _on_about_activate(self
, menuitem
, *args
):
656 widget
= self
._presenter
.credits()
659 def _on_straw_main_drag_data_received(self
, w
, context
,
660 x
, y
, data
, info
, time
):
661 if data
and data
.format
== 8:
662 url
= data
.data
.split("\n")[0]
663 straw
.subscribe_show("%s" % url
, self
._widget
)
664 context
.finish(True, False, time
)
666 context
.finish(False, False, time
)
669 def show_offline_dialog(self
):
670 return helpers
.report_offline_status(self
._widget
)
672 def get_widget_tree(self
):
673 return gtk
.glade
.get_widget_tree(self
._widget
)
676 self
._widget
.present()
678 def should_present(self
):
679 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
682 self
._widget
.present()
687 gnome
.program_init(straw
.PACKAGE
, straw
.VERSION
)
690 # initialize threading and environment
691 gobject
.threads_init()
692 config
= Config
.get_instance()
693 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
695 # build tray status icon
697 iconfile
= os
.path
.normpath(straw
.STRAW_DATA_DIR
+ "/straw.png")
698 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
699 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
700 image
.set_from_pixbuf(scaled_buf
)
702 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
703 self
.tray
.connect('activate', self
._tray
_clicked
)
704 except AttributeError:
707 self
.tray
= egg
.trayicon
.TrayIcon(straw
.PACKAGE
);
708 self
._eventbox
= gtk
.EventBox()
709 self
.tray
.add(self
._eventbox
)
710 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
711 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
712 self
._eventbox
.drag_dest_set(
713 gtk
.DEST_DEFAULT_ALL
,
714 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
715 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
716 self
._eventbox
.add(image
)
719 self
._tooltip
= gtk
.Tooltips()
720 self
.unread_count
= 0
721 # end build tray status icon
723 FeedManager
.setup(storage_path
= "test.db")
726 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
728 #if config.first_time:
729 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
730 # feeds.import_opml(filepath)
732 #ImageCache.initialize()
735 #print feedfinder.feeds("http://eclipse.org", True)
737 xml
= gtk
.glade
.XML(os
.path
.join(straw
.STRAW_DATA_DIR
,'straw.glade'), "straw_main", gettext
.textdomain())
738 window
= xml
.get_widget('straw_main')
739 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
740 self
._main
_presenter
.view
.present()
742 #PollManager.get_instance().start_polling_loop()
743 # set the default icon for the windows
744 iconfile
= os
.path
.join(straw
.STRAW_DATA_DIR
,"straw.png")
745 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
747 straw
.start_services()
750 gtk
.gdk
.threads_init()
751 gtk
.gdk
.threads_enter()
753 gtk
.gdk
.threads_leave()
755 def _update(self
,flist
):
756 uritems
= urfeeds
= 0
757 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
761 if uritems
== self
.unread_count
:
763 self
.unread_count
= uritems
765 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
771 def _tray_clicked(self
, widget
, event
=None):
772 self
._main
_presenter
.view
.should_present()
773 if event
and not (event
.button
== 1):
775 self
._main
_presenter
.scroll_or_display_next_unread_item()
777 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
778 if data
and data
.format
== 8:
779 url
= data
.data
.split("\n")[0]
780 straw
.subscribe_show(url
="%s" % url
)
781 context
.finish(True, False, timestamp
)
783 context
.finish(False, False, timestamp
)