mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
core: port tag-list to C++
Also adds a new test, which tests merging of two tag-lists. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
640ecb345b
commit
f18acf6fb9
25 changed files with 195 additions and 227 deletions
|
@ -187,7 +187,7 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
|
||||||
dive->maxdepth.mm ? put_format(&buf, "\\def\\%smaximumdepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->maxdepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smaximumdepth{}\n", ssrf);
|
dive->maxdepth.mm ? put_format(&buf, "\\def\\%smaximumdepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->maxdepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smaximumdepth{}\n", ssrf);
|
||||||
dive->meandepth.mm ? put_format(&buf, "\\def\\%smeandepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->meandepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smeandepth{}\n", ssrf);
|
dive->meandepth.mm ? put_format(&buf, "\\def\\%smeandepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->meandepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smeandepth{}\n", ssrf);
|
||||||
|
|
||||||
std::string tags = taglist_get_tagstring(dive->tag_list);
|
std::string tags = taglist_get_tagstring(dive->tags);
|
||||||
put_format(&buf, "\\def\\%stype{%s}\n", ssrf, tags.c_str());
|
put_format(&buf, "\\def\\%stype{%s}\n", ssrf, tags.c_str());
|
||||||
put_format(&buf, "\\def\\%sviz{%s}\n", ssrf, qPrintable(viz));
|
put_format(&buf, "\\def\\%sviz{%s}\n", ssrf, qPrintable(viz));
|
||||||
put_format(&buf, "\\def\\%srating{%s}\n", ssrf, qPrintable(rating));
|
put_format(&buf, "\\def\\%srating{%s}\n", ssrf, qPrintable(rating));
|
||||||
|
|
|
@ -564,18 +564,17 @@ void EditTagsBase::redo()
|
||||||
QStringList EditTags::data(struct dive *d) const
|
QStringList EditTags::data(struct dive *d) const
|
||||||
{
|
{
|
||||||
QStringList res;
|
QStringList res;
|
||||||
for (const struct tag_entry *tag = d->tag_list; tag; tag = tag->next)
|
for (const divetag *tag: d->tags)
|
||||||
res.push_back(QString::fromStdString(tag->tag->name));
|
res.push_back(QString::fromStdString(tag->name));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditTags::set(struct dive *d, const QStringList &v) const
|
void EditTags::set(struct dive *d, const QStringList &v) const
|
||||||
{
|
{
|
||||||
taglist_free(d->tag_list);
|
d->tags.clear();
|
||||||
d->tag_list = NULL;
|
|
||||||
for (const QString &tag: v)
|
for (const QString &tag: v)
|
||||||
taglist_add_tag(&d->tag_list, qPrintable(tag));
|
taglist_add_tag(d->tags, tag.toStdString());
|
||||||
taglist_cleanup(&d->tag_list);
|
taglist_cleanup(d->tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EditTags::fieldName() const
|
QString EditTags::fieldName() const
|
||||||
|
@ -627,8 +626,7 @@ static void swapCandQString(QString &q, char *&c)
|
||||||
q = std::move(tmp);
|
q = std::move(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn),
|
PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn)
|
||||||
tags(nullptr)
|
|
||||||
{
|
{
|
||||||
if (what.notes)
|
if (what.notes)
|
||||||
notes = data->notes;
|
notes = data->notes;
|
||||||
|
@ -653,7 +651,7 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
|
||||||
if (what.divesite)
|
if (what.divesite)
|
||||||
divesite = data->dive_site;
|
divesite = data->dive_site;
|
||||||
if (what.tags)
|
if (what.tags)
|
||||||
tags = taglist_copy(data->tag_list);
|
tags = data->tags;
|
||||||
if (what.cylinders) {
|
if (what.cylinders) {
|
||||||
cylinders = data->cylinders;
|
cylinders = data->cylinders;
|
||||||
// Paste cylinders is "special":
|
// Paste cylinders is "special":
|
||||||
|
@ -695,7 +693,6 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
|
||||||
|
|
||||||
PasteState::~PasteState()
|
PasteState::~PasteState()
|
||||||
{
|
{
|
||||||
taglist_free(tags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasteState::swap(dive_components what)
|
void PasteState::swap(dive_components what)
|
||||||
|
@ -723,7 +720,7 @@ void PasteState::swap(dive_components what)
|
||||||
if (what.divesite)
|
if (what.divesite)
|
||||||
std::swap(divesite, d->dive_site);
|
std::swap(divesite, d->dive_site);
|
||||||
if (what.tags)
|
if (what.tags)
|
||||||
std::swap(tags, d->tag_list);
|
std::swap(tags, d->tags);
|
||||||
if (what.cylinders)
|
if (what.cylinders)
|
||||||
std::swap(cylinders, d->cylinders);
|
std::swap(cylinders, d->cylinders);
|
||||||
if (what.weights)
|
if (what.weights)
|
||||||
|
@ -1397,7 +1394,7 @@ EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_s
|
||||||
changedFields |= DiveField::CHILL;
|
changedFields |= DiveField::CHILL;
|
||||||
if (!same_string(oldDive->suit, newDive->suit))
|
if (!same_string(oldDive->suit, newDive->suit))
|
||||||
changedFields |= DiveField::SUIT;
|
changedFields |= DiveField::SUIT;
|
||||||
if (taglist_get_tagstring(oldDive->tag_list) != taglist_get_tagstring(newDive->tag_list)) // This is cheating. Do we have a taglist comparison function?
|
if (taglist_get_tagstring(oldDive->tags) != taglist_get_tagstring(newDive->tags)) // This is cheating. Do we have a taglist comparison function?
|
||||||
changedFields |= DiveField::TAGS;
|
changedFields |= DiveField::TAGS;
|
||||||
if (oldDive->dcs[0].divemode != newDive->dcs[0].divemode)
|
if (oldDive->dcs[0].divemode != newDive->dcs[0].divemode)
|
||||||
changedFields |= DiveField::MODE;
|
changedFields |= DiveField::MODE;
|
||||||
|
|
|
@ -299,7 +299,7 @@ struct PasteState {
|
||||||
int current;
|
int current;
|
||||||
int surge;
|
int surge;
|
||||||
int chill;
|
int chill;
|
||||||
tag_entry *tags;
|
tag_list tags;
|
||||||
cylinder_table cylinders;
|
cylinder_table cylinders;
|
||||||
weightsystem_table weightsystems;
|
weightsystem_table weightsystems;
|
||||||
int number;
|
int number;
|
||||||
|
|
|
@ -265,26 +265,26 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
|
||||||
* Weather, values table, 0 to 6
|
* Weather, values table, 0 to 6
|
||||||
* Subsurface don't have this record but we can use tags
|
* Subsurface don't have this record but we can use tags
|
||||||
*/
|
*/
|
||||||
dt_dive->tag_list = NULL;
|
dt_dive->tags.clear();
|
||||||
read_bytes(1);
|
read_bytes(1);
|
||||||
switch (tmp_1byte) {
|
switch (tmp_1byte) {
|
||||||
case 1:
|
case 1:
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "clear")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "clear"));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "misty")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "misty"));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "fog")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "fog"));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "rain")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "rain"));
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "storm")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "storm"));
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "snow")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "snow"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// unknown, do nothing
|
// unknown, do nothing
|
||||||
|
@ -304,22 +304,22 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
|
||||||
read_bytes(1);
|
read_bytes(1);
|
||||||
switch (tmp_1byte) {
|
switch (tmp_1byte) {
|
||||||
case 1:
|
case 1:
|
||||||
dt_dive->suit = strdup(QT_TRANSLATE_NOOP("gettextFromC", "No suit"));
|
dt_dive->suit = strdup(translate("gettextFromC", "No suit"));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
dt_dive->suit = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Shorty"));
|
dt_dive->suit = strdup(translate("gettextFromC", "Shorty"));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
dt_dive->suit = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Combi"));
|
dt_dive->suit = strdup(translate("gettextFromC", "Combi"));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
dt_dive->suit = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Wet suit"));
|
dt_dive->suit = strdup(translate("gettextFromC", "Wet suit"));
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
dt_dive->suit = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Semidry suit"));
|
dt_dive->suit = strdup(translate("gettextFromC", "Semidry suit"));
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
dt_dive->suit = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Dry suit"));
|
dt_dive->suit = strdup(translate("gettextFromC", "Dry suit"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// unknown, do nothing
|
// unknown, do nothing
|
||||||
|
@ -380,28 +380,28 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
|
||||||
*/
|
*/
|
||||||
read_bytes(1);
|
read_bytes(1);
|
||||||
if (bit_set(tmp_1byte, 2))
|
if (bit_set(tmp_1byte, 2))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "no stop")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "no stop"));
|
||||||
if (bit_set(tmp_1byte, 3))
|
if (bit_set(tmp_1byte, 3))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "deco")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "deco"));
|
||||||
if (bit_set(tmp_1byte, 4))
|
if (bit_set(tmp_1byte, 4))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "single ascent")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "single ascent"));
|
||||||
if (bit_set(tmp_1byte, 5))
|
if (bit_set(tmp_1byte, 5))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "multiple ascent")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "multiple ascent"));
|
||||||
if (bit_set(tmp_1byte, 6))
|
if (bit_set(tmp_1byte, 6))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "fresh water")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "fresh water"));
|
||||||
if (bit_set(tmp_1byte, 7))
|
if (bit_set(tmp_1byte, 7))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "salt water")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "salt water"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dive Type 2 - Bit table, use tags again
|
* Dive Type 2 - Bit table, use tags again
|
||||||
*/
|
*/
|
||||||
read_bytes(1);
|
read_bytes(1);
|
||||||
if (bit_set(tmp_1byte, 0)) {
|
if (bit_set(tmp_1byte, 0)) {
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup("nitrox"));
|
taglist_add_tag(dt_dive->tags, "nitrox");
|
||||||
is_nitrox = 1;
|
is_nitrox = 1;
|
||||||
}
|
}
|
||||||
if (bit_set(tmp_1byte, 1)) {
|
if (bit_set(tmp_1byte, 1)) {
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup("rebreather"));
|
taglist_add_tag(dt_dive->tags, "rebreather");
|
||||||
is_SCR = 1;
|
is_SCR = 1;
|
||||||
dt_dive->dcs[0].divemode = PSCR;
|
dt_dive->dcs[0].divemode = PSCR;
|
||||||
}
|
}
|
||||||
|
@ -411,36 +411,36 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
|
||||||
*/
|
*/
|
||||||
read_bytes(1);
|
read_bytes(1);
|
||||||
if (bit_set(tmp_1byte, 0))
|
if (bit_set(tmp_1byte, 0))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "sight seeing")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "sight seeing"));
|
||||||
if (bit_set(tmp_1byte, 1))
|
if (bit_set(tmp_1byte, 1))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "club dive")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "club dive"));
|
||||||
if (bit_set(tmp_1byte, 2))
|
if (bit_set(tmp_1byte, 2))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "instructor")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "instructor"));
|
||||||
if (bit_set(tmp_1byte, 3))
|
if (bit_set(tmp_1byte, 3))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "instruction")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "instruction"));
|
||||||
if (bit_set(tmp_1byte, 4))
|
if (bit_set(tmp_1byte, 4))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "night")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "night"));
|
||||||
if (bit_set(tmp_1byte, 5))
|
if (bit_set(tmp_1byte, 5))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "cave")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "cave"));
|
||||||
if (bit_set(tmp_1byte, 6))
|
if (bit_set(tmp_1byte, 6))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "ice")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "ice"));
|
||||||
if (bit_set(tmp_1byte, 7))
|
if (bit_set(tmp_1byte, 7))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "search")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "search"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dive Activity 2 - Bit table, use tags again
|
* Dive Activity 2 - Bit table, use tags again
|
||||||
*/
|
*/
|
||||||
read_bytes(1);
|
read_bytes(1);
|
||||||
if (bit_set(tmp_1byte, 0))
|
if (bit_set(tmp_1byte, 0))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "wreck")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "wreck"));
|
||||||
if (bit_set(tmp_1byte, 1))
|
if (bit_set(tmp_1byte, 1))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "river")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "river"));
|
||||||
if (bit_set(tmp_1byte, 2))
|
if (bit_set(tmp_1byte, 2))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "drift")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "drift"));
|
||||||
if (bit_set(tmp_1byte, 3))
|
if (bit_set(tmp_1byte, 3))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "photo")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "photo"));
|
||||||
if (bit_set(tmp_1byte, 4))
|
if (bit_set(tmp_1byte, 4))
|
||||||
taglist_add_tag(&dt_dive->tag_list, strdup(QT_TRANSLATE_NOOP("gettextFromC", "other")));
|
taglist_add_tag(dt_dive->tags, translate("gettextFromC", "other"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Other activities - String 1st byte = long
|
* Other activities - String 1st byte = long
|
||||||
|
@ -450,7 +450,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
|
||||||
if (tmp_1byte != 0) {
|
if (tmp_1byte != 0) {
|
||||||
read_string(tmp_string1);
|
read_string(tmp_string1);
|
||||||
snprintf(buffer, sizeof(buffer), "%s: %s\n",
|
snprintf(buffer, sizeof(buffer), "%s: %s\n",
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "Other activities"),
|
translate("gettextFromC", "Other activities"),
|
||||||
tmp_string1);
|
tmp_string1);
|
||||||
tmp_notes_str = strdup(buffer);
|
tmp_notes_str = strdup(buffer);
|
||||||
free(tmp_string1);
|
free(tmp_string1);
|
||||||
|
@ -474,7 +474,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
|
||||||
read_string(tmp_string1);
|
read_string(tmp_string1);
|
||||||
int len = snprintf(buffer, sizeof(buffer), "%s%s:\n%s",
|
int len = snprintf(buffer, sizeof(buffer), "%s%s:\n%s",
|
||||||
tmp_notes_str ? tmp_notes_str : "",
|
tmp_notes_str ? tmp_notes_str : "",
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "Datatrak/Wlog notes"),
|
translate("gettextFromC", "Datatrak/Wlog notes"),
|
||||||
tmp_string1);
|
tmp_string1);
|
||||||
dt_dive->notes = (char *)calloc((len +1), 1);
|
dt_dive->notes = (char *)calloc((len +1), 1);
|
||||||
memcpy(dt_dive->notes, buffer, len);
|
memcpy(dt_dive->notes, buffer, len);
|
||||||
|
@ -630,7 +630,7 @@ static void wlog_compl_parser(std::string &wl_mem, struct dive *dt_dive, int dco
|
||||||
*/
|
*/
|
||||||
tmp = (int) two_bytes_to_int(runner[pos_weight + 1], runner[pos_weight]);
|
tmp = (int) two_bytes_to_int(runner[pos_weight + 1], runner[pos_weight]);
|
||||||
if (tmp != 0x7fff) {
|
if (tmp != 0x7fff) {
|
||||||
weightsystem_t ws = { {tmp * 10}, QT_TRANSLATE_NOOP("gettextFromC", "unknown"), false };
|
weightsystem_t ws = { {tmp * 10}, translate("gettextFromC", "unknown"), false };
|
||||||
dt_dive->weightsystems.push_back(std::move(ws));
|
dt_dive->weightsystems.push_back(std::move(ws));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ static void free_dive_structures(struct dive *d)
|
||||||
free(d->notes);
|
free(d->notes);
|
||||||
free(d->suit);
|
free(d->suit);
|
||||||
/* free tags, additional dive computers, and pictures */
|
/* free tags, additional dive computers, and pictures */
|
||||||
taglist_free(d->tag_list);
|
d->tags.clear();
|
||||||
d->cylinders.clear();
|
d->cylinders.clear();
|
||||||
d->weightsystems.clear();
|
d->weightsystems.clear();
|
||||||
clear_picture_table(&d->pictures);
|
clear_picture_table(&d->pictures);
|
||||||
|
@ -211,7 +211,6 @@ void copy_dive(const struct dive *s, struct dive *d)
|
||||||
d->notes = copy_string(s->notes);
|
d->notes = copy_string(s->notes);
|
||||||
d->suit = copy_string(s->suit);
|
d->suit = copy_string(s->suit);
|
||||||
copy_pictures(&s->pictures, &d->pictures);
|
copy_pictures(&s->pictures, &d->pictures);
|
||||||
d->tag_list = taglist_copy(s->tag_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_dive_onedc(const struct dive *s, const struct divecomputer &sdc, struct dive *d)
|
static void copy_dive_onedc(const struct dive *s, const struct divecomputer &sdc, struct dive *d)
|
||||||
|
@ -253,7 +252,7 @@ void selective_copy_dive(const struct dive *s, struct dive *d, struct dive_compo
|
||||||
s->dive_site->add_dive(d);
|
s->dive_site->add_dive(d);
|
||||||
}
|
}
|
||||||
if (what.tags)
|
if (what.tags)
|
||||||
d->tag_list = taglist_copy(s->tag_list);
|
d->tags = s->tags;
|
||||||
if (what.cylinders)
|
if (what.cylinders)
|
||||||
copy_cylinder_types(s, d);
|
copy_cylinder_types(s, d);
|
||||||
if (what.weights)
|
if (what.weights)
|
||||||
|
@ -2349,7 +2348,7 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset,
|
||||||
MERGE_NONZERO(res, a, b, surge);
|
MERGE_NONZERO(res, a, b, surge);
|
||||||
MERGE_NONZERO(res, a, b, chill);
|
MERGE_NONZERO(res, a, b, chill);
|
||||||
copy_pictures(a->pictures.nr ? &a->pictures : &b->pictures, &res->pictures);
|
copy_pictures(a->pictures.nr ? &a->pictures : &b->pictures, &res->pictures);
|
||||||
taglist_merge(&res->tag_list, a->tag_list, b->tag_list);
|
res->tags = taglist_merge(a->tags, b->tags);
|
||||||
/* if we get dives without any gas / cylinder information in an import, make sure
|
/* if we get dives without any gas / cylinder information in an import, make sure
|
||||||
* that there is at leatst one entry in the cylinder map for that dive */
|
* that there is at leatst one entry in the cylinder map for that dive */
|
||||||
auto cylinders_map_a = std::make_unique<int[]>(std::max(size_t(1), a->cylinders.size()));
|
auto cylinders_map_a = std::make_unique<int[]>(std::max(size_t(1), a->cylinders.size()));
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "divecomputer.h"
|
#include "divecomputer.h"
|
||||||
#include "equipment.h"
|
#include "equipment.h"
|
||||||
#include "picture.h" // TODO: remove
|
#include "picture.h" // TODO: remove
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -46,7 +47,7 @@ struct dive {
|
||||||
int salinity = 0; // kg per 10000 l
|
int salinity = 0; // kg per 10000 l
|
||||||
int user_salinity = 0; // water density reflecting a user-specified type
|
int user_salinity = 0; // water density reflecting a user-specified type
|
||||||
|
|
||||||
struct tag_entry *tag_list = nullptr;
|
tag_list tags;
|
||||||
std::vector<divecomputer> dcs; // Attn: pointers to divecomputers are not stable!
|
std::vector<divecomputer> dcs; // Attn: pointers to divecomputers are not stable!
|
||||||
int id = 0; // unique ID for this dive
|
int id = 0; // unique ID for this dive
|
||||||
struct picture_table pictures = { };
|
struct picture_table pictures = { };
|
||||||
|
|
|
@ -818,8 +818,8 @@ static bool check(const filter_constraint &c, const QStringList &list)
|
||||||
static bool has_tags(const filter_constraint &c, const struct dive *d)
|
static bool has_tags(const filter_constraint &c, const struct dive *d)
|
||||||
{
|
{
|
||||||
QStringList dive_tags;
|
QStringList dive_tags;
|
||||||
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
|
for (const divetag *tag: d->tags)
|
||||||
dive_tags.push_back(QString::fromStdString(tag->tag->name).trimmed());
|
dive_tags.push_back(QString::fromStdString(tag->name).trimmed());
|
||||||
return check(c, dive_tags);
|
return check(c, dive_tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,8 +123,8 @@ static std::vector<QString> getWords(const dive *d)
|
||||||
tokenize(QString(d->diveguide), res);
|
tokenize(QString(d->diveguide), res);
|
||||||
tokenize(QString(d->buddy), res);
|
tokenize(QString(d->buddy), res);
|
||||||
tokenize(QString(d->suit), res);
|
tokenize(QString(d->suit), res);
|
||||||
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
|
for (const divetag *tag: d->tags)
|
||||||
tokenize(QString::fromStdString(tag->tag->name), res);
|
tokenize(QString::fromStdString(tag->name), res);
|
||||||
for (auto &cyl: d->cylinders)
|
for (auto &cyl: d->cylinders)
|
||||||
tokenize(QString::fromStdString(cyl.type.description), res);
|
tokenize(QString::fromStdString(cyl.type.description), res);
|
||||||
for (auto &ws: d->weightsystems)
|
for (auto &ws: d->weightsystems)
|
||||||
|
|
|
@ -155,7 +155,7 @@ static int dm4_tags(void *param, int, char **data, char **)
|
||||||
struct parser_state *state = (struct parser_state *)param;
|
struct parser_state *state = (struct parser_state *)param;
|
||||||
|
|
||||||
if (data[0])
|
if (data[0])
|
||||||
taglist_add_tag(&state->cur_dive->tag_list, data[0]);
|
taglist_add_tag(state->cur_dive->tags, data[0]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,7 +261,7 @@ static void parse_dive_tags(char *, struct git_parser_state *state)
|
||||||
{
|
{
|
||||||
for (const std::string &tag: state->converted_strings) {
|
for (const std::string &tag: state->converted_strings) {
|
||||||
if (!tag.empty())
|
if (!tag.empty())
|
||||||
taglist_add_tag(&state->active_dive->tag_list, tag.c_str());
|
taglist_add_tag(state->active_dive->tags, tag.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ enum ParseState {
|
||||||
FINDSTART,
|
FINDSTART,
|
||||||
FINDEND
|
FINDEND
|
||||||
};
|
};
|
||||||
static void divetags(const char *buffer, struct tag_entry **tags)
|
static void divetags(const char *buffer, tag_list *tags)
|
||||||
{
|
{
|
||||||
int i = 0, start = 0, end = 0;
|
int i = 0, start = 0, end = 0;
|
||||||
enum ParseState state = FINDEND;
|
enum ParseState state = FINDEND;
|
||||||
|
@ -116,7 +116,7 @@ static void divetags(const char *buffer, struct tag_entry **tags)
|
||||||
if (i > 0 && buffer[i - 1] != '\\') {
|
if (i > 0 && buffer[i - 1] != '\\') {
|
||||||
std::string s(buffer + start, i - start);
|
std::string s(buffer + start, i - start);
|
||||||
state = FINDSTART;
|
state = FINDSTART;
|
||||||
taglist_add_tag(tags, s.c_str());
|
taglist_add_tag(*tags, s.c_str());
|
||||||
} else {
|
} else {
|
||||||
state = FINDSTART;
|
state = FINDSTART;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ static void divetags(const char *buffer, struct tag_entry **tags)
|
||||||
end = len - 1;
|
end = len - 1;
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
std::string s(buffer + start, i - start);
|
std::string s(buffer + start, i - start);
|
||||||
taglist_add_tag(tags, buffer + start);
|
taglist_add_tag(*tags, buffer + start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1254,7 +1254,7 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
|
||||||
return;
|
return;
|
||||||
if (MATCH("number", get_index, &dive->number))
|
if (MATCH("number", get_index, &dive->number))
|
||||||
return;
|
return;
|
||||||
if (MATCH("tags", divetags, &dive->tag_list))
|
if (MATCH("tags", divetags, &dive->tags))
|
||||||
return;
|
return;
|
||||||
if (MATCH("tripflag", get_notrip, &dive->notrip))
|
if (MATCH("tripflag", get_notrip, &dive->notrip))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -104,17 +104,16 @@ static void save_overview(struct membuffer *b, struct dive *dive)
|
||||||
show_utf8(b, "notes ", dive->notes, "\n");
|
show_utf8(b, "notes ", dive->notes, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_tags(struct membuffer *b, struct tag_entry *tags)
|
static void save_tags(struct membuffer *b, const tag_list &tags)
|
||||||
{
|
{
|
||||||
const char *sep = " ";
|
const char *sep = " ";
|
||||||
|
|
||||||
if (!tags)
|
if (tags.empty())
|
||||||
return;
|
return;
|
||||||
put_string(b, "tags");
|
put_string(b, "tags");
|
||||||
while (tags) {
|
for (const divetag *tag: tags) {
|
||||||
show_utf8(b, sep, tags->tag->source.empty() ? tags->tag->name.c_str() : tags->tag->source.c_str(), "");
|
show_utf8(b, sep, tag->source.empty() ? tag->name.c_str() : tag->source.c_str(), "");
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
tags = tags->next;
|
|
||||||
}
|
}
|
||||||
put_string(b, "\n");
|
put_string(b, "\n");
|
||||||
}
|
}
|
||||||
|
@ -449,7 +448,7 @@ static void create_dive_buffer(struct dive *dive, struct membuffer *b)
|
||||||
SAVE("airpressure", surface_pressure.mbar);
|
SAVE("airpressure", surface_pressure.mbar);
|
||||||
cond_put_format(dive->notrip, b, "notrip\n");
|
cond_put_format(dive->notrip, b, "notrip\n");
|
||||||
cond_put_format(dive->invalid, b, "invalid\n");
|
cond_put_format(dive->invalid, b, "invalid\n");
|
||||||
save_tags(b, dive->tag_list);
|
save_tags(b, dive->tags);
|
||||||
if (dive->dive_site)
|
if (dive->dive_site)
|
||||||
put_format(b, "divesiteid %08x\n", dive->dive_site->uuid);
|
put_format(b, "divesiteid %08x\n", dive->dive_site->uuid);
|
||||||
if (verbose && dive->dive_site)
|
if (verbose && dive->dive_site)
|
||||||
|
|
|
@ -311,18 +311,16 @@ void put_HTML_watertemp(struct membuffer *b, const struct dive *dive, const char
|
||||||
static void put_HTML_tags(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
|
static void put_HTML_tags(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
|
||||||
{
|
{
|
||||||
put_string(b, pre);
|
put_string(b, pre);
|
||||||
struct tag_entry *tag = dive->tag_list;
|
|
||||||
|
|
||||||
if (!tag)
|
if (dive->tags.empty())
|
||||||
put_string(b, "[\"--\"");
|
put_string(b, "[\"--\"");
|
||||||
|
|
||||||
const char *separator = "[";
|
const char *separator = "[";
|
||||||
while (tag) {
|
for (const divetag *tag: dive->tags) {
|
||||||
put_format(b, "%s\"", separator);
|
put_format(b, "%s\"", separator);
|
||||||
separator = ", ";
|
separator = ", ";
|
||||||
put_HTML_quoted(b, tag->tag->name.c_str());
|
put_HTML_quoted(b, tag->name.c_str());
|
||||||
put_string(b, "\"");
|
put_string(b, "\"");
|
||||||
tag = tag->next;
|
|
||||||
}
|
}
|
||||||
put_string(b, "]");
|
put_string(b, "]");
|
||||||
put_string(b, post);
|
put_string(b, post);
|
||||||
|
|
|
@ -367,17 +367,16 @@ static void save_events(struct membuffer *b, struct dive *dive, const struct div
|
||||||
save_one_event(b, dive, ev);
|
save_one_event(b, dive, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_tags(struct membuffer *b, struct tag_entry *entry)
|
static void save_tags(struct membuffer *b, const tag_list &tags)
|
||||||
{
|
{
|
||||||
if (entry) {
|
if (!tags.empty()) {
|
||||||
const char *sep = " tags='";
|
const char *sep = " tags='";
|
||||||
do {
|
for (const divetag *tag: tags) {
|
||||||
const struct divetag *tag = entry->tag;
|
|
||||||
put_string(b, sep);
|
put_string(b, sep);
|
||||||
/* If the tag has been translated, write the source to the xml file */
|
/* If the tag has been translated, write the source to the xml file */
|
||||||
quote(b, tag->source.empty() ? tag->name.c_str() : tag->source.c_str(), 1);
|
quote(b, tag->source.empty() ? tag->name.c_str() : tag->source.c_str(), 1);
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
} while ((entry = entry->next) != NULL);
|
}
|
||||||
put_string(b, "'");
|
put_string(b, "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,7 +508,7 @@ void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize)
|
||||||
if (dive->maxcns)
|
if (dive->maxcns)
|
||||||
put_format(b, " cns='%d%%'", dive->maxcns);
|
put_format(b, " cns='%d%%'", dive->maxcns);
|
||||||
|
|
||||||
save_tags(b, dive->tag_list);
|
save_tags(b, dive->tags);
|
||||||
if (dive->dive_site)
|
if (dive->dive_site)
|
||||||
put_format(b, " divesiteid='%8x'", dive->dive_site->uuid);
|
put_format(b, " divesiteid='%8x'", dive->dive_site->uuid);
|
||||||
if (dive->user_salinity)
|
if (dive->user_salinity)
|
||||||
|
|
125
core/tag.cpp
125
core/tag.cpp
|
@ -22,124 +22,87 @@ static const char *default_tags[] = {
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "deco")
|
QT_TRANSLATE_NOOP("gettextFromC", "deco")
|
||||||
};
|
};
|
||||||
|
|
||||||
/* copy an element in a list of tags */
|
divetag::divetag(std::string name, std::string source) :
|
||||||
static void copy_tl(struct tag_entry *st, struct tag_entry *dt)
|
name(std::move(name)), source(std::move(source))
|
||||||
{
|
{
|
||||||
dt->tag = st->tag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before)
|
/* remove duplicates and empty tags */
|
||||||
|
void taglist_cleanup(tag_list &list)
|
||||||
{
|
{
|
||||||
while (start && start != before) {
|
// Remove empty tags
|
||||||
if (start->tag->name == before->tag->name)
|
list.erase(std::remove_if(list.begin(), list.end(), [](const divetag *tag) { return tag->name.empty(); }),
|
||||||
return true;
|
list.end());
|
||||||
start = start->next;
|
|
||||||
}
|
// Sort (should be a NOP, because we add in a sorted way, but let's make sure)
|
||||||
return false;
|
std::sort(list.begin(), list.end());
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
list.erase(std::unique(list.begin(), list.end(),
|
||||||
|
[](const divetag *tag1, const divetag *tag2) { return tag1->name == tag2->name; }),
|
||||||
|
list.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove duplicates and empty nodes */
|
std::string taglist_get_tagstring(const tag_list &list)
|
||||||
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 ((*tl)->tag->name.empty() || tag_seen_before(*tag_list, *tl)) {
|
|
||||||
*tl = (*tl)->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tl = &(*tl)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string taglist_get_tagstring(struct tag_entry *tag_list)
|
|
||||||
{
|
|
||||||
bool first_tag = true;
|
|
||||||
std::string res;
|
std::string res;
|
||||||
for (struct tag_entry *tmp = tag_list; tmp != NULL; tmp = tmp->next) {
|
for (const divetag *tag: list) {
|
||||||
if (tmp->tag->name.empty())
|
if (tag->name.empty())
|
||||||
continue;
|
continue;
|
||||||
if (!first_tag)
|
if (!res.empty())
|
||||||
res += ", ";
|
res += ", ";
|
||||||
res += tmp->tag->name;
|
res += tag->name;
|
||||||
first_tag = false;
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a tag to the tag_list, keep the list sorted */
|
/* Add a tag to the tag_list, keep the list sorted */
|
||||||
static void taglist_add_divetag(struct tag_entry **tag_list, const struct divetag *tag)
|
static void taglist_add_divetag(tag_list &list, const struct divetag *tag)
|
||||||
{
|
{
|
||||||
struct tag_entry *next, *entry;
|
// Use binary search to enter at sorted position
|
||||||
|
auto it = std::lower_bound(list.begin(), list.end(), tag,
|
||||||
while ((next = *tag_list) != NULL) {
|
[](const struct divetag *tag1, const struct divetag *tag2)
|
||||||
int cmp = next->tag->name.compare(tag->name);
|
{ return tag1->name < tag2->name; });
|
||||||
|
// Don't add if it already exists
|
||||||
/* Already have it? */
|
if (it == list.end() || (*it)->name != tag->name)
|
||||||
if (!cmp)
|
list.insert(it, tag);
|
||||||
return;
|
|
||||||
/* 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 = (tag_entry *)malloc(sizeof(struct tag_entry));
|
|
||||||
entry->next = next;
|
|
||||||
entry->tag = tag;
|
|
||||||
*tag_list = entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const divetag *register_tag(const char *s, const char *source)
|
static const divetag *register_tag(std::string s, std::string source)
|
||||||
{
|
{
|
||||||
// binary search
|
// binary search
|
||||||
auto it = std::lower_bound(g_tag_list.begin(), g_tag_list.end(), s,
|
auto it = std::lower_bound(g_tag_list.begin(), g_tag_list.end(), s,
|
||||||
[](const std::unique_ptr<divetag> &tag, const char *s)
|
[](const std::unique_ptr<divetag> &tag, const std::string &s)
|
||||||
{ return tag->name < s; });
|
{ return tag->name < s; });
|
||||||
if (it == g_tag_list.end() || (*it)->name != s) {
|
if (it == g_tag_list.end() || (*it)->name != s)
|
||||||
std::string source_s = empty_string(source) ? std::string() : std::string(source);
|
it = g_tag_list.insert(it, std::make_unique<divetag>(std::move(s), std::move(source)));
|
||||||
it = g_tag_list.insert(it, std::make_unique<divetag>(s, source));
|
|
||||||
}
|
|
||||||
return it->get();
|
return it->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void taglist_add_tag(struct tag_entry **tag_list, const char *tag)
|
void taglist_add_tag(tag_list &list, const std::string &tag)
|
||||||
{
|
{
|
||||||
bool is_default_tag = std::find_if(std::begin(default_tags), std::end(default_tags),
|
bool is_default_tag = std::find_if(std::begin(default_tags), std::end(default_tags),
|
||||||
[&tag] (const char *default_tag) { return tag == default_tag; });
|
[&tag] (const char *default_tag) { return tag == default_tag; });
|
||||||
|
|
||||||
/* Only translate default tags */
|
/* Only translate default tags */
|
||||||
/* TODO: Do we really want to translate user-supplied tags if they happen to be known!? */
|
/* TODO: Do we really want to translate user-supplied tags if they happen to be known!? */
|
||||||
const char *translation = is_default_tag ? translate("gettextFromC", tag) : tag;
|
std::string translation = is_default_tag ? translate("gettextFromC", tag.c_str()) : tag;
|
||||||
const char *source = is_default_tag ? tag : nullptr;
|
std::string source = is_default_tag ? tag : std::string();
|
||||||
const struct divetag *d_tag = register_tag(translation, source);
|
const struct divetag *d_tag = register_tag(std::move(translation), std::move(source));
|
||||||
|
|
||||||
taglist_add_divetag(tag_list, d_tag);
|
taglist_add_divetag(list, d_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 */
|
/* Merge src1 and src2, write to *dst */
|
||||||
void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2)
|
tag_list taglist_merge(const tag_list &src1, const tag_list &src2)
|
||||||
{
|
{
|
||||||
struct tag_entry *entry;
|
tag_list dst;
|
||||||
|
|
||||||
for (entry = src1; entry; entry = entry->next)
|
for (const divetag *t: src1)
|
||||||
taglist_add_divetag(dst, entry->tag);
|
taglist_add_divetag(dst, t);
|
||||||
for (entry = src2; entry; entry = entry->next)
|
for (const divetag *t: src2)
|
||||||
taglist_add_divetag(dst, entry->tag);
|
taglist_add_divetag(dst, t);
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void taglist_init_global()
|
void taglist_init_global()
|
||||||
|
|
28
core/tag.h
28
core/tag.h
|
@ -19,25 +19,18 @@ struct divetag {
|
||||||
* This enables us to write a non-localized tag to the xml file.
|
* This enables us to write a non-localized tag to the xml file.
|
||||||
*/
|
*/
|
||||||
std::string source;
|
std::string source;
|
||||||
divetag(const char *n, const char *s) : name(n), source(s)
|
divetag(std::string name, std::string source);
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tag_entry {
|
using tag_list = std::vector<const divetag *>;
|
||||||
const struct divetag *tag;
|
|
||||||
struct tag_entry *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
void taglist_add_tag(struct tag_entry **tag_list, const char *tag);
|
void taglist_add_tag(tag_list &list, const std::string &tag);
|
||||||
|
|
||||||
/* cleans up a list: removes empty tags and duplicates */
|
/* cleans up a list: removes empty tags and duplicates */
|
||||||
void taglist_cleanup(struct tag_entry **tag_list);
|
void taglist_cleanup(tag_list &list);
|
||||||
|
|
||||||
void taglist_init_global();
|
void taglist_init_global();
|
||||||
void taglist_free(struct tag_entry *tag_list);
|
tag_list taglist_merge(const tag_list &src1, const tag_list &src2);
|
||||||
struct tag_entry *taglist_copy(struct tag_entry *s);
|
|
||||||
void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* divetags are only stored once, each dive only contains
|
* divetags are only stored once, each dive only contains
|
||||||
|
@ -46,14 +39,7 @@ void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_en
|
||||||
*/
|
*/
|
||||||
extern std::vector<std::unique_ptr<divetag>> g_tag_list;
|
extern std::vector<std::unique_ptr<divetag>> g_tag_list;
|
||||||
|
|
||||||
/*
|
/* Comma separated list of tags names or empty string */
|
||||||
* Writes all divetags form tag_list into internally allocated buffer
|
std::string taglist_get_tagstring(const tag_list &tags);
|
||||||
* Function returns pointer to allocated buffer
|
|
||||||
* Buffer contains comma separated list of tags names or null terminated string
|
|
||||||
*/
|
|
||||||
extern std::string taglist_get_tagstring(struct tag_entry *tag_list);
|
|
||||||
|
|
||||||
/* Comma separated list of tags names or null terminated string */
|
|
||||||
std::string taglist_get_tagstring(struct tag_entry *tag_list);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -341,11 +341,8 @@ void DiveComponentSelection::buttonClicked(QAbstractButton *button)
|
||||||
text << tr("Suit: ") << current_dive->suit << "\n";
|
text << tr("Suit: ") << current_dive->suit << "\n";
|
||||||
if (what-> tags) {
|
if (what-> tags) {
|
||||||
text << tr("Tags: ");
|
text << tr("Tags: ");
|
||||||
tag_entry *entry = current_dive->tag_list;
|
for (const divetag *tag: current_dive->tags)
|
||||||
while (entry) {
|
text << tag->name.c_str() << " ";
|
||||||
text << entry->tag->name.c_str() << " ";
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
text << "\n";
|
text << "\n";
|
||||||
}
|
}
|
||||||
if (what->cylinders) {
|
if (what->cylinders) {
|
||||||
|
|
|
@ -118,7 +118,7 @@ void TabDiveNotes::divesChanged(const QVector<dive *> &dives, DiveField field)
|
||||||
if (field.divesite)
|
if (field.divesite)
|
||||||
updateDiveSite(currentDive);
|
updateDiveSite(currentDive);
|
||||||
if (field.tags)
|
if (field.tags)
|
||||||
ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tag_list)));
|
ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tags)));
|
||||||
if (field.buddy)
|
if (field.buddy)
|
||||||
ui.buddy->setText(currentDive->buddy);
|
ui.buddy->setText(currentDive->buddy);
|
||||||
if (field.diveguide)
|
if (field.diveguide)
|
||||||
|
@ -253,7 +253,7 @@ void TabDiveNotes::updateData(const std::vector<dive *> &, dive *currentDive, in
|
||||||
// reset labels in case we last displayed trip notes
|
// reset labels in case we last displayed trip notes
|
||||||
ui.LocationLabel->setText(tr("Location"));
|
ui.LocationLabel->setText(tr("Location"));
|
||||||
ui.NotesLabel->setText(tr("Notes"));
|
ui.NotesLabel->setText(tr("Notes"));
|
||||||
ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tag_list)));
|
ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tags)));
|
||||||
bool isManual = is_dc_manually_added_dive(¤tDive->dcs[0]);
|
bool isManual = is_dc_manually_added_dive(¤tDive->dcs[0]);
|
||||||
ui.depth->setVisible(isManual);
|
ui.depth->setVisible(isManual);
|
||||||
ui.depthLabel->setVisible(isManual);
|
ui.depthLabel->setVisible(isManual);
|
||||||
|
|
|
@ -552,7 +552,7 @@ QVariant TemplateLayout::getValue(QString list, QString property, const State &s
|
||||||
} else if (property == "notes") {
|
} else if (property == "notes") {
|
||||||
return formatNotes(d);
|
return formatNotes(d);
|
||||||
} else if (property == "tags") {
|
} else if (property == "tags") {
|
||||||
return QString::fromStdString(taglist_get_tagstring(d->tag_list));
|
return QString::fromStdString(taglist_get_tagstring(d->tags));
|
||||||
} else if (property == "gas") {
|
} else if (property == "gas") {
|
||||||
return formatGas(d);
|
return formatGas(d);
|
||||||
} else if (property == "sac") {
|
} else if (property == "sac") {
|
||||||
|
|
|
@ -1324,7 +1324,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
|
||||||
}
|
}
|
||||||
// normalize the tag list we have and the one we get from the UI
|
// normalize the tag list we have and the one we get from the UI
|
||||||
// try hard to deal with accidental white space issues
|
// try hard to deal with accidental white space issues
|
||||||
QStringList existingTagList = QString::fromStdString(taglist_get_tagstring(d->tag_list)).split(",", SKIP_EMPTY);
|
QStringList existingTagList = QString::fromStdString(taglist_get_tagstring(d->tags)).split(",", SKIP_EMPTY);
|
||||||
QStringList newTagList = tags.split(",", SKIP_EMPTY);
|
QStringList newTagList = tags.split(",", SKIP_EMPTY);
|
||||||
QStringList newCleanTagList;
|
QStringList newCleanTagList;
|
||||||
for (QString s: newTagList) {
|
for (QString s: newTagList) {
|
||||||
|
@ -1335,10 +1335,9 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
|
||||||
existingTagList.sort();
|
existingTagList.sort();
|
||||||
if (newCleanTagList.join(",") != existingTagList.join(",")) {
|
if (newCleanTagList.join(",") != existingTagList.join(",")) {
|
||||||
diveChanged = true;
|
diveChanged = true;
|
||||||
taglist_free(d->tag_list);
|
d->tags.clear();
|
||||||
d->tag_list = nullptr;
|
|
||||||
for (QString tag: newCleanTagList)
|
for (QString tag: newCleanTagList)
|
||||||
taglist_add_tag(&d->tag_list, qPrintable(tag));
|
taglist_add_tag(d->tags, qPrintable(tag));
|
||||||
}
|
}
|
||||||
if (d->rating != rating) {
|
if (d->rating != rating) {
|
||||||
diveChanged = true;
|
diveChanged = true;
|
||||||
|
|
|
@ -294,7 +294,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
|
||||||
case MobileListModel::SumWeightRole: return formatSumWeight(d);
|
case MobileListModel::SumWeightRole: return formatSumWeight(d);
|
||||||
case MobileListModel::DiveGuideRole: return QString(d->diveguide);
|
case MobileListModel::DiveGuideRole: return QString(d->diveguide);
|
||||||
case MobileListModel::BuddyRole: return QString(d->buddy);
|
case MobileListModel::BuddyRole: return QString(d->buddy);
|
||||||
case MobileListModel::TagsRole: return QString::fromStdString(taglist_get_tagstring(d->tag_list));
|
case MobileListModel::TagsRole: return QString::fromStdString(taglist_get_tagstring(d->tags));
|
||||||
case MobileListModel::NotesRole: return formatNotes(d);
|
case MobileListModel::NotesRole: return formatNotes(d);
|
||||||
case MobileListModel::GpsRole: return formatDiveGPS(d);
|
case MobileListModel::GpsRole: return formatDiveGPS(d);
|
||||||
case MobileListModel::GpsDecimalRole: return format_gps_decimal(d);
|
case MobileListModel::GpsDecimalRole: return format_gps_decimal(d);
|
||||||
|
@ -347,7 +347,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
|
||||||
else
|
else
|
||||||
return d->maxcns;
|
return d->maxcns;
|
||||||
case TAGS:
|
case TAGS:
|
||||||
return QString::fromStdString(taglist_get_tagstring(d->tag_list));
|
return QString::fromStdString(taglist_get_tagstring(d->tags));
|
||||||
case PHOTOS:
|
case PHOTOS:
|
||||||
break;
|
break;
|
||||||
case COUNTRY:
|
case COUNTRY:
|
||||||
|
@ -1767,8 +1767,8 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
|
||||||
case MAXCNS:
|
case MAXCNS:
|
||||||
return lessThanHelper(d1->maxcns - d2->maxcns, row_diff);
|
return lessThanHelper(d1->maxcns - d2->maxcns, row_diff);
|
||||||
case TAGS: {
|
case TAGS: {
|
||||||
std::string s1 = taglist_get_tagstring(d1->tag_list);
|
std::string s1 = taglist_get_tagstring(d1->tags);
|
||||||
std::string s2 = taglist_get_tagstring(d2->tag_list);
|
std::string s2 = taglist_get_tagstring(d2->tags);
|
||||||
int diff = strCmp(s1, s2);
|
int diff = strCmp(s1, s2);
|
||||||
return lessThanHelper(diff, row_diff);
|
return lessThanHelper(diff, row_diff);
|
||||||
}
|
}
|
||||||
|
|
|
@ -691,7 +691,7 @@ static void smtk_parse_relations(MdbHandle *mdb, struct dive *dive, char *dive_i
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
continue;
|
continue;
|
||||||
if (tag)
|
if (tag)
|
||||||
taglist_add_tag(&dive->tag_list, str.c_str());
|
taglist_add_tag(dive->tags, str);
|
||||||
else
|
else
|
||||||
concat(tmp, ", ", str);
|
concat(tmp, ", ", str);
|
||||||
if (str.find("SCR") != std::string::npos)
|
if (str.find("SCR") != std::string::npos)
|
||||||
|
@ -717,7 +717,7 @@ static void smtk_parse_other(struct dive *dive, const std::vector<std::string> &
|
||||||
const std::string &str = list[i];
|
const std::string &str = list[i];
|
||||||
if (!str.empty()) {
|
if (!str.empty()) {
|
||||||
if (tag)
|
if (tag)
|
||||||
taglist_add_tag(&dive->tag_list, str.c_str());
|
taglist_add_tag(dive->tags, str);
|
||||||
else
|
else
|
||||||
concat(&dive->notes, "\n", format_string_std("Smartrak %s: %s", data_name, str.c_str()));
|
concat(&dive->notes, "\n", format_string_std("Smartrak %s: %s", data_name, str.c_str()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1501,8 +1501,8 @@ struct DiveGuideVariable : public StatsVariableTemplate<StatsVariable::Type::Dis
|
||||||
struct TagBinner : public StringBinner<TagBinner, StringBin> {
|
struct TagBinner : public StringBinner<TagBinner, StringBin> {
|
||||||
std::vector<QString> to_bin_values(const dive *d) const {
|
std::vector<QString> to_bin_values(const dive *d) const {
|
||||||
std::vector<QString> tags;
|
std::vector<QString> tags;
|
||||||
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
|
for (const divetag *tag: d->tags)
|
||||||
tags.push_back(QString::fromStdString(tag->tag->name).trimmed());
|
tags.push_back(QString::fromStdString(tag->name).trimmed());
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1513,7 +1513,7 @@ struct TagVariable : public StatsVariableTemplate<StatsVariable::Type::Discrete>
|
||||||
return StatsTranslations::tr("Tags");
|
return StatsTranslations::tr("Tags");
|
||||||
}
|
}
|
||||||
QString diveCategories(const dive *d) const override {
|
QString diveCategories(const dive *d) const override {
|
||||||
return QString::fromStdString(taglist_get_tagstring(d->tag_list));
|
return QString::fromStdString(taglist_get_tagstring(d->tags));
|
||||||
}
|
}
|
||||||
std::vector<const StatsBinner *> binners() const override {
|
std::vector<const StatsBinner *> binners() const override {
|
||||||
return { &tag_binner };
|
return { &tag_binner };
|
||||||
|
|
|
@ -15,29 +15,29 @@ void TestTagList::cleanupTestCase()
|
||||||
|
|
||||||
void TestTagList::testGetTagstringNoTags()
|
void TestTagList::testGetTagstringNoTags()
|
||||||
{
|
{
|
||||||
struct tag_entry *tag_list = NULL;
|
tag_list tags;
|
||||||
std::string tagstring = taglist_get_tagstring(tag_list);
|
std::string tagstring = taglist_get_tagstring(tags);
|
||||||
QVERIFY(tagstring.empty());
|
QVERIFY(tagstring.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTagList::testGetTagstringSingleTag()
|
void TestTagList::testGetTagstringSingleTag()
|
||||||
{
|
{
|
||||||
struct tag_entry *tag_list = NULL;
|
tag_list tags;
|
||||||
taglist_add_tag(&tag_list, "A new tag");
|
taglist_add_tag(tags, "A new tag");
|
||||||
std::string tagstring = taglist_get_tagstring(tag_list);
|
std::string tagstring = taglist_get_tagstring(tags);
|
||||||
QCOMPARE(QString::fromStdString(tagstring), QString::fromUtf8("A new tag"));
|
QCOMPARE(QString::fromStdString(tagstring), QString::fromUtf8("A new tag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTagList::testGetTagstringMultipleTags()
|
void TestTagList::testGetTagstringMultipleTags()
|
||||||
{
|
{
|
||||||
struct tag_entry *tag_list = NULL;
|
tag_list tags;
|
||||||
taglist_add_tag(&tag_list, "A new tag");
|
taglist_add_tag(tags, "A new tag");
|
||||||
taglist_add_tag(&tag_list, "A new tag 1");
|
taglist_add_tag(tags, "A new tag 1");
|
||||||
taglist_add_tag(&tag_list, "A new tag 2");
|
taglist_add_tag(tags, "A new tag 2");
|
||||||
taglist_add_tag(&tag_list, "A new tag 3");
|
taglist_add_tag(tags, "A new tag 3");
|
||||||
taglist_add_tag(&tag_list, "A new tag 4");
|
taglist_add_tag(tags, "A new tag 4");
|
||||||
taglist_add_tag(&tag_list, "A new tag 5");
|
taglist_add_tag(tags, "A new tag 5");
|
||||||
std::string tagstring = taglist_get_tagstring(tag_list);
|
std::string tagstring = taglist_get_tagstring(tags);
|
||||||
QCOMPARE(QString::fromStdString(tagstring),
|
QCOMPARE(QString::fromStdString(tagstring),
|
||||||
QString::fromUtf8(
|
QString::fromUtf8(
|
||||||
"A new tag, "
|
"A new tag, "
|
||||||
|
@ -50,11 +50,11 @@ void TestTagList::testGetTagstringMultipleTags()
|
||||||
|
|
||||||
void TestTagList::testGetTagstringWithAnEmptyTag()
|
void TestTagList::testGetTagstringWithAnEmptyTag()
|
||||||
{
|
{
|
||||||
struct tag_entry *tag_list = NULL;
|
tag_list tags;
|
||||||
taglist_add_tag(&tag_list, "A new tag");
|
taglist_add_tag(tags, "A new tag");
|
||||||
taglist_add_tag(&tag_list, "A new tag 1");
|
taglist_add_tag(tags, "A new tag 1");
|
||||||
taglist_add_tag(&tag_list, "");
|
taglist_add_tag(tags, "");
|
||||||
std::string tagstring = taglist_get_tagstring(tag_list);
|
std::string tagstring = taglist_get_tagstring(tags);
|
||||||
QCOMPARE(QString::fromStdString(tagstring),
|
QCOMPARE(QString::fromStdString(tagstring),
|
||||||
QString::fromUtf8(
|
QString::fromUtf8(
|
||||||
"A new tag, "
|
"A new tag, "
|
||||||
|
@ -63,11 +63,40 @@ void TestTagList::testGetTagstringWithAnEmptyTag()
|
||||||
|
|
||||||
void TestTagList::testGetTagstringEmptyTagOnly()
|
void TestTagList::testGetTagstringEmptyTagOnly()
|
||||||
{
|
{
|
||||||
struct tag_entry *tag_list = NULL;
|
tag_list tags;
|
||||||
taglist_add_tag(&tag_list, "");
|
taglist_add_tag(tags, "");
|
||||||
std::string tagstring = taglist_get_tagstring(tag_list);
|
std::string tagstring = taglist_get_tagstring(tags);
|
||||||
QCOMPARE(QString::fromStdString(tagstring),
|
QCOMPARE(QString::fromStdString(tagstring),
|
||||||
QString::fromUtf8(""));
|
QString::fromUtf8(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestTagList::testMergeTags()
|
||||||
|
{
|
||||||
|
tag_list tags1, tags2;
|
||||||
|
taglist_add_tag(tags1, "A new tag");
|
||||||
|
taglist_add_tag(tags1, "A new tag 6");
|
||||||
|
taglist_add_tag(tags1, "A new tag 1");
|
||||||
|
taglist_add_tag(tags1, "A new tag 2");
|
||||||
|
taglist_add_tag(tags1, "");
|
||||||
|
taglist_add_tag(tags1, "A new tag 2");
|
||||||
|
taglist_add_tag(tags1, "A new tag 3");
|
||||||
|
taglist_add_tag(tags1, "A new tag");
|
||||||
|
taglist_add_tag(tags2, "");
|
||||||
|
taglist_add_tag(tags2, "A new tag 1");
|
||||||
|
taglist_add_tag(tags2, "A new tag 4");
|
||||||
|
taglist_add_tag(tags2, "A new tag 2");
|
||||||
|
taglist_add_tag(tags2, "A new tag 5");
|
||||||
|
tag_list tags3 = taglist_merge(tags1, tags2);
|
||||||
|
std::string tagstring = taglist_get_tagstring(tags3);
|
||||||
|
QCOMPARE(QString::fromStdString(tagstring),
|
||||||
|
QString::fromUtf8(
|
||||||
|
"A new tag, "
|
||||||
|
"A new tag 1, "
|
||||||
|
"A new tag 2, "
|
||||||
|
"A new tag 3, "
|
||||||
|
"A new tag 4, "
|
||||||
|
"A new tag 5, "
|
||||||
|
"A new tag 6"));
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(TestTagList)
|
QTEST_GUILESS_MAIN(TestTagList)
|
||||||
|
|
|
@ -15,6 +15,7 @@ private slots:
|
||||||
void testGetTagstringMultipleTags();
|
void testGetTagstringMultipleTags();
|
||||||
void testGetTagstringWithAnEmptyTag();
|
void testGetTagstringWithAnEmptyTag();
|
||||||
void testGetTagstringEmptyTagOnly();
|
void testGetTagstringEmptyTagOnly();
|
||||||
|
void testMergeTags();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue