Tagging rewrite
Closed, ResolvedPublic

Description

Rewriting tagging

TODO/Tests:

  • Add tag in brush presets docker
  • Remove tag in brush presets docker
  • Rename tag in brush presets docker
  • Update tag to the filtered out resources
  • Add resource to tag ibpd
  • Add resource to a new tag ibpd
  • Remove resource from tag ibpd
  • Filtering by tag in combobox
  • Filtering by names in the filter below
  • Filtering by tags in the filter below
  • Make sure "All" tag behaves correctly
  • Make sure we cannot remove or rename All tag
  • Make sure that rename/add new signals are with QString, unless we provide a way to change/write other fields as well
  • Remove all TODO: RESOURCES: from code (when they are all solved, of course)
  • Remove all old code in KisTaggingManager and friends
  • Make tag chooser widget use layour changed signals to reset the index, remove all old code that reseted the index manually
  • Make KisResourceItemChooserContextMenu use TagModel and clean up the code
  • Fix tag Completer
  • Make sure KisDitherWidget work
  • KisGradientChooser
  • KisPatternChooser
  • KisPresetChooser
  • KisWorkspaceChooser
  • KisPaletteListWidget
  • KisGamutMasksChooser
  • tasksetsdocker
  • Palettize
  • KisBrushChooser
  • check what's up with gamutmasks_dock.h
  • KisTagModel::allTags() should be refatored out, every time I need all tags, I need to reiterate over the model
  • Change UI in tags adding/removing from whatever it is now to a one list with checkboxes
  • Find a way to mark some tags as inactive (@rempt)
  • KisTagModel::renameTag() (@rempt)
  • KisResourceModel::tagsForResource() (@rempt)

