6da19a649bc8d6341705944817449c1bd05738d4
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
()
159 self
._restore
_state
()
162 def _init_widgets(self
):
163 widget_tree
= self
._view
.get_widget_tree()
165 self
._itemlist
_view
_notebook
= widget_tree
.get_widget('mode_view_notebook')
166 self
._feedlist
_view
_notebook
= widget_tree
.get_widget('left_mode_view_notebook')
168 item_view_container
= widget_tree
.get_widget('item_view_container')
169 item_list_container
= widget_tree
.get_widget('item_list_container')
171 self
.update_all_button
= widget_tree
.get_widget("toolbar_refresh_all_button")
173 parent_paned
= item_view_container
.get_parent()
174 parent_parent_widget
= parent_paned
.get_parent()
177 layout
= Config
.get(OPTION_PANE_LAYOUT
)
179 if layout
not in ("horizontal", "vertical"):
182 if layout
== "vertical":
183 new_paned
= gtk
.VPaned()
184 child_list
.append(item_list_container
)
185 child_list
.append(item_view_container
)
186 elif layout
== "horizontal":
187 new_paned
= gtk
.HPaned()
188 child_list
.append(item_view_container
)
189 child_list
.append(item_list_container
)
191 for child
in child_list
:
192 child
.reparent(new_paned
)
194 parent_parent_widget
.remove(parent_paned
)
195 parent_parent_widget
.add(new_paned
)
197 new_paned
.connect("size-allocate", self
._view
._on
_main
_sub
_pane
_size
_allocate
)
198 new_paned
.set_position(Config
.get(OPTION_SUB_PANE_POS
))
201 def _init_presenters(self
):
202 widget_tree
= self
._view
.get_widget_tree()
203 self
._toolbar
_presenter
= ToolbarPresenter(view
=ToolbarView(widget_tree
.get_widget('toolbar_default')))
204 self
._error
_presenter
= ErrorPresenter(widget_tree
.get_widget('statusbar_error_indicator'))
206 self
._item
_view
= ItemView(widget_tree
.get_widget('item_view_container'))
208 view
= ItemListView(widget_tree
.get_widget('item_selection_treeview'))
209 self
._itemlist
_presenter
= ItemListPresenter(view
=view
)
211 view
.add_selection_changed_listener(self
._item
_view
)
212 view
.add_selection_changed_listener(self
)
214 view
= FeedsView(widget_tree
.get_widget('feed_selection_treeview'))
215 self
._feed
_list
_presenter
= FeedsPresenter(view
=view
)
216 view
.add_selection_changed_listener(self
._itemlist
_presenter
)
217 view
.add_selection_changed_listener(self
._error
_presenter
)
219 self
._offline
_presenter
= OfflineToggle(widget_tree
.get_widget('offline_toggle'))
221 self
._status
_presenter
= StatusPresenter(view
= widget_tree
.get_widget("main_statusbar"))
222 # self._find_presenter = FindPresenter(view=FindView(widget_tree.get_widget("find_vbox")))
224 def set_current_item(self
, item
):
225 self
._current
_item
= item
226 self
._current
_item
_connect
_id
= item
.connect("is-read-changed", self
._on
_current
_item
_is
_read
_changed
)
228 def _restore_state(self
):
229 self
._feed
_list
_presenter
.restore_state()
231 def clear_current_item(self
):
232 if self
._current
_item
:
233 self
._current
_item
.disconnect(self
._current
_item
_connect
_id
)
234 self
._current
_item
= None
236 def set_current_item_is_read(self
, is_read
):
237 if self
._current
_item
:
238 self
._current
_item
.props
.is_read
= is_read
240 def _on_current_item_is_read_changed(self
, obj
, is_read
):
241 self
._toolbar
_presenter
.set_change_read_button_state(is_read
)
243 def itemlist_selection_changed(self
, selection
, column
):
244 self
.clear_current_item()
246 (model
, treeiter
) = selection
.get_selected()
247 if not treeiter
: return
248 item
= model
.get_value(treeiter
, column
)
249 self
._toolbar
_presenter
.set_change_read_button_state(item
.is_read
)
250 self
.set_current_item(item
)
252 def add_category(self
):
253 self
._feed
_list
_presenter
.add_category()
255 def copy_itemview_text_selection(self
):
256 helpers
.set_clipboard_text(self
._item
_view
.get_selected_text())
258 def check_allocation(self
, widget
, event
):
259 def check_size(widget
, width
, height
, x
, y
):
260 if width
== widget
.allocation
.width
and height
== widget
.allocation
.height
:
261 Config
.set(OPTION_WINDOW_SIZE_W
, width
)
262 Config
.set(OPTION_WINDOW_SIZE_H
, height
)
264 if widget
.window
and (x
, y
) == widget
.window
.get_position():
265 Config
.set(OPTION_WINDOW_LEFT
, x
)
266 Config
.set(OPTION_WINDOW_TOP
, y
)
268 config_position
= (Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
))
270 if (event
.width
, event
.height
, event
.x
, event
.y
) != \
271 (widget
.allocation
.width
, widget
.allocation
.height
, config_position
[0], config_position
[1]):
272 gobject
.timeout_add(1000, check_size
, widget
, event
.width
, event
.height
, event
.x
, event
.y
)
274 def check_main_pane_position(self
, widget
):
275 def check_position((position
, widget
)):
276 if position
== widget
.get_position():
277 Config
.set(OPTION_MAIN_PANE_POS
, position
)
279 pos
= widget
.get_position()
281 if pos
!= Config
.get(OPTION_MAIN_PANE_POS
):
282 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
284 def check_sub_pane_position(self
, widget
):
285 def check_position((position
, widget
)):
286 if position
== widget
.get_position():
287 Config
.set(OPTION_SUB_PANE_POS
, position
)
289 pos
= widget
.get_position()
291 if pos
!= Config
.get(OPTION_SUB_PANE_POS
):
292 gobject
.timeout_add(1000, check_position
, (pos
, widget
))
295 return helpers
.credits()
298 if not self
._warn
_if
_offline
():
301 if not FeedManager
.is_update_all_running():
302 FeedManager
.update_all_feeds({ "task-start": [ self
._on
_feed
_poll
_started
],
303 "task-done": [ self
._on
_feed
_poll
_done
] })
304 self
.update_all_button
.set_sensitive(True)
305 self
.update_all_button
.set_stock_id(gtk
.STOCK_STOP
)
307 self
.update_all_button
.set_sensitive(False)
308 FeedManager
.stop_update_all()
310 def _on_feed_poll_started(self
, handler
, feed
):
313 def _on_feed_poll_done(self
, handler
, data
):
316 def _on_update_all_done(self
, obj
):
317 self
.update_all_button
.set_sensitive(True)
318 self
.update_all_button
.set_stock_id(gtk
.STOCK_REFRESH
)
320 def poll_current_category(self
):
321 if self
._warn
_if
_offline
():
322 self
._poll
_categories
([self
._curr
_category
])
324 def poll_current_feed(self
):
325 if self
._warn
_if
_offline
():
326 pm
= PollManager
.get_instance()
327 pm
.poll([self
._curr
_feed
])
329 def mark_feed_as_read(self
):
330 self
._curr
_feed
.mark_all_read()
332 def mark_all_as_read(self
):
333 print "TODO mark_all_as_read"
335 def remove_selected_feed(self
):
336 # self._feed_list_presenter.remove_selected_feed()
339 def show_search(self
):
340 # self._find_presenter.item_list.signal_connect(Event.ItemSelectionChangedSignal,
341 # self._item_view.item_selection_changed)
342 self
._item
_view
.display_empty_search()
343 self
._itemlist
_view
_notebook
.set_current_page(1)
344 self
._feedlist
_view
_notebook
.set_current_page(1)
345 self
._feedinfo
_presenter
.hide()
347 def hide_search(self
):
348 # self._find_presenter.clear()
349 self
._itemlist
_view
_notebook
.set_current_page(0)
350 self
._feedlist
_view
_notebook
.set_current_page(0)
351 self
._feedinfo
_presenter
.show()
352 # self._find_presenter.item_list.signal_disconnect(Event.ItemSelectionChangedSignal,
353 # self._item_view.item_selection_changed)
355 def _warn_if_offline(self
):
356 offline
= Config
.get(OPTION_OFFLINE
)
360 response
= self
._view
.show_offline_dialog()
362 if response
== gtk
.RESPONSE_OK
:
363 Config
.set(OPTION_OFFLINE
, not offline
)
370 def display_previous_feed(self
, item
= None):
372 Displays the feed before the current selected feed
374 self
._feed
_list
_presenter
.select_previous_feed()
376 def display_next_feed(self
, item
=None):
378 Displays the feed after the current selected feed
380 self
._feed
_list
_presenter
.select_next_feed()
383 def display_next_unread_feed(self
):
385 Displays the next feed with an unread item
387 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
390 def display_previous_item(self
, item
=None):
392 Displays the item before the current selected item. If the item is the
393 first item, scrolls to the previous feed
395 is_prev
= self
._itemlist
_presenter
.select_previous_item()
397 # TODO HACK - implement select_previous_feed(select_last=True) ...
398 # ... to select previous feed's last item
399 self
._feed
_list
_presenter
.select_previous_feed()
400 self
._itemlist
_presenter
.select_last_item()
404 def display_next_item(self
, item
=None):
406 Displays the item after the current selected item. If the item is the
407 last item, selectes the next feed. If the current feed is the last
408 feed in the list, it goes back and selects the first feed
410 is_next
= self
._itemlist
_presenter
.select_next_item()
412 is_next_feed
= self
._feed
_list
_presenter
.select_next_feed()
414 self
._feed
_list
_presenter
.select_firsteed_feed()
417 def scroll_or_display_next_unread_item(self
, item
=None):
418 has_unread_item
= False
419 if not self
._item
_view
.scroll_down():
420 has_unread_item
= self
._itemlist
_presenter
.select_next_unread_item()
421 if not has_unread_item
:
422 self
._feed
_list
_presenter
.select_next_feed(with_unread
=True)
425 def show_preferences_dialog(self
, parent
):
428 def show_feed_properties(self
, parent
):
429 feedproperties
.show(self
._curr
_feed
)
432 self
._feed
_list
_presenter
.store_state()
435 def _setup_filechooser_dialog(self
, title
, action
, extra_widget_title
):
437 Setup the file chooser dialog. This includes an extra widget (a combobox)
438 to include the categories to import or export
440 dialog
= gtk
.FileChooserDialog(title
, action
=action
,
441 buttons
=(gtk
.STOCK_CANCEL
,
443 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
446 for category
in FeedManager
.categories():
447 category_list
.append(category
)
449 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
450 combobox
= gtk
.ComboBox(model
)
451 celltitle
= gtk
.CellRendererText()
452 combobox
.pack_start(celltitle
,False)
453 combobox
.add_attribute(celltitle
, 'text', 0)
455 for category
in category_list
:
457 model
.set(it
, 0, category
.name
, 1, category
)
459 combobox
.set_active(0)
460 label
= gtk
.Label(extra_widget_title
)
461 label
.set_alignment(1.0,0.5)
462 hbox
= gtk
.HBox(spacing
=6)
463 hbox
.pack_start(label
,True,True,0)
464 hbox
.pack_end(combobox
,False,False,0)
467 dialog
.set_extra_widget(hbox
)
468 return (dialog
, combobox
)
470 def import_subscriptions(self
, parent
):
471 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Import Subscriptions"),
472 gtk
.FILE_CHOOSER_ACTION_OPEN
,
473 _("Add new subscriptions in:"))
474 ffilter
= gtk
.FileFilter()
475 ffilter
.set_name(_("OPML Files Only"))
476 ffilter
.add_pattern("*.xml")
477 ffilter
.add_pattern("*.opml")
478 dialog
.add_filter(ffilter
)
479 dialog
.set_transient_for(parent
)
480 response
= dialog
.run()
481 if response
== gtk
.RESPONSE_OK
:
482 filename
= dialog
.get_filename()
483 model
= combobox
.get_model()
484 category
= model
[combobox
.get_active()][1]
486 FeedManager
.import_opml(filename
, category
)
489 def export_subscriptions(self
, parent
):
490 (dialog
,combobox
) = self
._setup
_filechooser
_dialog
(_("Export Subscriptions"),
491 gtk
.FILE_CHOOSER_ACTION_SAVE
,
492 _("Select category to export:"))
493 def selection_changed(widget
, dialog
):
494 model
= widget
.get_model()
495 category
= model
[widget
.get_active()][1]
496 dialog
.set_current_name("Straw-%s.xml" % category
.name
)
498 combobox
.connect('changed', selection_changed
, dialog
)
499 selection_changed(combobox
, dialog
)
500 dialog
.set_transient_for(parent
)
501 response
= dialog
.run()
503 if response
== gtk
.RESPONSE_OK
:
504 filename
= dialog
.get_filename()
505 model
= combobox
.get_model()
506 root_category
= model
[combobox
.get_active()][1]
507 FeedManager
.export_opml(root_category
.id, filename
)
512 subscribe_show(parent
=self
.view
._widget
)
514 class ApplicationView(MVP
.WidgetView
):
518 def _initialize(self
):
519 self
._initialize
_dnd
()
520 self
._initialize
_window
_updater
()
521 self
._create
_unmodified
_accelerator
_group
()
522 self
._attach
_unmodified
_accelerator
_group
()
523 self
._initialize
_window
()
524 self
._find
_toggled
= False
526 def _initialize_window(self
):
527 widget_tree
= gtk
.glade
.get_widget_tree(self
._widget
)
528 if Config
.get(OPTION_WINDOW_MAX
):
529 self
._widget
.maximize()
531 # we use resize here since configure-event seems to
532 # overwrite the default size if we use set_default_size.
533 #self._widget.move(Config.get(OPTION_WINDOW_LEFT), Config.get(OPTION_WINDOW_TOP))
534 #self._widget.resize(Config.get(OPTION_WINDOW_SIZE_W), Config.get(OPTION_WINDOW_SIZE_H))
535 self
._widget
.window
.move_resize(Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
),
536 Config
.get(OPTION_WINDOW_SIZE_W
), Config
.get(OPTION_WINDOW_SIZE_H
))
537 self
.mmp
= widget_tree
.get_widget('main_main_pane')
538 self
.msp
= widget_tree
.get_widget('main_sub_pane')
540 self
.mmp
.set_position(Config
.get(OPTION_MAIN_PANE_POS
))
541 self
.msp
.set_position(Config
.get(OPTION_SUB_PANE_POS
))
543 def _initialize_dnd(self
):
544 self
._widget
.drag_dest_set(
545 gtk
.DEST_DEFAULT_ALL
,
546 [('_NETSCAPE_URL', 0, 0), ('text/uri-list ', 0, 1),
547 ('x-url/http', 0, 2)],
548 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
551 def _initialize_window_updater(self
):
552 #feedlist.signal_connect(Event.AllItemsReadSignal,
553 # lambda signal: self._update_title(feedlist))
554 #feedlist.signal_connect(Event.ItemReadSignal,
555 # lambda signal: self._update_title(feedlist))
556 #feedlist.signal_connect(Event.ItemsAddedSignal,
557 # lambda signal: self._update_title(feedlist))
558 #feedlist.signal_connect(Event.FeedsChangedSignal,
559 # lambda signal: self._update_title(feedlist))
562 def _update_title(self
, flist
):
563 uritems
= urfeeds
= 0
565 listfeeds
= flist
.flatten_list()
566 for ur
in [f
.number_of_unread
for f
in listfeeds
]:
571 urfeeds
= len(listfeeds
)
574 item_feed_map
= {'uritems': uritems
,
577 title
= _('%(uritems)d unread in %(urfeeds)d %(fstring)s') % item_feed_map
578 self
._widget
.set_title( title
+ " - %s" % straw
.defs
.PACKAGE
)
580 # We have a separate accelerator group for the unmodified and
581 # shifted accelerators, that is, stuff like space, N, P, etc. This
582 # is so that we can have the find pane work correctly
583 def _create_unmodified_accelerator_group(self
):
584 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
585 agroup
= gtk
.AccelGroup()
586 accels
= (('feed_mark_as_read', 'R', gtk
.gdk
.SHIFT_MASK
),
587 ('feed_mark_all_as_read', 'A', gtk
.gdk
.SHIFT_MASK
),
588 ('next_item', 'N', gtk
.gdk
.SHIFT_MASK
),
589 ('next_unread_feed', ' ', 0),
590 ('previous_item', 'P', gtk
.gdk
.SHIFT_MASK
))
591 for widget_name
, key
, mask
in accels
:
592 widget
= xml
.get_widget(widget_name
)
593 widget
.add_accelerator("activate", agroup
, ord(key
), mask
,
595 self
._unmodified
_accelerator
_group
= agroup
597 def _on_category_add_activate(self
, *args
):
598 self
._presenter
.add_category()
600 def _on_toolbar_change_read_state_button_toggled(self
, button
):
601 self
._presenter
.set_current_item_is_read(button
.get_active())
603 def _attach_unmodified_accelerator_group(self
):
604 self
._widget
.add_accel_group(self
._unmodified
_accelerator
_group
)
606 def _detach_unmodified_accelerator_group(self
):
607 self
._widget
.remove_accel_group(self
._unmodified
_accelerator
_group
)
609 def _on_straw_main_destroy_event(self
, *args
):
610 return self
._presenter
.quit()
612 def _on_straw_main_delete_event(self
, *args
):
613 return self
._presenter
.quit()
615 def _on_straw_main_window_state_event(self
, widget
, event
):
616 is_maximized
= widget
.window
.get_state() == gtk
.gdk
.WINDOW_STATE_MAXIMIZED
617 Config
.set(OPTION_WINDOW_MAX
, is_maximized
)
619 def _on_straw_main_configure_event(self
, widget
, event
, *args
):
620 if not (widget
.window
.get_state() & gtk
.gdk
.WINDOW_STATE_MAXIMIZED
):
621 self
._presenter
.check_allocation(widget
, event
)
623 def _on_main_main_pane_size_allocate(self
, widget
, *args
):
624 self
._presenter
.check_main_pane_position(widget
)
626 def _on_main_sub_pane_size_allocate(self
, widget
, *args
):
627 self
._presenter
.check_sub_pane_position(widget
)
630 def _on_feed_subscribe_activate(self
, *args
):
631 self
._presenter
.subscribe()
633 def _on_feed_unsubscribe_activate(self
, *args
):
634 self
._presenter
.remove_selected_feed()
636 def _on_subscription_import_activate(self
, *args
):
637 self
._presenter
.import_subscriptions(self
._widget
)
639 def _on_subscription_export_activate(self
, *args
):
640 self
._presenter
.export_subscriptions(self
._widget
)
642 def _on_feed_mark_as_read_activate(self
, *args
):
643 self
._presenter
.mark_feed_as_read()
645 def _on_feed_mark_all_as_read_activate(self
, *args
):
646 self
._presenter
.mark_all_as_read()
648 def _on_feed_refresh_selected_activate(self
, *args
):
649 self
._presenter
.poll_current_feed()
651 def _on_subscription_refresh_activate(self
, *args
):
652 self
._presenter
.poll_all()
654 def _on_quit_activate(self
, *args
):
655 return self
._presenter
.quit()
658 def _on_copy_activate(self
, *args
):
659 self
._presenter
.copy_itemview_text_selection()
661 def _on_find_activate(self
, widget
, *args
):
662 xml
= gtk
.glade
.get_widget_tree(self
._widget
)
663 menu_find
= xml
.get_widget('menu_find')
664 accel_label
= menu_find
.get_child()
666 if not self
._find
_toggled
:
667 self
._presenter
.show_search()
668 self
._detach
_unmodified
_accelerator
_group
()
669 self
._find
_toggled
= True
671 # save the "Find..." stock text for later recovery
672 self
._old
_label
_text
= accel_label
.get_text()
673 accel_label
.set_text(_('Return to feed list...'))
676 self
._presenter
.hide_search()
677 self
._attach
_unmodified
_accelerator
_group
()
678 self
._find
_toggled
= False
679 accel_label
.set_text(self
._old
_label
_text
)
681 def _on_preferences_activate(self
, *args
):
682 self
._presenter
.show_preferences_dialog(self
._widget
)
684 def _on_feed_information_activate(self
, *args
):
685 self
._presenter
.show_feed_properties(self
._widget
)
688 def _on_previous_item_activate(self
, *args
):
689 self
._presenter
.display_previous_item()
691 def _on_next_item_activate(self
, *args
):
692 self
._presenter
.display_next_item()
694 def _on_next_feed_activate(self
, *args
):
695 self
._presenter
.display_next_feed()
697 def _on_previous_feed_activate(self
, *args
):
698 self
._presenter
.display_previous_feed()
700 def _on_next_unread_feed_activate(self
, *args
):
701 self
._presenter
.display_next_unread_feed()
703 def _on_scroll_unread_items_activate(self
, *args
):
704 self
._presenter
.scroll_or_display_next_unread_item()
708 def _on_report_problem_activate(self
, menuitem
, *args
):
709 helpers
.url_show("http://bugzilla.gnome.org/simple-bug-guide.cgi?product=straw")
711 def _on_about_activate(self
, menuitem
, *args
):
712 widget
= self
._presenter
.credits()
715 def _on_straw_main_drag_data_received(self
, w
, context
,
716 x
, y
, data
, info
, time
):
717 if data
and data
.format
== 8:
718 url
= data
.data
.split("\n")[0]
719 subscribe_show("%s" % url
, self
._widget
)
720 context
.finish(True, False, time
)
722 context
.finish(False, False, time
)
725 def show_offline_dialog(self
):
726 return helpers
.report_offline_status(self
._widget
)
728 def get_widget_tree(self
):
729 return gtk
.glade
.get_widget_tree(self
._widget
)
732 self
._widget
.present()
734 def should_present(self
):
735 if self
._widget
.window
and self
._widget
.window
.get_state() is not gtk
.gdk
.WINDOW_STATE_WITHDRAWN
:
738 self
._widget
.present()
743 gnome
.program_init(straw
.defs
.PACKAGE
, straw
.defs
.VERSION
)
746 # initialize threading and environment
747 gobject
.threads_init()
749 #Config.set(OPTION_OFFLINEnfig.reload_css = os.getenv('STRAW_RELOAD_CSS') is not None
751 # build tray status icon
753 iconfile
= os
.path
.normpath(straw
.defs
.STRAW_DATA_DIR
+ "/straw.png")
754 pixbuf
= gtk
.gdk
.pixbuf_new_from_file(iconfile
)
755 scaled_buf
= pixbuf
.scale_simple(16,16,gtk
.gdk
.INTERP_BILINEAR
)
756 image
.set_from_pixbuf(scaled_buf
)
758 self
.tray
= gtk
.status_icon_new_from_pixbuf(scaled_buf
)
759 self
.tray
.connect('activate', self
._tray
_clicked
)
760 except AttributeError:
763 self
.tray
= egg
.trayicon
.TrayIcon(straw
.defs
.PACKAGE
);
764 self
._eventbox
= gtk
.EventBox()
765 self
.tray
.add(self
._eventbox
)
766 self
._eventbox
.connect('button_press_event', self
._tray
_clicked
)
767 self
._eventbox
.connect("drag-data-received", self
._on
_drag
_data
_received
)
768 self
._eventbox
.drag_dest_set(
769 gtk
.DEST_DEFAULT_ALL
,
770 [('_NETSCAPE_URL', 0, 0),('text/uri-list ', 0, 1),('x-url/http', 0, 2)],
771 gtk
.gdk
.ACTION_COPY | gtk
.gdk
.ACTION_MOVE
)
772 self
._eventbox
.add(image
)
775 self
._tooltip
= gtk
.Tooltips()
776 self
.unread_count
= 0
777 # end build tray status icon
779 FeedManager
.setup(storage_path
= "test.db")
782 ItemManager
.setup(storage_path
= "test.db")
785 #FeedManager.import_opml(os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml"))
787 #if config.first_time:
788 # filepath = os.path.join(straw.STRAW_DATA_DIR, "default_subscriptions.opml")
789 # feeds.import_opml(filepath)
791 #ImageCache.initialize()
793 xml
= gtk
.glade
.XML(os
.path
.join(straw
.defs
.STRAW_DATA_DIR
,'straw.glade'), "straw_main", gettext
.textdomain())
794 window
= xml
.get_widget('straw_main')
795 self
._main
_presenter
= ApplicationPresenter(view
= ApplicationView(window
))
796 self
._main
_presenter
.view
.present()
798 self
._main
_presenter
.view
._widget
.window
.move_resize(Config
.get(OPTION_WINDOW_LEFT
), Config
.get(OPTION_WINDOW_TOP
),
799 Config
.get(OPTION_WINDOW_SIZE_W
), Config
.get(OPTION_WINDOW_SIZE_H
))
801 #PollManager.get_instance().start_polling_loop()
802 # set the default icon for the windows
803 iconfile
= os
.path
.join(straw
.defs
.STRAW_DATA_DIR
,"straw.png")
804 gtk
.window_set_default_icon(gtk
.gdk
.pixbuf_new_from_file(iconfile
))
809 gtk
.gdk
.threads_init()
810 gtk
.gdk
.threads_enter()
812 gtk
.gdk
.threads_leave()
814 def _update(self
,flist
):
815 uritems
= urfeeds
= 0
816 for ur
in [f
.number_of_unread
for f
in flist
.flatten_list()]:
820 if uritems
== self
.unread_count
:
822 self
.unread_count
= uritems
824 self
._tooltip
.set_tip(self
.tray
, _("%d new items")%uritems
)
830 def _tray_clicked(self
, widget
, event
=None):
831 self
._main
_presenter
.view
.should_present()
833 if event
and not (event
.button
== 1):
835 self
._main
_presenter
.scroll_or_display_next_unread_item()
837 def _on_drag_data_received(self
, widget
, context
, x
, y
, data
, info
, timestamp
):
838 if data
and data
.format
== 8:
839 url
= data
.data
.split("\n")[0]
840 subscribe_show(url
="%s" % url
)
841 context
.finish(True, False, timestamp
)
843 context
.finish(False, False, timestamp
)