mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Cleanup: move tag functions into own translation unit
Make dive.h a bit slimmer. It's only a drop in the bucket - but at least when modifying tag functions not the *whole* application is rebuilt anymore. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
46c69fccb7
commit
6200909ba4
25 changed files with 321 additions and 267 deletions
|
@ -144,6 +144,8 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||||
subsurfacestartup.h
|
subsurfacestartup.h
|
||||||
subsurfacesysinfo.cpp
|
subsurfacesysinfo.cpp
|
||||||
subsurfacesysinfo.h
|
subsurfacesysinfo.h
|
||||||
|
tag.c
|
||||||
|
tag.h
|
||||||
taxonomy.c
|
taxonomy.c
|
||||||
taxonomy.h
|
taxonomy.h
|
||||||
time.c
|
time.c
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "divesite.h"
|
#include "divesite.h"
|
||||||
#include "ssrf.h"
|
#include "ssrf.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
static unsigned int two_bytes_to_int(unsigned char x, unsigned char y)
|
static unsigned int two_bytes_to_int(unsigned char x, unsigned char y)
|
||||||
{
|
{
|
||||||
|
|
223
core/dive.c
223
core/dive.c
|
@ -14,24 +14,14 @@
|
||||||
#include "qthelper.h"
|
#include "qthelper.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "membuffer.h"
|
#include "membuffer.h"
|
||||||
|
#include "tag.h"
|
||||||
|
#include "structured_list.h"
|
||||||
|
|
||||||
/* one could argue about the best place to have this variable -
|
/* one could argue about the best place to have this variable -
|
||||||
* it's used in the UI, but it seems to make the most sense to have it
|
* it's used in the UI, but it seems to make the most sense to have it
|
||||||
* here */
|
* here */
|
||||||
struct dive displayed_dive;
|
struct dive displayed_dive;
|
||||||
|
|
||||||
struct tag_entry *g_tag_list = NULL;
|
|
||||||
|
|
||||||
static const char *default_tags[] = {
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "boat"), QT_TRANSLATE_NOOP("gettextFromC", "shore"), QT_TRANSLATE_NOOP("gettextFromC", "drift"),
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "deep"), QT_TRANSLATE_NOOP("gettextFromC", "cavern"), QT_TRANSLATE_NOOP("gettextFromC", "ice"),
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "wreck"), QT_TRANSLATE_NOOP("gettextFromC", "cave"), QT_TRANSLATE_NOOP("gettextFromC", "altitude"),
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "pool"), QT_TRANSLATE_NOOP("gettextFromC", "lake"), QT_TRANSLATE_NOOP("gettextFromC", "river"),
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "night"), QT_TRANSLATE_NOOP("gettextFromC", "fresh"), QT_TRANSLATE_NOOP("gettextFromC", "student"),
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "instructor"), QT_TRANSLATE_NOOP("gettextFromC", "photo"), QT_TRANSLATE_NOOP("gettextFromC", "video"),
|
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "deco")
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *cylinderuse_text[] = {
|
const char *cylinderuse_text[] = {
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
|
QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
|
||||||
};
|
};
|
||||||
|
@ -474,31 +464,6 @@ struct dive *alloc_dive(void)
|
||||||
return dive;
|
return dive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear everything but the first element;
|
|
||||||
* this works for taglist, picturelist, even dive computers */
|
|
||||||
#define STRUCTURED_LIST_FREE(_type, _start, _free) \
|
|
||||||
{ \
|
|
||||||
_type *_ptr = _start; \
|
|
||||||
while (_ptr) { \
|
|
||||||
_type *_next = _ptr->next; \
|
|
||||||
_free(_ptr); \
|
|
||||||
_ptr = _next; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STRUCTURED_LIST_COPY(_type, _first, _dest, _cpy) \
|
|
||||||
{ \
|
|
||||||
_type *_sptr = _first; \
|
|
||||||
_type **_dptr = &_dest; \
|
|
||||||
while (_sptr) { \
|
|
||||||
*_dptr = malloc(sizeof(_type)); \
|
|
||||||
_cpy(_sptr, *_dptr); \
|
|
||||||
_sptr = _sptr->next; \
|
|
||||||
_dptr = &(*_dptr)->next; \
|
|
||||||
} \
|
|
||||||
*_dptr = 0; \
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_dc(struct divecomputer *dc);
|
static void free_dc(struct divecomputer *dc);
|
||||||
static void free_dc_contents(struct divecomputer *dc);
|
static void free_dc_contents(struct divecomputer *dc);
|
||||||
|
|
||||||
|
@ -548,14 +513,6 @@ static void copy_pl(struct picture *sp, struct picture *dp)
|
||||||
dp->filename = copy_string(sp->filename);
|
dp->filename = copy_string(sp->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy an element in a list of tags */
|
|
||||||
static void copy_tl(struct tag_entry *st, struct tag_entry *dt)
|
|
||||||
{
|
|
||||||
dt->tag = malloc(sizeof(struct divetag));
|
|
||||||
dt->tag->name = copy_string(st->tag->name);
|
|
||||||
dt->tag->source = copy_string(st->tag->source);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_dive_structures(struct dive *d)
|
static void free_dive_structures(struct dive *d)
|
||||||
{
|
{
|
||||||
if (!d)
|
if (!d)
|
||||||
|
@ -3253,182 +3210,6 @@ static void join_dive_computers(struct dive *d, struct divecomputer *res,
|
||||||
remove_redundant_dc(res, prefer_downloaded);
|
remove_redundant_dc(res, prefer_downloaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before)
|
|
||||||
{
|
|
||||||
while (start && start != before) {
|
|
||||||
if (same_string(start->tag->name, before->tag->name))
|
|
||||||
return true;
|
|
||||||
start = start->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove duplicates and empty nodes */
|
|
||||||
void taglist_cleanup(struct tag_entry **tag_list)
|
|
||||||
{
|
|
||||||
struct tag_entry **tl = tag_list;
|
|
||||||
while (*tl) {
|
|
||||||
/* skip tags that are empty or that we have seen before */
|
|
||||||
if (empty_string((*tl)->tag->name) || tag_seen_before(*tag_list, *tl)) {
|
|
||||||
*tl = (*tl)->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tl = &(*tl)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *taglist_get_tagstring(struct tag_entry *tag_list)
|
|
||||||
{
|
|
||||||
bool first_tag = true;
|
|
||||||
struct membuffer b = { 0 };
|
|
||||||
struct tag_entry *tmp = tag_list;
|
|
||||||
while (tmp != NULL) {
|
|
||||||
if (!empty_string(tmp->tag->name)) {
|
|
||||||
if (first_tag) {
|
|
||||||
put_format(&b, "%s", tmp->tag->name);
|
|
||||||
first_tag = false;
|
|
||||||
} else {
|
|
||||||
put_format(&b, ", %s", tmp->tag->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
/* Ensures we do return null terminated empty string for:
|
|
||||||
* - empty tag list
|
|
||||||
* - tag list with empty tag only
|
|
||||||
*/
|
|
||||||
mb_cstring(&b);
|
|
||||||
return detach_buffer(&b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void taglist_free_divetag(struct divetag *tag)
|
|
||||||
{
|
|
||||||
if (tag->name != NULL)
|
|
||||||
free(tag->name);
|
|
||||||
if (tag->source != NULL)
|
|
||||||
free(tag->source);
|
|
||||||
free(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a tag to the tag_list, keep the list sorted */
|
|
||||||
static struct divetag *taglist_add_divetag(struct tag_entry **tag_list, struct divetag *tag)
|
|
||||||
{
|
|
||||||
struct tag_entry *next, *entry;
|
|
||||||
|
|
||||||
while ((next = *tag_list) != NULL) {
|
|
||||||
int cmp = strcmp(next->tag->name, tag->name);
|
|
||||||
|
|
||||||
/* Already have it? */
|
|
||||||
if (!cmp)
|
|
||||||
return next->tag;
|
|
||||||
/* Is the entry larger? If so, insert here */
|
|
||||||
if (cmp > 0)
|
|
||||||
break;
|
|
||||||
/* Continue traversing the list */
|
|
||||||
tag_list = &next->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert in front of it */
|
|
||||||
entry = malloc(sizeof(struct tag_entry));
|
|
||||||
entry->next = next;
|
|
||||||
entry->tag = tag;
|
|
||||||
*tag_list = entry;
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
int is_default_tag = 0;
|
|
||||||
struct divetag *ret_tag, *new_tag;
|
|
||||||
const char *translation;
|
|
||||||
new_tag = malloc(sizeof(struct divetag));
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++) {
|
|
||||||
if (strcmp(default_tags[i], tag) == 0) {
|
|
||||||
is_default_tag = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Only translate default tags */
|
|
||||||
if (is_default_tag) {
|
|
||||||
translation = translate("gettextFromC", tag);
|
|
||||||
new_tag->name = malloc(strlen(translation) + 1);
|
|
||||||
memcpy(new_tag->name, translation, strlen(translation) + 1);
|
|
||||||
new_tag->source = malloc(strlen(tag) + 1);
|
|
||||||
memcpy(new_tag->source, tag, strlen(tag) + 1);
|
|
||||||
} else {
|
|
||||||
new_tag->source = NULL;
|
|
||||||
new_tag->name = malloc(strlen(tag) + 1);
|
|
||||||
memcpy(new_tag->name, tag, strlen(tag) + 1);
|
|
||||||
}
|
|
||||||
/* Try to insert new_tag into g_tag_list if we are not operating on it */
|
|
||||||
if (tag_list != &g_tag_list) {
|
|
||||||
ret_tag = taglist_add_divetag(&g_tag_list, new_tag);
|
|
||||||
/* g_tag_list already contains new_tag, free the duplicate */
|
|
||||||
if (ret_tag != new_tag)
|
|
||||||
taglist_free_divetag(new_tag);
|
|
||||||
ret_tag = taglist_add_divetag(tag_list, ret_tag);
|
|
||||||
} else {
|
|
||||||
ret_tag = taglist_add_divetag(tag_list, new_tag);
|
|
||||||
if (ret_tag != new_tag)
|
|
||||||
taglist_free_divetag(new_tag);
|
|
||||||
}
|
|
||||||
return ret_tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void taglist_free(struct tag_entry *entry)
|
|
||||||
{
|
|
||||||
STRUCTURED_LIST_FREE(struct tag_entry, entry, free)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tag_entry *taglist_copy(struct tag_entry *s)
|
|
||||||
{
|
|
||||||
struct tag_entry *res;
|
|
||||||
STRUCTURED_LIST_COPY(struct tag_entry, s, res, copy_tl);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Merge src1 and src2, write to *dst */
|
|
||||||
static void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2)
|
|
||||||
{
|
|
||||||
struct tag_entry *entry;
|
|
||||||
|
|
||||||
for (entry = src1; entry; entry = entry->next)
|
|
||||||
taglist_add_divetag(dst, entry->tag);
|
|
||||||
for (entry = src2; entry; entry = entry->next)
|
|
||||||
taglist_add_divetag(dst, entry->tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
void taglist_init_global()
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++)
|
|
||||||
taglist_add_tag(&g_tag_list, default_tags[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool taglist_contains(struct tag_entry *tag_list, const char *tag)
|
|
||||||
{
|
|
||||||
while (tag_list) {
|
|
||||||
if (same_string(tag_list->tag->name, tag))
|
|
||||||
return true;
|
|
||||||
tag_list = tag_list->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list)
|
|
||||||
{
|
|
||||||
struct tag_entry *added_list = NULL;
|
|
||||||
while (new_list) {
|
|
||||||
if (!taglist_contains(original_list, new_list->tag->name))
|
|
||||||
taglist_add_tag(&added_list, new_list->tag->name);
|
|
||||||
new_list = new_list->next;
|
|
||||||
}
|
|
||||||
return added_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_dc_planner(const struct divecomputer *dc)
|
bool is_dc_planner(const struct divecomputer *dc)
|
||||||
{
|
{
|
||||||
return same_string(dc->model, "planned dive");
|
return same_string(dc->model, "planned dive");
|
||||||
|
|
46
core/dive.h
46
core/dive.h
|
@ -177,52 +177,6 @@ struct sample // BASE TYPE BYTES UNITS RANGE
|
||||||
// not calculated when planning a dive
|
// not calculated when planning a dive
|
||||||
}; // Total size of structure: 57 bytes, excluding padding at end
|
}; // Total size of structure: 57 bytes, excluding padding at end
|
||||||
|
|
||||||
struct divetag {
|
|
||||||
/*
|
|
||||||
* The name of the divetag. If a translation is available, name contains
|
|
||||||
* the translated tag
|
|
||||||
*/
|
|
||||||
char *name;
|
|
||||||
/*
|
|
||||||
* If a translation is available, we write the original tag to source.
|
|
||||||
* This enables us to write a non-localized tag to the xml file.
|
|
||||||
*/
|
|
||||||
char *source;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tag_entry {
|
|
||||||
struct divetag *tag;
|
|
||||||
struct tag_entry *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* divetags are only stored once, each dive only contains
|
|
||||||
* a list of tag_entries which then point to the divetags
|
|
||||||
* in the global g_tag_list
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern struct tag_entry *g_tag_list;
|
|
||||||
|
|
||||||
struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag);
|
|
||||||
struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Writes all divetags form tag_list into internally allocated buffer
|
|
||||||
* Function returns pointer to allocated buffer
|
|
||||||
* Buffer contains comma separated list of tags names or null terminated string
|
|
||||||
*
|
|
||||||
* NOTE! The returned buffer must be freed once used.
|
|
||||||
*/
|
|
||||||
char *taglist_get_tagstring(struct tag_entry *tag_list);
|
|
||||||
|
|
||||||
/* cleans up a list: removes empty tags and duplicates */
|
|
||||||
void taglist_cleanup(struct tag_entry **tag_list);
|
|
||||||
|
|
||||||
void taglist_init_global();
|
|
||||||
void taglist_free(struct tag_entry *tag_list);
|
|
||||||
struct tag_entry *taglist_copy(struct tag_entry *s);
|
|
||||||
bool taglist_contains(struct tag_entry *tag_list, const char *tag);
|
|
||||||
|
|
||||||
struct extra_data {
|
struct extra_data {
|
||||||
const char *key;
|
const char *key;
|
||||||
const char *value;
|
const char *value;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "membuffer.h"
|
#include "membuffer.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
static int dm4_events(void *param, int columns, char **data, char **column)
|
static int dm4_events(void *param, int columns, char **data, char **column)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "membuffer.h"
|
#include "membuffer.h"
|
||||||
#include "git-access.h"
|
#include "git-access.h"
|
||||||
#include "qthelper.h"
|
#include "qthelper.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
const char *saved_git_id = NULL;
|
const char *saved_git_id = NULL;
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "membuffer.h"
|
#include "membuffer.h"
|
||||||
#include "qthelper.h"
|
#include "qthelper.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
int verbose, quit, force_root;
|
int verbose, quit, force_root;
|
||||||
int last_xml_version = -1;
|
int last_xml_version = -1;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "exif.h"
|
#include "exif.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "tag.h"
|
||||||
#include "imagedownloader.h"
|
#include "imagedownloader.h"
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "qthelper.h"
|
#include "qthelper.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
#define VA_BUF(b, fmt) do { va_list args; va_start(args, fmt); put_vformat(b, fmt, args); va_end(args); } while (0)
|
#define VA_BUF(b, fmt) do { va_list args; va_start(args, fmt); put_vformat(b, fmt, args); va_end(args); } while (0)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "qthelper.h"
|
#include "qthelper.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "divesite.h"
|
#include "divesite.h"
|
||||||
|
#include "tag.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void write_attribute(struct membuffer *b, const char *att_name, const char *value, const char *separator)
|
void write_attribute(struct membuffer *b, const char *att_name, const char *value, const char *separator)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "git-access.h"
|
#include "git-access.h"
|
||||||
#include "qthelper.h"
|
#include "qthelper.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're outputting utf8 in xml.
|
* We're outputting utf8 in xml.
|
||||||
|
|
30
core/structured_list.h
Normal file
30
core/structured_list.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#ifndef STRUCTURED_LIST_H
|
||||||
|
#define STRUCTURED_LIST_H
|
||||||
|
|
||||||
|
/* Clear everything but the first element;
|
||||||
|
* this works for taglist, picturelist, even dive computers */
|
||||||
|
#define STRUCTURED_LIST_FREE(_type, _start, _free) \
|
||||||
|
{ \
|
||||||
|
_type *_ptr = _start; \
|
||||||
|
while (_ptr) { \
|
||||||
|
_type *_next = _ptr->next; \
|
||||||
|
_free(_ptr); \
|
||||||
|
_ptr = _next; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STRUCTURED_LIST_COPY(_type, _first, _dest, _cpy) \
|
||||||
|
{ \
|
||||||
|
_type *_sptr = _first; \
|
||||||
|
_type **_dptr = &_dest; \
|
||||||
|
while (_sptr) { \
|
||||||
|
*_dptr = malloc(sizeof(_type)); \
|
||||||
|
_cpy(_sptr, *_dptr); \
|
||||||
|
_sptr = _sptr->next; \
|
||||||
|
_dptr = &(*_dptr)->next; \
|
||||||
|
} \
|
||||||
|
*_dptr = 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
206
core/tag.c
Normal file
206
core/tag.c
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "structured_list.h"
|
||||||
|
#include "subsurface-string.h"
|
||||||
|
#include "membuffer.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct tag_entry *g_tag_list = NULL;
|
||||||
|
|
||||||
|
static const char *default_tags[] = {
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "boat"), QT_TRANSLATE_NOOP("gettextFromC", "shore"), QT_TRANSLATE_NOOP("gettextFromC", "drift"),
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "deep"), QT_TRANSLATE_NOOP("gettextFromC", "cavern"), QT_TRANSLATE_NOOP("gettextFromC", "ice"),
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "wreck"), QT_TRANSLATE_NOOP("gettextFromC", "cave"), QT_TRANSLATE_NOOP("gettextFromC", "altitude"),
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "pool"), QT_TRANSLATE_NOOP("gettextFromC", "lake"), QT_TRANSLATE_NOOP("gettextFromC", "river"),
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "night"), QT_TRANSLATE_NOOP("gettextFromC", "fresh"), QT_TRANSLATE_NOOP("gettextFromC", "student"),
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "instructor"), QT_TRANSLATE_NOOP("gettextFromC", "photo"), QT_TRANSLATE_NOOP("gettextFromC", "video"),
|
||||||
|
QT_TRANSLATE_NOOP("gettextFromC", "deco")
|
||||||
|
};
|
||||||
|
|
||||||
|
/* copy an element in a list of tags */
|
||||||
|
static void copy_tl(struct tag_entry *st, struct tag_entry *dt)
|
||||||
|
{
|
||||||
|
dt->tag = malloc(sizeof(struct divetag));
|
||||||
|
dt->tag->name = copy_string(st->tag->name);
|
||||||
|
dt->tag->source = copy_string(st->tag->source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before)
|
||||||
|
{
|
||||||
|
while (start && start != before) {
|
||||||
|
if (same_string(start->tag->name, before->tag->name))
|
||||||
|
return true;
|
||||||
|
start = start->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove duplicates and empty nodes */
|
||||||
|
void taglist_cleanup(struct tag_entry **tag_list)
|
||||||
|
{
|
||||||
|
struct tag_entry **tl = tag_list;
|
||||||
|
while (*tl) {
|
||||||
|
/* skip tags that are empty or that we have seen before */
|
||||||
|
if (empty_string((*tl)->tag->name) || tag_seen_before(*tag_list, *tl)) {
|
||||||
|
*tl = (*tl)->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tl = &(*tl)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *taglist_get_tagstring(struct tag_entry *tag_list)
|
||||||
|
{
|
||||||
|
bool first_tag = true;
|
||||||
|
struct membuffer b = { 0 };
|
||||||
|
struct tag_entry *tmp = tag_list;
|
||||||
|
while (tmp != NULL) {
|
||||||
|
if (!empty_string(tmp->tag->name)) {
|
||||||
|
if (first_tag) {
|
||||||
|
put_format(&b, "%s", tmp->tag->name);
|
||||||
|
first_tag = false;
|
||||||
|
} else {
|
||||||
|
put_format(&b, ", %s", tmp->tag->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
/* Ensures we do return null terminated empty string for:
|
||||||
|
* - empty tag list
|
||||||
|
* - tag list with empty tag only
|
||||||
|
*/
|
||||||
|
mb_cstring(&b);
|
||||||
|
return detach_buffer(&b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void taglist_free_divetag(struct divetag *tag)
|
||||||
|
{
|
||||||
|
if (tag->name != NULL)
|
||||||
|
free(tag->name);
|
||||||
|
if (tag->source != NULL)
|
||||||
|
free(tag->source);
|
||||||
|
free(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a tag to the tag_list, keep the list sorted */
|
||||||
|
static struct divetag *taglist_add_divetag(struct tag_entry **tag_list, struct divetag *tag)
|
||||||
|
{
|
||||||
|
struct tag_entry *next, *entry;
|
||||||
|
|
||||||
|
while ((next = *tag_list) != NULL) {
|
||||||
|
int cmp = strcmp(next->tag->name, tag->name);
|
||||||
|
|
||||||
|
/* Already have it? */
|
||||||
|
if (!cmp)
|
||||||
|
return next->tag;
|
||||||
|
/* Is the entry larger? If so, insert here */
|
||||||
|
if (cmp > 0)
|
||||||
|
break;
|
||||||
|
/* Continue traversing the list */
|
||||||
|
tag_list = &next->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert in front of it */
|
||||||
|
entry = malloc(sizeof(struct tag_entry));
|
||||||
|
entry->next = next;
|
||||||
|
entry->tag = tag;
|
||||||
|
*tag_list = entry;
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
int is_default_tag = 0;
|
||||||
|
struct divetag *ret_tag, *new_tag;
|
||||||
|
const char *translation;
|
||||||
|
new_tag = malloc(sizeof(struct divetag));
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++) {
|
||||||
|
if (strcmp(default_tags[i], tag) == 0) {
|
||||||
|
is_default_tag = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Only translate default tags */
|
||||||
|
if (is_default_tag) {
|
||||||
|
translation = translate("gettextFromC", tag);
|
||||||
|
new_tag->name = malloc(strlen(translation) + 1);
|
||||||
|
memcpy(new_tag->name, translation, strlen(translation) + 1);
|
||||||
|
new_tag->source = malloc(strlen(tag) + 1);
|
||||||
|
memcpy(new_tag->source, tag, strlen(tag) + 1);
|
||||||
|
} else {
|
||||||
|
new_tag->source = NULL;
|
||||||
|
new_tag->name = malloc(strlen(tag) + 1);
|
||||||
|
memcpy(new_tag->name, tag, strlen(tag) + 1);
|
||||||
|
}
|
||||||
|
/* Try to insert new_tag into g_tag_list if we are not operating on it */
|
||||||
|
if (tag_list != &g_tag_list) {
|
||||||
|
ret_tag = taglist_add_divetag(&g_tag_list, new_tag);
|
||||||
|
/* g_tag_list already contains new_tag, free the duplicate */
|
||||||
|
if (ret_tag != new_tag)
|
||||||
|
taglist_free_divetag(new_tag);
|
||||||
|
ret_tag = taglist_add_divetag(tag_list, ret_tag);
|
||||||
|
} else {
|
||||||
|
ret_tag = taglist_add_divetag(tag_list, new_tag);
|
||||||
|
if (ret_tag != new_tag)
|
||||||
|
taglist_free_divetag(new_tag);
|
||||||
|
}
|
||||||
|
return ret_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void taglist_free(struct tag_entry *entry)
|
||||||
|
{
|
||||||
|
STRUCTURED_LIST_FREE(struct tag_entry, entry, free)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tag_entry *taglist_copy(struct tag_entry *s)
|
||||||
|
{
|
||||||
|
struct tag_entry *res;
|
||||||
|
STRUCTURED_LIST_COPY(struct tag_entry, s, res, copy_tl);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Merge src1 and src2, write to *dst */
|
||||||
|
void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2)
|
||||||
|
{
|
||||||
|
struct tag_entry *entry;
|
||||||
|
|
||||||
|
for (entry = src1; entry; entry = entry->next)
|
||||||
|
taglist_add_divetag(dst, entry->tag);
|
||||||
|
for (entry = src2; entry; entry = entry->next)
|
||||||
|
taglist_add_divetag(dst, entry->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void taglist_init_global()
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++)
|
||||||
|
taglist_add_tag(&g_tag_list, default_tags[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool taglist_contains(struct tag_entry *tag_list, const char *tag)
|
||||||
|
{
|
||||||
|
while (tag_list) {
|
||||||
|
if (same_string(tag_list->tag->name, tag))
|
||||||
|
return true;
|
||||||
|
tag_list = tag_list->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list)
|
||||||
|
{
|
||||||
|
struct tag_entry *added_list = NULL;
|
||||||
|
while (new_list) {
|
||||||
|
if (!taglist_contains(original_list, new_list->tag->name))
|
||||||
|
taglist_add_tag(&added_list, new_list->tag->name);
|
||||||
|
new_list = new_list->next;
|
||||||
|
}
|
||||||
|
return added_list;
|
||||||
|
}
|
||||||
|
|
62
core/tag.h
Normal file
62
core/tag.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Dive tag related structures and helpers
|
||||||
|
#ifndef TAG_H
|
||||||
|
#define TAG_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct divetag {
|
||||||
|
/*
|
||||||
|
* The name of the divetag. If a translation is available, name contains
|
||||||
|
* the translated tag
|
||||||
|
*/
|
||||||
|
char *name;
|
||||||
|
/*
|
||||||
|
* If a translation is available, we write the original tag to source.
|
||||||
|
* This enables us to write a non-localized tag to the xml file.
|
||||||
|
*/
|
||||||
|
char *source;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tag_entry {
|
||||||
|
struct divetag *tag;
|
||||||
|
struct tag_entry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* divetags are only stored once, each dive only contains
|
||||||
|
* a list of tag_entries which then point to the divetags
|
||||||
|
* in the global g_tag_list
|
||||||
|
*/
|
||||||
|
extern struct tag_entry *g_tag_list;
|
||||||
|
|
||||||
|
struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag);
|
||||||
|
struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes all divetags form tag_list into internally allocated buffer
|
||||||
|
* Function returns pointer to allocated buffer
|
||||||
|
* Buffer contains comma separated list of tags names or null terminated string
|
||||||
|
*
|
||||||
|
* NOTE! The returned buffer must be freed once used.
|
||||||
|
*/
|
||||||
|
char *taglist_get_tagstring(struct tag_entry *tag_list);
|
||||||
|
|
||||||
|
/* cleans up a list: removes empty tags and duplicates */
|
||||||
|
void taglist_cleanup(struct tag_entry **tag_list);
|
||||||
|
|
||||||
|
void taglist_init_global();
|
||||||
|
void taglist_free(struct tag_entry *tag_list);
|
||||||
|
struct tag_entry *taglist_copy(struct tag_entry *s);
|
||||||
|
bool taglist_contains(struct tag_entry *tag_list, const char *tag);
|
||||||
|
void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -26,6 +26,7 @@
|
||||||
#include "uemis.h"
|
#include "uemis.h"
|
||||||
#include "divelist.h"
|
#include "divelist.h"
|
||||||
#include "divesite.h"
|
#include "divesite.h"
|
||||||
|
#include "tag.h"
|
||||||
#include "core/subsurface-string.h"
|
#include "core/subsurface-string.h"
|
||||||
|
|
||||||
#define ERR_FS_ALMOST_FULL QT_TRANSLATE_NOOP("gettextFromC", "Uemis Zurich: the file system is almost full.\nDisconnect/reconnect the dive computer\nand click \'Retry\'")
|
#define ERR_FS_ALMOST_FULL QT_TRANSLATE_NOOP("gettextFromC", "Uemis Zurich: the file system is almost full.\nDisconnect/reconnect the dive computer\nand click \'Retry\'")
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "core/divelist.h"
|
#include "core/divelist.h"
|
||||||
#include "core/qthelper.h" // for copy_qstring
|
#include "core/qthelper.h" // for copy_qstring
|
||||||
#include "core/subsurface-string.h"
|
#include "core/subsurface-string.h"
|
||||||
|
#include "core/tag.h"
|
||||||
#include "desktop-widgets/mapwidget.h" // TODO: Replace desktop-dependency by signal
|
#include "desktop-widgets/mapwidget.h" // TODO: Replace desktop-dependency by signal
|
||||||
|
|
||||||
namespace Command {
|
namespace Command {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "profile-widget/profilewidget2.h"
|
#include "profile-widget/profilewidget2.h"
|
||||||
#include "core/save-profiledata.h"
|
#include "core/save-profiledata.h"
|
||||||
#include "core/divesite.h"
|
#include "core/divesite.h"
|
||||||
|
#include "core/tag.h"
|
||||||
|
|
||||||
// Retrieves the current unit settings defined in the Subsurface preferences.
|
// Retrieves the current unit settings defined in the Subsurface preferences.
|
||||||
#define GET_UNIT(name, field, f, t) \
|
#define GET_UNIT(name, field, f, t) \
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "profile-widget/profilewidget2.h"
|
#include "profile-widget/profilewidget2.h"
|
||||||
#include "desktop-widgets/command.h"
|
#include "desktop-widgets/command.h"
|
||||||
#include "core/metadata.h"
|
#include "core/metadata.h"
|
||||||
|
#include "core/tag.h"
|
||||||
|
|
||||||
double MinMaxAvgWidget::average() const
|
double MinMaxAvgWidget::average() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -70,6 +70,7 @@ SOURCES += ../../subsurface-mobile-main.cpp \
|
||||||
../../core/membuffer.c \
|
../../core/membuffer.c \
|
||||||
../../core/sha1.c \
|
../../core/sha1.c \
|
||||||
../../core/strtod.c \
|
../../core/strtod.c \
|
||||||
|
../../core/tag.c \
|
||||||
../../core/taxonomy.c \
|
../../core/taxonomy.c \
|
||||||
../../core/time.c \
|
../../core/time.c \
|
||||||
../../core/uemis.c \
|
../../core/uemis.c \
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include "qt-models/completionmodels.h"
|
#include "qt-models/completionmodels.h"
|
||||||
#include "core/dive.h"
|
#include "core/dive.h"
|
||||||
|
#include "core/tag.h"
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/divelist.h"
|
#include "core/divelist.h"
|
||||||
#include "core/qthelper.h"
|
#include "core/qthelper.h"
|
||||||
#include "core/subsurface-string.h"
|
#include "core/subsurface-string.h"
|
||||||
|
#include "core/tag.h"
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "core/libdivecomputer.h"
|
#include "core/libdivecomputer.h"
|
||||||
#include "core/divesite.h"
|
#include "core/divesite.h"
|
||||||
#include "core/membuffer.h"
|
#include "core/membuffer.h"
|
||||||
|
#include "core/tag.h"
|
||||||
|
|
||||||
/* SmartTrak version, constant for every single file */
|
/* SmartTrak version, constant for every single file */
|
||||||
int smtk_version;
|
int smtk_version;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "core/qthelper.h"
|
#include "core/qthelper.h"
|
||||||
#include "core/subsurfacestartup.h"
|
#include "core/subsurfacestartup.h"
|
||||||
#include "core/settings/qPref.h"
|
#include "core/settings/qPref.h"
|
||||||
|
#include "core/tag.h"
|
||||||
#include "desktop-widgets/diveplanner.h"
|
#include "desktop-widgets/diveplanner.h"
|
||||||
#include "desktop-widgets/mainwindow.h"
|
#include "desktop-widgets/mainwindow.h"
|
||||||
#include "desktop-widgets/preferences/preferencesdialog.h"
|
#include "desktop-widgets/preferences/preferencesdialog.h"
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "core/subsurfacestartup.h"
|
#include "core/subsurfacestartup.h"
|
||||||
#include "core/settings/qPref.h"
|
#include "core/settings/qPref.h"
|
||||||
#include "core/settings/qPrefDisplay.h"
|
#include "core/settings/qPrefDisplay.h"
|
||||||
|
#include "core/tag.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include "testtaglist.h"
|
#include "testtaglist.h"
|
||||||
#include "core/dive.h"
|
#include "core/dive.h"
|
||||||
|
#include "core/tag.h"
|
||||||
|
|
||||||
void TestTagList::initTestCase()
|
void TestTagList::initTestCase()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue