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 import os
, gettext
, getopt
, sys
24 from xml
.sax
import saxutils
27 import gobject
, gtk
, gtk
.glade
32 from ItemView
import ItemView
33 from ItemList
import ItemListPresenter
, ItemListView
34 from FeedListView
import FeedsView
, FeedsPresenter
35 from OfflineToggle
import OfflineToggle
36 from MainloopManager
import MainloopManager
37 #from Find import FindPresenter, FindView
42 import TreeViewManager
45 from straw
import helpers
47 class StatusPresenter(MVP
.BasicPresenter
):
48 def _initialize(self
):
49 self
._mmgr
= straw
.get_status_manager()
50 self
._mmgr
.connect('changed', self
._display
)
52 def _display(self
, *args
):
53 cid
= self
._view
.get_context_id("straw_main")
55 self
._view
.push(cid
, self
._mmgr
.read_message())
59 def __init__(self
, widget
):
61 self
._tooltips
= gtk
.Tooltips()
63 #self._curr_feed = None
64 #self._curr_category = None
65 #fclist = FeedCategoryList.get_instance()
66 #fclist.connect('category-changed', self._category_changed)
68 def feedlist_selection_changed(self
, selection
, column
):
71 (model
, pathlist
) = selection
.get_selected_rows()
72 iters
= [model
.get_iter(path
) for path
in pathlist
]
75 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
77 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
78 errortexts
= [feed
.error
for feed
in errorfeeds
]
81 ### XXX display OPML Category error too
85 text
.append(_("Error:"))
90 self
._tooltips
.set_tip(self
._widget
,t
,t
)
91 self
._tooltips
.enable()
94 self
._tooltips
.disable()
101 class MenuFeedPropsPresenter(MVP
.BasicPresenter
):
103 def set_sensitive(self
, s
):
104 self
._view
.set_sensitive(s
)
107 class ToolbarView(MVP
.WidgetView
):
108 """ Widget: gtk.Toolbar"""
109 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
111 def _initialize(self
):
112 client
= gconf
.client_get_default()
113 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
115 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
116 gconf
.CLIENT_PRELOAD_NONE
)
117 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
118 self
._toolbar
_style
_changed
)
119 self
._widget
.set_tooltips(True)
121 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
122 value
= entry
.value
.get_string()
123 self
._presenter
.style_changed(value
)
125 def set_style(self
, style
):
126 self
._widget
.set_style(style
)
129 client
= gconf
.client_get_default()
130 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
133 class ToolbarPresenter(MVP
.BasicPresenter
):
134 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
135 'text':gtk
.TOOLBAR_TEXT
,
136 'icons':gtk
.TOOLBAR_ICONS
,
137 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
139 def _initialize(self
):
140 style
= self
._view
.get_style()
141 if style
in self
.STYLES
.keys():
142 self
._view
.set_style(self
.STYLES
[style
])
145 def style_changed(self
, value
):
146 if value
in self
.STYLES
.keys():
147 self
._view
.set_style(self
.STYLES
[value
])
150 class ApplicationPresenter(MVP
.BasicPresenter
):
151 def _initialize(self
):
152 self
._curr
_category
= None
153 self
._curr
_feed
= None
154 self
._curr
_item
= None
156 self
._init
_presenters
()
159 def _init_widgets(self
):
160 widget_tree
= self
._view
.get_widget_tree()
161 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
162 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
164 item_view_container
= widget_tree
.get_widget('item_view_container')
165 item_list_container
= widget_tree
.get_widget('item_list_container')
167 parent_paned
= item_view_container
.get_parent()
168 parent_parent_widget
= parent_paned
.get_parent()
170 config
= Config
.get_instance()
173 layout
= config
.pane_layout
174 if layout
== 'vertical':
175 new_paned
= gtk
.VPaned()
176 child_list
.append(item_list_container
)
177 child_list
.append(item_view_container
)
178 elif layout
== 'horizontal':
179 new_paned
= gtk
.HPaned()
180 child_list
.append(item_view_container
)
181 child_list
.append(item_list_container
)
182 else: # Use vertical layout as default
183 new_paned
= gtk
.VPaned()
184 child_list
.append(item_list_container
)
185 child_list
.append(item_view_container
)
187 for child
in child_list
:
188 child
.reparent(new_paned
)
190 parent_parent_widget
.remove(parent_paned
)
191 parent_parent_widget
.add(new_paned
)
195 def _init_presenters(self
):
196 widget_tree
= self
._view
.get_widget_tree()
197 toolbar_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
198 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
200 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
202 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
203 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
204 view
.add_selection_changed_listener(self
._item
_view
)
206 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
207 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
208 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
209 view
.add_selection_changed_listener(self
._error
_presenter
)
211 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
213 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
214 self
._menufp
_presenter
= MenuFeedPropsPresenter( view
= widget_tree
.get_widget('feed_information'))
215 self
._menufp
_presenter
.set_sensitive(False)
216 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
219 def copy_itemview_text_selection(self
):
220 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
222 def check_allocation(self
, widget
, event
):
223 config
= Config
.get_instance()
224 def check_size((width
, height
, widget
)):
225 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
226 config
.main_window_size
= (width
, height
)
227 if event
.width
!= widget
.allocation
.width
or event
.height
!= widget
.allocation
.height
:
228 gobject
.timeout_add(1000, check_size
, (
229 (event
.width
, event
.height
, widget
)))
231 def check_main_pane_position(self
, widget
):
232 config
= Config
.get_instance()
233 def check_position((position
, widget
)):
234 if position
== widget
.get_position():
235 config
.main_pane_position
= position
236 pos
= widget
.get_position()
237 if pos
!= config
.main_pane_position
:
238 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
240 def check_sub_pane_position(self
, widget
):
241 config
= Config
.get_instance()
242 def check_position((position
, widget
)):
243 if position
== widget
.get_position():
244 config
.sub_pane_position
= position
245 pos
= widget
.get_position()
246 if pos
!= config
.sub_pane_position
:
247 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
250 return helpers
.credits()
253 if self
._warn
_if
_offline
():
254 FeedManager
.update_all_feeds({})
256 def poll_current_category(self
):
257 if self
._warn
_if
_offline
():
258 self
._poll
_categories
([self
._curr
_category
])
261 def poll_current_feed(self
):
262 if self
._warn
_if
_offline
():
263 pm
= PollManager
.get_instance()
264 pm
.poll([self
._curr
_feed
])
267 def mark_feed_as_read(self
):
268 self
._curr
_feed
.mark_all_read()
270 def mark_all_as_read(self
):
271 print "TODO mark_all_as_read"
273 def remove_selected_feed(self
):
274 # self._feed_list_presenter.remove_selected_feed()
277 def show_search(self
):
278 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
279 # self._item_view.item_selection_changed)
280 self
._item
_view
.display_empty_search()
281 self
._itemlist
_view
_notebook
.set_current_page(1)
282 self
._feedlist
_view
_notebook
.set_current_page(1)
283 self
._feedinfo
_presenter
.hide()
285 def hide_search(self
):
286 # self._find_presenter.clear()
287 self
._itemlist
_view
_notebook
.set_current_page(0)
288 self
._feedlist
_view
_notebook
.set_current_page(0)
289 self
._feedinfo
_presenter
.show()
290 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
291 # self._item_view.item_selection_changed)
294 def _poll_categories(self
, fclist
):
295 pm
= PollManager
.get_instance()
296 pm
.poll_categories(fclist
)
299 def _warn_if_offline(self
):
300 config
= Config
.get_instance()
303 response
= self
._view
.show_offline_dialog()
304 if response
== gtk
.RESPONSE_OK
:
305 config
.offline
= not config
.offline
311 def display_previous_feed(self
, item
= None):
313 Displays the feed before the current selected feed
315 self
._feed
_list
_presenter
.select_previous_feed()
317 def display_next_feed(self
, item
=None):
319 Displays the feed after the current selected feed
321 self
._feed
_list
_presenter
.select_next_feed()
324 def display_next_unread_feed(self
):
326 Displays the next feed with an unread item
328 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
331 def display_previous_item(self
, item
=None):
333 Displays the item before the current selected item. If the item is the
334 first item, scrolls to the previous feed
336 is_prev
= self
._itemlist
_presenter
.select_previous_item()
338 # TODO HACK - implement select_previous_feed(select_last=True) ...
339 # ... to select previous feed's last item
340 self
._feed
_list
_presenter
.select_previous_feed()
341 self
._itemlist
_presenter
.select_last_item()
345 def display_next_item(self
, item
=None):
347 Displays the item after the current selected item. If the item is the
348 last item, selectes the next feed. If the current feed is the last
349 feed in the list, it goes back and selects the first feed
351 is_next
= self
._itemlist
_presenter
.select_next_item()
353 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
355 self
._feed
_list
_presenter
.select_firsteed_feed()
358 def scroll_or_display_next_unread_item(self
, item
=None):
359 has_unread_item
= False
360 if not self
._item
_view
.scroll_down():
361 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
362 if not has_unread_item
:
363 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
366 def show_preferences_dialog(self
, parent
):
367 straw
.preferences_show()
369 def show_feed_properties(self
, parent
):
370 straw
.feed_properties_show(self
._curr
_feed
)
375 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
377 Setup the file chooser dialog. This includes an extra widget (a combobox)
378 to include the categories to import or export
380 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
381 buttons
=(gtk
.STOCK_CANCEL
,
383 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
385 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
386 combobox
= gtk
.ComboBox(model
)
387 celltitle
= gtk
.CellRendererText()
388 combobox
.pack_start(celltitle
,False)
389 combobox
.add_attribute(celltitle
, 'text', 0)
393 #model.set(it, 0, category_list.all_category.title,
394 # 1, category_list.all_category)
396 # add user categories
397 #for category in category_list.user_categories:
398 # it = model.append()
399 # model.set(it, 0, category.title, 1, category)
402 combobox
.set_active(0)
403 label
= gtk
.Label(extra_widget_title
)
404 label
.set_alignment(1.0,0.5)
405 hbox
= gtk
.HBox(spacing
=6)
406 hbox
.pack_start(label
,True,True,0)
407 hbox
.pack_end(combobox
,False,False,0)
410 dialog
.set_extra_widget(hbox
)
411 return (dialog
, combobox
)
414 def import_subscriptions(self
, parent
):
415 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
416 gtk
.FILE_CHOOSER_ACTION_OPEN
,
417 _("Add new subscriptions in:"))
418 ffilter
= gtk
.FileFilter()
419 ffilter
.set_name(_("OPML Files Only"))
420 ffilter
.add_pattern("*.xml")
421 ffilter
.add_pattern("*.opml")
422 dialog
.add_filter(ffilter
)
423 dialog
.set_transient_for(parent
)
424 response
= dialog
.run()
425 if response
== gtk
.RESPONSE_OK
:
426 filename
= dialog
.get_filename()
427 model
= combobox
.get_model()
428 cat
= model
[combobox
.get_active()][1]
430 FeedManager
.import_opml(filename
)
433 def export_subscriptions(parent
):
434 (dialog
,combobox
) = _setup_filechooser_dialog(_("Export Subscriptions"),
435 gtk
.FILE_CHOOSER_ACTION_SAVE
,
436 _("Select category to export:"))
437 def selection_changed(widget
, dialog
):
438 model
= widget
.get_model()
439 category
= model
[widget
.get_active()][1]
440 dialog
.set_current_name("Straw-%s.xml" % category
.title
)
442 combobox
.connect('changed',
445 selection_changed(combobox
, dialog
)
446 dialog
.set_transient_for(parent
)
447 response
= dialog
.run()
448 if response
== gtk
.RESPONSE_OK
:
449 filename
= dialog
.get_filename()
450 model
= combobox
.get_model()
451 cat
= model
[combobox
.get_active()][1]
452 opml
.export(cat
.title
, cat
.feeds
, filename
)
456 class ApplicationView(MVP
.WidgetView
):
460 def _initialize(self
):
461 self
._config
= Config
.get_instance()
462 self
._initialize
_dnd
()
463 self
._initialize
_window
_updater
()
464 self
._create
_unmodified
_accelerator
_group
()
465 self
._attach
_unmodified
_accelerator
_group
()
466 self
._initialize
_window
()
467 self
._find
_toggled
= False
469 def _initialize_window(self
):
470 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
471 if self
._config
.window_maximized
:
472 self
._widget
.maximize()
474 # we use resize here since configure-event seems to
475 # overwrite the default size if we use set_default_size.
476 self
._widget
.resize(*self
._config
.main_window_size
)
477 mmp
= widget_tree
.get_widget('main_main_pane')
478 msp
= widget_tree
.get_widget('main_sub_pane')
479 mmp
.set_position(self
._config
.main_pane_position
)
480 msp
.set_position(self
._config
.sub_pane_position
)
482 def _initialize_dnd(self
):
483 self
._widget
.drag_dest_set(
484 gtk
.DEST_DEFAULT_ALL
,
485 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
486 ('x-url/http', 0, 2)],
487 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
490 def _initialize_window_updater(self
):
491 #feedlist.signal_connect(Event.AllItemsReadSignal,
492 # lambda signal: self._update_title(feedlist))
493 #feedlist.signal_connect(Event.ItemReadSignal,
494 # lambda signal: self._update_title(feedlist))
495 #feedlist.signal_connect(Event.ItemsAddedSignal,
496 # lambda signal: self._update_title(feedlist))
497 #feedlist.signal_connect(Event.FeedsChangedSignal,
498 # lambda signal: self._update_title(feedlist))
501 def _update_title(self
, flist
):
502 uritems
= urfeeds
= 0
504 listfeeds
= flist
.flatten_list()
505 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
510 urfeeds
= len(listfeeds
)
513 item_feed_map
= {'uritems': uritems
,
516 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
517 self
._widget
.set_title( title
+ " - %s" % straw
.PACKAGE
)
520 # We have a separate accelerator group for the unmodified and
521 # shifted accelerators, that is, stuff like space, N, P, etc. This
522 # is so that we can have the find pane work correctly
523 def _create_unmodified_accelerator_group(self
):
524 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
525 agroup
= gtk
.AccelGroup()
526 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
527 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
528 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
529 ('next_unread_feed', ' ', 0),
530 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
531 for widget_name
, key
, mask
in accels
:
532 widget
= xml
.get_widget(widget_name
)
533 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
535 self
._unmodified
_accelerator
_group
= agroup
537 def _on_category_add_activate(self
, *args
):
540 def _attach_unmodified_accelerator_group(self
):
541 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
543 def _detach_unmodified_accelerator_group(self
):
544 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
546 def _on_straw_main_destroy_event(self
, *args
):
547 return self
._presenter
.quit()
549 def _on_straw_main_delete_event(self
, *args
):
550 return self
._presenter
.quit()
552 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
553 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
554 self
._config
.window_maximized
= False
555 self
._presenter
.check_allocation(widget
, event
)
557 self
._config
.window_maximized
= True
560 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
561 self
._presenter
.check_main_pane_position(widget
)
563 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
564 self
._presenter
.check_sub_pane_position(widget
)
567 def _on_feed_subscribe_activate(self
, *args
):
568 straw
.subscribe_show(parent
=self
._widget
)
570 def _on_feed_unsubscribe_activate(self
, *args
):
571 self
._presenter
.remove_selected_feed()
573 def _on_subscription_import_activate(self
, *args
):
574 self
._presenter
.import_subscriptions(self
._widget
)
576 def _on_subscription_export_activate(self
, *args
):
577 self
._presenter
.export_subscriptions(self
._widget
)
579 def _on_feed_mark_as_read_activate(self
, *args
):
580 self
._presenter
.mark_feed_as_read()
582 def _on_feed_mark_all_as_read_activate(self
, *args
):
583 self
._presenter
.mark_all_as_read()
585 def _on_feed_refresh_selected_activate(self
, *args
):
586 self
._presenter
.poll_current_feed()
588 def _on_subscription_refresh_activate(self
, *args
):
589 #print self._widget.get_children()[0].set_stock_id(gtk.STOCK_STOP)
590 self
._presenter
.poll_all()
592 def _on_quit_activate(self
, *args
):
593 return self
._presenter
.quit()
596 def _on_copy_activate(self
, *args
):
597 self
._presenter
.copy_itemview_text_selection()
600 def _on_find_activate(self
, widget
, *args
):
601 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
602 menu_find
= xml
.get_widget('menu_find')
603 accel_label
= menu_find
.get_child()
605 if not self
._find
_toggled
:
606 self
._presenter
.show_search()
607 self
._detach
_unmodified
_accelerator
_group
()
608 self
._find
_toggled
= True
610 # save the "Find..." stock text for later recovery
611 self
._old
_label
_text
= accel_label
.get_text()
612 accel_label
.set_text(_('Return to feed list...'))
615 self
._presenter
.hide_search()
616 self
._attach
_unmodified
_accelerator
_group
()
617 self
._find
_toggled
= False
618 accel_label
.set_text(self
._old
_label
_text
)
620 def _on_preferences_activate(self
, *args
):
621 self
._presenter
.show_preferences_dialog(self
._widget
)
623 def _on_feed_information_activate(self
, *args
):
624 self
._presenter
.show_feed_properties(self
._widget
)
627 def _on_previous_item_activate(self
, *args
):
628 self
._presenter
.display_previous_item()
630 def _on_next_item_activate(self
, *args
):
631 self
._presenter
.display_next_item()
633 def _on_next_feed_activate(self
, *args
):
634 self
._presenter
.display_next_feed()
636 def _on_previous_feed_activate(self
, *args
):
637 self
._presenter
.display_previous_feed()
639 def _on_next_unread_feed_activate(self
, *args
):
640 self
._presenter
.display_next_unread_feed()
642 def _on_scroll_unread_items_activate(self
, *args
):
643 self
._presenter
.scroll_or_display_next_unread_item()
647 def _on_report_problem_activate(self
, menuitem
, *args
):
648 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
650 def _on_about_activate(self
, menuitem
, *args
):
651 widget
= self
._presenter
.credits()
654 def _on_straw_main_drag_data_received(self
, w
, context
,
655 x
, y
, data
, info
, time
):
656 if data
and data
.format
== 8:
657 url
= data
.data
.split("\n")[0]
658 straw
.subscribe_show("%s" % url
, self
._widget
)
659 context
.finish(True, False, time
)
661 context
.finish(False, False, time
)
664 def show_offline_dialog(self
):
665 return helpers
.report_offline_status(self
._widget
)
667 def get_widget_tree(self
):
668 return gtk
.glade
.get_widget_tree(self
._widget
)
671 self
._widget
.present()
673 def should_present(self
):
674 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
677 self
._widget
.present()
682 gnome
.program_init(straw
.PACKAGE
, straw
.VERSION
)
685 # initialize threading and environment
686 gobject
.threads_init()
687 config
= Config
.get_instance()
688 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
690 # build tray status icon
692 iconfile
= os
.path
.normpath(straw
.STRAW_DATA_DIR
+ "/straw.png")
693 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
694 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
695 image
.set_from_pixbuf(scaled_buf
)
697 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
698 self
.tray
.connect('activate', self
._tray
_clicked
)
699 except AttributeError:
702 self
.tray
= egg
.trayicon
.TrayIcon(straw
.PACKAGE
);
703 self
._eventbox
= gtk
.EventBox()
704 self
.tray
.add(self
._eventbox
)
705 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
706 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
707 self
._eventbox
.drag_dest_set(
708 gtk
.DEST_DEFAULT_ALL
,
709 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
710 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
711 self
._eventbox
.add(image
)
714 self
._tooltip
= gtk
.Tooltips()
715 self
.unread_count
= 0
716 # end build tray status icon
718 FeedManager
.setup(storage_path
= "test.db")
721 TreeViewManager
.setup(storage_path
= "test.db")
722 TreeViewManager
.init()
723 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
725 #if config.first_time:
726 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
727 # feeds.import_opml(filepath)
729 #ImageCache.initialize()
732 #print feedfinder.feeds("http://eclipse.org", True)
734 xml
= gtk
.glade
.XML(os
.path
.join(straw
.STRAW_DATA_DIR
,'straw.glade'), "straw_main", gettext
.textdomain())
735 window
= xml
.get_widget('straw_main')
736 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
737 self
._main
_presenter
.view
.present()
739 #PollManager.get_instance().start_polling_loop()
740 # set the default icon for the windows
741 iconfile
= os
.path
.join(straw
.STRAW_DATA_DIR
,"straw.png")
742 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
744 straw
.start_services()
747 gtk
.gdk
.threads_init()
748 gtk
.gdk
.threads_enter()
750 gtk
.gdk
.threads_leave()
752 def _update(self
,flist
):
753 uritems
= urfeeds
= 0
754 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
758 if uritems
== self
.unread_count
:
760 self
.unread_count
= uritems
762 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
768 def _tray_clicked(self
, widget
, event
=None):
769 self
._main
_presenter
.view
.should_present()
770 if event
and not (event
.button
== 1):
772 self
._main
_presenter
.scroll_or_display_next_unread_item()
774 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
775 if data
and data
.format
== 8:
776 url
= data
.data
.split("\n")[0]
777 straw
.subscribe_show(url
="%s" % url
)
778 context
.finish(True, False, timestamp
)
780 context
.finish(False, False, timestamp
)