Notes:
Note: "writing to the database" means: "using appropriate functions implemented by Boud to write stuff to database".
Note2: this is all quite rough, but it will get smoother when I learn what all of this actually means :P

  • (not my task) tags are initialized properly in all appropriate storages
    • (not my task) KisBundleStorage needs to read tags from .desktop files, too (and don't remove reading from manifest!)
  • tags are then written to database during the creation of the database
  • tags are written to database during loading brand new resource storages (like bundles)
  • tags changes are written to database when the user does something with them
  • tags/resources relationships changes are written to database when the user tags or untags resources
  • KisTagChooserWidget needs to use KisTagModel
  • KisTagToolButton needs to use KisTag
  • right-click tagging menu in the resource chooser implementation needs to use KisTagModel
  • KisResourceTaggingManager might have a problem with recursive signals (I got rid of most signals and make TagChooser and ContextMenu use models directly)
  • make a map of interconnectivity between: KisTagChooserWidget, KisTagFilterWidget, KisTagToolButton, "right-click menu" (above), KisResourceTaggingManager, KisResourceChooser, TaggingManager
  • remove old code responsible for tagging: loading the tag files, keeping a list of tags and tag-resource relations, keeping that updated, saving it out to disk, and presenting that data to the tagging widgets
tymond created this task.Nov 15 2019, 3:25 PM
tymond triaged this task as High priority.
tymond updated the task description. (Show Details)Nov 21 2019, 7:11 PM
tymond updated the task description. (Show Details)
tymond updated the task description. (Show Details)Nov 21 2019, 7:14 PM
tymond added a comment.EditedNov 22 2019, 2:47 PM

From today's discussion:

  • KisTagModel::allTags() should be refatored out, every time I need all tags, I need to reiterate over the model
  • Change UI in tags adding/removing from whatever it is now to a one list with checkboxes
  • Find a way to mark some tags as inactive (@rempt)
  • KisTagModel::renameTag() (@rempt)
  • KisResourceModel::tagsForResource() (@rempt)
tymond updated the task description. (Show Details)Nov 22 2019, 2:50 PM
rempt added a comment.Nov 22 2019, 3:46 PM

Note: tags can already be inactive. What we don't have is a way to mark tags as inactive because the storage they come from is inactive. This needs thinking.

tymond added a comment.EditedNov 22 2019, 8:12 PM
tymond updated the task description. (Show Details)Nov 26 2019, 11:24 AM
tymond added a comment.EditedNov 26 2019, 11:27 AM

When renaming a tag, the tag loses all of its resources (in the view) - it's because KisTagFilterProxyModel uses names list to filter the resources. I guess I should invalidate the KisResourceModel somehow. I also guess that this situation is not unique to KisTagModel -> KisResourceModel (I guess KisStorageModel in particular needs some signals and invalidating other models too). Do we have any strategy we agreed upon? If not, what should I do to fix this?

EDIT: Maybe that suggests that tagsForResource should be in KisTagModel, not KisResourceModel?

tymond updated the task description. (Show Details)Nov 26 2019, 11:29 AM
tymond updated the task description. (Show Details)Nov 26 2019, 5:50 PM
tymond added a comment.EditedNov 26 2019, 9:00 PM

@rempt please review if both queries are correct:

For now I'm working on my own branch and pushing to the fork because the main branch is broken; you can't open Krita twice with the same resources correctly (see the bugs spreadsheet).

Yes, that looks correct. I'm not sure I see the problem with krita running twice, though. Did you remove the sqlite file after I added a field to storages?

woltherav added a comment.EditedNov 27 2019, 1:10 PM

Yes, that looks correct. I'm not sure I see the problem with krita running twice, though. Did you remove the sqlite file after I added a field to storages?

I have the same problem here, so I am confused you don't get this issue. And yes, sqlite removed multiple times. When the sqlite is first made, everything is found, but running it again it just doesn't seem to load anything inside a bundle. This was after the your last attempt to ensure documentstorages get removed properly, I just didn't mention it because we were too busy.

Relevant commit: a7389c0ba420b30e920e17a5cbcfde951b8f2829

What's interesting is that if one checks out the older commit with the new database created by the new code, it's broken as well. Or, I don't know what's up, but brushes are not there.

Questions about design of tags:

  1. What about special tags? Right now I check them for id() < 0 ("All" tag has id -1, other special tags can have either -1 as well or -2, -3, -4 etc.).

1a) Is url() checked for uniqueness? What is the user wants to create a tag "All"? Do I need to check it specifically in the AddNewTag() code? (For renaming and removing, I'm checking by id()).

  1. Activeness of tags: we need to support at least two usecases: (1) user loads a bundle with a bunch of tags inside; then unloads/deactivates it; tags from the bundle are gone now; (2) user creates its own tags, they are not removed until the user say so.

We could make tags global or local depending on whether they have storage_id attached? or something like that, and then check "active" flag either in tags table or in the storage table (the storage is active = tag is active). Note: what if the user wants to remove the tag that was in the bundle?

  1. Is there any reason to create UI for adding url, name and comment separately? Right now there is only one textbox. The same text is written to all of them.
tymond updated the task description. (Show Details)Nov 27 2019, 3:45 PM
tymond added a comment.EditedNov 28 2019, 11:38 AM

Usage questions about filtering and tagging:

  1. Current behaviour of the filtering in the Brush Presets docker:
    • if the tag selected isn't "All", all presets from that tag are visible all the time, no matter what the filter says
    • all presets can be subjected to filtering, no matter what tags they have (except for those that have the active ones that cannot be filtered out)
    • is there are multiple filter words (as in, things separated by comma), it shows all presets that matches *any* of the filter
    • basically: preset has the tag from the combobox (if it's different from All) OR matches the first filter word OR matches the second one OR matches the third one etc.

      The behaviour I naively coded before checking what it should do exactly:
    • no matter the tag, only brushes from that tag are visible; and they are filtered out by the user
    • if there are multiple filter words, it shows presets that matches *all* filters (except for exact matches (words in ""), then name of the resource should be on the list of exact matches is there are at least one mentioned) (and filtering by tags is not implemented yet because of other things)
    • basically: preset has the tag from the combobox AND (if there is at least one exact match filter word, preset's name is on the list of matches) AND preset matches all other filters

      I could change it now to match the old one, but maybe it's a good time to consider if this is exactly what we want?
  1. The previous filtering behaviour was mostly useful for updating the tag. The behaviour I coded is not really useful since it can only remove presets from the tag.

    My suggestion: add a new button that will add a tag to all visible/filtered out presets (proposed icon: '+', popup with a textbox for a tag name). It can be useful even if we decide to keep the old behaviour; or precisely, I believe it would be useful for any kind of filtering, and then we could think what filtering would be really the most intuitive and useful in every day usage of Krita.
  1. My "pie in the sky" would be to allow users to select multiple brushes and just add tags/add to tags/remove from tags/etc. with right-click, but multiple select could give them wrong idea that multiple presets can be active at the same point in time, so I dunno.
    • Although it should be possible if there was this kind of checkbox-view like in an image gallery on smartphones... You first need to select one, using some weird GUI function, and then you see checkboxes over images. That won't give the idea that you can paint with multiple brushes.

Please tell me your thoughts.

tymond updated the task description. (Show Details)Nov 28 2019, 12:03 PM
tymond updated the task description. (Show Details)
tymond updated the task description. (Show Details)Nov 28 2019, 12:05 PM
tymond updated the task description. (Show Details)Nov 28 2019, 12:07 PM
tymond updated the task description. (Show Details)Nov 28 2019, 12:14 PM

Not loading tags from an inactive bundle now works: https://phabricator.kde.org/R37:420b8c649b48b7e161ae016521d96ebdf6583db8

However, to have the storage model inform the resource models that a bundle has been inactivated, the KisResourceModelProvider::resetAllModels() is called. This also needs to be implemented for KisTagModelProvider and called in KisStorageModel at the same location as KisResourceModelProvider::resetAllModels()

As tiar suggested I am adding my workflow here -

  • Currently I have a tag selected in the brush preset docker, If i need a brush that is outside of that tag, I just search for the brush name and it is added to current list. this way i don't need to switch tags and choose a brush outside of the selected tag.

In addition to this I support the suggestion of tiar for ability to add tags to multiple brush. I would also like to request ability to add a tag to all the filtered brush, for example if you filter some brushes with names starting from sketch it will helpful to add ability to tag them at once.

Deevad added a comment.Dec 9 2019, 2:59 PM

Feedback about my general usage of the tags:

  • I'm working 99% of the time with a single tag displayed on my Brush Preset Docker; a sort of "my favorite of the moment". I use other tags as folders ("Archive", "Experimental"). My brushes are rarely in two tags (exept the meta one "All" + the "folder" in question)
  • I never used the search field in 10 years. It looks cool but I would prefer to trade it against 25px height of vertical free space anytime and get this feature appearing only on activating a preferences.
  • I use a lot the two Brush Preset Dockers: when a brush presets is absent from the tag I actively use on the Brush Preset Docker but I want to select it anyway; I switch to the second Brush Preset Docker (the one plugged into the top toolbar) and setup it to display the "All" category (and then select the preset from that). When I do this too often for a single brush preset, I assign this preset to my active tag. I wish for my usage the top toolbar docker could remember my choice to display "All" all the time for that.
  • Inherit tags on saving: one of my frustration with tag happens often when I save a brush preset I just tweaked the settings or create a quick derivative preset from it (default brush size, opacity, etc). By default, the new brush preset doesn't inherit from the tags of the predecessor; so it falls always in the "All" category and I have to go there, assign my active tag to it to see it in my Brush Preset docker.

I hope this list will help and not add more noises to this complex refactor, all my encouragement on this big task and sorry to not be around for testing (the P&C book project absorbed all my attention lately and it contiunes).

Well here goes my 2 cents for now about tags. I have to read all to give a better feedback.

  • I use prefix (like "2019_" ) in names a lot. This helps me to keep organized my brushes while i am creating and refining them.
  • I also use good naming (for me) to know what my brush is about even without tag. So i include words like "pencil" "flat" "wc" "ink" and so on.
  • I use the search field when i am lost and i want to filter using words like "pencil" "splats" "blender" "2019"(when i want to see only my experimental brushes... i write 2 or three letters and look for my brush there.

I don't use oficial tags like "paint" or "texture" or whatever. I like to have a lot of brushes visible so i use "all" tag a lot.

I miss a tag with only the default 4 brushes. When i am teaching Krita to my students i have to remove from my krita folder everything related with experimental or developement stage. (not big problem certainly)

tymond updated the task description. (Show Details)Jan 21 2020, 8:08 PM
tymond closed this task as Resolved.