[Rhythmbox-devel] search extensibility



I just committed a patch (that had been sitting around for over a year)
that rearranges how searching works, making a few interesting things
possible.

The main thing that's new is a base class for translating a search
string into a database query.  Currently this is only used to do matches
on single properties (artist, album, title, or the 'search match' property),
but it could do anything at all.

To make this useful, the RBSourceHeader object now has a couple of
signals that allow plugins to add their own items to the search bar.
It emits the 'get-search-actions' signal when rebuilding the search bar,
using the returned values to add items.  The 'refresh-search-bar' signal
triggers this rebuild, so search actions can be added at any time.

Instead of the can_search method, sources now have a search-type
property that describes how searching should be done for the source.
Sources that don't allow searching use RB_SOURCE_SEARCH_NONE for this,
which disables searching and hides the search bar.
RB_SOURCE_SEARCH_INCREMENTAL provides the current search-as-you-type
behaviour, which should be used for most sources that allow searching.
RB_SOURCE_SEARCH_EXPLICIT only triggers the search when the user hits
enter, which is more suitable for sources that do searching using a
remote web service rather than using the rhythmbox database.
No current sources do this, though.

So, probably the most interesting thing that could be done with this is
to extend the search syntax.  The database query facilities should be
rich enough to support boolean logic, or something like the xesam user
query language, but it can't do arbitrary wildcard matching or regular
expressions.  I don't see much use for those anyway.

Here's a skeleton of a python plugin that creates a new search action.
Note that the python code only constructs the query, once per search,
it's not involved in running the query at all.


import rhythmdb, rb

class NewSearch(rb.SourceSearch):
	def __init__(self):
		rb.SourceSearch.__init__(self)

	def do_create_query(self, db, search_text):
		query = db.query_new()
		# .. create query somehow ..
		return query

	def is_subset(self, cur_text, new_text):
		return False


class NewSearchPlugin(rb.Plugin):
	def __init__(self):
		rb.Plugin.__init__(self)
		self.action_name = "NewSearch"

	def get_search_actions_cb(self, header, source):
		return (self.action_name,)		

	def activate(self, shell):
		self.id = shell.props.source_header.connect("get-search-actions", self.get_search_actions_cb)

		self.action_group = gtk.ActionGroup("NewSearchPluginActions")
		action = gtk.RadioAction(self.action_name, "something", "something", None, 0)
		self.action_group.add_action(action)

		self.search = NewSearch()
		self.search.action_attach(action)
		
		shell.props.ui_manager.insert_action_group(self.action_group, 0)

		shell.props.source_header.emit("refresh-search-bar")

	def deactivate(self, shell):
		shell.props.source_header.disconnect(self.id)
		self.id = 0

		shell.props.ui_manager.remove_action_group(self.action_group)
		self.action_group = None
		self.search = None



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]