Ticket #4398: feedback_in_zoom_views.patch

File feedback_in_zoom_views.patch, 22.0 KB (added by manuq, 10 years ago)

Adds feedback to the zoom views.

  • src/jarabe/desktop/favoriteslayout.py

    diff --git a/src/jarabe/desktop/favoriteslayout.py b/src/jarabe/desktop/favoriteslayout.py
    index 635a534..6e2a195 100644
    a b class ViewLayout(Layout): 
    5252        self._width = 0
    5353        self._height = 0
    5454
    55     def setup(self, allocation, owner_icon, activity_icon=None):
     55    def setup(self, allocation, owner_icon, activity_icon=None,
     56              message_box=None):
    5657        if self._grid is not None:
    5758            if self._width == allocation.width and \
    5859                    self._height == allocation.height:
    class ViewLayout(Layout): 
    6263        self._grid = Grid(int(allocation.width / _CELL_SIZE),
    6364                          int(allocation.height / _CELL_SIZE))
    6465        self._grid.connect('child-changed', self.__grid_child_changed_cb)
    65         self._allocate_owner_icon(allocation, owner_icon, activity_icon)
     66        self.allocate_fixed_icons(allocation, owner_icon, activity_icon,
     67                                  message_box)
     68
     69    def remove(self, child):
     70        if self._grid is None:
     71            # the Grid is created during allocation time, so it might not
     72            # exist yet when this method is called, SL #3814
     73            return
     74
     75        if self._grid.is_in_grid(child):
     76            self._grid.remove(child)
     77
     78    def allocate_fixed_icons(self, allocation, owner_icon, activity_icon,
     79                             message_box):
     80        # Add owner icon to the grid, precisely centered on the
     81        # screen.  If activity_icon is not None, add it directly below
     82        # the owner icon.  Also if message_box is not None, add it
     83        # below the previously added icon.
    6684
    67     def _allocate_owner_icon(self, allocation, owner_icon, activity_icon):
    68         # add owner icon to the grid, precisely centered on the screen
    69         # if not None, add an activity icon directly below the owner icon
    7085        owner_request = owner_icon.size_request()
    7186        owner_width, owner_height = owner_request.width, owner_request.height
    7287        height = allocation.height + allocation.y
    class ViewLayout(Layout): 
    8499        # coordinate for the top of the owner icon.
    85100        y -= owner_height / 2
    86101
     102        current_y = allocation.y + y
     103
    87104        # calculate x coordinate and create allocation
    88105        owner_icon_allocation = Gdk.Rectangle()
    89106        owner_icon_allocation.x = (width - owner_width) / 2
    90         owner_icon_allocation.y = allocation.y + y
     107        owner_icon_allocation.y = current_y
    91108        owner_icon_allocation.width = owner_width
    92109        owner_icon_allocation.height = owner_height
    93110        owner_icon.size_allocate(owner_icon_allocation)
    class ViewLayout(Layout): 
    100117        self._grid.add(owner_icon, owner_grid_width, owner_grid_height,
    101118                       grid_x, grid_y, locked=True)
    102119
    103         if activity_icon is None:
    104             return
    105 
    106         # Position the current activity below the XO icon
    107         # FIXME must ensure we cross into next grid cell here..
    108         activity_request = activity_icon.size_request()
    109         activity_icon_allocation = Gdk.Rectangle()
    110         activity_icon_allocation.x = (width - activity_request.width) / 2
    111         activity_icon_allocation.y = owner_icon_allocation.y + owner_height
    112         activity_icon_allocation.width = activity_request.width
    113         activity_icon_allocation.height = activity_request.height
    114         activity_icon.size_allocate(activity_icon_allocation)
    115 
    116         # Determine grid coordinates and add to grid
    117         activity_grid_width, activity_grid_height = \
    118             self._get_child_grid_size(activity_icon)
    119         x = int(activity_icon_allocation.x / float(_CELL_SIZE))
    120         y = int(activity_icon_allocation.y / float(_CELL_SIZE))
    121         self._grid.add(activity_icon, activity_grid_width,
    122                        activity_grid_height, x, y, locked=True)
     120        current_y += owner_height
     121
     122        if activity_icon is not None:
     123            # Position the current activity below the XO icon
     124            # FIXME must ensure we cross into next grid cell here..
     125            activity_request = activity_icon.size_request()
     126            activity_icon_allocation = Gdk.Rectangle()
     127            activity_icon_allocation.x = (width - activity_request.width) / 2
     128            activity_icon_allocation.y = current_y
     129            activity_icon_allocation.width = activity_request.width
     130            activity_icon_allocation.height = activity_request.height
     131            activity_icon.size_allocate(activity_icon_allocation)
     132
     133            # Determine grid coordinates and add to grid
     134            activity_grid_width, activity_grid_height = \
     135                self._get_child_grid_size(activity_icon)
     136            x = int(activity_icon_allocation.x / float(_CELL_SIZE))
     137            y = int(activity_icon_allocation.y / float(_CELL_SIZE))
     138            self._grid.add(activity_icon, activity_grid_width,
     139                           activity_grid_height, x, y, locked=True)
     140
     141            current_y += activity_icon_allocation.height
     142
     143        if message_box is not None:
     144            # Position the current activity below the XO icon
     145            # FIXME must ensure we cross into next grid cell here..
     146            size_request = message_box.size_request()
     147            allocation = Gdk.Rectangle()
     148            allocation.x = (width - size_request.width) / 2
     149            allocation.y = current_y
     150            allocation.width = size_request.width
     151            allocation.height = size_request.height
     152            message_box.size_allocate(allocation)
     153
     154            # Determine grid coordinates and add to grid
     155            grid_width, grid_height = \
     156                self._get_child_grid_size(message_box)
     157            x = int(allocation.x / float(_CELL_SIZE))
     158            y = int(allocation.y / float(_CELL_SIZE))
     159            self._grid.add(message_box, grid_width,
     160                           grid_height, x, y, locked=True)
     161
     162            current_y += allocation.height
    123163
    124164    def allocate_children(self, allocation, children):
    125165        pass
    class SpreadLayout(ViewLayout): 
    160200    def __init__(self):
    161201        ViewLayout.__init__(self)
    162202
    163     def remove(self, child):
    164         if self._grid is None:
    165             # the Grid is created during allocation time, so it might not
    166             # exist yet when this method is called, SL #3814
    167             return
    168 
    169         if self._grid.is_in_grid(child):
    170             self._grid.remove(child)
    171 
    172203    def allocate_children(self, allocation, children):
    173204        for child in children:
    174205            if not self._grid.is_in_grid(child):
  • src/jarabe/desktop/favoritesview.py

    diff --git a/src/jarabe/desktop/favoritesview.py b/src/jarabe/desktop/favoritesview.py
    index a9358f6..909a367 100644
    a b from gi.repository import GdkPixbuf 
    2929from sugar3.graphics import style
    3030from sugar3.graphics.icon import Icon
    3131from sugar3.graphics.icon import CanvasIcon
     32from sugar3.graphics.messagebox import MessageBox
    3233from sugar3.graphics.palettemenu import PaletteMenuBox
    3334from sugar3.graphics.palettemenu import PaletteMenuItem
    3435from sugar3.graphics.palettemenu import PaletteMenuItemSeparator
    _favorites_settings = None 
    7475class FavoritesBox(Gtk.VBox):
    7576    __gtype_name__ = 'SugarFavoritesBox'
    7677
     78    __gsignals__ = {
     79        'clear-clicked': (GObject.SignalFlags.RUN_FIRST, None, ([])),
     80    }
     81
    7782    def __init__(self):
    7883        Gtk.VBox.__init__(self)
    7984
    class FavoritesView(ViewContainer): 
    192197    layout = property(None, _set_layout)
    193198
    194199    def do_add(self, child):
    195         if child != self._owner_icon and child != self._activity_icon:
     200        if child not in self._get_fixed_icons():
    196201            self._children.append(child)
    197202            child.connect('button-press-event', self.__button_press_cb)
    198203            child.connect('button-release-event', self.__button_release_cb)
    class FavoritesView(ViewContainer): 
    340345
    341346    def set_filter(self, query):
    342347        query = query.strip()
     348        matches = 0
    343349        for icon in self.get_children():
    344             if icon not in [self._owner_icon, self._activity_icon]:
     350            if icon not in self._get_fixed_icons():
    345351                activity_name = icon.get_activity_name().decode('utf-8')
    346352                normalized_name = normalize_string(activity_name)
    347353                if normalized_name.find(query) > -1:
    348354                    icon.alpha = 1.0
     355                    matches += 1
    349356                else:
    350357                    icon.alpha = 0.33
    351358
     359        if not matches:
     360            self._add_clear_message()
     361        else:
     362            self._remove_message()
     363
    352364    def __register_activate_cb(self, icon):
    353365        alert = Alert()
    354366        try:
    class FavoritesView(ViewContainer): 
    377389            if hasattr(icon, 'set_resume_mode'):
    378390                icon.set_resume_mode(self._resume_mode)
    379391
     392    def _add_clear_message(self):
     393        self._message_box = MessageBox(_('No matching activities'))
     394        self.add(self._message_box)
     395        self._message_box.show()
     396
     397        clear_button = Gtk.Button(label=_('Clear search'))
     398        clear_button.connect('clicked', self.__clear_button_clicked_cb)
     399        clear_button.props.image = Icon(icon_name='dialog-cancel',
     400                                        icon_size=Gtk.IconSize.BUTTON)
     401        self._message_box.add_button(clear_button)
     402        clear_button.show()
     403
     404        self._relocate_fixed_icons()
     405
     406    def __clear_button_clicked_cb(self, button):
     407        self._box.emit('clear-clicked')
     408
    380409
    381410class ActivityIcon(CanvasIcon):
    382411    __gtype_name__ = 'SugarFavoriteActivityIcon'
  • src/jarabe/desktop/groupbox.py

    diff --git a/src/jarabe/desktop/groupbox.py b/src/jarabe/desktop/groupbox.py
    index 91c9cb5..37873ff 100644
    a b  
    1515# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1616
    1717import logging
     18from gettext import gettext as _
     19
     20from gi.repository import Gtk
     21from gi.repository import GObject
    1822
    1923from sugar3.graphics import style
     24from sugar3.graphics.icon import Icon
     25from sugar3.graphics.messagebox import MessageBox
    2026
    2127from jarabe.view.buddyicon import BuddyIcon
    2228from jarabe.model.buddy import get_owner_instance
    from jarabe.util.normalize import normalize_string 
    3036class GroupBox(ViewContainer):
    3137    __gtype_name__ = 'SugarGroupBox'
    3238
     39    __gsignals__ = {
     40        'clear-clicked': (GObject.SignalFlags.RUN_FIRST, None, ([])),
     41    }
     42
    3343    def __init__(self, toolbar):
    3444        logging.debug('STARTUP: Loading the group view')
    3545
    class GroupBox(ViewContainer): 
    4454        toolbar.connect('query-changed', self._toolbar_query_changed_cb)
    4555        toolbar.search_entry.connect('icon-press',
    4656                                     self.__clear_icon_pressed_cb)
     57        self.connect('clear-clicked',
     58                     self.__clear_clicked_cb, toolbar)
     59
    4760        self._friends = {}
    4861
    4962        friends_model = friends.get_model()
    class GroupBox(ViewContainer): 
    5164        for friend in friends_model:
    5265            self.add_friend(friend)
    5366
     67        if not self._friends:
     68            self._add_no_friends_message()
     69
    5470        friends_model.connect('friend-added', self._friend_added_cb)
    5571        friends_model.connect('friend-removed', self._friend_removed_cb)
    5672
    class GroupBox(ViewContainer): 
    6379    def _friend_added_cb(self, data_model, buddy_info):
    6480        self.add_friend(buddy_info)
    6581
     82        if len(self._friends) == 1:
     83            self._remove_message()
     84
    6685    def _friend_removed_cb(self, data_model, key):
    6786        icon = self._friends[key]
    6887        self.remove(icon)
    6988        del self._friends[key]
    7089        icon.destroy()
    7190
     91        if not self._friends:
     92            self._add_no_friends_message()
     93
    7294    def _toolbar_query_changed_cb(self, toolbar, query):
    7395        self._query = normalize_string(query.decode('utf-8'))
    74         for icon in self.get_children():
     96
     97        # There are no friends.
     98        if not self._friends:
     99            return
     100
     101        children = [child for child in self.get_children()
     102                    if child not in self._get_fixed_icons()]
     103
     104        matches = 0
     105        for icon in children:
    75106            if hasattr(icon, 'set_filter'):
    76                 icon.set_filter(self._query)
     107                filtered = icon.set_filter(self._query)
     108                if not filtered:
     109                    matches += 1
     110
     111        # There are friends, but no one matches the search.
     112        if not matches:
     113            self._add_clear_message()
     114            return
     115
     116        # There are friends and they match the search.
     117        self._remove_message()
    77118
    78119    def __clear_icon_pressed_cb(self, entry, icon_pos, event):
    79120        self.grab_focus()
     121
     122    def _add_no_friends_message(self):
     123        self._remove_message()
     124
     125        self._message_box = MessageBox(_('There are no friends'))
     126        self.add(self._message_box)
     127        self._message_box.show()
     128
     129        self._relocate_fixed_icons()
     130
     131    def _add_clear_message(self):
     132        self._remove_message()
     133
     134        self._message_box = MessageBox(_('No matching friends'))
     135        self.add(self._message_box)
     136        self._message_box.show()
     137
     138        clear_button = Gtk.Button(label=_('Clear search'))
     139        clear_button.connect('clicked', self.__clear_button_clicked_cb)
     140        clear_button.props.image = Icon(icon_name='dialog-cancel',
     141                                        icon_size=Gtk.IconSize.BUTTON)
     142        self._message_box.add_button(clear_button)
     143        clear_button.show()
     144
     145        self._relocate_fixed_icons()
     146
     147    def __clear_button_clicked_cb(self, button):
     148        self.emit('clear-clicked')
     149
     150    def __clear_clicked_cb(self, widget, toolbar):
     151        toolbar.clear_query()
  • src/jarabe/desktop/homebox.py

    diff --git a/src/jarabe/desktop/homebox.py b/src/jarabe/desktop/homebox.py
    index b87c345..99d0dcb 100644
    a b class HomeBox(Gtk.VBox): 
    4848        toolbar.connect('view-changed', self.__toolbar_view_changed_cb)
    4949        toolbar.search_entry.connect('icon-press',
    5050                                     self.__clear_icon_pressed_cb)
     51        self._favorites_box.connect('clear-clicked',
     52                                    self.__clear_clicked_cb, toolbar)
    5153        self._list_view.connect('clear-clicked',
    52                                 self.__activitylist_clear_clicked_cb, toolbar)
     54                                self.__clear_clicked_cb, toolbar)
    5355
    5456        self._set_view(_FAVORITES_VIEW)
    5557        self._query = ''
    class HomeBox(Gtk.VBox): 
    108110    def __toolbar_view_changed_cb(self, toolbar, view):
    109111        self._set_view(view)
    110112
    111     def __activitylist_clear_clicked_cb(self, widget, toolbar):
     113    def __clear_clicked_cb(self, widget, toolbar):
    112114        toolbar.clear_query()
    113115
    114116    def __clear_icon_pressed_cb(self, entry, icon_pos, event):
  • src/jarabe/desktop/meshbox.py

    diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
    index bc5dbde..baab5d2 100644
    a b from gi.repository import Gtk 
    2727from gi.repository import GConf
    2828
    2929from sugar3.graphics.icon import Icon
     30from sugar3.graphics.messagebox import MessageBox
    3031from sugar3.graphics.icon import CanvasIcon
    3132from sugar3.graphics import style
    3233from sugar3.graphics.palette import Palette
    class NetworkManagerObserver(object): 
    347348class MeshBox(ViewContainer):
    348349    __gtype_name__ = 'SugarMeshBox'
    349350
     351    __gsignals__ = {
     352        'clear-clicked': (GObject.SignalFlags.RUN_FIRST, None, ([])),
     353    }
     354
    350355    def __init__(self, toolbar):
    351356        logging.debug('STARTUP: Loading the mesh view')
    352357
    class MeshBox(ViewContainer): 
    373378        toolbar.search_entry.connect('icon-press',
    374379                                     self.__clear_icon_pressed_cb)
    375380
     381        self.connect('clear-clicked',
     382                     self.__clear_clicked_cb, toolbar)
     383
    376384        for buddy_model in self._model.get_buddies():
    377385            self._add_buddy(buddy_model)
    378386
    class MeshBox(ViewContainer): 
    597605
    598606    def _toolbar_query_changed_cb(self, toolbar, query):
    599607        self._query = normalize_string(query.decode('utf-8'))
    600         for icon in self.get_children():
     608
     609        children = [child for child in self.get_children()
     610                    if child not in self._get_fixed_icons()]
     611
     612        # There are no icons.
     613        if not children:
     614            return
     615
     616        matches = 0
     617        for icon in children:
    601618            if hasattr(icon, 'set_filter'):
    602                 icon.set_filter(self._query)
     619                filtered = icon.set_filter(self._query)
     620                if not filtered:
     621                    matches += 1
     622
     623        # There are icons, but no one matches the search.
     624        if not matches:
     625            self._add_clear_message()
     626            return
     627
     628        # There are icons and they match the search.
     629        self._remove_message()
    603630
    604631    def __clear_icon_pressed_cb(self, entry, icon_pos, event):
    605632        self.grab_focus()
     633
     634    def _add_clear_message(self):
     635        self._remove_message()
     636
     637        self._message_box = MessageBox(_('No matching networks or buddies'))
     638        self.add(self._message_box)
     639        self._message_box.show()
     640
     641        clear_button = Gtk.Button(label=_('Clear search'))
     642        clear_button.connect('clicked', self.__clear_button_clicked_cb)
     643        clear_button.props.image = Icon(icon_name='dialog-cancel',
     644                                        icon_size=Gtk.IconSize.BUTTON)
     645        self._message_box.add_button(clear_button)
     646        clear_button.show()
     647
     648        self._relocate_fixed_icons()
     649
     650    def __clear_button_clicked_cb(self, button):
     651        self.emit('clear-clicked')
     652
     653    def __clear_clicked_cb(self, widget, toolbar):
     654        toolbar.clear_query()
  • src/jarabe/desktop/networkviews.py

    diff --git a/src/jarabe/desktop/networkviews.py b/src/jarabe/desktop/networkviews.py
    index 63e860d..5f91e7e 100644
    a b class WirelessNetworkView(EventPulsingIcon): 
    383383        self._filtered = normalized_name.find(query) == -1
    384384        self._update_icon()
    385385        self._update_color()
     386        return self._filtered
    386387
    387388    def create_keydialog(self, response):
    388389        keydialog.create(self._ssid, self._flags, self._wpa_flags,
    class SugarAdhocView(EventPulsingIcon): 
    591592        name = self._NAME + str(self._channel)
    592593        self._filtered = name.lower().find(query) == -1
    593594        self._update_color()
     595        return self._filtered
    594596
    595597
    596598class OlpcMeshView(EventPulsingIcon):
    class OlpcMeshView(EventPulsingIcon): 
    719721    def set_filter(self, query):
    720722        self._filtered = (query != '')
    721723        self._update_color()
     724        return self._filtered
    722725
    723726    def disconnect(self):
    724727        device_object_path = self._mesh_mgr.mesh_device.object_path
  • src/jarabe/desktop/viewcontainer.py

    diff --git a/src/jarabe/desktop/viewcontainer.py b/src/jarabe/desktop/viewcontainer.py
    index 4ff690d..e95f464 100644
    a b class ViewContainer(Gtk.Container): 
    3232
    3333        self._activity_icon = None
    3434        self._owner_icon = None
     35        self._message_box = None
     36
    3537        self._layout = None
    3638
    3739        self._children = []
    class ViewContainer(Gtk.Container): 
    4749            self.add(self._activity_icon)
    4850            self._activity_icon.show()
    4951
     52    def _get_fixed_icons(self):
     53        return [self._owner_icon, self._activity_icon, self._message_box]
     54
    5055    def do_add(self, child):
    51         if child != self._owner_icon and child != self._activity_icon:
     56        if child not in self._get_fixed_icons():
    5257            self._children.append(child)
    5358        if child.get_realized():
    5459            child.set_parent_window(self.get_parent_window())
    class ViewContainer(Gtk.Container): 
    5863        was_visible = child.get_visible()
    5964        if child in self._children:
    6065            self._children.remove(child)
    61             child.unparent()
    62             self._layout.remove(child)
    63             if was_visible and self.get_visible():
    64                 self.queue_resize()
     66        child.unparent()
     67        self._layout.remove(child)
     68        if was_visible and self.get_visible():
     69            self.queue_resize()
    6570
    6671    def do_size_allocate(self, allocation):
    6772        self.set_allocation(allocation)
    6873        if self._owner_icon:
    6974            self._layout.setup(allocation, self._owner_icon,
    70                                        self._activity_icon)
     75                               self._activity_icon, self._message_box)
    7176
    7277        self._layout.allocate_children(allocation, self._children)
    7378
    class ViewContainer(Gtk.Container): 
    7883            callback(self._owner_icon)
    7984        if self._activity_icon:
    8085            callback(self._activity_icon)
     86        if self._message_box:
     87            callback(self._message_box)
     88
     89    def _remove_message(self):
     90        if self._message_box:
     91            self.remove(self._message_box)
     92            self._message_box = None
    8193
    8294    def set_layout(self, layout):
    8395        for child in self.get_children():
    8496            self.remove(child)
    8597        self._layout = layout
     98
     99    def _relocate_fixed_icons(self):
     100        # The fixed icons are allocated when this container does
     101        # size_allocate.  So we skip if this container wasn't
     102        # allocated yet, that is when allocation size = (1, 1)
     103        allocation = self.get_allocation()
     104        if allocation.width == 1 and allocation.height == 1:
     105            return
     106
     107        self._layout.allocate_fixed_icons(allocation, self._owner_icon,
     108                                          self._activity_icon,
     109                                          self._message_box)
  • src/jarabe/view/buddyicon.py

    diff --git a/src/jarabe/view/buddyicon.py b/src/jarabe/view/buddyicon.py
    index 6320113..47ce1f6 100644
    a b class BuddyIcon(CanvasIcon): 
    7272        self._filtered = (normalized_name.find(query) == -1) \
    7373                and not self._buddy.is_owner()
    7474        self._update_color()
     75        return self._filtered