Hello, Multi-record per label is possible with gLabels and the attached patch against latest xlog. The patch brings two optional features for TSV export (in menu Parmaters|Dialog and windows|Export): 1) sort by DXCC 2) Group by callsign The first one shockingly does what it says. For people who care about their QSL managers and buro :-) The second one imply the first one, and put on the same line up to a certain number of rows having the same callsign. Then, taking the advantage of gLabels (see attached picture) of not complaining about inexistant extra fields, we get multi-records. This patch has been tested with the QSLing of a LXpedition we had this summer on IOTA EU-157. Cheer up, cards are coming! 73 -- Stephane - F8CFE
Attachment:
glabels_multi_records.png
Description: PNG image
Index: src/cfg.c =================================================================== RCS file: /sources/xlog/xlog/src/cfg.c,v retrieving revision 1.5 diff -u -p -r1.5 cfg.c --- src/cfg.c 28 Aug 2008 07:50:44 -0000 1.5 +++ src/cfg.c 24 Nov 2008 21:00:49 -0000 @@ -176,6 +176,8 @@ config_create (void) preferences.backup = 1; preferences.fcc = 0; preferences.tsvcalc = 0; + preferences.tsvsortbydxcc = 0; + preferences.tsvgroupbycallsign = 1; preferences.viewscoring = 1; preferences.scorex = 10; preferences.scorey = 300; @@ -644,6 +646,16 @@ static void config_load_from_keyfile (GK preferences.tsvcalc = 0; else preferences.tsvcalc = preferences.tsvcalc - 1; + preferences.tsvsortbydxcc = g_key_file_get_integer (file, "saveas", "tsvsortbydxcc", NULL); + if (preferences.tsvsortbydxcc == 0) + preferences.tsvsortbydxcc = 0; + else + preferences.tsvsortbydxcc = preferences.tsvsortbydxcc - 1; + preferences.tsvgroupbycallsign = g_key_file_get_integer (file, "saveas", "tsvgroupbycallsign", NULL); + if (preferences.tsvgroupbycallsign == 0) + preferences.tsvgroupbycallsign = 1; + else + preferences.tsvgroupbycallsign = preferences.tsvgroupbycallsign - 1; } /* @@ -772,6 +784,8 @@ savepreferences (void) g_key_file_set_integer (file, "saveas", "adif", preferences.saveasadif + 1); g_key_file_set_integer_list (file, "saveas", "tsvcolumns", preferences.saveastsv2, 18); g_key_file_set_integer (file, "saveas", "tsvcalc", preferences.tsvcalc + 1); + g_key_file_set_integer (file, "saveas", "tsvsortbydxcc", preferences.tsvsortbydxcc + 1); + g_key_file_set_integer (file, "saveas", "tsvgroupbycallsign", preferences.tsvgroupbycallsign + 1); gchar *buffer = g_key_file_to_data(file, NULL, NULL); g_key_file_free(file); Index: src/cfg.h =================================================================== RCS file: /sources/xlog/xlog/src/cfg.h,v retrieving revision 1.2 diff -u -p -r1.2 cfg.h --- src/cfg.h 16 May 2008 07:04:06 -0000 1.2 +++ src/cfg.h 24 Nov 2008 21:00:49 -0000 @@ -85,6 +85,8 @@ typedef struct gint saveasadif; gint *saveastsv2; gint tsvcalc; + gint tsvsortbydxcc; + gint tsvgroupbycallsign; gint handlebarpos; gchar *cwf1; gchar *cwf2; Index: src/gui_dialogsdialog.c =================================================================== RCS file: /sources/xlog/xlog/src/gui_dialogsdialog.c,v retrieving revision 1.34 diff -u -p -r1.34 gui_dialogsdialog.c --- src/gui_dialogsdialog.c 19 May 2008 10:36:53 -0000 1.34 +++ src/gui_dialogsdialog.c 24 Nov 2008 21:00:49 -0000 @@ -55,13 +55,15 @@ on_menu_dialogs_activate(GtkMenuItem * m *badif, *hsep, *bu1, *bu2, *bu3, *bu4, *bu5, *bu6, *bu7, *bu8, *bu9, *bu10, *bu11, *bu12, *bu13, *bu14, *bu15, *bu16, *bu17, *bu18, - *b4treeview, *tsvhbox, *bucalc, + *b4treeview, *tsvhbox, *bucalc, *busortbydxcc, + *groupbycallsignhbox, *groupbycallsignlabel, *groupbycallsignentry, *bb1, *bb2, *bb3, *bb4, *bb5, *bb6, *bb7, *bb8, *bb9, *bb10, *bb11, *bb12, *bb13, *bb14, *bb15, *bb16, *bb17, *bb18, *bb19, *bb20, *bb21, *bb22, *bb23, *bb24, *bb25, *bb26, *bb27, *bb28, *bb29, *vbox3, *bwac, *bwas, *bwaz, *biota, *bloc, *countrytreeview, *dxcctreeview; gboolean check; + gchar *temp; GtkTreeViewColumn *column; GtkTreeIter iter; gint i, j, response; @@ -176,7 +178,7 @@ on_menu_dialogs_activate(GtkMenuItem * m vbox2 = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (frame), vbox2); label = gtk_label_new -(_("Fields to export when saving as TSV (Tab Separated Value) for glabels")); +(_("Fields to export when saving as TSV (Tab Separated Value) for gLabels")); gtk_container_add (GTK_CONTAINER (vbox2), label); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); hsep = gtk_hseparator_new (); @@ -256,6 +258,27 @@ on_menu_dialogs_activate(GtkMenuItem * m (GTK_TOGGLE_BUTTON (bucalc), preferences.tsvcalc); gtk_box_pack_start (GTK_BOX (vbox2), bucalc, FALSE, FALSE, 0); + hsep = gtk_hseparator_new (); + gtk_container_add (GTK_CONTAINER (vbox2), hsep); + busortbydxcc = gtk_check_button_new_with_label (_("Sort by DXCC")); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (busortbydxcc), preferences.tsvsortbydxcc); + gtk_box_pack_start (GTK_BOX (vbox2), busortbydxcc, FALSE, FALSE, 0); + + hsep = gtk_hseparator_new (); + gtk_container_add (GTK_CONTAINER (vbox2), hsep); + groupbycallsignhbox = gtk_hbox_new (TRUE, 0); + gtk_container_add (GTK_CONTAINER (vbox2), groupbycallsignhbox); + groupbycallsignlabel = gtk_label_new (_("Group by call-sign")); + gtk_box_pack_start (GTK_BOX (groupbycallsignhbox), groupbycallsignlabel, FALSE, FALSE, 0); + groupbycallsignentry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (groupbycallsignhbox), groupbycallsignentry, TRUE, TRUE, 2); + gtk_entry_set_max_length (GTK_ENTRY (groupbycallsignentry), 2); + gtk_entry_set_activates_default (GTK_ENTRY (groupbycallsignentry), TRUE); + temp = g_strdup_printf ("%d", preferences.tsvgroupbycallsign); + gtk_entry_set_text (GTK_ENTRY (groupbycallsignentry), temp); + g_free(temp); + vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (notebook), vbox); frame = gtk_frame_new (_("Bands")); @@ -544,6 +567,15 @@ on_menu_dialogs_activate(GtkMenuItem * m else preferences.tsvcalc = 0; + check = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(busortbydxcc)); + if (check) + preferences.tsvsortbydxcc = 1; + else + preferences.tsvsortbydxcc = 0; + + temp = gtk_editable_get_chars (GTK_EDITABLE (groupbycallsignentry), 0, -1); + preferences.tsvgroupbycallsign = atoi(temp); + check = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(bb1)); preferences.scoringbands[BAND_2190] = check ? 1 : 0; check = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(bb2)); Index: src/log.c =================================================================== RCS file: /sources/xlog/xlog/src/log.c,v retrieving revision 1.56 diff -u -p -r1.56 log.c --- src/log.c 23 May 2008 10:30:33 -0000 1.56 +++ src/log.c 24 Nov 2008 21:00:50 -0000 @@ -43,6 +43,7 @@ #include "log.h" #include "support.h" #include "main.h" +#include "dxcc.h" extern GtkWidget *mainnotebook; extern programstatetype programstate; @@ -416,14 +417,49 @@ childcheck (void) } #endif +typedef gchar *item_t[QSO_FIELDS]; + +static int savelog_compar_groupbycall(const void *b, const void *a) +{ + const gchar **item_a, **item_b; + item_a = (const gchar **)a; + item_b = (const gchar **)b; + + return strcmp(item_a[CALL], item_b[CALL]); +} + + +extern GPtrArray *dxcc; + +static int savelog_compar_sortbydxcc(const void *b, const void *a) +{ + gint rescmp; + gchar **item_a, **item_b; + item_a = (gchar **)a; + item_b = (gchar **)b; + + struct info info_a, info_b; + info_a = lookupcountry_by_callsign (item_a[CALL]); + info_b = lookupcountry_by_callsign (item_b[CALL]); + dxcc_data *d_a = g_ptr_array_index (dxcc, info_a.country); + dxcc_data *d_b = g_ptr_array_index (dxcc, info_b.country); + + /* Sort by DXCC first, then group by call sign within same DXCC */ + rescmp = strcmp(d_a->px, d_b->px); + if (rescmp != 0) + return rescmp; + return strcmp(item_a[CALL], item_b[CALL]); +} + /* saving of the log */ void savelog (gpointer arg, gchar * logfile, gint type, gint first, gint last) { LOGDB *lp; - gint i, j, pid; + gint i, j, pid, exported; G_CONST_RETURN gchar *label; gchar **item, *pathstr; + item_t *sorteditems; gint fields[QSO_FIELDS], widths[QSO_FIELDS]; logtype *logw = (logtype *) arg; GtkTreeViewColumn *column; @@ -459,6 +495,7 @@ savelog (gpointer arg, gchar * logfile, if (lp) { model = gtk_tree_view_get_model (GTK_TREE_VIEW(logw->treeview)); +#if 0 for (i = logw->qsos - first; i >= logw->qsos - last; i--) { pathstr = g_strdup_printf ("%d", i); @@ -477,6 +514,37 @@ fields[j] == QTH || fields[j] == U1 || f gtk_tree_path_free (path); g_free (pathstr); } +#else + exported = last - first + 1; + sorteditems = g_new0 (item_t, exported); + for (i = logw->qsos - first; i >= logw->qsos - last; i--) + { + pathstr = g_strdup_printf ("%d", i); + path = gtk_tree_path_new_from_string (pathstr); + gtk_tree_model_get_iter (model, &iter, path); + for (j = 0; j < logw->columns; j++) + { + gtk_tree_model_get + (model, &iter, logw->logfields[j], &sorteditems[i-first+1][fields[j]], -1); + if (fields[j] == DATE || fields[j] == NAME || +fields[j] == QTH || fields[j] == U1 || fields[j] == U2 || fields[j] == REMARKS) + sorteditems[i-first+1][fields[j]] = g_locale_from_utf8 + (sorteditems[i-first+1][fields[j]], -1, NULL, NULL, NULL); + } + gtk_tree_path_free (path); + g_free (pathstr); + } + if (preferences.tsvsortbydxcc) + qsort(sorteditems, exported, sizeof(gchar*)*QSO_FIELDS, &savelog_compar_sortbydxcc); + else if (preferences.tsvgroupbycallsign > 1) + qsort(sorteditems, exported, sizeof(gchar*)*QSO_FIELDS, &savelog_compar_groupbycall); + + for (i = exported-1; i >= 0; i--) + { + log_file_qso_append (lp, sorteditems[i]); + } + g_free(sorteditems); +#endif log_file_close (lp); _exit (0); } Index: src/logfile/labels.c =================================================================== RCS file: /sources/xlog/xlog/src/logfile/labels.c,v retrieving revision 1.21 diff -u -p -r1.21 labels.c --- src/logfile/labels.c 16 May 2008 07:38:19 -0000 1.21 +++ src/logfile/labels.c 24 Nov 2008 21:00:50 -0000 @@ -56,18 +56,30 @@ const struct log_ops labels_ops = { .extension = ".labels", }; +typedef struct { + FILE *fp; + gint groupbycallsign; + gchar *prev_call; +} labels_priv_t; /* * open for read */ gint labels_open (LOGDB * handle) { - FILE *fp; + labels_priv_t *priv; + + priv = g_new0(labels_priv_t, 1); + if (!priv) + return -1; - fp = fopen (handle->path, "r"); - if (!fp) + priv->fp = fopen (handle->path, "r"); + if (!priv->fp) { + g_free(priv); return -1; - handle->priv = (gpointer) fp; + } + handle->priv = (gpointer) priv; + priv->groupbycallsign = preferences.tsvgroupbycallsign; return 0; } @@ -78,28 +90,52 @@ labels_open (LOGDB * handle) gint labels_create (LOGDB * handle) { - FILE *fp; + labels_priv_t *priv; - fp = fopen (handle->path, "w"); - if (!fp) + priv = g_new0(labels_priv_t, 1); + if (!priv) return -1; - handle->priv = (gpointer) fp; + + priv->fp = fopen (handle->path, "w"); + if (!priv->fp) { + g_free(priv); + return -1; + } + handle->priv = (gpointer) priv; + priv->groupbycallsign = preferences.tsvgroupbycallsign; return 0; } void labels_close (LOGDB * handle) { - FILE *fp = (FILE *) handle->priv; - fclose (fp); + labels_priv_t *priv = (labels_priv_t*)handle->priv; + if (priv->prev_call) { + g_free(priv->prev_call); + priv->prev_call = NULL; + } + fprintf (priv->fp, "\n"); + fclose (priv->fp); + g_free(priv); } gint labels_qso_append (LOGDB * handle, const qso_t * q) { - FILE *fp = (FILE *) handle->priv; + labels_priv_t *priv = (labels_priv_t*)handle->priv; + FILE *fp = priv->fp; gint kms, miles, l, result; + if (priv->prev_call && (strcmp(q[CALL],priv->prev_call) || --priv->groupbycallsign <= 0)) { + fprintf (fp, "\n"); + priv->groupbycallsign = preferences.tsvgroupbycallsign; + } + if (priv->prev_call) { + g_free(priv->prev_call); + priv->prev_call = NULL; + } + priv->prev_call = g_strdup(q[CALL]); + if (preferences.saveastsv2[0] == 1) { if (q[DATE]) fprintf (fp, "%s\t", q[DATE]); else fprintf (fp, "\t"); @@ -199,7 +235,6 @@ labels_qso_append (LOGDB * handle, const { if (q[REMARKS]) fprintf (fp, "%s\t", q[REMARKS]); else fprintf (fp, "\t"); } - fprintf (fp, "\n"); return 0; }