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 add_category(self
):
218 self
._feed
_list
_presenter
.add_category()
220 def copy_itemview_text_selection(self
):
221 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
223 def check_allocation(self
, widget
, event
):
224 config
= Config
.get_instance()
225 def check_size((width
, height
, widget
)):
226 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
227 config
.main_window_size
= (width
, height
)
228 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
229 gobject
.timeout_add(1000, check_size
, (
230 (event
.width
, event
.height
, widget
)))
232 def check_main_pane_position(self
, widget
):
233 config
= Config
.get_instance()
234 def check_position((position
, widget
)):
235 if position
== widget
.get_position():
236 config
.main_pane_position
= position
237 pos
= widget
.get_position()
238 if pos
!= config
.main_pane_position
:
239 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
241 def check_sub_pane_position(self
, widget
):
242 config
= Config
.get_instance()
243 def check_position((position
, widget
)):
244 if position
== widget
.get_position():
245 config
.sub_pane_position
= position
246 pos
= widget
.get_position()
247 if pos
!= config
.sub_pane_position
:
248 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
251 return helpers
.credits()
254 if self
._warn
_if
_offline
():
255 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
256 "task-done": [ self
._on
_feed
_poll
_done
] })
258 def _on_feed_poll_started(self
, handler
, feed
):
261 def _on_feed_poll_done(self
, handler
, data
):
264 def poll_current_category(self
):
265 if self
._warn
_if
_offline
():
266 self
._poll
_categories
([self
._curr
_category
])
268 def poll_current_feed(self
):
269 if self
._warn
_if
_offline
():
270 print self
._curr
_feed
271 pm
= PollManager
.get_instance()
272 pm
.poll([self
._curr
_feed
])
274 def mark_feed_as_read(self
):
275 self
._curr
_feed
.mark_all_read()
277 def mark_all_as_read(self
):
278 print "TODO mark_all_as_read"
280 def remove_selected_feed(self
):
281 # self._feed_list_presenter.remove_selected_feed()
284 def show_search(self
):
285 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
286 # self._item_view.item_selection_changed)
287 self
._item
_view
.display_empty_search()
288 self
._itemlist
_view
_notebook
.set_current_page(1)
289 self
._feedlist
_view
_notebook
.set_current_page(1)
290 self
._feedinfo
_presenter
.hide()
292 def hide_search(self
):
293 # self._find_presenter.clear()
294 self
._itemlist
_view
_notebook
.set_current_page(0)
295 self
._feedlist
_view
_notebook
.set_current_page(0)
296 self
._feedinfo
_presenter
.show()
297 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
298 # self._item_view.item_selection_changed)
301 def _poll_categories(self
, fclist
):
302 pm
= PollManager
.get_instance()
303 pm
.poll_categories(fclist
)
306 def _warn_if_offline(self
):
307 config
= Config
.get_instance()
310 response
= self
._view
.show_offline_dialog()
311 if response
== gtk
.RESPONSE_OK
:
312 config
.offline
= not config
.offline
318 def display_previous_feed(self
, item
= None):
320 Displays the feed before the current selected feed
322 self
._feed
_list
_presenter
.select_previous_feed()
324 def display_next_feed(self
, item
=None):
326 Displays the feed after the current selected feed
328 self
._feed
_list
_presenter
.select_next_feed()
331 def display_next_unread_feed(self
):
333 Displays the next feed with an unread item
335 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
338 def display_previous_item(self
, item
=None):
340 Displays the item before the current selected item. If the item is the
341 first item, scrolls to the previous feed
343 is_prev
= self
._itemlist
_presenter
.select_previous_item()
345 # TODO HACK - implement select_previous_feed(select_last=True) ...
346 # ... to select previous feed's last item
347 self
._feed
_list
_presenter
.select_previous_feed()
348 self
._itemlist
_presenter
.select_last_item()
352 def display_next_item(self
, item
=None):
354 Displays the item after the current selected item. If the item is the
355 last item, selectes the next feed. If the current feed is the last
356 feed in the list, it goes back and selects the first feed
358 is_next
= self
._itemlist
_presenter
.select_next_item()
360 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
362 self
._feed
_list
_presenter
.select_firsteed_feed()
365 def scroll_or_display_next_unread_item(self
, item
=None):
366 has_unread_item
= False
367 if not self
._item
_view
.scroll_down():
368 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
369 if not has_unread_item
:
370 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
373 def show_preferences_dialog(self
, parent
):
374 straw
.preferences_show()
376 def show_feed_properties(self
, parent
):
377 straw
.feed_properties_show(self
._curr
_feed
)
382 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
384 Setup the file chooser dialog. This includes an extra widget (a combobox)
385 to include the categories to import or export
387 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
388 buttons
=(gtk
.STOCK_CANCEL
,
390 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
393 for category
in FeedManager
.categories():
394 category_list
.append(category
)
396 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
397 combobox
= gtk
.ComboBox(model
)
398 celltitle
= gtk
.CellRendererText()
399 combobox
.pack_start(celltitle
,False)
400 combobox
.add_attribute(celltitle
, 'text', 0)
402 for category
in category_list
:
404 model
.set(it
, 0, category
.name
, 1, category
)
406 combobox
.set_active(0)
407 label
= gtk
.Label(extra_widget_title
)
408 label
.set_alignment(1.0,0.5)
409 hbox
= gtk
.HBox(spacing
=6)
410 hbox
.pack_start(label
,True,True,0)
411 hbox
.pack_end(combobox
,False,False,0)
414 dialog
.set_extra_widget(hbox
)
415 return (dialog
, combobox
)
417 def import_subscriptions(self
, parent
):
418 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
419 gtk
.FILE_CHOOSER_ACTION_OPEN
,
420 _("Add new subscriptions in:"))
421 ffilter
= gtk
.FileFilter()
422 ffilter
.set_name(_("OPML Files Only"))
423 ffilter
.add_pattern("*.xml")
424 ffilter
.add_pattern("*.opml")
425 dialog
.add_filter(ffilter
)
426 dialog
.set_transient_for(parent
)
427 response
= dialog
.run()
428 if response
== gtk
.RESPONSE_OK
:
429 filename
= dialog
.get_filename()
430 model
= combobox
.get_model()
431 category
= model
[combobox
.get_active()][1]
433 FeedManager
.import_opml(filename
, category
)
436 def export_subscriptions(self
, parent
):
437 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Export Subscriptions"),
438 gtk
.FILE_CHOOSER_ACTION_SAVE
,
439 _("Select category to export:"))
440 def selection_changed(widget
, dialog
):
441 model
= widget
.get_model()
442 category
= model
[widget
.get_active()][1]
443 dialog
.set_current_name("Straw-%s.xml" % category
.name
)
445 combobox
.connect('changed', selection_changed
, dialog
)
446 selection_changed(combobox
, dialog
)
447 dialog
.set_transient_for(parent
)
448 response
= dialog
.run()
450 if response
== gtk
.RESPONSE_OK
:
451 filename
= dialog
.get_filename()
452 model
= combobox
.get_model()
453 root_category
= model
[combobox
.get_active()][1]
454 FeedManager
.export_opml(root_category
.id, filename
)
459 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
):
543 self
._presenter
.add_category()
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
)