M src/pages.py => src/pages.py +9 -3
@@ 27,9 27,10 @@ from gi.repository import Dazzle
from gi.repository import Handy
import lesana
+import xapian
from .appsettings import AppSettings
-from .widgets import PlaceholderWidget
+from .widgets import PlaceholderWidget, CollectionSearchEntry
from .form import EntryForm
logger = logging.getLogger(__name__)
@@ 452,7 453,7 @@ class CollectionPageHeaderBar(BasePageTitleBar):
column = Handy.Clamp(maximum_size=500, hexpand=True)
box = Gtk.HBox()
- self.searchentry = Gtk.SearchEntry()
+ self.searchentry = CollectionSearchEntry()
self.searchentry.connect("search-changed", page.do_search)
box.pack_start(self.searchentry, True, True, 4)
box.pack_start(self.searchmenubtn, False, False, 0)
@@ 503,6 504,7 @@ class CollectionPageHeaderBar(BasePageTitleBar):
for k in search_aliases.keys():
self.searchmenumodel.append(k, f"win.searchalias({k!r})")
self.searchmenubtn.set_visible(bool(search_aliases))
+ self.searchentry.set_autocompletition(self.page.collection)
def on_back_button_clicked(self, *args):
win = self.page.window
@@ 557,7 559,11 @@ class CollectionPage(BaseListPage):
self.collection.start_search("*")
return self.collection.get_all_search_results()
else:
- self.collection.start_search(self.query)
+ try:
+ self.collection.start_search(self.query)
+ except xapian.QueryParserError as e:
+ logger.info(e)
+
return self.collection.get_all_search_results()
def build_row(self, obj):
M src/widgets.py => src/widgets.py +47 -0
@@ 16,6 16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
+from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import GtkSource
@@ 220,3 221,49 @@ class CommitDialog(Gtk.Dialog):
def get_message(self):
return self.message.get_text()
+
+
+class CollectionSearchEntry(Gtk.SearchEntry):
+ def __init__(self):
+ super().__init__()
+ self.model = Gtk.ListStore(GObject.TYPE_STRING)
+ self.model.append(["culo"])
+ completion = Gtk.EntryCompletion.new()
+ completion.set_model(self.model)
+ completion.set_text_column(0)
+ completion.set_match_func(self._match)
+ completion.connect("match-selected", self._match_selected)
+ self.set_completion(completion)
+
+ def _match(self, completion, key, iter, user_data=None) -> bool:
+
+ cp = self.props.cursor_position
+ k = key[:cp].split(" ")[-1]
+ return self.model.get(iter, 0)[0].startswith(k)
+
+ def _match_selected(self, completion, model, iter) -> bool:
+ # replace the word under cursor position
+ v = model.get(iter, 0)[0]
+
+ t = self.get_text()
+ cp = self.props.cursor_position
+ pre = t[:cp].split(" ")[:-1]
+ post = t[cp:].split(" ")[1:]
+ newt = pre + [v] + post
+
+ newcp = len(" ".join(pre)) + len(v) + 1
+
+ self.set_text(" ".join(newt))
+ self.emit("move_cursor", Gtk.MovementStep.LOGICAL_POSITIONS, -cp, False)
+ self.emit("move_cursor", Gtk.MovementStep.LOGICAL_POSITIONS, newcp, False)
+ return True
+
+ def set_autocompletition(self, collection) -> None:
+ self.model.clear()
+ for field in collection.settings.get('fields', []):
+ name = field.get('name', None)
+ if name:
+ self.model.append([f"{name}:"])
+ if 'values' in field:
+ for value in field.get('values'):
+ self.model.append([f"{name}:{value} "])