[Sugar-devel] [PATCH GetBooks v2] Port to Gtk3 SL #3681

Manuel Kaufmann humitos at gmail.com
Wed Jun 20 09:38:07 EDT 2012


This is a big change that ports Get Books to Gtk3. Here are the steps[1]
that I followed to this port.

There are some things that are not working as they worked before the
port, but all of them are related with the Gtk3 theme instead with the
Get Books itself.

[1] http://wiki.sugarlabs.org/go/User:Humitos/PortingGetBooks

Signed-off-by: Manuel Kaufmann <humitos at gmail.com>
---
 GetIABooksActivity.py |  312 ++++++++++++++++++++++++-------------------------
 devicemanager.py      |   43 +++----
 extListview.py        |  169 ++++++++++++++++-----------
 listview.py           |   57 +++++----
 opds.py               |   54 ++++-----
 setup.py              |    2 +-
 6 files changed, 330 insertions(+), 307 deletions(-)

diff --git a/GetIABooksActivity.py b/GetIABooksActivity.py
index 0a06069..9d818d7 100644
--- a/GetIABooksActivity.py
+++ b/GetIABooksActivity.py
@@ -19,32 +19,33 @@
 import os
 import logging
 import time
-import gtk
-
-OLD_TOOLBAR = False
-try:
-    from sugar.graphics.toolbarbox import ToolbarBox
-    from sugar.activity.widgets import StopButton
-except ImportError:
-    OLD_TOOLBAR = True
-
-from sugar.graphics import style
-from sugar.graphics.toolbutton import ToolButton
-from sugar.graphics.toggletoolbutton import ToggleToolButton
-from sugar.graphics.toolcombobox import ToolComboBox
-from sugar.graphics.combobox import ComboBox
-from sugar.graphics import iconentry
-from sugar import profile
-from sugar.activity import activity
-from sugar.activity.widgets import ToolbarButton
-from sugar.bundle.activitybundle import ActivityBundle
-from sugar.datastore import datastore
-from sugar.graphics.alert import NotifyAlert
-from sugar.graphics.alert import Alert
-from sugar.graphics.icon import Icon
+
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GdkPixbuf
+from gi.repository import GObject
+from gi.repository import Pango
+
+
+from sugar3.graphics.toolbarbox import ToolbarBox
+from sugar3.activity.widgets import StopButton
+from sugar3.graphics import style
+from sugar3.graphics.toolbutton import ToolButton
+from sugar3.graphics.toggletoolbutton import ToggleToolButton
+from sugar3.graphics.toolcombobox import ToolComboBox
+from sugar3.graphics.combobox import ComboBox
+from sugar3.graphics import iconentry
+from sugar3 import profile
+from sugar3.activity import activity
+from sugar3.activity.widgets import ToolbarButton
+from sugar3.bundle.activitybundle import ActivityBundle
+from sugar3.datastore import datastore
+from sugar3.graphics.alert import NotifyAlert
+from sugar3.graphics.alert import Alert
+from sugar3.graphics.icon import Icon
 from gettext import gettext as _
+
 import dbus
-import gobject
 import ConfigParser
 import base64
 
@@ -86,39 +87,27 @@ class GetIABooksActivity(activity.Activity):
         else:
             self._read_configuration()
 
-        if OLD_TOOLBAR:
-            toolbox = activity.ActivityToolbox(self)
-            activity_toolbar = toolbox.get_activity_toolbar()
-
-            self.set_toolbox(toolbox)
-            self._books_toolbar = gtk.Toolbar()
-            self._add_search_controls(self._books_toolbar)
-            self.toolbox.add_toolbar(_('Books'), self._books_toolbar)
-            self._books_toolbar.show()
-            toolbox.show()
-            toolbox.set_current_toolbar(1)
-        else:
-            toolbar_box = ToolbarBox()
-            activity_button = ToolButton()
-            color = profile.get_color()
-            bundle = ActivityBundle(activity.get_bundle_path())
-            icon = Icon(file=bundle.get_icon(), xo_color=color)
-            activity_button.set_icon_widget(icon)
-            activity_button.show()
+        toolbar_box = ToolbarBox()
+        activity_button = ToolButton()
+        color = profile.get_color()
+        bundle = ActivityBundle(activity.get_bundle_path())
+        icon = Icon(file=bundle.get_icon(), xo_color=color)
+        activity_button.set_icon_widget(icon)
+        activity_button.show()
 
-            toolbar_box.toolbar.insert(activity_button, 0)
-            self._add_search_controls(toolbar_box.toolbar)
+        toolbar_box.toolbar.insert(activity_button, 0)
+        self._add_search_controls(toolbar_box.toolbar)
 
-            separator = gtk.SeparatorToolItem()
-            separator.props.draw = False
-            separator.set_expand(True)
-            toolbar_box.toolbar.insert(separator, -1)
+        separator = Gtk.SeparatorToolItem()
+        separator.props.draw = False
+        separator.set_expand(True)
+        toolbar_box.toolbar.insert(separator, -1)
 
-            toolbar_box.toolbar.insert(StopButton(self), -1)
+        toolbar_box.toolbar.insert(StopButton(self), -1)
 
-            self.set_toolbar_box(toolbar_box)
-            toolbar_box.show_all()
-            self._books_toolbar = toolbar_box.toolbar
+        self.set_toolbar_box(toolbar_box)
+        toolbar_box.show_all()
+        self._books_toolbar = toolbar_box.toolbar
 
         self._create_controls()
 
@@ -236,14 +225,14 @@ class GetIABooksActivity(activity.Activity):
         logging.error('catalogs %s', self.catalogs)
 
     def _add_search_controls(self, toolbar):
-        book_search_item = gtk.ToolItem()
+        book_search_item = Gtk.ToolItem()
         toolbar.search_entry = iconentry.IconEntry()
         toolbar.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
                                                 'system-search')
         toolbar.search_entry.add_clear_button()
         toolbar.search_entry.connect('activate',
                 self.__search_entry_activate_cb)
-        width = int(gtk.gdk.screen_width() / 4)
+        width = int(Gdk.Screen.width() / 4)
         toolbar.search_entry.set_size_request(width, -1)
         book_search_item.add(toolbar.search_entry)
         toolbar.search_entry.show()
@@ -268,7 +257,7 @@ class GetIABooksActivity(activity.Activity):
         if len(self.languages) > 0:
             toolbar.config_toolbarbutton = ToolbarButton()
             toolbar.config_toolbarbutton.props.icon_name = 'preferences-system'
-            toolbar.config_toolbarbox = gtk.Toolbar()
+            toolbar.config_toolbarbox = Gtk.Toolbar()
             toolbar.config_toolbarbutton.props.page = toolbar.config_toolbarbox
             toolbar.language_combo = ComboBox()
             toolbar.language_combo.props.sensitive = True
@@ -321,7 +310,10 @@ class GetIABooksActivity(activity.Activity):
         self.queryresults = opds.RemoteQueryResult(catalog_config,
                 '', query_language)
         self.show_message(_('Performing lookup, please wait...'))
