From fe774bf35bffed6249b8cc0feaa3859aca7ca4ea Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Thu, 12 Jun 2008 14:11:25 +0000 Subject: First go at autocompletion. Still using a fake, in-memory backend. --- diff --git a/globalhistory.py b/globalhistory.py new file mode 100644 index 0000000..635deca --- /dev/null +++ b/globalhistory.py @@ -0,0 +1,81 @@ +# Copyright (C) 2008, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from xpcom import components +from xpcom.components import interfaces +from xpcom.server.factory import Factory + +import places + +_global_history = None + +class GlobalHistory: + _com_interfaces_ = interfaces.nsIGlobalHistory, \ + interfaces.nsIGlobalHistory2, \ + interfaces.nsIGlobalHistory3 + + cid = '{2a53cf28-c48e-4a01-ba18-3d3fef3e2985}' + description = 'Sugar Global History' + + def __init__(self): + self._store = places.get_store() + + def addPage(self, url): + self.addURI(url, False, True, None) + + def isVisited(self, uri): + place = self._store.lookup_place(uri.spec) + return place != None + + def addURI(self, uri, redirect, toplevel, referrer): + place = places.Place(uri.spec) + + place.redirect = redirect + place.toplevel = toplevel + place.referrer = referrer + + self._store.add_place(place) + + def setPageTitle(self, uri, title): + place = self._store.lookup_place(uri.spec) + if place: + place.title = title + self._store.update_place(place) + + def addDocumentRedirect(self, old_channel, new_channel, flags, toplevel): + pass + + def getURIGeckoFlags(self, uri): + place = self._store.lookup_place(uri.spec) + if place: + return place.gecko_flags + else: + return 0 + + def setURIGeckoFlags(self, uri, flags): + place = self._store.lookup_place(uri.spec) + if place: + place.gecko_flags = flags + self._store.update_place(place) + +def init(): + global _global_history + _global_history = GlobalHistory() + +components.registrar.registerFactory(GlobalHistory.cid, + GlobalHistory.description, + '@mozilla.org/browser/global-history;2', + Factory(GlobalHistory)) diff --git a/places.py b/places.py new file mode 100644 index 0000000..481c16b --- /dev/null +++ b/places.py @@ -0,0 +1,72 @@ +# Copyright (C) 2008, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +_store = None + +class Place(object): + def __init__(self, uri): + self.uri = uri + self.redirect = False + self.toplevel = True + self.referrer = None + self.title = None + self.gecko_flags = 0 + self.visits = 0 + +class MemoryStore(object): + def __init__(self): + self._places = {} + + def search(self, text): + result = [] + for place in self._places.values(): + if text in place.uri or text in place.title: + result.append(place) + return result + + def add_place(self, place): + self._places[place.uri] = place + + def lookup_place(self, uri): + try: + return self._places[uri] + except KeyError: + return None + + def update_place(self, place): + self._places[place.uri] = place + +class SQliteStore(object): + def __init__(self): + pass + + def search(self, text): + pass + + def add_place(self, place): + pass + + def lookup_place(self, uri): + pass + + def update_place(self, place): + pass + +def get_store(): + global _store + if _store == None: + _store = MemoryStore() + return _store diff --git a/webactivity.py b/webactivity.py index 4b4544a..4bf55bd 100755 --- a/webactivity.py +++ b/webactivity.py @@ -71,6 +71,7 @@ import downloadmanager import sessionhistory import progresslistener import filepicker +import globalhistory _LIBRARY_PATH = '/usr/share/library-common/index.html' @@ -100,6 +101,7 @@ class WebActivity(activity.Activity): sessionhistory.init(self._browser) progresslistener.init(self._browser) filepicker.init(self) + globalhistory.init() toolbox = activity.ActivityToolbox(self) diff --git a/webtoolbar.py b/webtoolbar.py index 8987a37..a3c59ba 100755 --- a/webtoolbar.py +++ b/webtoolbar.py @@ -16,9 +16,11 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from gettext import gettext as _ +import logging import gobject import gtk +import pango from xpcom.components import interfaces from xpcom import components @@ -29,9 +31,124 @@ from sugar._sugarext import AddressEntry import sessionhistory import progresslistener import filepicker +import places _MAX_HISTORY_ENTRIES = 15 +class WebEntry(AddressEntry): + COL_ADDRESS = 0 + COL_TITLE = 1 + + def __init__(self): + gobject.GObject.__init__(self) + + self._popup_hid = None + self._search_view = self._search_create_view() + + self._search_window = gtk.Window(gtk.WINDOW_POPUP) + self._search_window.add(self._search_view) + self._search_view.show() + + self.connect('focus-in-event', self.__focus_in_event_cb) + self.connect('populate-popup', self.__populate_popup_cb) + self._focus_out_hid = self.connect( + 'focus-out-event', self.__focus_out_event_cb) + self._change_hid = self.connect('changed', self.__changed_cb) + + def _set_address(self, address): + self.handler_block(self._change_hid) + self._address = address + self.handler_unblock(self._change_hid) + + address = gobject.property(type=str, setter=_set_address) + + def _set_title(self, title): + self.handler_block(self._change_hid) + self._title = title + self.handler_unblock(self._change_hid) + + title = gobject.property(type=str, setter=_set_title) + + def _search_create_view(self): + view = gtk.TreeView() + view.props.headers_visible=False + + column = gtk.TreeViewColumn() + view.append_column(column) + + cell = gtk.CellRendererText() + cell.props.ellipsize = pango.ELLIPSIZE_END + cell.props.ellipsize_set = True + column.pack_start(cell, True) + + column.set_attributes(cell, text=self.COL_ADDRESS) + + cell = gtk.CellRendererText() + cell.props.ellipsize = pango.ELLIPSIZE_END + cell.props.ellipsize_set = True + cell.props.alignment = pango.ALIGN_LEFT + cell.props.font = 'Bold' + column.pack_start(cell) + + column.set_attributes(cell, text=self.COL_TITLE) + + return view + + def _search_update(self): + list_store = gtk.ListStore(str, str) + + for place in places.get_store().search(self.props.text): + list_store.append([place.uri, place.title]) + + self._search_view.set_model(list_store) + + return len(list_store) > 0 + + def _search_popup(self): + entry_x, entry_y = self.window.get_origin() + entry_w, entry_h = self.size_request() + + x = entry_x + y = entry_y + entry_h + width = self.allocation.width + height = gtk.gdk.screen_height() / 3 + + self._search_window.move(x, y) + self._search_window.resize(width, height) + self._search_window.show() + + def _search_popdown(self): + self._search_window.hide() + + def __focus_in_event_cb(self, entry, event): + self.handler_block(self._change_hid) + self.props.text = self._address + self.handler_unblock(self._change_hid) + + self._search_popdown() + + def __focus_out_event_cb(self, entry, event): + self.handler_block(self._change_hid) + self.props.text = self._title + self.handler_unblock(self._change_hid) + + self._search_popdown() + + def __popup_unmap_cb(self, entry): + self.handler_unblock(self._focus_out_hid) + + def __populate_popup_cb(self, entry, menu): + self.handler_block(self._focus_out_hid) + self.__popup_hid = menu.connect('unmap', self.__popup_unmap_cb) + + def __changed_cb(self, entry): + self._address = self.props.text + + if not self.props.text or not self._search_update(): + self._search_popdown() + else: + self._search_popup() + class WebToolbar(gtk.Toolbar): __gtype_name__ = 'WebToolbar' @@ -67,7 +184,7 @@ class WebToolbar(gtk.Toolbar): self.insert(self._stop_and_reload, -1) self._stop_and_reload.show() - self._entry = AddressEntry() + self._entry = WebEntry() self._entry.connect('activate', self._entry_activate_cb) entry_item = gtk.ToolItem() -- cgit v0.9.1