149 lines
6.1 KiB
Plaintext
149 lines
6.1 KiB
Plaintext
=============================================================
|
|
How does resource tagging in Pika work?
|
|
=============================================================
|
|
|
|
|
|
PikaTagged
|
|
|
|
Tagging is not limited to a concrete class hierarchy, but any class
|
|
implementing the PikaTagged interface can be tagged. In addition to
|
|
methods for adding/removing/enumerating tags it also requires
|
|
PikaTagged objects to identify themselves:
|
|
|
|
* pika_tagged_get_identifier: used to get a unique identifier of a
|
|
PikaTagged object. For objects which are stored in a file it will
|
|
usually be a filename.
|
|
|
|
* pika_tagged_get_checksum: the identifier mentioned above has the problem
|
|
that it can change during sessions (for example, user moves or renames
|
|
a resource file). Therefore, there needs to be a way to get another
|
|
identifier from the data of the tagged object, so that tags stored between
|
|
session can be remapped properly.
|
|
|
|
|
|
PikaTag
|
|
|
|
Tags are represented by a PikaTag object. There are no limitations for
|
|
tag names except that they cannot contain a selected set of terminal
|
|
punctuation characters (used to separate tags), leading or trailing
|
|
whitespace and cannot begin with a reserved prefix for internal tags
|
|
('pika:'). These conditions are enforced when creating a tag object from a
|
|
tag string. The only reason for tag creation to fail is if there are
|
|
no characters left after trying to fix a tag according to the
|
|
rules above. Tag names are displayed as the user typed them (case
|
|
sensitive), but tag comparison is done case-insensitively.
|
|
|
|
Tags are immutable, i.e. when a tag is created with one name string, it
|
|
cannot be changed, but a new tag has to be created instead.
|
|
|
|
There are methods provided for convenient use with glib, a comparison
|
|
function which can be used to sort tag lists and functions for storing
|
|
tags in a GHashTable.
|
|
|
|
|
|
PikaTagCache
|
|
|
|
Between sessions, tags assigned to objects are stored in a cache
|
|
file. The cache file is a simple XML file, which lists all resources and
|
|
tags which are added to them. Resources which have no tags assigned
|
|
are listed here too, so that when we check the cache we know that they
|
|
have no tags assigned instead of trying to find out if the resource file
|
|
has been renamed.
|
|
|
|
When the session ends, a list of all resources and their tags
|
|
is constructed. Resources which were not loaded during this session,
|
|
but had tags assigned are also added to the list (they are saved
|
|
because they could be useful in the next session, for example, when
|
|
a temporarily disconnected network directory is reconnected). The list
|
|
is then written to a tag cache file in the user's home directory.
|
|
|
|
When the session starts, the previously saved resource and tag mapping has to
|
|
be loaded and assigned to PikaTagged objects. First the tag cache is
|
|
loaded from file, and then containers are added (PikaContainer objects
|
|
which contain items implementing the PikaTagged interface). After that,
|
|
loaded resources are assigned tags:
|
|
|
|
If a resource identifier matches an identifier in the cache,
|
|
corresponding tags are assigned to the PikaTagged object.
|
|
Else, if the identifier is not found in the tag cache,
|
|
an attempt is made to check if the resource file has been
|
|
moved/renamed. In such case the checksum is used to match the
|
|
PikaTagged object with all of the records in the tag cache.
|
|
If a match is found,
|
|
the identifier is updated in the tag cache.
|
|
Otherwise,
|
|
the loaded PikaTagged object is considered to be a newly
|
|
added resource.
|
|
|
|
|
|
PikaFilteredContainer
|
|
|
|
A PikaFilteredContainer is a "view" (representation) of a
|
|
PikaContainer. It is related to tagging in that it can be used to
|
|
filter a PikaContainer to contain only PikaTagged objects which have
|
|
certain tags assigned. It is automatically updated with any changes in
|
|
the PikaContainer it wraps. However, items should not be added or removed
|
|
from this container manually as changes do not affect the original
|
|
container and would be lost when the PikaFilteredContainer is
|
|
updated. Instead, the contents should be changed by setting a tag list
|
|
which would be used to filter PikaTagged objects containing all of the
|
|
given PikaTags.
|
|
|
|
PikaFilteredContainer can use any PikaContainer as a source
|
|
container. Therefore, it is possible to use the decorator design pattern
|
|
to implement additional container views, such as a view combining items
|
|
from multiple containers.
|
|
|
|
|
|
PikaTagEntry widget
|
|
|
|
The PikaTagEntry widget extends GtkEntry and is used to either assign or
|
|
query tags depending on the selected mode. The widget support various
|
|
usability features:
|
|
|
|
* Jellybeans: When a tag is entered and confirmed by either separator,
|
|
pressing return or otherwise, it becomes a jellybean, i.e. a single
|
|
unit, not a bunch of characters. Navigating in a PikaTagEntry,
|
|
deleting tags, etc. can be performed much faster. However, while a tag
|
|
is just being entered (not yet confirmed), all actions operate on
|
|
characters as usual.
|
|
|
|
* Custom auto completion is implemented in the PikaTagEntry widget which
|
|
allows to complete tags in the middle of a tag list, doesn't offer
|
|
already completed tags, tab cycles all possible completions, etc.
|
|
|
|
* If the PikaTagEntry is empty and unused it displays a description for
|
|
the user regarding its purpose.
|
|
|
|
When operating in tag assignment mode, tags are assigned only when
|
|
the user hits the return key.
|
|
|
|
When operating in tag query mode, the given PikaFilteredContainer is
|
|
filtered as the user types. The PikaTagEntry also remembers recently used
|
|
configurations, which can be cycled using up and down arrow keys.
|
|
|
|
|
|
PikaComboTagEntry widget
|
|
|
|
The PikaComboTagEntry widget extends PikaTagEntry and adds the ability to pick
|
|
tags from a menu-like list (using the PikaTagPopup widget).
|
|
|
|
|
|
PikaTagPopup widget
|
|
|
|
The PikaTagPopup widget is used as a tag list menu from the PikaComboTagEntry
|
|
widget. It is not designed to be used with any other widget.
|
|
|
|
PikaTagPopup has many visual and behavioral similarities to GtkMenu.
|
|
In particular, it uses menu-like scrolling.
|
|
|
|
PikaTagPopup implements various usability features, some of which are:
|
|
|
|
* Tags which would result in an empty selection of resources are made
|
|
insensitive.
|
|
|
|
* Closing either with the keyboard or by clicking outside the popup area.
|
|
|
|
* Underlining of highlighted (hovered) tags.
|
|
|