-        self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+        # README: I think we should create some global variables for
+        # each cursor that we are using to avoid the creation of them
+        # every time that we want to change it
+        self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH))
 
         self.queryresults.connect('updated', self.__query_updated_cb)
 
@@ -428,14 +420,18 @@ class GetIABooksActivity(activity.Activity):
         treestore, coldex = \
                 self.catalog_listview.get_selection().get_selected()
         len_cat = len(self.catalog_history)
-        if self.catalog_history[len_cat - 1]['catalogs'] == []:
+        if len_cat > 0 and self.catalog_history[len_cat - 1]['catalogs'] == []:
             self.catalog_history.pop()
             len_cat = len(self.catalog_history)
 
-        self.catalog_history.append(\
+        # README: when the Activity starts by default there is nothing
+        # selected and this signal is called, so we have to avoid this
+        # 'append' because it fails
+        if coldex is not None:
+            self.catalog_history.append(
                 {'title': treestore.get_value(coldex, 0),
                 'catalogs': []})
-        self.__switch_catalog_cb(treestore.get_value(coldex, 0))
+            self.__switch_catalog_cb(treestore.get_value(coldex, 0))
 
     def _sort_logfile(self, treemodel, itera, iterb):
         a = treemodel.get_value(itera, 0)
@@ -455,42 +451,44 @@ class GetIABooksActivity(activity.Activity):
             self.tree_scroller.show_all()
             self.separa.show()
         else:
-            self.tree_scroller.hide_all()
+            # README: hide_all() doesn't exist anymore
+            # http://developer.gnome.org/gtk3/3.5/GtkWidget.html#gtk-widget-hide
+            self.tree_scroller.hide()
             self.separa.hide()
 
     def _create_controls(self):
         self._download_content_length = 0
         self._download_content_type = None
-        self.progressbox = gtk.HBox(spacing=20)
-        self.progressbar = gtk.ProgressBar()
-        self.progressbar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
+        self.progressbox = Gtk.Box(spacing=20,
+                                   orientation=Gtk.Orientation.HORIZONTAL)
+        self.progressbar = Gtk.ProgressBar()
         self.progressbar.set_fraction(0.0)
-        self.progressbox.pack_start(self.progressbar, expand=True,
-                fill=True)
-        self.cancel_btn = gtk.Button(stock=gtk.STOCK_CANCEL)
+        self.progressbox.pack_start(self.progressbar, expand=True, fill=True,
+                                    padding=0)
+        self.cancel_btn = Gtk.Button(stock=Gtk.STOCK_CANCEL)
         self.cancel_btn.connect('clicked', self.__cancel_btn_clicked_cb)
         self.progressbox.pack_start(self.cancel_btn, expand=False,
-                fill=False)
+                                    fill=False, padding=0)
 
-        self.msg_label = gtk.Label()
+        self.msg_label = Gtk.Label()
 
-        self.list_box = gtk.HBox()
+        self.list_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
 
         # Catalogs treeview
-        self.catalog_listview = gtk.TreeView()
+        self.catalog_listview = Gtk.TreeView()
         self.catalog_listview.headers_clickble = True
         self.catalog_listview.hover_expand = True
         self.catalog_listview.rules_hint = True
         self.catalog_listview.connect('cursor-changed', self.move_down_catalog)
         self.catalog_listview.set_enable_search(False)
-        self.treemodel = gtk.ListStore(gobject.TYPE_STRING)
-        sorter = gtk.TreeModelSort(self.treemodel)
-        sorter.set_sort_column_id(0, gtk.SORT_ASCENDING)
-        sorter.set_sort_func(0, self._sort_logfile)
-        self.catalog_listview.set_model(sorter)
-        renderer = gtk.CellRendererText()
-        renderer.set_property('wrap-mode', gtk.WRAP_WORD)
-        self.treecol = gtk.TreeViewColumn(_('Catalogs'), renderer, text=0)
+
+        self.treemodel = Gtk.ListStore(str)
+        self.treemodel.set_sort_column_id(0, Gtk.SortType.ASCENDING)
+        self.catalog_listview.set_model(self.treemodel)
+
+        renderer = Gtk.CellRendererText()
+        renderer.set_property('wrap-mode', Pango.WrapMode.WORD)
+        self.treecol = Gtk.TreeViewColumn(_('Catalogs'), renderer, text=0)
         self.treecol.set_property('clickable', True)
         self.treecol.connect('clicked', self.move_up_catalog)
         self.catalog_listview.append_column(self.treecol)
@@ -508,38 +506,42 @@ class GetIABooksActivity(activity.Activity):
             self.treemodel.clear()
             for p in self.categories:
                 self.path_iter[p['text']] = self.treemodel.append([p['text']])
-        self.tree_scroller = gtk.ScrolledWindow(hadjustment=None,
-                vadjustment=None)
-        self.tree_scroller.set_policy(gtk.POLICY_NEVER,
-                gtk.POLICY_AUTOMATIC)
+        self.tree_scroller = Gtk.ScrolledWindow(hadjustment=None,
+                                                vadjustment=None)
+        self.tree_scroller.set_policy(Gtk.PolicyType.NEVER,
+                Gtk.PolicyType.AUTOMATIC)
         self.tree_scroller.add(self.catalog_listview)
-        self.list_box.pack_start(self.tree_scroller, expand=False, fill=False)
-        self.separa = gtk.VSeparator()
-        self.list_box.pack_start(self.separa, expand=False, fill=False)
+        self.list_box.pack_start(self.tree_scroller, expand=False,
+                                 fill=False, padding=0)
+        self.separa = Gtk.VSeparator()
+        self.list_box.pack_start(self.separa, expand=False,
+                                 fill=False, padding=0)
 
         # books listview
         self.listview = ListView(self._lang_code_handler)
         self.listview.connect('selection-changed', self.selection_cb)
         self.listview.set_enable_search(False)
 
-        self.list_scroller = gtk.ScrolledWindow(hadjustment=None,
-                vadjustment=None)
-        self.list_scroller.set_policy(gtk.POLICY_AUTOMATIC,
-                gtk.POLICY_AUTOMATIC)
+        self.list_scroller = Gtk.ScrolledWindow(hadjustment=None,
+                                                vadjustment=None)
+        self.list_scroller.set_policy(Gtk.PolicyType.AUTOMATIC,
+                                      Gtk.PolicyType.AUTOMATIC)
         vadjustment = self.list_scroller.get_vadjustment()
         vadjustment.connect('value-changed',
                 self.__vadjustment_value_changed_cb)
         self.list_scroller.add(self.listview)
-        self.list_box.pack_start(self.list_scroller, expand=True, fill=True)
-
-        self.scrolled = gtk.ScrolledWindow()
-        self.scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
-        self.scrolled.props.shadow_type = gtk.SHADOW_NONE
-        self.textview = gtk.TextView()
+        self.list_box.pack_start(self.list_scroller, expand=True,
+                                 fill=True, padding=0)
+
+        self.scrolled = Gtk.ScrolledWindow()
+        self.scrolled.set_policy(Gtk.PolicyType.NEVER,
+                                 Gtk.PolicyType.AUTOMATIC)
+        self.scrolled.props.shadow_type = Gtk.ShadowType.NONE
+        self.textview = Gtk.TextView()
         self.textview.set_editable(False)
         self.textview.set_cursor_visible(False)
