32ff0271137c8632a1f32d8a3075bb4181804612
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 log
= error
.get_logger()
51 class StatusPresenter(MVP
.BasicPresenter
):
52 def _initialize(self
):
53 self
._mmgr
= get_status_manager()
54 self
._mmgr
.connect('changed', self
._display
)
56 def _display(self
, *args
):
57 cid
= self
._view
.get_context_id("straw_main")
59 self
._view
.push(cid
, self
._mmgr
.read_message())
63 def __init__(self
, widget
):
65 self
._tooltips
= gtk
.Tooltips()
67 #self._curr_feed = None
68 #self._curr_category = None
69 #fclist = FeedCategoryList.get_instance()
70 #fclist.connect('category-changed', self._category_changed)
72 def feedlist_selection_changed(self
, selection
, column
):
75 (model
, pathlist
) = selection
.get_selected_rows()
76 iters
= [model
.get_iter(path
) for path
in pathlist
]
79 nodes
= [model
.get_value(treeiter
, column
) for treeiter
in iters
]
81 errorfeeds
= [node
.feed
for node
in nodes
if node
.feed
and node
.feed
.error
]
82 errortexts
= [feed
.error
for feed
in errorfeeds
]
85 ### XXX display OPML Category error too
89 text
.append(_("Error:"))
94 self
._tooltips
.set_tip(self
._widget
, t
, t
)
95 self
._tooltips
.enable()
98 self
._tooltips
.disable()
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()
140 if style
in self
.STYLES
.keys():
141 self
._view
.set_style(self
.STYLES
[style
])
143 widget_tree
= gtk
.glade
.get_widget_tree(self
._view
._widget
)
144 self
.change_read_state_button
= widget_tree
.get_widget("toolbar_change_read_state_button")
146 def style_changed(self
, value
):
147 if value
in self
.STYLES
.keys():
148 self
._view
.set_style(self
.STYLES
[value
])
150 def set_change_read_button_state(self
, new_state
):
151 self
.change_read_state_button
.set_active(new_state
)
153 class ApplicationPresenter(MVP
.BasicPresenter
):
154 def _initialize(self
):
155 FeedManager
._get
_instance
().connect("update-all-done", self
._on
_update
_all
_done
)
157 self
._current
_item
= None
160 self
._init
_presenters
()
161 self
._restore
_state
()
164 def _init_widgets(self
):
165 widget_tree
= self
._view
.get_widget_tree()
167 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
168 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
170 item_view_container
= widget_tree
.get_widget('item_view_container')
171 item_list_container
= widget_tree
.get_widget('item_list_container')
173 self
.update_all_button
= widget_tree
.get_widget("toolbar_refresh_all_button")
175 parent_paned
= item_view_container
.get_parent()
176 parent_parent_widget
= parent_paned
.get_parent()
179 layout
= Config
.get(OPTION_PANE_LAYOUT
)
181 if layout
not in ("horizontal", "vertical"):
184 if layout
== "vertical":
185 new_paned
= gtk
.VPaned()
186 child_list
.append(item_list_container
)
187 child_list
.append(item_view_container
)
188 elif layout
== "horizontal":
189 new_paned
= gtk
.HPaned()
190 child_list
.append(item_view_container
)
191 child_list
.append(item_list_container
)
193 for child
in child_list
:
194 child
.reparent(new_paned
)
196 parent_parent_widget
.remove(parent_paned
)
197 parent_parent_widget
.add(new_paned
)
199 new_paned
.connect("size-allocate", self
._view
._on
_main
_sub
_pane
_size
_allocate
)
200 new_paned
.set_position(Config
.get(OPTION_SUB_PANE_POS
))
203 def _init_presenters(self
):
204 widget_tree
= self
._view
.get_widget_tree()
205 self
._toolbar
_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
206 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
208 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
210 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
211 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
213 view
.add_selection_changed_listener(self
._item
_view
)
214 view
.add_selection_changed_listener(self
)
216 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
217 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
218 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
219 view
.add_selection_changed_listener(self
._error
_presenter
)
221 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
223 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
224 #self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
226 def set_current_item(self
, item
):
227 self
._current
_item
= item
228 self
._current
_item
_connect
_id
= item
.connect("is-read-changed", self
._on
_current
_item
_is
_read
_changed
)
230 def _restore_state(self
):
231 self
._feed
_list
_presenter
.restore_state()
233 def clear_current_item(self
):
234 if self
._current
_item
:
235 self
._current
_item
.disconnect(self
._current
_item
_connect
_id
)
236 self
._current
_item
= None
238 def set_current_item_is_read(self
, is_read
):
239 if self
._current
_item
:
240 self
._current
_item
.props
.is_read
= is_read
242 def _on_current_item_is_read_changed(self
, obj
, is_read
):
243 self
._toolbar
_presenter
.set_change_read_button_state(is_read
)
245 def itemlist_selection_changed(self
, selection
, column
):
246 self
.clear_current_item()
248 (model
, treeiter
) = selection
.get_selected()
249 if not treeiter
: return
250 item
= model
.get_value(treeiter
, column
)
251 self
._toolbar
_presenter
.set_change_read_button_state(item
.is_read
)
252 self
.set_current_item(item
)
254 def add_category(self
):
255 self
._feed
_list
_presenter
.add_category()
257 def copy_itemview_text_selection(self
):
258 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
260 def check_allocation(self
, widget
, event
):
261 def check_size(widget
, width
, height
, x
, y
):
262 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
263 Config
.set(OPTION_WINDOW_SIZE_W
, width
)
264 Config
.set(OPTION_WINDOW_SIZE_H
, height
)
266 if widget
.window
and (x
, y
) == widget
.window
.get_position():
267 Config
.set(OPTION_WINDOW_LEFT
, x
)
268 Config
.set(OPTION_WINDOW_TOP
, y
)
270 config_position
= (Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
))
272 if (event
.width
, event
.height
, event
.x
, event
.y
) != \
273 (widget
.allocation
.width
, widget
.allocation
.height
, config_position
[0], config_position
[1]):
274 gobject
.timeout_add(1000, check_size
, widget
, event
.width
, event
.height
, event
.x
, event
.y
)
276 def check_main_pane_position(self
, widget
):
277 def check_position((position
, widget
)):
278 if position
== widget
.get_position():
279 Config
.set(OPTION_MAIN_PANE_POS
, position
)
281 pos
= widget
.get_position()
283 if pos
!= Config
.get(OPTION_MAIN_PANE_POS
):
284 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
286 def check_sub_pane_position(self
, widget
):
287 def check_position((position
, widget
)):
288 if position
== widget
.get_position():
289 Config
.set(OPTION_SUB_PANE_POS
, position
)
291 pos
= widget
.get_position()
293 if pos
!= Config
.get(OPTION_SUB_PANE_POS
):
294 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
297 return helpers
.credits()
300 if not self
._warn
_if
_offline
():
303 if not FeedManager
.is_update_all_running():
304 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
305 "task-done": [ self
._on
_feed
_poll
_done
] })
306 self
.update_all_button
.set_sensitive(True)
307 self
.update_all_button
.set_stock_id(gtk
.STOCK_STOP
)
309 self
.update_all_button
.set_sensitive(False)
310 FeedManager
.stop_update_all()
312 def _on_feed_poll_started(self
, handler
, feed
):
315 def _on_feed_poll_done(self
, handler
, data
):
318 def _on_update_all_done(self
, obj
):
319 self
.update_all_button
.set_sensitive(True)
320 self
.update_all_button
.set_stock_id(gtk
.STOCK_REFRESH
)
322 def poll_current_category(self
):
323 if self
._warn
_if
_offline
():
324 self
._poll
_categories
([self
._curr
_category
])
326 def poll_current_feed(self
):
327 if self
._warn
_if
_offline
():
328 pm
= PollManager
.get_instance()
329 pm
.poll([self
._curr
_feed
])
331 def mark_feed_as_read(self
):
332 self
._curr
_feed
.mark_all_read()
334 def mark_all_as_read(self
):
335 print "TODO mark_all_as_read"
337 def remove_selected_feed(self
):
338 # self._feed_list_presenter.remove_selected_feed()
341 def show_search(self
):
342 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
343 # self._item_view.item_selection_changed)
344 self
._item
_view
.display_empty_search()
345 self
._itemlist
_view
_notebook
.set_current_page(1)
346 self
._feedlist
_view
_notebook
.set_current_page(1)
347 self
._feedinfo
_presenter
.hide()
349 def hide_search(self
):
350 # self._find_presenter.clear()
351 self
._itemlist
_view
_notebook
.set_current_page(0)
352 self
._feedlist
_view
_notebook
.set_current_page(0)
353 self
._feedinfo
_presenter
.show()
354 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
355 # self._item_view.item_selection_changed)
357 def _warn_if_offline(self
):
358 offline
= Config
.get(OPTION_OFFLINE
)
362 response
= self
._view
.show_offline_dialog()
364 if response
== gtk
.RESPONSE_OK
:
365 Config
.set(OPTION_OFFLINE
, not offline
)
372 def display_previous_feed(self
, item
= None):
374 Displays the feed before the current selected feed
376 self
._feed
_list
_presenter
.select_previous_feed()
378 def display_next_feed(self
, item
=None):
380 Displays the feed after the current selected feed
382 self
._feed
_list
_presenter
.select_next_feed()
385 def display_next_unread_feed(self
):
387 Displays the next feed with an unread item
389 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
392 def display_previous_item(self
, item
=None):
394 Displays the item before the current selected item. If the item is the
395 first item, scrolls to the previous feed
397 is_prev
= self
._itemlist
_presenter
.select_previous_item()
399 # TODO HACK - implement select_previous_feed(select_last=True) ...
400 # ... to select previous feed's last item
401 self
._feed
_list
_presenter
.select_previous_feed()
402 self
._itemlist
_presenter
.select_last_item()
406 def display_next_item(self
, item
=None):
408 Displays the item after the current selected item. If the item is the
409 last item, selectes the next feed. If the current feed is the last
410 feed in the list, it goes back and selects the first feed
412 is_next
= self
._itemlist
_presenter
.select_next_item()
414 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
416 self
._feed
_list
_presenter
.select_firsteed_feed()
419 def scroll_or_display_next_unread_item(self
, item
=None):
420 has_unread_item
= False
421 if not self
._item
_view
.scroll_down():
422 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
423 if not has_unread_item
:
424 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
427 def show_preferences_dialog(self
, parent
):
430 def show_feed_properties(self
, parent
):
431 feedproperties
.show(self
._curr
_feed
)
434 self
._feed
_list
_presenter
.store_state()
437 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
439 Setup the file chooser dialog. This includes an extra widget (a combobox)
440 to include the categories to import or export
442 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
443 buttons
=(gtk
.STOCK_CANCEL
,
445 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
448 for category
in FeedManager
.categories():
449 category_list
.append(category
)
451 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
452 combobox
= gtk
.ComboBox(model
)
453 celltitle
= gtk
.CellRendererText()
454 combobox
.pack_start(celltitle
, False)
455 combobox
.add_attribute(celltitle
, 'text', 0)
457 for category
in category_list
:
459 model
.set(it
, 0, category
.name
, 1, category
)
461 combobox
.set_active(0)
462 label
= gtk
.Label(extra_widget_title
)
463 label
.set_alignment(1.0, 0.5)
464 hbox
= gtk
.HBox(spacing
=6)
465 hbox
.pack_start(label
, True, True, 0)
466 hbox
.pack_end(combobox
, False, False, 0)
469 dialog
.set_extra_widget(hbox
)
470 return (dialog
, combobox
)
472 def import_subscriptions(self
, parent
):
473 (dialog
, combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
474 gtk
.FILE_CHOOSER_ACTION_OPEN
,
475 _("Add new subscriptions in:"))
476 ffilter
= gtk
.FileFilter()
477 ffilter
.set_name(_("OPML Files Only"))
478 ffilter
.add_pattern("*.xml")
479 ffilter
.add_pattern("*.opml")
480 dialog
.add_filter(ffilter
)
481 dialog
.set_transient_for(parent
)
482 response
= dialog
.run()
483 if response
== gtk
.RESPONSE_OK
:
484 filename
= dialog
.get_filename()
485 model
= combobox
.get_model()
486 category
= model
[combobox
.get_active()][1]
488 FeedManager
.import_opml(filename
, category
)
491 def export_subscriptions(self
, parent
):
492 (dialog
, combobox
) = self
._setup
_filechooser
_dialog
(_("Export Subscriptions"),
493 gtk
.FILE_CHOOSER_ACTION_SAVE
,
494 _("Select category to export:"))
495 def selection_changed(widget
, dialog
):
496 model
= widget
.get_model()
497 category
= model
[widget
.get_active()][1]
498 dialog
.set_current_name("Straw-%s.xml" % category
.name
)
500 combobox
.connect('changed', selection_changed
, dialog
)
501 selection_changed(combobox
, dialog
)
502 dialog
.set_transient_for(parent
)
503 response
= dialog
.run()
505 if response
== gtk
.RESPONSE_OK
:
506 filename
= dialog
.get_filename()
507 model
= combobox
.get_model()
508 root_category
= model
[combobox
.get_active()][1]
509 FeedManager
.export_opml(root_category
.id, filename
)
514 subscribe_show(parent
=self
.view
._widget
)
516 class ApplicationView(MVP
.WidgetView
):
520 def _initialize(self
):
521 self
._initialize
_dnd
()
522 self
._initialize
_window
_updater
()
523 self
._create
_unmodified
_accelerator
_group
()
524 self
._attach
_unmodified
_accelerator
_group
()
525 self
._initialize
_window
()
526 self
._find
_toggled
= False
528 def _initialize_window(self
):
529 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
530 if Config
.get(OPTION_WINDOW_MAX
):
531 self
._widget
.maximize()
533 # we use resize here since configure-event seems to
534 # overwrite the default size if we use set_default_size.
535 #self._widget.move(Config.get(OPTION_WINDOW_LEFT), Config.get(OPTION_WINDOW_TOP))
536 #self._widget.resize(Config.get(OPTION_WINDOW_SIZE_W), Config.get(OPTION_WINDOW_SIZE_H))
537 self
._widget
.window
.move_resize(Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
),
538 Config
.get(OPTION_WINDOW_SIZE_W
), Config
.get(OPTION_WINDOW_SIZE_H
))
539 self
.mmp
= widget_tree
.get_widget('main_main_pane')
540 self
.msp
= widget_tree
.get_widget('main_sub_pane')
542 self
.mmp
.set_position(Config
.get(OPTION_MAIN_PANE_POS
))
543 self
.msp
.set_position(Config
.get(OPTION_SUB_PANE_POS
))
545 def _initialize_dnd(self
):
546 self
._widget
.drag_dest_set(
547 gtk
.DEST_DEFAULT_ALL
,
548 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
549 ('x-url/http', 0, 2)],
550 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
553 def _initialize_window_updater(self
):
554 #feedlist.signal_connect(Event.AllItemsReadSignal,
555 # lambda signal: self._update_title(feedlist))
556 #feedlist.signal_connect(Event.ItemReadSignal,
557 # lambda signal: self._update_title(feedlist))
558 #feedlist.signal_connect(Event.ItemsAddedSignal,
559 # lambda signal: self._update_title(feedlist))
560 #feedlist.signal_connect(Event.FeedsChangedSignal,
561 # lambda signal: self._update_title(feedlist))
564 def _update_title(self
, flist
):
565 uritems
= urfeeds
= 0
567 listfeeds
= flist
.flatten_list()
568 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
573 urfeeds
= len(listfeeds
)
576 item_feed_map
= {'uritems': uritems
,
579 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
580 self
._widget
.set_title(title
+ " - %s" % straw
.defs
.PACKAGE
)
582 # We have a separate accelerator group for the unmodified and
583 # shifted accelerators, that is, stuff like space, N, P, etc. This
584 # is so that we can have the find pane work correctly
585 def _create_unmodified_accelerator_group(self
):
586 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
587 agroup
= gtk
.AccelGroup()
588 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
589 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
590 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
591 ('next_unread_feed', ' ', 0),
592 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
593 for widget_name
, key
, mask
in accels
:
594 widget
= xml
.get_widget(widget_name
)
595 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
597 self
._unmodified
_accelerator
_group
= agroup
599 def _on_category_add_activate(self
, *args
):
600 self
._presenter
.add_category()
602 def _on_toolbar_change_read_state_button_toggled(self
, button
):
603 self
._presenter
.set_current_item_is_read(button
.get_active())
605 def _attach_unmodified_accelerator_group(self
):
606 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
608 def _detach_unmodified_accelerator_group(self
):
609 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
611 def _on_straw_main_destroy_event(self
, *args
):
612 return self
._presenter
.quit()
614 def _on_straw_main_delete_event(self
, *args
):
615 return self
._presenter
.quit()
617 def _on_straw_main_window_state_event(self
, widget
, event
):
618 is_maximized
= widget
.window
.get_state() == gtk
.gdk
.WINDOW_STATE_MAXIMIZED
619 Config
.set(OPTION_WINDOW_MAX
, is_maximized
)
621 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
622 if not (widget
.window
.get_state() & gtk
.gdk
.WINDOW_STATE_MAXIMIZED
):
623 self
._presenter
.check_allocation(widget
, event
)
625 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
626 self
._presenter
.check_main_pane_position(widget
)
628 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
629 self
._presenter
.check_sub_pane_position(widget
)
632 def _on_feed_subscribe_activate(self
, *args
):
633 self
._presenter
.subscribe()
635 def _on_feed_unsubscribe_activate(self
, *args
):
636 self
._presenter
.remove_selected_feed()
638 def _on_subscription_import_activate(self
, *args
):
639 self
._presenter
.import_subscriptions(self
._widget
)
641 def _on_subscription_export_activate(self
, *args
):
642 self
._presenter
.export_subscriptions(self
._widget
)
644 def _on_feed_mark_as_read_activate(self
, *args
):
645 self
._presenter
.mark_feed_as_read()
647 def _on_feed_mark_all_as_read_activate(self
, *args
):
648 self
._presenter
.mark_all_as_read()
650 def _on_feed_refresh_selected_activate(self
, *args
):
651 self
._presenter
.poll_current_feed()
653 def _on_subscription_refresh_activate(self
, *args
):
654 self
._presenter
.poll_all()
656 def _on_quit_activate(self
, *args
):
657 return self
._presenter
.quit()
660 def _on_copy_activate(self
, *args
):
661 self
._presenter
.copy_itemview_text_selection()
663 def _on_find_activate(self
, widget
, *args
):
664 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
665 menu_find
= xml
.get_widget('menu_find')
666 accel_label
= menu_find
.get_child()
668 if not self
._find
_toggled
:
669 self
._presenter
.show_search()
670 self
._detach
_unmodified
_accelerator
_group
()
671 self
._find
_toggled
= True
673 # save the "Find..." stock text for later recovery
674 self
._old
_label
_text
= accel_label
.get_text()
675 accel_label
.set_text(_('Return to feed list...'))
678 self
._presenter
.hide_search()
679 self
._attach
_unmodified
_accelerator
_group
()
680 self
._find
_toggled
= False
681 accel_label
.set_text(self
._old
_label
_text
)
683 def _on_preferences_activate(self
, *args
):
684 self
._presenter
.show_preferences_dialog(self
._widget
)
686 def _on_feed_information_activate(self
, *args
):
687 self
._presenter
.show_feed_properties(self
._widget
)
690 def _on_previous_item_activate(self
, *args
):
691 self
._presenter
.display_previous_item()
693 def _on_next_item_activate(self
, *args
):
694 self
._presenter
.display_next_item()
696 def _on_next_feed_activate(self
, *args
):
697 self
._presenter
.display_next_feed()
699 def _on_previous_feed_activate(self
, *args
):
700 self
._presenter
.display_previous_feed()
702 def _on_next_unread_feed_activate(self
, *args
):
703 self
._presenter
.display_next_unread_feed()
705 def _on_scroll_unread_items_activate(self
, *args
):
706 self
._presenter
.scroll_or_display_next_unread_item()
710 def _on_report_problem_activate(self
, menuitem
, *args
):
711 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
713 def _on_about_activate(self
, menuitem
, *args
):
714 widget
= self
._presenter
.credits()
717 def _on_straw_main_drag_data_received(self
, w
, context
,
718 x
, y
, data
, info
, time
):
719 if data
and data
.format
== 8:
720 url
= data
.data
.split("\n")[0]
721 subscribe_show("%s" % url
, self
._widget
)
722 context
.finish(True, False, time
)
724 context
.finish(False, False, time
)
727 def show_offline_dialog(self
):
728 return helpers
.report_offline_status(self
._widget
)
730 def get_widget_tree(self
):
731 return gtk
.glade
.get_widget_tree(self
._widget
)
734 self
._widget
.present()
736 def should_present(self
):
737 if self
._widget
.window
and self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
740 self
._widget
.present()
745 gnome
.program_init(straw
.defs
.PACKAGE
, straw
.defs
.VERSION
)
747 # initialize threading and environment
748 gobject
.threads_init()
750 #Config.set(OPTION_OFFLINEnfig.reload_css = os.getenv('STRAW_RELOAD_CSS') is not None
752 # build tray status icon
754 iconfile
= os
.path
.normpath(straw
.defs
.STRAW_DATA_DIR
+ "/straw.png")
755 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
756 scaled_buf
= pixbuf
.scale_simple(16, 16, gtk
.gdk
.INTERP_BILINEAR
)
757 image
.set_from_pixbuf(scaled_buf
)
759 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
760 self
.tray
.connect('activate', self
._tray
_clicked
)
761 except AttributeError:
764 self
.tray
= egg
.trayicon
.TrayIcon(straw
.defs
.PACKAGE
);
765 self
._eventbox
= gtk
.EventBox()
766 self
.tray
.add(self
._eventbox
)
767 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
768 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
769 self
._eventbox
.drag_dest_set(
770 gtk
.DEST_DEFAULT_ALL
,
771 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1), ('x-url/http', 0, 2)],
772 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
773 self
._eventbox
.add(image
)
776 self
._tooltip
= gtk
.Tooltips()
777 self
.unread_count
= 0
778 # end build tray status icon
780 FeedManager
.setup(storage_path
= "test.db")
783 ItemManager
.setup(storage_path
= "test.db")
786 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
788 #if config.first_time:
789 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
790 # feeds.import_opml(filepath)
792 #ImageCache.initialize()
794 xml
= gtk
.glade
.XML(os
.path
.join(straw
.defs
.STRAW_DATA_DIR
, 'straw.glade'), "straw_main", gettext
.textdomain())
795 window
= xml
.get_widget('straw_main')
796 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
797 self
._main
_presenter
.view
.present()
799 #PollManager.get_instance().start_polling_loop()
800 # set the default icon for the windows
801 iconfile
= os
.path
.join(straw
.defs
.STRAW_DATA_DIR
, "straw.png")
802 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
807 gtk
.gdk
.threads_init()
808 gtk
.gdk
.threads_enter()
810 gtk
.gdk
.threads_leave()
812 def _update(self
, flist
):
813 uritems
= urfeeds
= 0
814 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
818 if uritems
== self
.unread_count
:
820 self
.unread_count
= uritems
822 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
828 def _tray_clicked(self
, widget
, event
=None):
829 self
._main
_presenter
.view
.should_present()
831 if event
and not (event
.button
== 1):
833 self
._main
_presenter
.scroll_or_display_next_unread_item()
835 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
836 if data
and data
.format
== 8:
837 url
= data
.data
.split("\n")[0]
838 subscribe_show(url
="%s" % url
)
839 context
.finish(True, False, timestamp
)
841 context
.finish(False, False, timestamp
)