[kupfer: 1/53] Allow to manually configure default actions for objects
- From: Ulrik Sverdrup <usverdrup src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [kupfer: 1/53] Allow to manually configure default actions for objects
- Date: Thu, 24 Mar 2011 16:30:38 +0000 (UTC)
commit fdd2e101a8b2c36eb01b7ee5d6a64512517013b0
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date: Thu Mar 24 17:22:31 2011 +0100
Allow to manually configure default actions for objects
kupfer/core/data.py | 42 +++++++++++++++++++++++++++++++++++++++---
kupfer/core/learn.py | 36 +++++++++++++++++++++++++++++++++++-
kupfer/core/search.py | 3 ++-
kupfer/ui/browser.py | 23 +++++++++++++++++++++++
4 files changed, 99 insertions(+), 5 deletions(-)
---
diff --git a/kupfer/core/data.py b/kupfer/core/data.py
index f9f3bf9..08d3a8d 100644
--- a/kupfer/core/data.py
+++ b/kupfer/core/data.py
@@ -145,11 +145,13 @@ class Searcher (object):
match, match_iter = peekfirst(decorator(valid_check(unique_matches)))
return match, match_iter
- def rank_actions(self, objects, key, item_check=None, decorator=None):
+ def rank_actions(self, objects, key, leaf, item_check=None, decorator=None):
"""
rank @objects, which should be a sequence of KupferObjects,
for @key, with the action ranker algorithm.
+ @leaf is the Leaf the action is going to be invoked on
+
Filters and return value like .score().
"""
if not item_check: item_check = identity
@@ -160,7 +162,7 @@ class Searcher (object):
rankables = search.score_objects(rankables, key)
matches = search.bonus_objects(rankables, key)
else:
- matches = search.score_actions(rankables)
+ matches = search.score_actions(rankables, leaf)
matches = sorted(matches, key=operator.attrgetter("rank"), reverse=True)
match, match_iter = peekfirst(decorator(matches))
@@ -348,7 +350,7 @@ class PrimaryActionPane (Pane):
if is_valid_cached(obj.object):
yield obj
- match, match_iter = self.searcher.rank_actions(actions, key,
+ match, match_iter = self.searcher.rank_actions(actions, key, leaf,
decorator=valid_decorator)
self.emit_search_result(match, match_iter, context)
@@ -839,6 +841,40 @@ class DataController (gobject.GObject, pretty.OutputMixin):
if found and not found == self.source_pane.get_selection():
self._insert_object(SourcePane, found)
+ def mark_as_default(self, pane):
+ """
+ Make the object selected on @pane as default
+ for the selection in previous pane.
+ """
+ if pane is SourcePane or pane is ObjectPane:
+ raise RuntimeError("Setting default on pane 1 or 3 not supported")
+ obj = self.source_pane.get_selection()
+ act = self.action_pane.get_selection()
+ assert obj and act
+ learn.set_correlation(act, obj)
+
+ def get_object_has_affinity(self, pane):
+ """
+ Return ``True`` if we have any recorded affinity
+ for the object selected in @pane
+ """
+ panectl = self._panectl_table[pane]
+ selection = panectl.get_selection()
+ if not selection:
+ return None
+ return learn.get_object_has_affinity(selection)
+
+ def erase_object_affinity(self, pane):
+ """
+ Erase all learned and configured affinity for
+ the selection of @pane
+ """
+ panectl = self._panectl_table[pane]
+ selection = panectl.get_selection()
+ if not selection:
+ return None
+ return learn.erase_object_affinity(selection)
+
def compose_selection(self):
leaf, action, iobj = self._get_current_command_objects()
if leaf is None:
diff --git a/kupfer/core/learn.py b/kupfer/core/learn.py
index fe31139..4369f40 100644
--- a/kupfer/core/learn.py
+++ b/kupfer/core/learn.py
@@ -6,6 +6,7 @@ from kupfer import conspickle
from kupfer import pretty
mnemonics_filename = "mnemonics.pickle"
+CORRELATION_KEY = 'kupfer.bonus.correlation'
class Mnemonics (object):
"""
@@ -102,6 +103,39 @@ def get_record_score(obj, key=u""):
mnscore += 50 * (1 - 1.0/(exact + 1))
return fav + mnscore
+
+def get_correlation_bonus(obj, for_leaf):
+ """
+ Get the bonus rank for @obj when used with @for_leaf
+ """
+ if _register.setdefault(CORRELATION_KEY, {}).get(repr(for_leaf)) == repr(obj):
+ return 50
+ else:
+ return 0
+
+def set_correlation(obj, for_leaf):
+ """
+ Register @obj to get a bonus when used with @for_leaf
+ """
+ _register.setdefault(CORRELATION_KEY, {})[repr(for_leaf)] = repr(obj)
+
+def _get_mnemonic_items(in_register):
+ return [(k,v) for k,v in in_register.items() if k != CORRELATION_KEY]
+
+def get_object_has_affinity(obj):
+ """
+ Return if @obj has any positive score in the register
+ """
+ return bool(_register.get(repr(obj)) or
+ _register.get(CORRELATION_KEY, {}).get(repr(obj)))
+
+def erase_object_affinity(obj):
+ """
+ Remove all track of affinity for @obj
+ """
+ _register.pop(repr(obj), None)
+ _register.get(CORRELATION_KEY, {}).pop(repr(obj), None)
+
def _prune_register():
"""
Remove items with chance (len/25000)
@@ -121,7 +155,7 @@ def _prune_register():
alpha = flux/goalitems**2
chance = min(0.1, len(_register)*alpha)
- for leaf, mn in _register.items():
+ for leaf, mn in _get_mnemonic_items(_register):
if rand() > chance:
continue
mn.decrement()
diff --git a/kupfer/core/search.py b/kupfer/core/search.py
index 26a2278..d7240fa 100644
--- a/kupfer/core/search.py
+++ b/kupfer/core/search.py
@@ -75,13 +75,14 @@ def score_objects(rankables, key):
yield rb
-def score_actions(rankables):
+def score_actions(rankables, for_leaf):
"""Alternative (rigid) scoring mechanism for objects,
putting much more weight in rank_adjust
"""
get_record_score = learn.get_record_score
for obj in rankables:
ra = obj.object.rank_adjust
+ ra += learn.get_correlation_bonus(obj.object, for_leaf)
if ra > 0:
obj.rank = 50 + ra + get_record_score(obj.object)//2
elif ra == 0:
diff --git a/kupfer/ui/browser.py b/kupfer/ui/browser.py
index 3c5a153..0d269ba 100644
--- a/kupfer/ui/browser.py
+++ b/kupfer/ui/browser.py
@@ -1344,6 +1344,17 @@ class Interface (gobject.GObject):
def compose_action(self):
self.data_controller.compose_selection()
+ def mark_as_default(self):
+ if self.action.get_match_state() != State.Match:
+ return False
+ self.data_controller.mark_as_default(data.ActionPane)
+ return True
+
+ def erase_affinity_for_first_pane(self):
+ self.data_controller.erase_object_affinity(data.SourcePane)
+ return True
+
+
def comma_trick(self):
if self.current.get_match_state() != State.Match:
return False
@@ -1367,6 +1378,18 @@ class Interface (gobject.GObject):
yield (_("Select Selected Text"), self.select_selected_text)
if self.get_can_enter_text_mode():
yield (_("Toggle Text Mode"), self.toggle_text_mode_quick)
+ if self.action.get_match_state() == State.Match:
+ match = self.action.get_current()
+ # TRANS: Remember = Make the action '%s' default
+ yield (_('Remember "%s" for this Object') % unicode(match),
+ self.mark_as_default)
+ if self.search.get_match_state() == State.Match:
+ if self.data_controller.get_object_has_affinity(data.SourcePane):
+ match = self.search.get_current()
+ # TRANS: Affinity= learned and/or configured bonus rank
+ # TRANS: when matching it in search
+ yield (_('Forget Affinity for "%s"') % unicode(match),
+ self.erase_affinity_for_first_pane)
def _pane_reset(self, controller, pane, item):
wid = self._widget_for_pane(pane)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]