-        self.textview.set_wrap_mode(gtk.WRAP_WORD)
-        self.textview.set_justification(gtk.JUSTIFY_LEFT)
+        self.textview.set_wrap_mode(Gtk.WrapMode.WORD)
+        self.textview.set_justification(Gtk.Justification.LEFT)
         self.textview.set_left_margin(20)
         self.textview.set_right_margin(20)
         self.scrolled.add(self.textview)
@@ -547,10 +549,10 @@ class GetIABooksActivity(activity.Activity):
         self.separa.hide()
         self.tree_scroller.hide()
 
-        vbox_download = gtk.VBox()
+        vbox_download = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
 
-        hbox_format = gtk.HBox()
-        format_label = gtk.Label(_('Format:'))
+        hbox_format = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
+        format_label = Gtk.Label(label=_('Format:'))
         self.format_combo = ComboBox()
         for key in _MIMETYPES.keys():
             self.format_combo.append_item(_MIMETYPES[key], key)
@@ -563,23 +565,23 @@ class GetIABooksActivity(activity.Activity):
         hbox_format.pack_start(self.format_combo, False, False, 10)
         vbox_download.pack_start(hbox_format, False, False, 10)
 
-        self._download = gtk.Button(_('Get Book'))
+        self._download = Gtk.Button(_('Get Book'))
         self._download.props.sensitive = False
         self._download.connect('clicked', self.__get_book_cb)
         vbox_download.pack_start(self._download, False, False, 10)
 
-        bottom_hbox = gtk.HBox()
+        bottom_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
 
         if self.show_images:
             self.__image_downloader = None
-            self.image = gtk.Image()
+            self.image = Gtk.Image()
             self.add_default_image()
             bottom_hbox.pack_start(self.image, False, False, 10)
         bottom_hbox.pack_start(self.scrolled, True, True, 10)
         bottom_hbox.pack_start(vbox_download, False, False, 10)
         bottom_hbox.show_all()
 
-        vbox = gtk.VBox()
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
         vbox.pack_start(self.msg_label, False, False, 10)
         vbox.pack_start(self.progressbox, False, False, 10)
         vbox.pack_start(self.list_box, True, True, 0)
@@ -596,7 +598,6 @@ class GetIABooksActivity(activity.Activity):
         if len(self.catalogs) > 0:
             self.bt_catalogs.set_active(True)
 
-
     def can_close(self):
         self._lang_code_handler.close()
         if self.queryresults is not None:
@@ -679,7 +680,7 @@ class GetIABooksActivity(activity.Activity):
 
     def get_pixbuf_from_buffer(self, image_buffer):
         """Buffer To Pixbuf"""
-        pixbuf_loader = gtk.gdk.PixbufLoader()
+        pixbuf_loader = GdkPixbuf.PixbufLoader()
         pixbuf_loader.write(image_buffer)
         pixbuf_loader.close()
         pixbuf = pixbuf_loader.get_pixbuf()
@@ -718,11 +719,11 @@ class GetIABooksActivity(activity.Activity):
         self.add_image(file_path)
 
     def add_image(self, file_path):
-        pixbuf = gtk.gdk.pixbuf_new_from_file(file_path)
+        pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_path)
         self.add_image_buffer(pixbuf)
 
     def add_image_buffer(self, pixbuf):
-        image_height = int(gtk.gdk.screen_height() / 4)
+        image_height = int(Gdk.Screen.height() / 4)
         image_width = image_height / 3 * 2
         width, height = pixbuf.get_width(), pixbuf.get_height()
         scale = 1
@@ -731,20 +732,26 @@ class GetIABooksActivity(activity.Activity):
             scale_y = image_height / float(height)
             scale = min(scale_x, scale_y)
 
-        pixbuf2 = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, \
-                            pixbuf.get_has_alpha(), \
-                            pixbuf.get_bits_per_sample(), \
-                            image_width, image_height)
-        pixbuf2.fill(style.COLOR_PANEL_GREY.get_int())
+        pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB,
+                                       pixbuf.get_has_alpha(),
+                                       pixbuf.get_bits_per_sample(),
+                                       image_width, image_height)
+
+        # FIXME: I used this darker color instead of
+        # style.COLOR_PANEL_GREY because there is a big difference on
+        # the image. We should find the way to use the same color on
+        # the .png loaded than in the rest of the square and remove
+        # the 1px border
+        pixbuf2.fill(style.COLOR_BUTTON_GREY.get_int())
 
         margin_x = int((image_width - (width * scale)) / 2)
         margin_y = int((image_height - (height * scale)) / 2)
 
-        pixbuf.scale(pixbuf2, margin_x, margin_y, \
-                            image_width - (margin_x * 2), \
-                            image_height - (margin_y * 2), \
-                            margin_x, margin_y, scale, scale, \
-                            gtk.gdk.INTERP_BILINEAR)
+        pixbuf.scale(pixbuf2, margin_x, margin_y,
+                     image_width - (margin_x * 2),
+                     image_height - (margin_y * 2),
+                     margin_x, margin_y, scale, scale,
+                     GdkPixbuf.InterpType.BILINEAR)
 
         self.image.set_from_pixbuf(pixbuf2)
 
@@ -793,7 +800,7 @@ class GetIABooksActivity(activity.Activity):
                             self.source, search_text)
 
             self.show_message(_('Performing lookup, please wait...'))
-            self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+            self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH))
             self.queryresults.connect('updated', self.__query_updated_cb)
 
     def __query_updated_cb(self, query, midway):
@@ -818,7 +825,7 @@ class GetIABooksActivity(activity.Activity):
                 if only_english:
                     self.show_message(
                             _('Sorry, we only found english books.'))
-        self.window.set_cursor(None)
+        self.get_window().set_cursor(None)
         self._allow_suspend()
 
     def catalogs_updated(self, query, midway):
@@ -919,7 +926,7 @@ class GetIABooksActivity(activity.Activity):
     def get_book(self):
         self.enable_button(False)
         self.progressbox.show_all()
-        gobject.idle_add(self.download_book,  self.download_url)
+        GObject.idle_add(self.download_book, self.download_url)
 
     def download_book(self,  url):
         self._inhibit_suspend()
@@ -960,8 +967,8 @@ class GetIABooksActivity(activity.Activity):
                           bytes_downloaded)
         total = self._download_content_length
         self.set_downloaded_bytes(bytes_downloaded,  total)
-        while gtk.events_pending():
-            gtk.main_iteration()
+        while Gtk.events_pending():
+            Gtk.main_iteration()
 
     def _get_book_error_cb(self, getter, err):
         self.listview.props.sensitive = True
