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 #fclist = feeds.category_list
255 #self._poll_categories(fclist.all_categories)
257 FeedManager
.update_all_feeds({})
260 def poll_current_category(self
):
261 if self
._warn
_if
_offline
():
262 self
._poll
_categories
([self
._curr
_category
])
265 def poll_current_feed(self
):
266 if self
._warn
_if
_offline
():
267 pm
= PollManager
.get_instance()
268 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
)
378 ItemStore
.get_instance().stop()
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
))
391 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
392 combobox
= gtk
.ComboBox(model
)
393 celltitle
= gtk
.CellRendererText()
394 combobox
.pack_start(celltitle
,False)
395 combobox
.add_attribute(celltitle
, 'text', 0)
399 #model.set(it, 0, category_list.all_category.title,
400 # 1, category_list.all_category)
402 # add user categories
403 #for category in category_list.user_categories:
404 # it = model.append()
405 # model.set(it, 0, category.title, 1, category)
408 combobox
.set_active(0)
409 label
= gtk
.Label(extra_widget_title
)
410 label
.set_alignment(1.0,0.5)
411 hbox
= gtk
.HBox(spacing
=6)
412 hbox
.pack_start(label
,True,True,0)
413 hbox
.pack_end(combobox
,False,False,0)
416 dialog
.set_extra_widget(hbox
)
417 return (dialog
, combobox
)
420 def import_subscriptions(self
, parent
):
421 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
422 gtk
.FILE_CHOOSER_ACTION_OPEN
,
423 _("Add new subscriptions in:"))
424 ffilter
= gtk
.FileFilter()
425 ffilter
.set_name(_("OPML Files Only"))
426 ffilter
.add_pattern("*.xml")
427 ffilter
.add_pattern("*.opml")
428 dialog
.add_filter(ffilter
)
429 dialog
.set_transient_for(parent
)
430 response
= dialog
.run()
431 if response
== gtk
.RESPONSE_OK
:
432 filename
= dialog
.get_filename()
433 model
= combobox
.get_model()
434 cat
= model
[combobox
.get_active()][1]
436 FeedManager
.import_opml(filename
)
439 def export_subscriptions(parent
):
440 (dialog
,combobox
) = _setup_filechooser_dialog(_("Export Subscriptions"),
441 gtk
.FILE_CHOOSER_ACTION_SAVE
,
442 _("Select category to export:"))
443 def selection_changed(widget
, dialog
):
444 model
= widget
.get_model()
445 category
= model
[widget
.get_active()][1]
446 dialog
.set_current_name("Straw-%s.xml" % category
.title
)
448 combobox
.connect('changed',
451 selection_changed(combobox
, dialog
)
452 dialog
.set_transient_for(parent
)
453 response
= dialog
.run()
454 if response
== gtk
.RESPONSE_OK
:
455 filename
= dialog
.get_filename()
456 model
= combobox
.get_model()
457 cat
= model
[combobox
.get_active()][1]
458 opml
.export(cat
.title
, cat
.feeds
, filename
)
462 class ApplicationView(MVP
.WidgetView
):
466 def _initialize(self
):
467 self
._config
= Config
.get_instance()
468 self
._initialize
_dnd
()
469 self
._initialize
_window
_updater
()
470 self
._create
_unmodified
_accelerator
_group
()
471 self
._attach
_unmodified
_accelerator
_group
()
472 self
._initialize
_window
()
473 self
._find
_toggled
= False
475 def _initialize_window(self
):
476 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
477 if self
._config
.window_maximized
:
478 self
._widget
.maximize()
480 # we use resize here since configure-event seems to
481 # overwrite the default size if we use set_default_size.
482 self
._widget
.resize(*self
._config
.main_window_size
)
483 mmp
= widget_tree
.get_widget('main_main_pane')
484 msp
= widget_tree
.get_widget('main_sub_pane')
485 mmp
.set_position(self
._config
.main_pane_position
)
486 msp
.set_position(self
._config
.sub_pane_position
)
488 def _initialize_dnd(self
):
489 self
._widget
.drag_dest_set(
490 gtk
.DEST_DEFAULT_ALL
,
491 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
492 ('x-url/http', 0, 2)],
493 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
496 def _initialize_window_updater(self
):
497 #feedlist.signal_connect(Event.AllItemsReadSignal,
498 # lambda signal: self._update_title(feedlist))
499 #feedlist.signal_connect(Event.ItemReadSignal,
500 # lambda signal: self._update_title(feedlist))
501 #feedlist.signal_connect(Event.ItemsAddedSignal,
502 # lambda signal: self._update_title(feedlist))
503 #feedlist.signal_connect(Event.FeedsChangedSignal,
504 # lambda signal: self._update_title(feedlist))
507 def _update_title(self
, flist
):
508 uritems
= urfeeds
= 0
510 listfeeds
= flist
.flatten_list()
511 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
516 urfeeds
= len(listfeeds
)
519 item_feed_map
= {'uritems': uritems
,
522 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
523 self
._widget
.set_title( title
+ " - %s" % straw
.PACKAGE
)
526 # We have a separate accelerator group for the unmodified and
527 # shifted accelerators, that is, stuff like space, N, P, etc. This
528 # is so that we can have the find pane work correctly
529 def _create_unmodified_accelerator_group(self
):
530 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
531 agroup
= gtk
.AccelGroup()
532 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
533 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
534 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
535 ('next_unread_feed', ' ', 0),
536 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
537 for widget_name
, key
, mask
in accels
:
538 widget
= xml
.get_widget(widget_name
)
539 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
541 self
._unmodified
_accelerator
_group
= agroup
543 def _on_category_add_activate(self
, *args
):
546 def _attach_unmodified_accelerator_group(self
):
547 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
549 def _detach_unmodified_accelerator_group(self
):
550 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
552 def _on_straw_main_destroy_event(self
, *args
):
553 return self
._presenter
.quit()
555 def _on_straw_main_delete_event(self
, *args
):
556 return self
._presenter
.quit()
558 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
559 if widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_MAXIMIZED
:
560 self
._config
.window_maximized
= False
561 self
._presenter
.check_allocation(widget
, event
)
563 self
._config
.window_maximized
= True
566 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
567 self
._presenter
.check_main_pane_position(widget
)
569 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
570 self
._presenter
.check_sub_pane_position(widget
)
573 def _on_feed_subscribe_activate(self
, *args
):
574 straw
.subscribe_show(parent
=self
._widget
)
576 def _on_feed_unsubscribe_activate(self
, *args
):
577 self
._presenter
.remove_selected_feed()
579 def _on_subscription_import_activate(self
, *args
):
580 self
._presenter
.import_subscriptions(self
._widget
)
582 def _on_subscription_export_activate(self
, *args
):
583 self
._presenter
.export_subscriptions(self
._widget
)
585 def _on_feed_mark_as_read_activate(self
, *args
):
586 self
._presenter
.mark_feed_as_read()
588 def _on_feed_mark_all_as_read_activate(self
, *args
):
589 self
._presenter
.mark_all_as_read()
591 def _on_feed_refresh_selected_activate(self
, *args
):
592 self
._presenter
.poll_current_feed()
594 def _on_subscription_refresh_activate(self
, *args
):
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
)
688 # initialize threading and environment
689 gobject
.threads_init()
690 config
= Config
.get_instance()
691 config
.reload_css
= os
.getenv('STRAW_RELOAD_CSS') is not None
693 # build tray status icon
695 iconfile
= os
.path
.normpath(straw
.STRAW_DATA_DIR
+ "/straw.png")
696 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
697 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
698 image
.set_from_pixbuf(scaled_buf
)
700 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
701 self
.tray
.connect('activate', self
._tray
_clicked
)
702 except AttributeError:
705 self
.tray
= egg
.trayicon
.TrayIcon(straw
.PACKAGE
);
706 self
._eventbox
= gtk
.EventBox()
707 self
.tray
.add(self
._eventbox
)
708 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
709 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
710 self
._eventbox
.drag_dest_set(
711 gtk
.DEST_DEFAULT_ALL
,
712 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
713 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
714 self
._eventbox
.add(image
)
717 self
._tooltip
= gtk
.Tooltips()
718 self
.unread_count
= 0
719 # end build tray status icon
721 FeedManager
.setup(storage_path
= "test.db")
724 TreeViewManager
.setup(storage_path
= "test.db")
725 TreeViewManager
.init()
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()
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()
753 def _update(self
,flist
):
754 uritems
= urfeeds
= 0
755 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
759 if uritems
== self
.unread_count
:
761 self
.unread_count
= uritems
763 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
770 def _tray_clicked(self
, widget
, event
=None):
771 self
._main
_presenter
.view
.should_present()
772 if event
and not (event
.button
== 1):
774 self
._main
_presenter
.scroll_or_display_next_unread_item()
776 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
777 if data
and data
.format
== 8:
778 url
= data
.data
.split("\n")[0]
779 straw
.subscribe_show(url
="%s" % url
)
780 context
.finish(True, False, timestamp
)
782 context
.finish(False, False, timestamp
)