From f31daf2ba4d932ad9e255ab4bacaf7bffd12a58e Mon Sep 17 00:00:00 2001 From: Neui Date: Sun, 5 Sep 2021 18:50:31 +0200 Subject: [PATCH] Workaround: Separate saved searches with tags name Since unfortunately saved searches and tags share the same namespace, it makes it difficult to create a saved search with the exact name as an existing tag. As a current workaround until we separate them, we just prefix the saved searches with SEARCH_TAG_PREFIX, which an user is unlikely to use. From what I can see, it still displays properly in the UI after some fixes, aside from existing bugs. In the XML file this prefix isn't added, because it would be redudant and make it easier to deal with in future versions. --- GTG/backends/backend_localfile.py | 3 ++- GTG/core/datastore.py | 5 +++-- GTG/core/requester.py | 6 +++--- GTG/core/tag.py | 10 +++++++++- GTG/gtk/browser/tag_editor.py | 7 +++---- .../export/export_templates/template_simple.html | 2 +- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/GTG/backends/backend_localfile.py b/GTG/backends/backend_localfile.py index d29c42b28b..83fa3b3447 100644 --- a/GTG/backends/backend_localfile.py +++ b/GTG/backends/backend_localfile.py @@ -34,6 +34,7 @@ from GTG.core import xml from GTG.core import firstrun_tasks from GTG.core import versioning +from GTG.core.tag import SEARCH_TAG_PREFIX from typing import Dict from lxml import etree as et @@ -257,7 +258,7 @@ def save_tags(self, tagnames, tagstore) -> None: # Don't save the @ in the name element.set('id', tid) - element.set('name', tagname) + element.set('name', tag.get_friendly_name()) # Remove these and don't re-add them if not needed element.attrib.pop('icon', None) diff --git a/GTG/core/datastore.py b/GTG/core/datastore.py index 62f47a22e2..eb4a7d3643 100644 --- a/GTG/core/datastore.py +++ b/GTG/core/datastore.py @@ -30,7 +30,7 @@ from GTG.core.config import CoreConfig from GTG.core import requester from GTG.core.search import parse_search_query, search_filter, InvalidQuery -from GTG.core.tag import Tag, SEARCH_TAG +from GTG.core.tag import Tag, SEARCH_TAG, SEARCH_TAG_PREFIX from GTG.core.task import Task from GTG.core.treefactory import TreeFactory from GTG.core.borg import Borg @@ -139,6 +139,7 @@ def new_search_tag(self, name, query, attributes={}, tid=None, save=True): init_attr["label"] = name init_attr["query"] = query + name = SEARCH_TAG_PREFIX + name tag = Tag(name, req=self.requester, attributes=init_attr, tid=tid) self._add_new_tag(name, tag, search_filter, parameters, parent_id=SEARCH_TAG) @@ -206,7 +207,7 @@ def rename_tag(self, oldname, newname): newname = '_' + newname label, num = newname, 1 - while self._tagstore.has_node(label): + while self._tagstore.has_node(SEARCH_TAG_PREFIX + label): num += 1 label = newname + " " + str(num) diff --git a/GTG/core/requester.py b/GTG/core/requester.py index f0c03ee15b..8f5148658c 100644 --- a/GTG/core/requester.py +++ b/GTG/core/requester.py @@ -22,7 +22,7 @@ import logging from gi.repository import GObject -from GTG.core.tag import Tag +from GTG.core.tag import Tag, SEARCH_TAG_PREFIX log = logging.getLogger(__name__) @@ -192,7 +192,7 @@ def new_search_tag(self, query): name, number = label, 1 already_search = False while True: - tag = self.get_tag(name) + tag = self.get_tag(SEARCH_TAG_PREFIX + name) if tag is None: break @@ -207,7 +207,7 @@ def new_search_tag(self, query): if not already_search: tag = self.ds.new_search_tag(name, query) - return name + return SEARCH_TAG_PREFIX + name def remove_tag(self, name): """ calls datastore to remove a given tag """ diff --git a/GTG/core/tag.py b/GTG/core/tag.py index 07972afbea..068e5a27e6 100644 --- a/GTG/core/tag.py +++ b/GTG/core/tag.py @@ -36,6 +36,7 @@ SEP_TAG = "gtg-tags-sep" SEARCH_TAG = "search" +SEARCH_TAG_PREFIX = "__SAVED_SEARCH_" # For name inside the tagtree def extract_tags_from_text(text): """ Given a string, returns a list of the @tags contained in that """ @@ -140,9 +141,16 @@ def add_child(self, child_id): TreeNode.add_child(self, child_id) def get_name(self): - """Return the name of the tag.""" + """Return the internal name of the tag, as saved in the tree.""" return self.get_attribute("name") + def get_friendly_name(self): + """Return the name of the tag, but without the internal search tag prefix.""" + if self.is_search_tag(): + return self.get_attribute("name")[len(SEARCH_TAG_PREFIX):] + else: + return self.get_attribute("name") + def set_save_callback(self, save): self._save = save diff --git a/GTG/gtk/browser/tag_editor.py b/GTG/gtk/browser/tag_editor.py index 8b2acbd19d..bba7954319 100644 --- a/GTG/gtk/browser/tag_editor.py +++ b/GTG/gtk/browser/tag_editor.py @@ -177,8 +177,8 @@ def set_tag(self, tag): icon = tag.get_attribute('icon') self._set_emoji(self._emoji_entry, text=icon if icon else '') - self.tag_name = tag.get_name() - self.set_title(self._title_format % ('@' + tag.get_name(),)) + self.tag_name = tag.get_friendly_name() + self.set_title(self._title_format % ('@' + self.tag_name,)) rgba = Gdk.RGBA(1.0, 1.0, 1.0, 1.0) if color := tag.get_attribute('color'): @@ -187,7 +187,6 @@ def set_tag(self, tag): tag.get_name(), color) self.has_color = bool(color) self.tag_rgba = rgba - self.tag_name = tag.get_name() self.tag_is_actionable = \ self.tag.get_attribute("nonactionable") != "True" @@ -238,7 +237,7 @@ def _apply(self, widget: GObject.Object): self.tag.set_attribute('nonactionable', str(not self.tag_is_actionable)) - if self.tag_name != self.tag.get_name(): + if self.tag_name != self.tag.get_friendly_name(): log.debug("Renaming %r → %r", self.tag.get_name(), self.tag_name) self.req.rename_tag(self.tag.get_name(), self.tag_name) self.tag = self.req.get_tag(self.tag_name) diff --git a/GTG/plugins/export/export_templates/template_simple.html b/GTG/plugins/export/export_templates/template_simple.html index 2eb58c44a2..dfc6e09c27 100644 --- a/GTG/plugins/export/export_templates/template_simple.html +++ b/GTG/plugins/export/export_templates/template_simple.html @@ -159,7 +159,7 @@ ## #for $tag in $plugin_api.get_requester().get_tag_tree().get_all_nodes() -## $tag.get_name() +## $tag.get_friendly_name() ## #end for -->