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
35 import gobject
, gtk
, gtk
.glade
37 import os
, gettext
, getopt
, sys
43 #from Find import FindPresenter, FindView
46 class StatusPresenter(MVP
.BasicPresenter
):
47 def _initialize(self
):
48 self
._mmgr
= straw
.get_status_manager()
49 self
._mmgr
.connect('changed', self
._display
)
51 def _display(self
, *args
):
52 cid
= self
._view
.get_context_id("straw_main")
54 self
._view
.push(cid
, self
._mmgr
.read_message())
58 def __init__(self
, widget
):
60 self
._tooltips
= gtk
.Tooltips()
62 #self._curr_feed = None
63 #self._curr_category = None
64 #fclist = FeedCategoryList.get_instance()
65 #fclist.connect('category-changed', self._category_changed)
67 def feedlist_selection_changed(self
, selection
, column
):
70 (model
, pathlist
) = selection
.get_selected_rows()
71 iters
= [model
.get_iter(path
) for path
in pathlist
]
74 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
76 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
77 errortexts
= [feed
.error
for feed
in errorfeeds
]
80 ### XXX display OPML Category error too
84 text
.append(_("Error:"))
89 self
._tooltips
.set_tip(self
._widget
,t
,t
)
90 self
._tooltips
.enable()
93 self
._tooltips
.disable()
100 class MenuFeedPropsPresenter(MVP
.BasicPresenter
):
102 def set_sensitive(self
, s
):
103 self
._view
.set_sensitive(s
)
106 class ToolbarView(MVP
.WidgetView
):
107 """ Widget: gtk.Toolbar"""
108 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
110 def _initialize(self
):
111 client
= gconf
.client_get_default()
112 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
114 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
115 gconf
.CLIENT_PRELOAD_NONE
)
116 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
117 self
._toolbar
_style
_changed
)
118 self
._widget
.set_tooltips(True)
120 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
121 value
= entry
.value
.get_string()
122 self
._presenter
.style_changed(value
)
124 def set_style(self
, style
):
125 self
._widget
.set_style(style
)
128 client
= gconf
.client_get_default()
129 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
132 class ToolbarPresenter(MVP
.BasicPresenter
):
133 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
134 'text':gtk
.TOOLBAR_TEXT
,
135 'icons':gtk
.TOOLBAR_ICONS
,
136 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
138 def _initialize(self
):
139 style
= self
._view
.get_style()
140 if style
in self
.STYLES
.keys():
141 self
._view
.set_style(self
.STYLES
[style
])
144 def style_changed(self
, value
):
145 if value
in self
.STYLES
.keys():
146 self
._view
.set_style(self
.STYLES
[value
])
149 class ApplicationPresenter(MVP
.BasicPresenter
):
150 def _initialize(self
):
151 self
._curr
_category
= None
152 self
._curr
_feed
= None
153 self
._curr
_item
= None
155 self
._init
_presenters
()
158 def _init_widgets(self
):
159 widget_tree
= self
._view
.get_widget_tree()
160 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
161 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
163 item_view_container
= widget_tree
.get_widget('item_view_container')
164 item_list_container
= widget_tree
.get_widget('item_list_container')
166 parent_paned
= item_view_container
.get_parent()
167 parent_parent_widget
= parent_paned
.get_parent()
169 config
= Config
.get_instance()
172 layout
= config
.pane_layout
173 if layout
== 'vertical':
174 new_paned
= gtk
.VPaned()
175 child_list
.append(item_list_container
)
176 child_list
.append(item_view_container
)
177 elif layout
== 'horizontal':
178 new_paned
= gtk
.HPaned()
179 child_list
.append(item_view_container
)
180 child_list
.append(item_list_container
)
181 else: # Use vertical layout as default
182 new_paned
= gtk
.VPaned()
183 child_list
.append(item_list_container
)
184 child_list
.append(item_view_container
)
186 for child
in child_list
:
187 child
.reparent(new_paned
)
189 parent_parent_widget
.remove(parent_paned
)
190 parent_parent_widget
.add(new_paned
)
194 def _init_presenters(self
):
195 widget_tree
= self
._view
.get_widget_tree()
196 toolbar_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
197 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
199 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
201 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
202 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
203 view
.add_selection_changed_listener(self
._item
_view
)
205 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
206 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
207 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
208 view
.add_selection_changed_listener(self
._error
_presenter
)
210 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
212 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
213 self
._menufp
_presenter
= MenuFeedPropsPresenter( view
= widget_tree
.get_widget('feed_information'))
214 self
._menufp
_presenter
.set_sensitive(False)
215 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
218 def copy_itemview_text_selection(self
):
219 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
221 def check_allocation(self
, widget
, event
):
222 config
= Config
.get_instance()
223 def check_size((width
, height
, widget
)):
224 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
225 config
.main_window_size
= (width
, height
)
226 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
227 gobject
.timeout_add(1000, check_size
, (
228 (event
.width
, event
.height
, widget
)))
230 def check_main_pane_position(self
, widget
):
231 config
= Config
.get_instance()
232 def check_position((position
, widget
)):
233 if position
== widget
.get_position():
234 config
.main_pane_position
= position
235 pos
= widget
.get_position()
236 if pos
!= config
.main_pane_position
:
237 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
239 def check_sub_pane_position(self
, widget
):
240 config
= Config
.get_instance()
241 def check_position((position
, widget
)):
242 if position
== widget
.get_position():
243 config
.sub_pane_position
= position
244 pos
= widget
.get_position()
245 if pos
!= config
.sub_pane_position
:
246 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
249 return helpers
.credits()
252 if self
._warn
_if
_offline
():
253 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
254 "task-done": [ self
._on
_feed
_poll
_done
] })
256 def _on_feed_poll_started(self
, handler
, feed
):
259 def _on_feed_poll_done(self
, handler
, data
):
262 def poll_current_category(self
):
263 if self
._warn
_if
_offline
():
264 self
._poll
_categories
([self
._curr
_category
])
267 def poll_current_feed(self
):
268 if self
._warn
_if
_offline
():
269 pm
= PollManager
.get_instance()
270 pm
.poll([self
._curr
_feed
])
273 def mark_feed_as_read(self
):
274 self
._curr
_feed
.mark_all_read()
276 def mark_all_as_read(self
):
277 print "TODO mark_all_as_read"
279 def remove_selected_feed(self
):
280 # self._feed_list_presenter.remove_selected_feed()
283 def show_search(self
):
284 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
285 # self._item_view.item_selection_changed)
286 self
._item
_view
.display_empty_search()
287 self
._itemlist
_view
_notebook
.set_current_page(1)
288 self
._feedlist
_view
_notebook
.set_current_page(1)
289 self
._feedinfo
_presenter
.hide()
291 def hide_search(self
):
292 # self._find_presenter.clear()
293 self
._itemlist
_view
_notebook
.set_current_page(0)
294 self
._feedlist
_view
_notebook
.set_current_page(0)
295 self
._feedinfo
_presenter
.show()
296 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
297 # self._item_view.item_selection_changed)
300 def _poll_categories(self
, fclist
):
301 pm
= PollManager
.get_instance()
302 pm
.poll_categories(fclist
)
305 def _warn_if_offline(self
):
306 config
= Config
.get_instance()
309 response
= self
._view
.show_offline_dialog()
310 if response
== gtk
.RESPONSE_OK
:
311 config
.offline
= not config
.offline
317 def display_previous_feed(self
, item
= None):
319 Displays the feed before the current selected feed
321 self
._feed
_list
_presenter
.select_previous_feed()
323 def display_next_feed(self
, item
=None):
325 Displays the feed after the current selected feed
327 self
._feed
_list
_presenter
.select_next_feed()
330 def display_next_unread_feed(self
):
332 Displays the next feed with an unread item
334 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
337 def display_previous_item(self
, item
=None):
339 Displays the item before the current selected item. If the item is the
340 first item, scrolls to the previous feed
342 is_prev
= self
._itemlist
_presenter
.select_previous_item()
344 # TODO HACK - implement select_previous_feed(select_last=True) ...
345 # ... to select previous feed's last item
346 self
._feed
_list
_presenter
.select_previous_feed()
347 self
._itemlist
_presenter
.select_last_item()
351 def display_next_item(self
, item
=None):
353 Displays the item after the current selected item. If the item is the
354 last item, selectes the next feed. If the current feed is the last
355 feed in the list, it goes back and selects the first feed
357 is_next
= self
._itemlist
_presenter
.select_next_item()
359 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
361 self
._feed
_list
_presenter
.select_firsteed_feed()
364 def scroll_or_display_next_unread_item(self
, item
=None):
365 has_unread_item
= False
366 if not self
._item
_view
.scroll_down():
367 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
368 if not has_unread_item
:
369 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
372 def show_preferences_dialog(self
, parent
):
373 straw
.preferences_show()
375 def show_feed_properties(self
, parent
):
376 straw
.feed_properties_show(self
._curr
_feed
)
381 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
383 Setup the file chooser dialog. This includes an extra widget (a combobox)
384 to include the categories to import or export
386 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
387 buttons
=(gtk
.STOCK_CANCEL
,
389 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
392 for category
in FeedManager
.categories():
393 category_list
.append(category
)
397 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
398 combobox
= gtk
.ComboBox(model
)
399 celltitle
= gtk
.CellRendererText()
400 combobox
.pack_start(celltitle
,False)
401 combobox
.add_attribute(celltitle
, 'text', 0)
403 for category
in category_list
:
405 model
.set(it
, 0, category
.name
, 1, category
)
407 combobox
.set_active(0)
408 label
= gtk
.Label(extra_widget_title
)
409 label
.set_alignment(1.0,0.5)
410 hbox
= gtk
.HBox(spacing
=6)
411 hbox
.pack_start(label
,True,True,0)
412 hbox
.pack_end(combobox
,False,False,0)
415 dialog
.set_extra_widget(hbox
)
416 return (dialog
, combobox
)
418 def import_subscriptions(self
, parent
):
419 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
420 gtk
.FILE_CHOOSER_ACTION_OPEN
,
421 _("Add new subscriptions in:"))
422 ffilter
= gtk
.FileFilter()
423 ffilter
.set_name(_("OPML Files Only"))
424 ffilter
.add_pattern("*.xml")
425 ffilter
.add_pattern("*.opml")
426 dialog
.add_filter(ffilter
)
427 dialog
.set_transient_for(parent
)
428 response
= dialog
.run()
429 if response
== gtk
.RESPONSE_OK
:
430 filename
= dialog
.get_filename()
431 model
= combobox
.get_model()
432 category
= model
[combobox
.get_active()][1]
434 FeedManager
.import_opml(filename
, category
)
437 def export_subscriptions(parent
):
438 (dialog
,combobox
) = _setup_filechooser_dialog(_("Export Subscriptions"),
439 gtk
.FILE_CHOOSER_ACTION_SAVE
,
440 _("Select category to export:"))
441 def selection_changed(widget
, dialog
):
442 model
= widget
.get_model()
443 category
= model
[widget
.get_active()][1]
444 dialog
.set_current_name("Straw-%s.xml" % category
.title
)
446 combobox
.connect('changed',
449 selection_changed(combobox
, dialog
)
450 dialog
.set_transient_for(parent
)
451 response
= dialog
.run()
452 if response
== gtk
.RESPONSE_OK
:
453 filename
= dialog
.get_filename()
454 model
= combobox
.get_model()
455 cat
= model
[combobox
.get_active()][1]
456 opml
.export(cat
.title
, cat
.feeds
, filename
)
460 straw
.subscribe_show(parent
=self
.view
._widget
)
463 class ApplicationView(MVP
.WidgetView
):
467 def _initialize(self
):
468 self
._config
= Config
.get_instance()
469 self
._initialize
_dnd
()
470 self
._initialize
_window
_updater
()
471 self
._create
_unmodified
_accelerator
_group
()
472 self
._attach
_unmodified
_accelerator
_group
()
473 self
._initialize
_window
()
474 self
._find
_toggled
= False
476 def _initialize_window(self
):
477 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
478 if self
._config
.window_maximized
:
479 self
._widget
.maximize()
481 # we use resize here since configure-event seems to
482 # overwrite the default size if we use set_default_size.
483 self
._widget
.resize(*self
._config
.main_window_size
)
484 mmp
= widget_tree
.get_widget('main_main_pane')
485 msp
= widget_tree
.get_widget('main_sub_pane')
486 mmp
.set_position(self
._config
.main_pane_position
)
487 msp
.set_position(self
._config
.sub_pane_position
)
489 def _initialize_dnd(self
):
490 self
._widget
.drag_dest_set(
491 gtk
.DEST_DEFAULT_ALL
,
492 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
493 ('x-url/http', 0, 2)],
494 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
497 def _initialize_window_updater(self
):
498 #feedlist.signal_connect(Event.AllItemsReadSignal,
499 # lambda signal: self._update_title(feedlist))
500 #feedlist.signal_connect(Event.ItemReadSignal,
501 # lambda signal: self._update_title(feedlist))
502 #feedlist.signal_connect(Event.ItemsAddedSignal,
503 # lambda signal: self._update_title(feedlist))
504 #feedlist.signal_connect(Event.FeedsChangedSignal,
505 # lambda signal: self._update_title(feedlist))
508 def _update_title(self
, flist
):
509 uritems
= urfeeds
= 0
511 listfeeds
= flist
.flatten_list()
512 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
517 urfeeds
= len(listfeeds
)
520 item_feed_map
= {'uritems': uritems
,
523 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
524 self
._widget
.set_title( title
+ " - %s" % straw
.PACKAGE
)
527 # We have a separate accelerator group for the unmodified and
528 # shifted accelerators, that is, stuff like space, N, P, etc. This
529 # is so that we can have the find pane work correctly
530 def _create_unmodified_accelerator_group(self
):
531 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
532 agroup
= gtk
.AccelGroup()
533 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
534 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
535 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
536 ('next_unread_feed', ' ', 0),
537 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
538 for widget_name
, key
, mask
in accels
:
539 widget
= xml
.get_widget(widget_name
)
540 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
542 self
._unmodified
_accelerator
_group
= agroup
544 def _on_category_add_activate(self
, *args
):
547 def _attach_unmodified_accelerator_group(self
):
548 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
550 def _detach_unmodified_accelerator_group(self
):
551 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
553 def _on_straw_main_destroy_event(self
, *args
):
554 return self
._presenter
.quit()
556 def _on_straw_main_delete_event(self
, *args
):
557 return self
._presenter
.quit()
559 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
560 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
561 self
._config
.window_maximized
= False
562 self
._presenter
.check_allocation(widget
, event
)
564 self
._config
.window_maximized
= True
567 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
568 self
._presenter
.check_main_pane_position(widget
)
570 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
571 self
._presenter
.check_sub_pane_position(widget
)
574 def _on_feed_subscribe_activate(self
, *args
):
575 self
._presenter
.subscribe()
577 def _on_feed_unsubscribe_activate(self
, *args
):
578 self
._presenter
.remove_selected_feed()
580 def _on_subscription_import_activate(self
, *args
):
581 self
._presenter
.import_subscriptions(self
._widget
)
583 def _on_subscription_export_activate(self
, *args
):
584 self
._presenter
.export_subscriptions(self
._widget
)
586 def _on_feed_mark_as_read_activate(self
, *args
):
587 self
._presenter
.mark_feed_as_read()
589 def _on_feed_mark_all_as_read_activate(self
, *args
):
590 self
._presenter
.mark_all_as_read()
592 def _on_feed_refresh_selected_activate(self
, *args
):
593 self
._presenter
.poll_current_feed()
595 def _on_subscription_refresh_activate(self
, *args
):
596 #print self._widget.get_children()[0].set_stock_id(gtk.STOCK_STOP)
597 self
._presenter
.poll_all()
599 def _on_quit_activate(self
, *args
):
600 return self
._presenter
.quit()
603 def _on_copy_activate(self
, *args
):
604 self
._presenter
.copy_itemview_text_selection()
607 def _on_find_activate(self
, widget
, *args
):
608 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
609 menu_find
= xml
.get_widget('menu_find')
610 accel_label
= menu_find
.get_child()
612 if not self
._find
_toggled
:
613 self
._presenter
.show_search()
614 self
._detach
_unmodified
_accelerator
_group
()
615 self
._find
_toggled
= True
617 # save the "Find..." stock text for later recovery
618 self
._old
_label
_text
= accel_label
.get_text()
619 accel_label
.set_text(_('Return to feed list...'))
622 self
._presenter
.hide_search()
623 self
._attach
_unmodified
_accelerator
_group
()
624 self
._find
_toggled
= False
625 accel_label
.set_text(self
._old
_label
_text
)
627 def _on_preferences_activate(self
, *args
):
628 self
._presenter
.show_preferences_dialog(self
._widget
)
630 def _on_feed_information_activate(self
, *args
):
631 self
._presenter
.show_feed_properties(self
._widget
)
634 def _on_previous_item_activate(self
, *args
):
635 self
._presenter
.display_previous_item()
637 def _on_next_item_activate(self
, *args
):
638 self
._presenter
.display_next_item()
640 def _on_next_feed_activate(self
, *args
):
641 self
._presenter
.display_next_feed()
643 def _on_previous_feed_activate(self
, *args
):
644 self
._presenter
.display_previous_feed()
646 def _on_next_unread_feed_activate(self
, *args
):
647 self
._presenter
.display_next_unread_feed()
649 def _on_scroll_unread_items_activate(self
, *args
):
650 self
._presenter
.scroll_or_display_next_unread_item()
654 def _on_report_problem_activate(self
, menuitem
, *args
):
655 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
657 def _on_about_activate(self
, menuitem
, *args
):
658 widget
= self
._presenter
.credits()
661 def _on_straw_main_drag_data_received(self
, w
, context
,
662 x
, y
, data
, info
, time
):
663 if data
and data
.format
== 8:
664 url
= data
.data
.split("\n")[0]
665 straw
.subscribe_show("%s" % url
, self
._widget
)
666 context
.finish(True, False, time
)
668 context
.finish(False, False, time
)
671 def show_offline_dialog(self
):
672 return helpers
.report_offline_status(self
._widget
)
674 def get_widget_tree(self
):
675 return gtk
.glade
.get_widget_tree(self
._widget
)
678 self
._widget
.present()
680 def should_present(self
):
681 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
684 self
._widget
.present()
689 gnome
.program_init(straw
.PACKAGE
, straw
.VERSION
)
692 # initialize threading and environment
693 gobject
.threads_init()
694 config
= Config
.get_instance()
695 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
697 # build tray status icon
699 iconfile
= os
.path
.normpath(straw
.STRAW_DATA_DIR
+ "/straw.png")
700 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
701 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
702 image
.set_from_pixbuf(scaled_buf
)
704 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
705 self
.tray
.connect('activate', self
._tray
_clicked
)
706 except AttributeError:
709 self
.tray
= egg
.trayicon
.TrayIcon(straw
.PACKAGE
);
710 self
._eventbox
= gtk
.EventBox()
711 self
.tray
.add(self
._eventbox
)
712 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
713 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
714 self
._eventbox
.drag_dest_set(
715 gtk
.DEST_DEFAULT_ALL
,
716 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
717 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
718 self
._eventbox
.add(image
)
721 self
._tooltip
= gtk
.Tooltips()
722 self
.unread_count
= 0
723 # end build tray status icon
725 FeedManager
.setup(storage_path
= "test.db")
728 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
730 #if config.first_time:
731 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
732 # feeds.import_opml(filepath)
734 #ImageCache.initialize()
737 #print feedfinder.feeds("http://eclipse.org", True)
739 xml
= gtk
.glade
.XML(os
.path
.join(straw
.STRAW_DATA_DIR
,'straw.glade'), "straw_main", gettext
.textdomain())
740 window
= xml
.get_widget('straw_main')
741 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
742 self
._main
_presenter
.view
.present()
744 #PollManager.get_instance().start_polling_loop()
745 # set the default icon for the windows
746 iconfile
= os
.path
.join(straw
.STRAW_DATA_DIR
,"straw.png")
747 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
749 straw
.start_services()
752 gtk
.gdk
.threads_init()
753 gtk
.gdk
.threads_enter()
755 gtk
.gdk
.threads_leave()
757 def _update(self
,flist
):
758 uritems
= urfeeds
= 0
759 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
763 if uritems
== self
.unread_count
:
765 self
.unread_count
= uritems
767 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
773 def _tray_clicked(self
, widget
, event
=None):
774 self
._main
_presenter
.view
.should_present()
775 if event
and not (event
.button
== 1):
777 self
._main
_presenter
.scroll_or_display_next_unread_item()
779 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
780 if data
and data
.format
== 8:
781 url
= data
.data
.split("\n")[0]
782 straw
.subscribe_show(url
="%s" % url
)
783 context
.finish(True, False, timestamp
)
785 context
.finish(False, False, timestamp
)