@@ -1017,7 +1024,7 @@ class GetIABooksActivity(activity.Activity):
         textbuffer = self.textview.get_buffer()
         journal_entry.metadata['description'] = \
             textbuffer.get_text(textbuffer.get_start_iter(),
-                textbuffer.get_end_iter())
+                                textbuffer.get_end_iter(), True)
         if self.exist_cover_image:
             image_buffer = self._get_preview_image_buffer()
             journal_entry.metadata['preview'] = dbus.ByteArray(image_buffer)
@@ -1046,11 +1053,11 @@ class GetIABooksActivity(activity.Activity):
         _stop_alert.props.title = title
         _stop_alert.props.msg = msg
         open_icon = Icon(icon_name='zoom-activity')
-        _stop_alert.add_button(gtk.RESPONSE_APPLY,
+        _stop_alert.add_button(Gtk.ResponseType.APPLY,
                                     _('Show in Journal'), open_icon)
         open_icon.show()
         ok_icon = Icon(icon_name='dialog-ok')
-        _stop_alert.add_button(gtk.RESPONSE_OK, _('Ok'), ok_icon)
+        _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
         ok_icon.show()
         # Remove other alerts
         for alert in self._alerts:
@@ -1061,7 +1068,7 @@ class GetIABooksActivity(activity.Activity):
         _stop_alert.show()
 
     def __stop_response_cb(self, alert, response_id):
-        if response_id is gtk.RESPONSE_APPLY:
+        if response_id is Gtk.ResponseType.APPLY:
             activity.show_object_in_journal(self._object_id)
         self.remove_alert(alert)
 
@@ -1077,39 +1084,30 @@ class GetIABooksActivity(activity.Activity):
             scale_y = preview_height / float(height)
             scale = min(scale_x, scale_y)
 
-        pixbuf2 = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, \
-                            pixbuf.get_has_alpha(), \
-                            pixbuf.get_bits_per_sample(), \
-                            preview_width, preview_height)
+        pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB,
+                                       pixbuf.get_has_alpha(),
+                                       pixbuf.get_bits_per_sample(),
+                                       preview_width, preview_height)
         pixbuf2.fill(style.COLOR_WHITE.get_int())
 
         margin_x = int((preview_width - (width * scale)) / 2)
         margin_y = int((preview_height - (height * scale)) / 2)
 
-        pixbuf.scale(pixbuf2, margin_x, margin_y, \
-                            preview_width - (margin_x * 2), \
-                            preview_height - (margin_y * 2), \
-                            margin_x, margin_y, scale, scale, \
-                            gtk.gdk.INTERP_BILINEAR)
-        preview_data = []
-
-        def save_func(buf, data):
-            data.append(buf)
+        pixbuf.scale(pixbuf2, margin_x, margin_y,
+                     preview_width - (margin_x * 2),
+                     preview_height - (margin_y * 2),
+                     margin_x, margin_y, scale, scale,
+                     GdkPixbuf.InterpType.BILINEAR)
 
-        pixbuf2.save_to_callback(save_func, 'png', user_data=preview_data)
-        preview_data = ''.join(preview_data)
-        return preview_data
+        # README: GdkPixbuf.Pixbuf.save_to_callback is no longer
+        # available, so we use save_to_bufferv instead.
+        succes, data = pixbuf2.save_to_bufferv('png', [], [])
+        return data
 
     def _get_cover_image_buffer(self):
         pixbuf = self.image.get_pixbuf()
-        cover_data = []
-
-        def save_func(buf, data):
-            data.append(buf)
-
-        pixbuf.save_to_callback(save_func, 'png', user_data=cover_data)
-        cover_data = ''.join(cover_data)
-        return cover_data
+        succes, data = pixbuf.save_to_bufferv('png', [], [])
+        return data
 
     def _show_error_alert(self, title, text=None):
         alert = NotifyAlert(timeout=20)
@@ -1190,16 +1188,16 @@ class GetIABooksActivity(activity.Activity):
         pass
 
 
-class ButtonWithImage(gtk.Button):
+class ButtonWithImage(Gtk.Button):
 
     def __init__(self, label_text):
-        gtk.Button.__init__(self, _('Catalogs'))
+        GObject.GObject.__init__(self,)
         self.icon_move_up = Icon(icon_name='go-up')
-        self.remove(self.get_children()[0])
-        self.hbox = gtk.HBox()
+        # self.remove(self.get_children()[0])
+        self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
         self.add(self.hbox)
         self.hbox.add(self.icon_move_up)
-        self.label = gtk.Label(label_text)
+        self.label = Gtk.Label(label=label_text)
         self.hbox.add(self.label)
         self.show_all()
 
diff --git a/devicemanager.py b/devicemanager.py
index f673fce..7630126 100644
--- a/devicemanager.py
+++ b/devicemanager.py
@@ -18,22 +18,23 @@
 
 import os
 import logging
-import gobject
 import dbus
 
-UDISK_DEVICE_PATH = 'org.freedesktop.UDisks.Device'
+from gi.repository import GObject
 
+# UDISK_DEVICE_PATH = 'org.freedesktop.UDisks.Device'
 
