diff --git a/issues/issue-80dcba1e15932bfe35f89899171e6166b2e4203c.yaml b/issues/issue-80dcba1e15932bfe35f89899171e6166b2e4203c.yaml index 06c636b..f3a658e 100644 --- a/issues/issue-80dcba1e15932bfe35f89899171e6166b2e4203c.yaml +++ b/issues/issue-80dcba1e15932bfe35f89899171e6166b2e4203c.yaml @@ -5,8 +5,8 @@ type: :feature component: pygtk release: 1.0.0 reporter: Julio Biason -status: :unstarted -disposition: +status: :closed +disposition: :fixed creation_time: 2009-12-15 17:03:04.005105 Z references: [] @@ -23,3 +23,7 @@ log_events: - Julio Biason - assigned to release 1.0.0 from unassigned - "" +- - 2009-12-25 14:36:20.235206 Z + - Julio Biason + - closed with disposition fixed + - "" diff --git a/mitterlib/ui/ui_pygtk.py b/mitterlib/ui/ui_pygtk.py index 46f3ff1..168cc63 100644 --- a/mitterlib/ui/ui_pygtk.py +++ b/mitterlib/ui/ui_pygtk.py @@ -230,13 +230,18 @@ class Interface(object): main_window.connect('delete-event', self._quit_app) main_window.connect('size-request', self._grid_resize) - grid = self._create_grid() (menu, toolbar, accelerators) = self._create_menu_and_toolbar() update_field = self._create_update_box() self._statusbar = self._create_statusbar() self._main_tabs = gtk.Notebook() - self._main_tabs.insert_page(grid, gtk.Label('Messages')) + + (grid_widget, self._grid) = self._create_grid('_new_message_count') + self._main_tabs.insert_page(grid_widget, gtk.Label('Messages')) + + (replies_widget, self._replies) = self._create_grid( + '_new_replies_count') + self._main_tabs.insert_page(replies_widget, gtk.Label('Replies')) update_box = gtk.VPaned() update_box.pack1(self._main_tabs, resize=True, shrink=False) @@ -255,16 +260,16 @@ class Interface(object): return main_window - def _create_grid(self): + def _create_grid(self, counter): """Add the displaying grid.""" # Store NetworkData objects only grid_store = gtk.ListStore(object) grid_store.set_sort_column_id(0, gtk.SORT_ASCENDING) grid_store.set_sort_func(0, self._order_datetime) - self._grid = gtk.TreeView(grid_store) - self._grid.set_property('headers-visible', False) - self._grid.set_rules_hint(True) # change color for each row + grid = gtk.TreeView(grid_store) + grid.set_property('headers-visible', False) + grid.set_rules_hint(True) # change color for each row user_renderer = gtk.CellRendererPixbuf() user_column = gtk.TreeViewColumn('User', user_renderer) @@ -281,21 +286,20 @@ class Interface(object): message_column.set_cell_data_func(message_renderer, self._cell_renderer_message) - self._grid.append_column(user_column) - self._grid.append_column(message_column) + grid.append_column(user_column) + grid.append_column(message_column) - self._grid.set_resize_mode(gtk.RESIZE_IMMEDIATE) - self._grid.connect('cursor-changed', self._message_selected) - self._grid.connect('button-press-event', self._click_message) - self._grid.connect('popup-menu', self._message_popup) # Menu button - self._grid.connect('cursor-changed', self._mark_message_read, - '_new_message_count') + grid.set_resize_mode(gtk.RESIZE_IMMEDIATE) + grid.connect('cursor-changed', self._message_selected) + grid.connect('button-press-event', self._click_message) + grid.connect('popup-menu', self._message_popup) # Menu button + grid.connect('cursor-changed', self._mark_message_read, counter) scrolled_window = gtk.ScrolledWindow() scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) - scrolled_window.add(self._grid) + scrolled_window.add(grid) - return scrolled_window + return (scrolled_window, grid) def _create_menu_and_toolbar(self): """Create the main menu and the toolbar.""" @@ -692,6 +696,10 @@ class Interface(object): self._main_tabs.set_tab_label_text(child, 'Messages (%d)' % (self._new_message_count)) + child = self._main_tabs.get_nth_page(1) + self._main_tabs.set_tab_label_text(child, 'Replies (%d)' % + (self._new_replies_count)) + if self._statusicon: if self._new_message_count == 0: self._statusicon.set_from_pixbuf(self._images['main']) @@ -700,6 +708,53 @@ class Interface(object): return + def _fill_store(self, store, data): + """Using the results from the request, fill a gtk.Store.""" + for message in data: + _log.debug('Data: %s', str(message)) + message.read = False + pic = message.avatar + if not pic in self._avatars: + # set the user avatar to the default image, so it won't get + # queued again. Once downloaded, the _post_download_pic will + # update the image and force a redraw. + self._avatars[pic] = self._images['avatar'] + self._threads.add_work(self._post_download_pic, + self._exception_download_pic, + self._download_pic, + pic) + + store.prepend([message]) + store.sort_column_changed() + return + + def _update_word_wrap(self, widget): + """Update the word wrap for the widget.""" + model = widget.get_model() + if len(model) == 0: + # don't try to update if there are no data to be updated + return + + (win_width, win_height) = self._main_window.get_size() + column = widget.get_column(1) + iter = model.get_iter_first() + path = model.get_path(iter) + + cell_rectangle = widget.get_cell_area(path, column) + width = win_width - 70 # 48 = icon size + # TODO: Find out where those 12 pixels came from and/or if they + # are platform specific. + + for renderer in column.get_cell_renderers(): + renderer.set_property('wrap-width', width) + + while iter: + path = model.get_path(iter) + model.row_changed(path, iter) + iter = model.iter_next(iter) + return + + # ------------------------------------------------------------ # Widget callback functions # ------------------------------------------------------------ @@ -764,32 +819,8 @@ class Interface(object): """Called when the window is resized. We use it to set the proper word-wrapping in the message column.""" - model = self._grid.get_model() - if len(model) == 0: - # nothing in the list, so we don't have what to set proper word - # wrapping - return - - (win_width, win_height) = self._main_window.get_size() - #_log.debug('Widget size: %d', win_width) - - column = self._grid.get_column(1) - iter = model.get_iter_first() - path = model.get_path(iter) - - cell_rectangle = self._grid.get_cell_area(path, column) - width = win_width - 70 # 48 = icon size - # TODO: Find out where those 12 pixels came from and/or if they - # are platform specific. - - for renderer in column.get_cell_renderers(): - renderer.set_property('wrap-width', width) - - while iter: - path = model.get_path(iter) - model.row_changed(path, iter) - iter = model.iter_next(iter) - + self._update_word_wrap(self._grid) + self._update_word_wrap(self._replies) return def _order_datetime(self, model, iter1, iter2, user_data=None): @@ -833,8 +864,14 @@ class Interface(object): def _clear_posts(self, widget, user_data=None): """Clear the list of posts from the grid.""" - self._grid.get_model().clear() - self._new_message_count = 0 + page = self._main_tabs.get_current_page() + if page == 0: + # messages + self._grid.get_model().clear() + self._new_message_count = 0 + elif page == 1: + self._replies.get_model().clear() + self._new_replies_count = 0 self._message_count_updated() return @@ -1038,40 +1075,19 @@ class Interface(object): """Function called after the data from the messages list is retrieved.""" _log.debug('%d new tweets', len(results)) - interval = self._options[self.NAMESPACE]['refresh_interval'] - self._update_statusbar('%d new messages retrieved. Next update in ' \ - '%d minutes.' % (len(results), interval)) store = self._grid.get_model() - for message in results: - _log.debug('Data: %s', str(message)) - message.read = False - pic = message.avatar - if not pic in self._avatars: - # set the user avatar to the default image, so it won't get - # queued again. Once downloaded, the _post_download_pic will - # update the image and force a redraw. - self._avatars[pic] = self._images['avatar'] - self._threads.add_work(self._post_download_pic, - self._exception_download_pic, - self._download_pic, - pic) - - store.prepend([message]) - store.sort_column_changed() + self._fill_store(store, results) self._grid.queue_draw() - # once our update went fine, we can queue the next one. This avoids - # any problems if case there is an exception. - - interval = self._options[self.NAMESPACE]['refresh_interval'] - _log.debug('Queueing next refresh in %d minutes', interval) - self._refresh_id = gobject.timeout_add( - interval * 60 * 1000, - self._refresh, None) - self._new_message_count += len(results) self._message_count_updated() + + # now get replies + self._update_statusbar('Retrieving replies...') + self._threads.add_work(self._post_get_replies, + self._exception_get_messages, + self._connection.replies) return def _exception_get_messages(self, widget, exception): @@ -1091,6 +1107,31 @@ class Interface(object): self._statusicon.set_from_pixbuf(self._images['icon-error']) return + ### replies callback + def _post_get_replies(self, widget, results): + """Called after we retrieve the replies.""" + _log.debug("%d new replies", len(results)) + + store = self._replies.get_model() + self._fill_store(store, results) + self._replies.queue_draw() + + self._new_replies_count += len(results) + self._message_count_updated() + + # once our update went fine, we can queue the next one. This avoids + # any problems if case there is an exception. + + interval = self._options[self.NAMESPACE]['refresh_interval'] + _log.debug('Queueing next refresh in %d minutes', interval) + self._update_statusbar('%d new messages retrieved. Next update in ' \ + '%d minutes.' % (len(results), interval)) + self._refresh_id = gobject.timeout_add( + interval * 60 * 1000, + self._refresh, None) + + return + ### image download function def _download_pic(self, url): """Download a picture from the web. Can be used in a thread.""" @@ -1250,6 +1291,7 @@ class Interface(object): self._reply_message_id = None self._favourite_iter = None self._new_message_count = 0 + self._new_replies_count = 0 return