#3119: Implement some basic search capabilities in the mesh view.

This commit is contained in:
Tomeu Vizoso
2007-11-04 15:07:15 +01:00
parent 45c740fb93
commit 32fc5d3161
8 changed files with 143 additions and 21 deletions
+17 -3
View File
@@ -22,9 +22,9 @@ from view.BuddyMenu import BuddyMenu
class BuddyIcon(CanvasIcon):
def __init__(self, shell, buddy, size=style.STANDARD_ICON_SIZE):
CanvasIcon.__init__(self, icon_name='computer-xo',
xo_color=buddy.get_color(), size=size)
CanvasIcon.__init__(self, icon_name='computer-xo', size=size)
self._greyed_out = False
self._shell = shell
self._buddy = buddy
self._buddy.connect('appeared', self._buddy_presence_change_cb)
@@ -34,7 +34,21 @@ class BuddyIcon(CanvasIcon):
palette = BuddyMenu(shell, buddy)
self.set_palette(palette)
self._update_color()
def _buddy_presence_change_cb(self, buddy, color=None):
# Update the icon's color when the buddy comes and goes
self.props.xo_color = buddy.get_color()
self._update_color()
def _update_color(self):
if self._greyed_out:
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
else:
self.props.xo_color = self._buddy.get_color()
def set_filter(self, query):
self._greyed_out = (self._buddy.get_nick().lower().find(query) == -1) \
and not self._buddy.is_owner()
self._update_color()
+1 -1
View File
@@ -20,12 +20,12 @@ import hippo
import gobject
from sugar import profile
from sugar.graphics.spreadlayout import SpreadLayout
from sugar.graphics import style
from sugar.graphics.icon import CanvasIcon
from sugar.graphics.palette import Palette
from view.home.FriendView import FriendView
from view.home.spreadlayout import SpreadLayout
class FriendsBox(hippo.CanvasBox):
__gtype_name__ = 'SugarFriendsBox'
+1
View File
@@ -10,4 +10,5 @@ sugar_PYTHON = \
MyIcon.py \
proc_smaps.py \
snowflakelayout.py \
spreadlayout.py \
transitionbox.py
+113 -10
View File
@@ -15,19 +15,19 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import random
from gettext import gettext as _
import logging
import hippo
import gobject
import gtk
from gettext import gettext as _
from sugar.graphics.spreadlayout import SpreadLayout
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from sugar.graphics import xocolor
from sugar.graphics.icon import get_icon_state
from sugar.graphics import style
from sugar.graphics import palette
from sugar.graphics import iconentry
from sugar import profile
from model import accesspointmodel
@@ -38,6 +38,7 @@ from hardware import nmclient
from view.BuddyIcon import BuddyIcon
from view.pulsingicon import PulsingIcon
from view.home.snowflakelayout import SnowflakeLayout
from view.home.spreadlayout import SpreadLayout
from hardware.nmclient import NM_802_11_CAP_PROTO_WEP, NM_802_11_CAP_PROTO_WPA, NM_802_11_CAP_PROTO_WPA2
@@ -50,6 +51,7 @@ class AccessPointView(PulsingIcon):
self._model = model
self._meshdev = mesh_device
self._disconnect_item = None
self._greyed_out = False
self.connect('activated', self._activate_cb)
@@ -146,11 +148,21 @@ class AccessPointView(PulsingIcon):
if self._disconnect_item:
self._disconnect_item.hide()
self.props.pulse_time = 0.0
self.props.colors = [
[ style.Color(self._device_stroke).get_svg(),
style.Color(self._device_fill).get_svg() ]
]
if self._greyed_out:
self.props.colors = [
[ style.COLOR_INACTIVE_STROKE.get_svg(),
style.COLOR_INACTIVE_FILL.get_svg() ]
]
else:
self.props.colors = [
[ style.Color(self._device_stroke).get_svg(),
style.Color(self._device_fill).get_svg() ]
]
def set_filter(self, query):
self._greyed_out = self._model.props.name.lower().find(query) == -1
self._update_state()
_MESH_ICON_NAME = 'network-mesh'
@@ -277,9 +289,81 @@ class ActivityView(hippo.CanvasBox):
bundle_id = self._model.get_bundle_id()
self._shell.join_activity(bundle_id, self._model.get_id())
def set_filter(self, query):
if self._model.activity.props.name.lower().find(query) == -1:
self._icon.xo_color = [style.COLOR_INACTIVE_STROKE.get_svg(),
style.COLOR_INACTIVE_FILL.get_svg()]
else:
self._icon.xo_color = self._model.get_color()
_AUTOSEARCH_TIMEOUT = 1000
class MeshToolbar(gtk.Toolbar):
__gtype_name__ = 'MeshToolbar'
__gsignals__ = {
'query-changed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
([str]))
}
def __init__(self):
gtk.Toolbar.__init__(self)
self._query = None
self._autosearch_timer = None
self._add_separator()
tool_item = gtk.ToolItem()
tool_item.set_expand(True)
self.insert(tool_item, -1)
tool_item.show()
self._search_entry = iconentry.IconEntry()
self._search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'system-search')
self._search_entry.add_clear_button()
self._search_entry.connect('activate', self._entry_activated_cb)
self._search_entry.connect('changed', self._entry_changed_cb)
tool_item.add(self._search_entry)
self._search_entry.show()
self._add_separator()
def _add_separator(self):
separator = gtk.SeparatorToolItem()
separator.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
separator.props.draw = False
self.insert(separator, -1)
separator.show()
def _entry_activated_cb(self, entry):
if self._autosearch_timer:
gobject.source_remove(self._autosearch_timer)
new_query = entry.props.text
if self._query != new_query:
self._query = new_query
self.emit('query-changed', self._query)
def _entry_changed_cb(self, entry):
if not entry.props.text:
entry.activate()
return
if self._autosearch_timer:
gobject.source_remove(self._autosearch_timer)
self._autosearch_timer = gobject.timeout_add(_AUTOSEARCH_TIMEOUT,
self._autosearch_timer_cb)
def _autosearch_timer_cb(self):
logging.debug('_autosearch_timer_cb')
self._autosearch_timer = None
self._search_entry.activate()
return False
class MeshBox(hippo.CanvasBox):
def __init__(self, shell):
hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff)
hippo.CanvasBox.__init__(self)
self._shell = shell
self._model = shell.get_model().get_mesh()
@@ -289,9 +373,18 @@ class MeshBox(hippo.CanvasBox):
self._mesh = {}
self._buddy_to_activity = {}
self._suspended = True
self._query = ''
self._layout = SpreadLayout()
self.set_layout(self._layout)
self._toolbar = MeshToolbar()
self._toolbar.connect('query-changed', self._toolbar_query_changed_cb)
self.append(hippo.CanvasWidget(widget=self._toolbar))
self._layout_box = hippo.CanvasBox(background_color=0xe2e2e2ff)
self.append(self._layout_box, hippo.PACK_EXPAND)
center_vertical_offset = - style.GRID_CELL_SIZE
self._layout = SpreadLayout(center_vertical_offset)
self._layout_box.set_layout(self._layout)
for buddy_model in self._model.get_buddies():
self._add_alone_buddy(buddy_model)
@@ -377,6 +470,9 @@ class MeshBox(hippo.CanvasBox):
else:
self._layout.add(icon)
if hasattr(icon, 'set_filter'):
icon.set_filter(self._query)
self._buddies[buddy_model.get_key()] = icon
def _remove_alone_buddy(self, buddy_model):
@@ -441,3 +537,10 @@ class MeshBox(hippo.CanvasBox):
self._suspended = False
for ap in self._access_points.values():
ap.props.paused = False
def _toolbar_query_changed_cb(self, toolbar, query):
self._query = query.lower()
for icon in self._layout_box.get_children():
if hasattr(icon, 'set_filter'):
icon.set_filter(self._query)
+242
View File
@@ -0,0 +1,242 @@
# Copyright (C) 2007 Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
from numpy import array
from random import random
import hippo
import gobject
import gtk
_PLACE_TRIALS = 20
_MAX_WEIGHT = 255
_CELL_SIZE = 4
class _Grid(gobject.GObject):
__gsignals__ = {
'child-changed' : (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT]))
}
def __init__(self, width, height):
gobject.GObject.__init__(self)
self.width = width
self.height = height
self._children = []
self._collisions = []
self._collisions_sid = 0
self._array = array([0], dtype='b')
self._array.resize(width * height)
def add(self, child, width, height):
trials = _PLACE_TRIALS
weight = _MAX_WEIGHT
while trials > 0 and weight:
x = int(random() * (self.width - width))
y = int(random() * (self.height - height))
rect = gtk.gdk.Rectangle(x, y, width, height)
new_weight = self._compute_weight(rect)
if weight > new_weight:
weight = new_weight
trials -= 1
child.grid_rect = rect
child.locked = False
self._add_child(child)
if weight > 0:
self._detect_collisions(child)
def remove(self, child):
self._children.remove(child)
self._remove_weight(child.grid_rect)
child.grid_rect = None
def _add_child(self, child):
self._children.append(child)
self.add_weight(child.grid_rect)
def _move_child(self, child, new_rect):
self._remove_weight(child.grid_rect)
self.add_weight(new_rect)
child.grid_rect = new_rect
self.emit('child-changed', child)
def _shift_child(self, child):
rect = child.grid_rect
weight = self._compute_weight(rect)
new_rects = []
if (rect.x + rect.width < self.width - 1):
new_rects.append(gtk.gdk.Rectangle(rect.x + 1, rect.y,
rect.width, rect.height))
if (rect.x - 1 > 0):
new_rects.append(gtk.gdk.Rectangle(rect.x - 1, rect.y,
rect.width, rect.height))
if (rect.y + rect.height < self.height - 1):
new_rects.append(gtk.gdk.Rectangle(rect.x, rect.y + 1,
rect.width, rect.height))
if (rect.y - 1 > 0):
new_rects.append(gtk.gdk.Rectangle(rect.x, rect.y - 1,
rect.width, rect.height))
best_rect = None
for new_rect in new_rects:
new_weight = self._compute_weight(new_rect)
if new_weight < weight:
best_rect = new_rect
weight = new_weight
if best_rect:
self._move_child(child, best_rect)
return weight
def _solve_collisions(self):
for collision in self._collisions[:]:
weight = self._shift_child(collision)
if not weight:
self._collisions.remove(collision)
return (len(self._collisions) > 0)
def _detect_collisions(self, child):
collision_found = False
for c in self._children:
intersection = child.grid_rect.intersect(c.grid_rect)
if c != child and intersection.width > 0:
if c not in self._collisions:
collision_found = True
self._collisions.append(c)
if collision_found:
if child not in self._collisions:
self._collisions.append(child)
# if len(self._collisions) and not self._collisions_sid:
# self._collisions_sid = gobject.idle_add(self._solve_collisions)
def add_weight(self, rect):
for i in range(rect.x, rect.x + rect.width):
for j in range(rect.y, rect.y + rect.height):
self[j, i] += 1
def _remove_weight(self, rect):
for i in range(rect.x, rect.x + rect.width):
for j in range(rect.y, rect.y + rect.height):
self[j, i] -= 1
def _compute_weight(self, rect):
weight = 0
for i in range(rect.x, rect.x + rect.width):
for j in range(rect.y, rect.y + rect.height):
weight += self[j, i]
return weight
def __getitem__(self, (row, col)):
return self._array[col + row * self.width]
def __setitem__(self, (row, col), value):
self._array[col + row * self.width] = value
class SpreadLayout(gobject.GObject, hippo.CanvasLayout):
__gtype_name__ = 'SugarSpreadLayout'
def __init__(self, center_vertical_offset=0):
gobject.GObject.__init__(self)
self._center_vertical_offset = center_vertical_offset
min_width, width = self.do_get_width_request()
min_height, height = self.do_get_height_request(width)
self._grid = _Grid(width / _CELL_SIZE, height / _CELL_SIZE)
self._grid.connect('child-changed', self._grid_child_changed_cb)
def add_center(self, child):
self._box.append(child)
width, height = self._get_child_grid_size(child)
rect = gtk.gdk.Rectangle(int((self._grid.width - width) / 2),
int((self._grid.height - height) / 2),
width + 1, height + 1)
self._grid.add_weight(rect)
box_child = self._box.find_box_child(child)
box_child.grid_rect = None
def add(self, child):
self._box.append(child)
width, height = self._get_child_grid_size(child)
box_child = self._box.find_box_child(child)
self._grid.add(box_child, width, height)
def remove(self, child):
box_child = self._box.find_box_child(child)
self._grid.remove(box_child)
self._box.remove(child)
def do_set_box(self, box):
self._box = box
def do_get_height_request(self, for_width):
return 0, gtk.gdk.screen_height()
def do_get_width_request(self):
return 0, gtk.gdk.screen_width()
def do_allocate(self, x, y, width, height,
req_width, req_height, origin_changed):
for child in self._box.get_layout_children():
rect = child.grid_rect
if child.grid_rect:
child.allocate(rect.x * _CELL_SIZE,
rect.y * _CELL_SIZE,
rect.width * _CELL_SIZE,
rect.height * _CELL_SIZE,
origin_changed)
else:
min_w, child_width = child.get_width_request()
min_h, child_height = child.get_height_request(child_width)
child_x = x + (width - child_width) / 2
child_y = y + (height - child_height + self._center_vertical_offset) / 2
child.allocate(child_x, child_y, child_width, child_height,
origin_changed)
def _get_child_grid_size(self, child):
min_width, width = child.get_width_request()
min_height, height = child.get_height_request(width)
return int(width / _CELL_SIZE), int(height / _CELL_SIZE)
def _grid_child_changed_cb(self, grid, box_child):
box_child.item.emit_request_changed()
+1 -1
View File
@@ -19,9 +19,9 @@ import gobject
from sugar.graphics import style
from sugar.graphics import animator
from sugar.graphics.spreadlayout import SpreadLayout
from view.home.MyIcon import MyIcon
from view.home.spreadlayout import SpreadLayout
class _Animation(animator.Animation):
def __init__(self, icon, start_size, end_size):