-class DeviceManager(gobject.GObject):
+
+class DeviceManager(GObject.GObject):
 
     __gsignals__ = {
-        'device-changed': (gobject.SIGNAL_RUN_FIRST,
-                          gobject.TYPE_NONE,
+        'device-changed': (GObject.SignalFlags.RUN_FIRST,
+                          None,
                           ([])),
     }
 
     def __init__(self):
-        gobject.GObject.__init__(self)
+        GObject.GObject.__init__(self)
 
         self._devices = {}
         self._bus = dbus.SystemBus()
@@ -59,21 +60,21 @@ class DeviceManager(gobject.GObject):
 
     def _get_props_from_device(self, device):
         # http://hal.freedesktop.org/docs/udisks/Device.html
-        device_obj = self._bus.get_object('org.freedesktop.UDisks', device)
-        device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
-        props = {}
-        props['mounted'] = bool(device_props.Get(UDISK_DEVICE_PATH,
-                'DeviceIsMounted'))
-        if props['mounted']:
-            props['mount_path'] = str(device_props.Get(UDISK_DEVICE_PATH,
-                    'DeviceMountPaths')[0])
-            props['removable'] = bool(device_props.Get(UDISK_DEVICE_PATH,
-                    'DriveCanDetach'))
-            props['label'] = str(device_props.Get(UDISK_DEVICE_PATH,
-                    'IdLabel'))
-            props['size'] = int(device_props.Get(UDISK_DEVICE_PATH,
-                    'DeviceSize'))
-            return props
+        # device_obj = self._bus.get_object('org.freedesktop.UDisks', device)
+        # device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
+        # props = {}
+        # props['mounted'] = bool(device_props.Get(UDISK_DEVICE_PATH,
+        #         'DeviceIsMounted'))
+        # if props['mounted']:
+        #     props['mount_path'] = str(device_props.Get(UDISK_DEVICE_PATH,
+        #             'DeviceMountPaths')[0])
+        #     props['removable'] = bool(device_props.Get(UDISK_DEVICE_PATH,
+        #             'DriveCanDetach'))
+        #     props['label'] = str(device_props.Get(UDISK_DEVICE_PATH,
+        #             'IdLabel'))
+        #     props['size'] = int(device_props.Get(UDISK_DEVICE_PATH,
+        #             'DeviceSize'))
+        #     return props
         return None
 
     def _have_catalog(self, props):
diff --git a/extListview.py b/extListview.py
index cf0b450..060eddc 100644
--- a/extListview.py
+++ b/extListview.py
@@ -34,12 +34,12 @@
 #
 # v1.3:
 #   * Greatly improved speed when sorting a lot of rows
-#   * Added support for gtk.CellRendererToggle
+#   * Added support for Gtk.CellRendererToggle
 #   * Improved replaceContent() method
 #   * Added a call to set_cursor() when removing selected row(s)
 #   * Added getFirstSelectedRow(), appendRows(), addColumnAttribute(),
 #   unselectAll() and selectAll() methods
-#   * Set expand to False when calling pack_start()
+#   * Set expand to False when calling pack_start(, True, True, 0)
 #
 # v1.2:
 #   * Fixed D'n'D reordering bugs
@@ -52,35 +52,21 @@
 #     the empty area
 #   * Sort indicators are now displayed whenever needed
 
-import gtk
 import random
+import logging
 
-from gtk import gdk
-from gobject import signal_new, TYPE_INT, TYPE_STRING, TYPE_BOOLEAN, \
-TYPE_PYOBJECT, TYPE_NONE, SIGNAL_RUN_LAST
+from gi.repository import Gtk
+from gi.repository import GObject
+from gi.repository import Gdk
 
 
 # Internal d'n'd (reordering)
 DND_REORDERING_ID = 1024
 DND_INTERNAL_TARGET = ('extListview-internal',
-                        gtk.TARGET_SAME_WIDGET, DND_REORDERING_ID)
+                        Gtk.TargetFlags.SAME_WIDGET, DND_REORDERING_ID)
 
 
-# Custom signals
-signal_new('extlistview-dnd', gtk.TreeView, SIGNAL_RUN_LAST, TYPE_NONE,
-            (gdk.DragContext, TYPE_INT, TYPE_INT, gtk.SelectionData, TYPE_INT,
-            TYPE_PYOBJECT))
-signal_new('extlistview-modified', gtk.TreeView, SIGNAL_RUN_LAST, TYPE_NONE,
-            ())
-signal_new('extlistview-button-pressed', gtk.TreeView, SIGNAL_RUN_LAST,
-            TYPE_NONE, (gdk.Event, TYPE_PYOBJECT))
-signal_new('extlistview-column-visibility-changed', gtk.TreeView,
-            SIGNAL_RUN_LAST, TYPE_NONE, (TYPE_STRING, TYPE_BOOLEAN))
-signal_new('button-press-event', gtk.TreeViewColumn, SIGNAL_RUN_LAST,
-            TYPE_NONE, (gdk.Event, ))
-
-
-class ExtListViewColumn(gtk.TreeViewColumn):
+class ExtListViewColumn(Gtk.TreeViewColumn):
     """
         TreeViewColumn does not signal right-click events, and we need them
         This subclass is equivalent to TreeViewColumn, but it signals these
@@ -90,10 +76,15 @@ class ExtListViewColumn(gtk.TreeViewColumn):
         (http://www.sacredchao.net/quodlibet)
     """
 
+    __gsignals__ = {
+        'button-press-event': (GObject.SignalFlags.RUN_LAST, None,
+                               (object,)),
+        }
+
     def __init__(self, title=None, cell_renderer=None, **args):
-        """ Constructor, see gtk.TreeViewColumn """
-        gtk.TreeViewColumn.__init__(self, title, cell_renderer, **args)
-        label = gtk.Label(title)
+        """ Constructor, see Gtk.TreeViewColumn """
+        GObject.GObject.__init__(self)
+        label = Gtk.Label(label=title)
         self.set_widget(label)
         label.show()
         label.__realize = label.connect('realize', self.onRealize)
@@ -101,7 +92,7 @@ class ExtListViewColumn(gtk.TreeViewColumn):
     def onRealize(self, widget):
         widget.disconnect(widget.__realize)
         del widget.__realize
-        button = widget.get_ancestor(gtk.Button)
+        button = widget.get_ancestor(Gtk.Button)
         if button is not None:
             button.connect('button-press-event', self.onButtonPressed)
 
@@ -109,7 +100,17 @@ class ExtListViewColumn(gtk.TreeViewColumn):
         self.emit('button-press-event', event)
 
 
-class ExtListView(gtk.TreeView):
+class ExtListView(Gtk.TreeView):
+
+    __gsignals__ = {
+        'extlistview-modified': (GObject.SignalFlags.RUN_LAST, None,
+                                 ()),
+
+        # README: I had to change gdk.Event to object on the arguments
+        # sent to the callback because with Gdk.Event it didn't work
+        # 'extlistview-button-pressed': (GObject.SignalFlags.RUN_LAST, None,
+        #                                (object, bool)),
+        }
 
     def __init__(self, columns, sortable=True, dndTargets=[], useMarkup=False,
             canShowHideColumns=True):
