3 This is the main module that binds everything together.
7 __copyright__
= "Copyright (c) 2002-2005 Free Software Foundation, Inc."
8 __license__
= """ GNU General Public License
10 This program is free software; you can redistribute it and/or modify it under the
11 terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA. """
23 from Constants
import *
24 from FeedListView
import FeedsView
, FeedsPresenter
25 from ItemList
import ItemListPresenter
, ItemListView
26 from ItemView
import ItemView
27 from MainloopManager
import MainloopManager
28 from MessageManager
import post_status_message
, get_status_manager
, start_services
29 from OfflineToggle
import OfflineToggle
30 from subscribe
import subscribe_show
31 from xml
.sax
import saxutils
40 import gobject
, gtk
, gtk
.glade
42 import os
, gettext
, getopt
, sys
49 class StatusPresenter(MVP
.BasicPresenter
):
50 def _initialize(self
):
51 self
._mmgr
= get_status_manager()
52 self
._mmgr
.connect('changed', self
._display
)
54 def _display(self
, *args
):
55 cid
= self
._view
.get_context_id("straw_main")
57 self
._view
.push(cid
, self
._mmgr
.read_message())
61 def __init__(self
, widget
):
63 self
._tooltips
= gtk
.Tooltips()
65 #self._curr_feed = None
66 #self._curr_category = None
67 #fclist = FeedCategoryList.get_instance()
68 #fclist.connect('category-changed', self._category_changed)
70 def feedlist_selection_changed(self
, selection
, column
):
73 (model
, pathlist
) = selection
.get_selected_rows()
74 iters
= [model
.get_iter(path
) for path
in pathlist
]
77 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
79 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
80 errortexts
= [feed
.error
for feed
in errorfeeds
]
83 ### XXX display OPML Category error too
87 text
.append(_("Error:"))
92 self
._tooltips
.set_tip(self
._widget
,t
,t
)
93 self
._tooltips
.enable()
96 self
._tooltips
.disable()
103 class ToolbarView(MVP
.WidgetView
):
104 """ Widget: gtk.Toolbar"""
105 GCONF_DESKTOP_INTERFACE
= "/desktop/gnome/interface"
107 def _initialize(self
):
108 client
= gconf
.client_get_default()
109 if not client
.dir_exists(self
.GCONF_DESKTOP_INTERFACE
):
111 client
.add_dir(self
.GCONF_DESKTOP_INTERFACE
,
112 gconf
.CLIENT_PRELOAD_NONE
)
113 client
.notify_add(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style",
114 self
._toolbar
_style
_changed
)
115 self
._widget
.set_tooltips(True)
117 def _toolbar_style_changed(self
, client
, notify_id
, entry
, *args
):
118 value
= entry
.value
.get_string()
119 self
._presenter
.style_changed(value
)
121 def set_style(self
, style
):
122 self
._widget
.set_style(style
)
125 client
= gconf
.client_get_default()
126 current_style
= client
.get_string(self
.GCONF_DESKTOP_INTERFACE
+"/toolbar_style")
129 class ToolbarPresenter(MVP
.BasicPresenter
):
130 STYLES
= {'both':gtk
.TOOLBAR_BOTH
,
131 'text':gtk
.TOOLBAR_TEXT
,
132 'icons':gtk
.TOOLBAR_ICONS
,
133 'both-horiz':gtk
.TOOLBAR_BOTH_HORIZ
}
135 def _initialize(self
):
136 style
= self
._view
.get_style()
138 if style
in self
.STYLES
.keys():
139 self
._view
.set_style(self
.STYLES
[style
])
141 widget_tree
= gtk
.glade
.get_widget_tree(self
._view
._widget
)
142 self
.change_read_state_button
= widget_tree
.get_widget("toolbar_change_read_state_button")
144 def style_changed(self
, value
):
145 if value
in self
.STYLES
.keys():
146 self
._view
.set_style(self
.STYLES
[value
])
148 def set_change_read_button_state(self
, new_state
):
149 self
.change_read_state_button
.set_active(new_state
)
151 class ApplicationPresenter(MVP
.BasicPresenter
):
152 def _initialize(self
):
153 FeedManager
._get
_instance
().connect("update-all-done", self
._on
_update
_all
_done
)
155 self
._current
_item
= None
158 self
._init
_presenters
()
161 def _init_widgets(self
):
162 widget_tree
= self
._view
.get_widget_tree()
164 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
165 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
167 item_view_container
= widget_tree
.get_widget('item_view_container')
168 item_list_container
= widget_tree
.get_widget('item_list_container')
170 self
.update_all_button
= widget_tree
.get_widget("toolbar_refresh_all_button")
172 parent_paned
= item_view_container
.get_parent()
173 parent_parent_widget
= parent_paned
.get_parent()
176 layout
= Config
.get(OPTION_PANE_LAYOUT
)
178 if layout
not in ("horizontal", "vertical"):
181 if layout
== "vertical":
182 new_paned
= gtk
.VPaned()
183 child_list
.append(item_list_container
)
184 child_list
.append(item_view_container
)
185 elif layout
== "horizontal":
186 new_paned
= gtk
.HPaned()
187 child_list
.append(item_view_container
)
188 child_list
.append(item_list_container
)
190 for child
in child_list
:
191 child
.reparent(new_paned
)
193 parent_parent_widget
.remove(parent_paned
)
194 parent_parent_widget
.add(new_paned
)
196 new_paned
.connect("size-allocate", self
._view
._on
_main
_sub
_pane
_size
_allocate
)
197 new_paned
.set_position(Config
.get(OPTION_SUB_PANE_POS
))
200 def _init_presenters(self
):
201 widget_tree
= self
._view
.get_widget_tree()
202 self
._toolbar
_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
203 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
205 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
207 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
208 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
210 view
.add_selection_changed_listener(self
._item
_view
)
211 view
.add_selection_changed_listener(self
)
213 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
214 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
215 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
216 view
.add_selection_changed_listener(self
._error
_presenter
)
218 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
220 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
221 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
223 def set_current_item(self
, item
):
224 self
._current
_item
= item
225 self
._current
_item
_connect
_id
= item
.connect("is-read-changed", self
._on
_current
_item
_is
_read
_changed
)
227 def clear_current_item(self
):
228 if self
._current
_item
:
229 self
._current
_item
.disconnect(self
._current
_item
_connect
_id
)
230 self
._current
_item
= None
232 def set_current_item_is_read(self
, is_read
):
233 if self
._current
_item
:
234 self
._current
_item
.props
.is_read
= is_read
236 def _on_current_item_is_read_changed(self
, obj
, is_read
):
237 self
._toolbar
_presenter
.set_change_read_button_state(is_read
)
239 def itemlist_selection_changed(self
, selection
, column
):
240 self
.clear_current_item()
242 (model
, treeiter
) = selection
.get_selected()
243 if not treeiter
: return
244 item
= model
.get_value(treeiter
, column
)
245 self
._toolbar
_presenter
.set_change_read_button_state(item
.is_read
)
246 self
.set_current_item(item
)
248 def add_category(self
):
249 self
._feed
_list
_presenter
.add_category()
251 def copy_itemview_text_selection(self
):
252 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
254 def check_allocation(self
, widget
, event
):
255 def check_size(widget
, width
, height
, x
, y
):
256 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
257 Config
.set(OPTION_WINDOW_SIZE_W
, width
)
258 Config
.set(OPTION_WINDOW_SIZE_H
, height
)
260 if (x
, y
) == widget
.window
.get_position():
261 Config
.set(OPTION_WINDOW_LEFT
, x
)
262 Config
.set(OPTION_WINDOW_TOP
, y
)
264 config_position
= (Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
))
266 if (event
.width
, event
.height
, event
.x
, event
.y
) != \
267 (widget
.allocation
.width
, widget
.allocation
.height
, config_position
[0], config_position
[1]):
268 gobject
.timeout_add(1000, check_size
, widget
, event
.width
, event
.height
, event
.x
, event
.y
)
270 def check_main_pane_position(self
, widget
):
271 def check_position((position
, widget
)):
272 if position
== widget
.get_position():
273 Config
.set(OPTION_MAIN_PANE_POS
, position
)
275 pos
= widget
.get_position()
277 if pos
!= Config
.get(OPTION_MAIN_PANE_POS
):
278 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
280 def check_sub_pane_position(self
, widget
):
281 def check_position((position
, widget
)):
282 if position
== widget
.get_position():
283 Config
.set(OPTION_SUB_PANE_POS
, position
)
285 pos
= widget
.get_position()
287 if pos
!= Config
.get(OPTION_SUB_PANE_POS
):
288 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
291 return helpers
.credits()
294 if not self
._warn
_if
_offline
():
297 if not FeedManager
.is_update_all_running():
298 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
299 "task-done": [ self
._on
_feed
_poll
_done
] })
300 self
.update_all_button
.set_sensitive(True)
301 self
.update_all_button
.set_stock_id(gtk
.STOCK_STOP
)
303 self
.update_all_button
.set_sensitive(False)
304 FeedManager
.stop_update_all()
306 def _on_feed_poll_started(self
, handler
, feed
):
309 def _on_feed_poll_done(self
, handler
, data
):
312 def _on_update_all_done(self
, obj
):
313 self
.update_all_button
.set_sensitive(True)
314 self
.update_all_button
.set_stock_id(gtk
.STOCK_REFRESH
)
316 def poll_current_category(self
):
317 if self
._warn
_if
_offline
():
318 self
._poll
_categories
([self
._curr
_category
])
320 def poll_current_feed(self
):
321 if self
._warn
_if
_offline
():
322 pm
= PollManager
.get_instance()
323 pm
.poll([self
._curr
_feed
])
325 def mark_feed_as_read(self
):
326 self
._curr
_feed
.mark_all_read()
328 def mark_all_as_read(self
):
329 print "TODO mark_all_as_read"
331 def remove_selected_feed(self
):
332 # self._feed_list_presenter.remove_selected_feed()
335 def show_search(self
):
336 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
337 # self._item_view.item_selection_changed)
338 self
._item
_view
.display_empty_search()
339 self
._itemlist
_view
_notebook
.set_current_page(1)
340 self
._feedlist
_view
_notebook
.set_current_page(1)
341 self
._feedinfo
_presenter
.hide()
343 def hide_search(self
):
344 # self._find_presenter.clear()
345 self
._itemlist
_view
_notebook
.set_current_page(0)
346 self
._feedlist
_view
_notebook
.set_current_page(0)
347 self
._feedinfo
_presenter
.show()
348 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
349 # self._item_view.item_selection_changed)
351 def _warn_if_offline(self
):
352 offline
= Config
.get(OPTION_OFFLINE
)
356 response
= self
._view
.show_offline_dialog()
358 if response
== gtk
.RESPONSE_OK
:
359 Config
.set(OPTION_OFFLINE
, not offline
)
366 def display_previous_feed(self
, item
= None):
368 Displays the feed before the current selected feed
370 self
._feed
_list
_presenter
.select_previous_feed()
372 def display_next_feed(self
, item
=None):
374 Displays the feed after the current selected feed
376 self
._feed
_list
_presenter
.select_next_feed()
379 def display_next_unread_feed(self
):
381 Displays the next feed with an unread item
383 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
386 def display_previous_item(self
, item
=None):
388 Displays the item before the current selected item. If the item is the
389 first item, scrolls to the previous feed
391 is_prev
= self
._itemlist
_presenter
.select_previous_item()
393 # TODO HACK - implement select_previous_feed(select_last=True) ...
394 # ... to select previous feed's last item
395 self
._feed
_list
_presenter
.select_previous_feed()
396 self
._itemlist
_presenter
.select_last_item()
400 def display_next_item(self
, item
=None):
402 Displays the item after the current selected item. If the item is the
403 last item, selectes the next feed. If the current feed is the last
404 feed in the list, it goes back and selects the first feed
406 is_next
= self
._itemlist
_presenter
.select_next_item()
408 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
410 self
._feed
_list
_presenter
.select_firsteed_feed()
413 def scroll_or_display_next_unread_item(self
, item
=None):
414 has_unread_item
= False
415 if not self
._item
_view
.scroll_down():
416 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
417 if not has_unread_item
:
418 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
421 def show_preferences_dialog(self
, parent
):
424 def show_feed_properties(self
, parent
):
425 feedproperties
.show(self
._curr
_feed
)
430 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
432 Setup the file chooser dialog. This includes an extra widget (a combobox)
433 to include the categories to import or export
435 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
436 buttons
=(gtk
.STOCK_CANCEL
,
438 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
441 for category
in FeedManager
.categories():
442 category_list
.append(category
)
444 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
445 combobox
= gtk
.ComboBox(model
)
446 celltitle
= gtk
.CellRendererText()
447 combobox
.pack_start(celltitle
,False)
448 combobox
.add_attribute(celltitle
, 'text', 0)
450 for category
in category_list
:
452 model
.set(it
, 0, category
.name
, 1, category
)
454 combobox
.set_active(0)
455 label
= gtk
.Label(extra_widget_title
)
456 label
.set_alignment(1.0,0.5)
457 hbox
= gtk
.HBox(spacing
=6)
458 hbox
.pack_start(label
,True,True,0)
459 hbox
.pack_end(combobox
,False,False,0)
462 dialog
.set_extra_widget(hbox
)
463 return (dialog
, combobox
)
465 def import_subscriptions(self
, parent
):
466 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
467 gtk
.FILE_CHOOSER_ACTION_OPEN
,
468 _("Add new subscriptions in:"))
469 ffilter
= gtk
.FileFilter()
470 ffilter
.set_name(_("OPML Files Only"))
471 ffilter
.add_pattern("*.xml")
472 ffilter
.add_pattern("*.opml")
473 dialog
.add_filter(ffilter
)
474 dialog
.set_transient_for(parent
)
475 response
= dialog
.run()
476 if response
== gtk
.RESPONSE_OK
:
477 filename
= dialog
.get_filename()
478 model
= combobox
.get_model()
479 category
= model
[combobox
.get_active()][1]
481 FeedManager
.import_opml(filename
, category
)
484 def export_subscriptions(self
, parent
):
485 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Export Subscriptions"),
486 gtk
.FILE_CHOOSER_ACTION_SAVE
,
487 _("Select category to export:"))
488 def selection_changed(widget
, dialog
):
489 model
= widget
.get_model()
490 category
= model
[widget
.get_active()][1]
491 dialog
.set_current_name("Straw-%s.xml" % category
.name
)
493 combobox
.connect('changed', selection_changed
, dialog
)
494 selection_changed(combobox
, dialog
)
495 dialog
.set_transient_for(parent
)
496 response
= dialog
.run()
498 if response
== gtk
.RESPONSE_OK
:
499 filename
= dialog
.get_filename()
500 model
= combobox
.get_model()
501 root_category
= model
[combobox
.get_active()][1]
502 FeedManager
.export_opml(root_category
.id, filename
)
507 subscribe_show(parent
=self
.view
._widget
)
509 class ApplicationView(MVP
.WidgetView
):
513 def _initialize(self
):
514 self
._initialize
_dnd
()
515 self
._initialize
_window
_updater
()
516 self
._create
_unmodified
_accelerator
_group
()
517 self
._attach
_unmodified
_accelerator
_group
()
518 self
._initialize
_window
()
519 self
._find
_toggled
= False
521 def _initialize_window(self
):
522 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
523 if Config
.get(OPTION_WINDOW_MAX
):
524 self
._widget
.maximize()
526 # we use resize here since configure-event seems to
527 # overwrite the default size if we use set_default_size.
528 #self._widget.move(Config.get(OPTION_WINDOW_LEFT), Config.get(OPTION_WINDOW_TOP))
529 #self._widget.resize(Config.get(OPTION_WINDOW_SIZE_W), Config.get(OPTION_WINDOW_SIZE_H))
530 self
._widget
.window
.move_resize(Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
),
531 Config
.get(OPTION_WINDOW_SIZE_W
), Config
.get(OPTION_WINDOW_SIZE_H
))
532 self
.mmp
= widget_tree
.get_widget('main_main_pane')
533 self
.msp
= widget_tree
.get_widget('main_sub_pane')
535 self
.mmp
.set_position(Config
.get(OPTION_MAIN_PANE_POS
))
536 self
.msp
.set_position(Config
.get(OPTION_SUB_PANE_POS
))
538 def _initialize_dnd(self
):
539 self
._widget
.drag_dest_set(
540 gtk
.DEST_DEFAULT_ALL
,
541 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
542 ('x-url/http', 0, 2)],
543 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
546 def _initialize_window_updater(self
):
547 #feedlist.signal_connect(Event.AllItemsReadSignal,
548 # lambda signal: self._update_title(feedlist))
549 #feedlist.signal_connect(Event.ItemReadSignal,
550 # lambda signal: self._update_title(feedlist))
551 #feedlist.signal_connect(Event.ItemsAddedSignal,
552 # lambda signal: self._update_title(feedlist))
553 #feedlist.signal_connect(Event.FeedsChangedSignal,
554 # lambda signal: self._update_title(feedlist))
557 def _update_title(self
, flist
):
558 uritems
= urfeeds
= 0
560 listfeeds
= flist
.flatten_list()
561 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
566 urfeeds
= len(listfeeds
)
569 item_feed_map
= {'uritems': uritems
,
572 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
573 self
._widget
.set_title( title
+ " - %s" % straw
.defs
.PACKAGE
)
575 # We have a separate accelerator group for the unmodified and
576 # shifted accelerators, that is, stuff like space, N, P, etc. This
577 # is so that we can have the find pane work correctly
578 def _create_unmodified_accelerator_group(self
):
579 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
580 agroup
= gtk
.AccelGroup()
581 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
582 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
583 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
584 ('next_unread_feed', ' ', 0),
585 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
586 for widget_name
, key
, mask
in accels
:
587 widget
= xml
.get_widget(widget_name
)
588 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
590 self
._unmodified
_accelerator
_group
= agroup
592 def _on_category_add_activate(self
, *args
):
593 self
._presenter
.add_category()
595 def _on_toolbar_change_read_state_button_toggled(self
, button
):
596 self
._presenter
.set_current_item_is_read(button
.get_active())
598 def _attach_unmodified_accelerator_group(self
):
599 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
601 def _detach_unmodified_accelerator_group(self
):
602 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
604 def _on_straw_main_destroy_event(self
, *args
):
605 return self
._presenter
.quit()
607 def _on_straw_main_delete_event(self
, *args
):
608 return self
._presenter
.quit()
610 def _on_straw_main_window_state_event(self
, widget
, event
):
611 is_maximized
= widget
.window
.get_state() == gtk
.gdk
.WINDOW_STATE_MAXIMIZED
612 Config
.set(OPTION_WINDOW_MAX
, is_maximized
)
614 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
615 if not (widget
.window
.get_state() & gtk
.gdk
.WINDOW_STATE_MAXIMIZED
):
616 self
._presenter
.check_allocation(widget
, event
)
618 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
619 self
._presenter
.check_main_pane_position(widget
)
621 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
622 self
._presenter
.check_sub_pane_position(widget
)
625 def _on_feed_subscribe_activate(self
, *args
):
626 self
._presenter
.subscribe()
628 def _on_feed_unsubscribe_activate(self
, *args
):
629 self
._presenter
.remove_selected_feed()
631 def _on_subscription_import_activate(self
, *args
):
632 self
._presenter
.import_subscriptions(self
._widget
)
634 def _on_subscription_export_activate(self
, *args
):
635 self
._presenter
.export_subscriptions(self
._widget
)
637 def _on_feed_mark_as_read_activate(self
, *args
):
638 self
._presenter
.mark_feed_as_read()
640 def _on_feed_mark_all_as_read_activate(self
, *args
):
641 self
._presenter
.mark_all_as_read()
643 def _on_feed_refresh_selected_activate(self
, *args
):
644 self
._presenter
.poll_current_feed()
646 def _on_subscription_refresh_activate(self
, *args
):
647 self
._presenter
.poll_all()
649 def _on_quit_activate(self
, *args
):
650 return self
._presenter
.quit()
653 def _on_copy_activate(self
, *args
):
654 self
._presenter
.copy_itemview_text_selection()
656 def _on_find_activate(self
, widget
, *args
):
657 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
658 menu_find
= xml
.get_widget('menu_find')
659 accel_label
= menu_find
.get_child()
661 if not self
._find
_toggled
:
662 self
._presenter
.show_search()
663 self
._detach
_unmodified
_accelerator
_group
()
664 self
._find
_toggled
= True
666 # save the "Find..." stock text for later recovery
667 self
._old
_label
_text
= accel_label
.get_text()
668 accel_label
.set_text(_('Return to feed list...'))
671 self
._presenter
.hide_search()
672 self
._attach
_unmodified
_accelerator
_group
()
673 self
._find
_toggled
= False
674 accel_label
.set_text(self
._old
_label
_text
)
676 def _on_preferences_activate(self
, *args
):
677 self
._presenter
.show_preferences_dialog(self
._widget
)
679 def _on_feed_information_activate(self
, *args
):
680 self
._presenter
.show_feed_properties(self
._widget
)
683 def _on_previous_item_activate(self
, *args
):
684 self
._presenter
.display_previous_item()
686 def _on_next_item_activate(self
, *args
):
687 self
._presenter
.display_next_item()
689 def _on_next_feed_activate(self
, *args
):
690 self
._presenter
.display_next_feed()
692 def _on_previous_feed_activate(self
, *args
):
693 self
._presenter
.display_previous_feed()
695 def _on_next_unread_feed_activate(self
, *args
):
696 self
._presenter
.display_next_unread_feed()
698 def _on_scroll_unread_items_activate(self
, *args
):
699 self
._presenter
.scroll_or_display_next_unread_item()
703 def _on_report_problem_activate(self
, menuitem
, *args
):
704 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
706 def _on_about_activate(self
, menuitem
, *args
):
707 widget
= self
._presenter
.credits()
710 def _on_straw_main_drag_data_received(self
, w
, context
,
711 x
, y
, data
, info
, time
):
712 if data
and data
.format
== 8:
713 url
= data
.data
.split("\n")[0]
714 subscribe_show("%s" % url
, self
._widget
)
715 context
.finish(True, False, time
)
717 context
.finish(False, False, time
)
720 def show_offline_dialog(self
):
721 return helpers
.report_offline_status(self
._widget
)
723 def get_widget_tree(self
):
724 return gtk
.glade
.get_widget_tree(self
._widget
)
727 self
._widget
.present()
729 def should_present(self
):
730 if self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
733 self
._widget
.present()
738 gnome
.program_init(straw
.defs
.PACKAGE
, straw
.defs
.VERSION
)
741 # initialize threading and environment
742 gobject
.threads_init()
744 #Config.set(OPTION_OFFLINEnfig.reload_css = os.getenv('STRAW_RELOAD_CSS') is not None
746 # build tray status icon
748 iconfile
= os
.path
.normpath(straw
.defs
.STRAW_DATA_DIR
+ "/straw.png")
749 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
750 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
751 image
.set_from_pixbuf(scaled_buf
)
753 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
754 self
.tray
.connect('activate', self
._tray
_clicked
)
755 except AttributeError:
758 self
.tray
= egg
.trayicon
.TrayIcon(straw
.defs
.PACKAGE
);
759 self
._eventbox
= gtk
.EventBox()
760 self
.tray
.add(self
._eventbox
)
761 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
762 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
763 self
._eventbox
.drag_dest_set(
764 gtk
.DEST_DEFAULT_ALL
,
765 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
766 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
767 self
._eventbox
.add(image
)
770 self
._tooltip
= gtk
.Tooltips()
771 self
.unread_count
= 0
772 # end build tray status icon
774 FeedManager
.setup(storage_path
= "test.db")
777 ItemManager
.setup(storage_path
= "test.db")
780 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
782 #if config.first_time:
783 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
784 # feeds.import_opml(filepath)
786 #ImageCache.initialize()
788 xml
= gtk
.glade
.XML(os
.path
.join(straw
.defs
.STRAW_DATA_DIR
,'straw.glade'), "straw_main", gettext
.textdomain())
789 window
= xml
.get_widget('straw_main')
790 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
791 self
._main
_presenter
.view
.present()
793 self
._main
_presenter
.view
._widget
.window
.move_resize(Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
),
794 Config
.get(OPTION_WINDOW_SIZE_W
), Config
.get(OPTION_WINDOW_SIZE_H
))
796 #PollManager.get_instance().start_polling_loop()
797 # set the default icon for the windows
798 iconfile
= os
.path
.join(straw
.defs
.STRAW_DATA_DIR
,"straw.png")
799 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
804 gtk
.gdk
.threads_init()
805 gtk
.gdk
.threads_enter()
807 gtk
.gdk
.threads_leave()
809 def _update(self
,flist
):
810 uritems
= urfeeds
= 0
811 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
815 if uritems
== self
.unread_count
:
817 self
.unread_count
= uritems
819 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
825 def _tray_clicked(self
, widget
, event
=None):
826 self
._main
_presenter
.view
.should_present()
828 if event
and not (event
.button
== 1):
830 self
._main
_presenter
.scroll_or_display_next_unread_item()
832 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
833 if data
and data
.format
== 8:
834 url
= data
.data
.split("\n")[0]
835 subscribe_show(url
="%s" % url
)
836 context
.finish(True, False, timestamp
)
838 context
.finish(False, False, timestamp
)