@@ -125,7 +126,7 @@ class ExtListView(gtk.TreeView):
             If useMarkup is True, the 'markup' attributes is used instead of
             'text' for CellRendererTexts
         """
-        gtk.TreeView.__init__(self)
+        GObject.GObject.__init__(self)
 
         self.selection = self.get_selection()
 
@@ -140,7 +141,7 @@ class ExtListView(gtk.TreeView):
         self.set_rules_hint(True)
         self.set_headers_visible(True)
 
-        self.selection.set_mode(gtk.SELECTION_MULTIPLE)
+        self.selection.set_mode(Gtk.SelectionMode.MULTIPLE)
 
         # Create the columns
         nbEntries = 0
@@ -152,7 +153,7 @@ class ExtListView(gtk.TreeView):
             else:
                 column = ExtListViewColumn(title)
                 column.set_resizable(True)
-                #column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
+                # column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
                 column.set_expand(expandable)
                 column.set_visible(visible)
                 if canShowHideColumns:
@@ -169,11 +170,11 @@ class ExtListView(gtk.TreeView):
                     nbEntries += 1
                     dataTypes.append(type)
                     column.pack_start(renderer, False)
-                    if isinstance(renderer, gtk.CellRendererToggle):
+                    if isinstance(renderer, Gtk.CellRendererToggle):
                         column.add_attribute(renderer, 'active', nbEntries - 1)
-                    elif isinstance(renderer, gtk.CellRendererPixbuf):
+                    elif isinstance(renderer, Gtk.CellRendererPixbuf):
                         column.add_attribute(renderer, 'pixbuf', nbEntries - 1)
-                    elif isinstance(renderer, gtk.CellRendererText):
+                    elif isinstance(renderer, Gtk.CellRendererText):
                         if useMarkup:
                             column.add_attribute(renderer, 'markup',
                                 nbEntries - 1)
@@ -184,12 +185,12 @@ class ExtListView(gtk.TreeView):
         # Mark management
         self.markedRow = None
         self.markColumn = len(dataTypes)
-        dataTypes.append(TYPE_BOOLEAN)  # When there's no other solution,
-                                        # this additional entry helps in
-                                        # finding the marked row
+        dataTypes.append(bool)  # When there's no other solution,
+                                # this additional entry helps in
+                                # finding the marked row
 
         # Create the ListStore associated with this tree
-        self.store = gtk.ListStore(*dataTypes)
+        self.store = Gtk.ListStore(*dataTypes)
         self.set_model(self.store)
 
         # Drag'n'drop management
@@ -200,13 +201,17 @@ class ExtListView(gtk.TreeView):
         self.dndReordering = False
 
         if len(dndTargets) != 0:
-            self.enable_model_drag_dest(dndTargets, gdk.ACTION_DEFAULT)
+            self.enable_model_drag_dest(dndTargets, Gdk.DragAction.DEFAULT)
+
+        # self.connect('drag-begin', self.onDragBegin)
+        # self.connect('drag-motion', self.onDragMotion)
 
-        self.connect('drag-begin', self.onDragBegin)
-        self.connect('drag-motion', self.onDragMotion)
-        self.connect('button-press-event', self.onButtonPressed)
-        self.connect('drag-data-received', self.onDragDataReceived)
-        self.connect('button-release-event', self.onButtonReleased)
+        # README: this function is disconnected because it emit twice
+        # 'selection-changed'
+        # self.connect('button-press-event', self.onButtonPressed)
+
+        # self.connect('drag-data-received', self.onDragDataReceived)
+        # self.connect('button-release-event', self.onButtonReleased)
 
         # Show the list
         self.show()
@@ -314,7 +319,10 @@ class ExtListView(gtk.TreeView):
         criteria = self.sortColCriteria[column]
         rows.sort(lambda r1, r2: \
                 self.__cmpRows(r1, r2, criteria, self.sortAscending))
-        self.store.reorder([r[-1] for r in rows])
+        # FIXME: AttributeError: 'ListStore' object has no attribute 'reorder'
+        # Bug filled upstream:
+        #   - https://bugzilla.gnome.org/show_bug.cgi?id=677941
+        # self.store.reorder([r[-1] for r in rows])
 
         # Move the mark if needed
         if self.markedRow is not None:
@@ -322,9 +330,9 @@ class ExtListView(gtk.TreeView):
 
         column.set_sort_indicator(True)
         if self.sortAscending:
-            column.set_sort_order(gtk.SORT_ASCENDING)
+            column.set_sort_order(Gtk.SortType.ASCENDING)
         else:
-            column.set_sort_order(gtk.SORT_DESCENDING)
+            column.set_sort_order(Gtk.SortType.DESCENDING)
 
         self.emit('extlistview-modified')
 
@@ -349,6 +357,7 @@ class ExtListView(gtk.TreeView):
 
     def getFirstSelectedRow(self):
         """ Return only the first selected row """
+        # TODO: check if this fail on gtk2 version after click on the ListView
         return tuple(self.store[self.selection.get_selected_rows()[1][0]])[:-1]
 
     def getFirstSelectedRowIndex(self):
@@ -502,13 +511,13 @@ class ExtListView(gtk.TreeView):
         """ Enable the use of Drag'n'Drop to reorder the list """
         self.dndReordering = True
         self.dndTargets.append(DND_INTERNAL_TARGET)
-        self.enable_model_drag_dest(self.dndTargets, gdk.ACTION_DEFAULT)
+        self.enable_model_drag_dest(self.dndTargets, Gdk.DragAction.DEFAULT)
 
     def __isDropAfter(self, pos):
-        """ Helper function, True if pos is gtk.TREE_VIEW_DROP_AFTER or
-            gtk.TREE_VIEW_DROP_INTO_OR_AFTER """
-        return pos == gtk.TREE_VIEW_DROP_AFTER or \
-                pos == gtk.TREE_VIEW_DROP_INTO_OR_AFTER
+        """ Helper function, True if pos is Gtk.TreeViewDropPosition.AFTER or
+            Gtk.TreeViewDropPosition.INTO_OR_AFTER """
+        return pos == Gtk.TreeViewDropPosition.AFTER or \
+                pos == Gtk.TreeViewDropPosition.INTO_OR_AFTER
 
     def __moveSelectedRows(self, x, y):
         """ Internal function used for drag'n'drop """
@@ -516,11 +525,12 @@ class ExtListView(gtk.TreeView):
         dropInfo = self.get_dest_row_at_pos(int(x), int(y))
 
         if dropInfo is None:
-            pos, path = gtk.TREE_VIEW_DROP_INTO_OR_AFTER, len(self.store) - 1
+            pos, path = (Gtk.TreeViewDropPosition.INTO_OR_AFTER,
+                         len(self.store) - 1)
         else:
-            pos, path = dropInfo[1], dropInfo[0][0]
+            pos, path = (dropInfo[1], dropInfo[0][0])
             if self.__isDropAfter(pos) and path < len(self.store) - 1:
-                pos = gtk.TREE_VIEW_DROP_INTO_OR_BEFORE
+                pos = Gtk.TreeViewDropPosition.INTO_OR_BEFORE
                 path += 1
 
         self.freeze_child_notify()
@@ -567,17 +577,20 @@ class ExtListView(gtk.TreeView):
 
         if event.button == 1 or event.button == 3:
             if path is None:
+                # README: this emit the signal: selection-changed and
+                # there is nothing selected so we get an IndexError
                 self.selection.unselect_all()
                 tree.set_cursor(len(self.store))
             else:
                 if self.dndReordering and self.motionEvtId is None \
                     and event.button == 1:
                     self.dndStartPos = (int(event.x), int(event.y))
-                    self.motionEvtId = gtk.TreeView.connect(self, \
+                    self.motionEvtId = Gtk.TreeView.connect(self, \
                             'motion-notify-event', self.onMouseMotion)
 
-                stateClear = not (event.state & \
-                            (gdk.SHIFT_MASK | gdk.CONTROL_MASK))
+                stateClear = not (event.get_state() & \
+                                      (Gdk.ModifierType.SHIFT_MASK |
+                                       Gdk.ModifierType.CONTROL_MASK))
 
                 if stateClear and not self.selection.path_is_selected(path):
                     self.selection.unselect_all()
@@ -586,7 +599,7 @@ class ExtListView(gtk.TreeView):
                     retVal = (stateClear and self.getSelectedRowsCount() > 1 \
                             and self.selection.path_is_selected(path))
 
-        self.emit('extlistview-button-pressed', event, path)
+        # self.emit('extlistview-button-pressed', event, path)
 
         return retVal
 
@@ -599,11 +612,13 @@ class ExtListView(gtk.TreeView):
 
             if len(self.dndTargets) != 0:
                 self.enable_model_drag_dest(self.dndTargets,
-                    gdk.ACTION_DEFAULT)
+                    Gdk.DragAction.DEFAULT)
 
-        stateClear = not (event.state & (gdk.SHIFT_MASK | gdk.CONTROL_MASK))
+        stateClear = not (event.get_state() & \
+                              (Gdk.ModifierType.SHIFT_MASK |
+                               Gdk.ModifierType.CONTROL_MASK))
 
-        if stateClear and event.state & gdk.BUTTON1_MASK \
+        if stateClear and event.get_state() & Gdk.ModifierType.BUTTON1_MASK \
             and self.getSelectedRowsCount() > 1:
             pathInfo = self.get_path_at_pos(int(event.x), int(event.y))
             if pathInfo is not None:
@@ -616,14 +631,14 @@ class ExtListView(gtk.TreeView):
             self.drag_check_threshold(self.dndStartPos[0], self.dndStartPos[1],
             int(event.x), int(event.y)):
             self.dndContext = self.drag_begin([DND_INTERNAL_TARGET],
-                    gdk.ACTION_COPY, 1, event)
+                    Gdk.DragAction.COPY, 1, event)
 
     def onDragBegin(self, tree, context):
         """ A drag'n'drop operation has begun """
         if self.getSelectedRowsCount() == 1:
-            context.set_icon_stock(gtk.STOCK_DND, 0, 0)
+            context.set_icon_stock(Gtk.STOCK_DND, 0, 0)
         else:
-            context.set_icon_stock(gtk.STOCK_DND_MULTIPLE, 0, 0)
+            context.set_icon_stock(Gtk.STOCK_DND_MULTIPLE, 0, 0)
 
     def onDragDataReceived(self, tree, context, x, y, selection, dndId, time):
         """ Some data has been dropped into the list """
@@ -639,22 +654,29 @@ class ExtListView(gtk.TreeView):
         drop = self.get_dest_row_at_pos(int(x), int(y))
 
         if drop is not None and \
-            (drop[1] == gtk.TREE_VIEW_DROP_INTO_OR_AFTER or \
-            drop[1] == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
+            (drop[1] == Gtk.TreeViewDropPosition.INTO_OR_AFTER or \
+            drop[1] == Gtk.TreeViewDropPosition.INTO_OR_BEFORE):
             self.enable_model_drag_dest([('invalid-position', 0, -1)],
-                    gdk.ACTION_DEFAULT)
+                    Gdk.DragAction.DEFAULT)
         else:
-            self.enable_model_drag_dest(self.dndTargets, gdk.ACTION_DEFAULT)
+            self.enable_model_drag_dest(self.dndTargets,
+                                        Gdk.DragAction.DEFAULT)
 
     def onColumnHeaderClicked(self, column, event):
         """ A column header has been clicked """
+
         if event.button == 3:
             # Create a menu with a CheckMenuItem per column
-            menu = gtk.Menu()
+            menu = Gtk.Menu()
+
+            # README: it seems like we should use a Palette here
+            # from sugar3.graphics.palette import Palette
+            # menu = Palette('Humitos', text_maxlen=50)
+
             nbVisibleItems = 0
             lastVisibleItem = None
             for column in self.get_columns():
-                item = gtk.CheckMenuItem(column.get_title())
+                item = Gtk.CheckMenuItem(column.get_title())
                 item.set_active(column.get_visible())
                 item.connect('toggled', self.onShowHideColumn, column)
                 item.show()
@@ -669,7 +691,12 @@ class ExtListView(gtk.TreeView):
             if nbVisibleItems == 1:
                 lastVisibleItem.set_sensitive(False)
 
-            menu.popup(None, None, None, event.button, event.get_time())
+            # README: a new argument is needed. Although this is not working
+            # http://developer.gnome.org/gtk3/3.5/GtkMenu.html#gtk-menu-popup
+            menu.popup(None, None, None, None, event.button, event.get_time())
+
+            # FIXME: for some reason this menu.popup call is not
+            # showing the popup
 
     def onShowHideColumn(self, menuItem, column):
         """ Switch the visibility of the given column """
diff --git a/listview.py b/listview.py
index 7a1769a..8356bfc 100644
--- a/listview.py
+++ b/listview.py
@@ -16,42 +16,39 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-import gobject
-import gtk
-import pango
-import sys
-from gettext import gettext as _
-import logging
+from gi.repository import GObject
+from gi.repository import Gtk
+from gi.repository import Pango
 
+from gettext import gettext as _
 from extListview import ExtListView
 
-_logger = logging.getLogger('get-ia-books-activity')
-
 
 class ListView(ExtListView):
-    __txtRdr = gtk.CellRendererText()
-    __txtRdr.props.wrap_mode = pango.WRAP_WORD
+    __txtRdr = Gtk.CellRendererText()
+    __txtRdr.props.wrap_mode = Pango.WrapMode.WORD
     __txtRdr.props.wrap_width = 500
     __txtRdr.props.width = 500
     (ROW_TITLE, ROW_AUTHOR, ROW_PUBLISHER,
     ROW_LANGUAGE, ROW_PUB_DATE, ROW_BOOK) = range(6)
 
-    columns = ((_('Title'), [(__txtRdr, gobject.TYPE_STRING)],
+    columns = ((_('Title'), [(__txtRdr, GObject.TYPE_STRING)],
                     (ROW_TITLE,), False, True),
-               (_('Author'), [(__txtRdr, gobject.TYPE_STRING)],
+               (_('Author'), [(__txtRdr, GObject.TYPE_STRING)],
                     (ROW_AUTHOR, ROW_TITLE), False,  True),
-               (_('Publisher'), [(__txtRdr, gobject.TYPE_STRING)],
+               (_('Publisher'), [(__txtRdr, GObject.TYPE_STRING)],
                     (ROW_AUTHOR, ROW_TITLE), False,  False),
-               (_('Language'), [(__txtRdr, gobject.TYPE_STRING)],
+               (_('Language'), [(__txtRdr, GObject.TYPE_STRING)],
                     (ROW_AUTHOR, ROW_TITLE), False,  False),
-               (_('Publish Date'), [(__txtRdr, gobject.TYPE_STRING)],
+               (_('Publish Date'), [(__txtRdr, GObject.TYPE_STRING)],
                     (ROW_AUTHOR, ROW_TITLE), False,  False),
-               (None, [(None, gobject.TYPE_PYOBJECT)], (None,), False, False))
+               (None, [(None, GObject.TYPE_PYOBJECT)], (None,), False, False))
+
     __gsignals__ = {
-        'selection-changed': (gobject.SIGNAL_RUN_FIRST,
-                          gobject.TYPE_NONE,
-                          ([])),
-    }
+        'selection-changed': (GObject.SignalFlags.RUN_LAST,
+                              None,
+                              ([])),
+        }
 
     def __init__(self, lang_code_handler):
         ExtListView.__init__(self, self.columns, sortable=True,
@@ -61,8 +58,8 @@ class ListView(ExtListView):
         self._lang_code_handler = lang_code_handler
 
         selection = self.get_selection()
-        selection.set_mode(gtk.SELECTION_SINGLE)
-        selection.connect("changed", self.__selection_changed_cb)
+        selection.set_mode(Gtk.SelectionMode.SINGLE)
+        selection.connect('changed', self.__selection_changed_cb)
 
     def __selection_changed_cb(self, selection):
         self.emit('selection-changed')
@@ -78,16 +75,16 @@ class ListView(ExtListView):
             try:
                 lang = self._lang_code_handler.get_full_language_name(
                                                         book.get_language())
-            except:
+            except KeyError:
                 pass
-            try:
-                rows.append([book.get_title(), book.get_author(), \
-                    book.get_publisher(), lang, \
-                    book.get_published_year(), book])
-            except:
-                _logger.debug(sys.exc_info())
 
-        self.clear()
+            rows.append([book.get_title(), book.get_author(),
+                         book.get_publisher(), lang,
+                         book.get_published_year(), book])
+
+        # README: I had to remove the self.clear() here because it
+        # made the listview to scroll to the top on Gtk3
+
         self.insertRows(rows)
 
     def get_selected_book(self):
diff --git a/opds.py b/opds.py
index fc536f3..1cd6d62 100644
--- a/opds.py
+++ b/opds.py
@@ -16,18 +16,18 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-import logging
+from gi.repository import GObject
+from gi.repository import Gtk
+
+from sugar3 import network
 
+import logging
 import threading
 import os
 import urllib
-import gobject
-import gtk
 import time
 import csv
 
-from sugar import network
-
 import sys
 sys.path.insert(0, './')
 import feedparser
@@ -39,7 +39,7 @@ _REL_SUBSECTION = 'subsection'
 _REL_OPDS_POPULAR = u'http://opds-spec.org/sort/popular'
 _REL_OPDS_NEW = u'http://opds-spec.org/sort/new'
 
-gobject.threads_init()
+GObject.threads_init()
 
 
 class ReadURLDownloader(network.GlibURLDownloader):
@@ -100,7 +100,7 @@ class DownloadThread(threading.Thread):
 
         self.obj._feedobj = feedobj
         self.obj._ready = True
-        gobject.idle_add(self.obj.notify_updated, self.midway)
+        GObject.idle_add(self.obj.notify_updated, self.midway)
         return False
 
     def run(self):
@@ -222,16 +222,16 @@ class Book(object):
         return False
 
 
-class QueryResult(gobject.GObject):
+class QueryResult(GObject.GObject):
 
     __gsignals__ = {
-        'updated': (gobject.SIGNAL_RUN_FIRST,
-                          gobject.TYPE_NONE,
-                          ([gobject.TYPE_BOOLEAN])),
+        'updated': (GObject.SignalFlags.RUN_FIRST,
+                          None,
+                          ([bool])),
     }
 
     def __init__(self, configuration, queryterm, language):
-        gobject.GObject.__init__(self)
+        GObject.GObject.__init__(self)
         self._configuration = configuration
         self._uri = self._configuration['query_uri']
         self._queryterm = queryterm
@@ -369,7 +369,7 @@ class DownloadIAThread(threading.Thread):
         self._download_content_type = None
         self._booklist = []
         queryterm = self.obj._queryterm
-        search_tuple = queryterm.lower().split()
+        # search_tuple = queryterm.lower().split()
         FL = urllib.quote('fl[]')
         SORT = urllib.quote('sort[]')
         self.search_url = 'http://www.archive.org/advancedsearch.php?q=' +  \
@@ -384,7 +384,7 @@ class DownloadIAThread(threading.Thread):
         self.stopthread = threading.Event()
 
     def _download(self):
-        gobject.idle_add(self.download_csv, self.search_url)
+        GObject.idle_add(self.download_csv, self.search_url)
 
     def download_csv(self, url):
         logging.error('get csv from %s', url)
@@ -428,7 +428,7 @@ class DownloadIAThread(threading.Thread):
         reader.next()  # skip the first header row.
         for row in reader:
             if len(row) < 7:
-                _logger.debug("Server Error",  self.search_url)
+                _logger.debug("Server Error: %s",  self.search_url)
                 return
             entry = {}
             entry['author'] = row[0]
@@ -461,7 +461,7 @@ class DownloadIAThread(threading.Thread):
             self.obj._booklist.append(IABook(None, entry, ''))
 
         os.remove(tempfile)
-        gobject.idle_add(self.obj.notify_updated, self.midway)
+        GObject.idle_add(self.obj.notify_updated, self.midway)
         self.obj._ready = True
         return False
 
@@ -478,7 +478,7 @@ class InternetArchiveQueryResult(QueryResult):
     # because the server implementation is not working very well
 
     def __init__(self, queryterm, language, activity):
-        gobject.GObject.__init__(self)
+        GObject.GObject.__init__(self)
         self._activity = activity
         self._queryterm = queryterm
         self._language = language
@@ -519,7 +519,7 @@ class ImageDownloaderThread(threading.Thread):
             self._getter.start(path)
         except:
             _logger.debug("Connection timed out for")
-            gobject.idle_add(self.obj.notify_updated, None)
+            GObject.idle_add(self.obj.notify_updated, None)
 
         self._download_content_length = \
                 self._getter.get_content_length()
@@ -529,7 +529,7 @@ class ImageDownloaderThread(threading.Thread):
         _logger.debug("Got Cover Image %s (%s)", tempfile, suggested_name)
         self._getter = None
         if not self.stopthread.is_set():
-            gobject.idle_add(self.obj.notify_updated, tempfile)
+            GObject.idle_add(self.obj.notify_updated, tempfile)
 
     def _get_image_progress_cb(self, getter, bytes_downloaded):
         if self.stopthread.is_set():
@@ -545,15 +545,15 @@ class ImageDownloaderThread(threading.Thread):
         else:
             _logger.debug("Downloaded %u bytes...",
                           bytes_downloaded)
-        while gtk.events_pending():
-            gtk.main_iteration()
+        while Gtk.events_pending():
+            Gtk.main_iteration()
 
     def _get_image_error_cb(self, getter, err):
         _logger.debug("Error getting image: %s", err)
         self._download_content_length = 0
         self._download_content_type = None
         self._getter = None
-        gobject.idle_add(self.obj.notify_updated, None)
+        GObject.idle_add(self.obj.notify_updated, None)
 
     def run(self):
         self._download_image()
@@ -562,16 +562,16 @@ class ImageDownloaderThread(threading.Thread):
         self.stopthread.set()
 
 
-class ImageDownloader(gobject.GObject):
+class ImageDownloader(GObject.GObject):
 
     __gsignals__ = {
-        'updated': (gobject.SIGNAL_RUN_FIRST,
-                          gobject.TYPE_NONE,
-                          ([gobject.TYPE_STRING])),
+        'updated': (GObject.SignalFlags.RUN_FIRST,
+                          None,
+                          ([GObject.TYPE_STRING])),
     }
 
     def __init__(self, activity, url):
-        gobject.GObject.__init__(self)
+        GObject.GObject.__init__(self)
         self.threads = []
         self._activity = activity
         self._url = url
diff --git a/setup.py b/setup.py
index d3ab3a3..2f2c143 100755
--- a/setup.py
+++ b/setup.py
@@ -16,6 +16,6 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-from sugar.activity import bundlebuilder
+from sugar3.activity import bundlebuilder
 
 bundlebuilder.start()
-- 
1.7.10.2



More information about the Sugar-devel mailing list