From a09789d93e0160b14f1b06ad91080a249c252253 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 27 Dec 2020 12:12:13 -0800 Subject: [PATCH] output-item: Make label a part of every output_item. I didn't understand before that every output_item had a label of its own that users could separately edit. --- src/language/command.c | 2 +- src/language/data-io/print-space.c | 2 +- src/language/data-io/print.c | 3 +- src/language/lexer/lexer.c | 3 +- src/language/stats/reliability.c | 6 +- src/language/utilities/echo.c | 6 +- src/language/utilities/host.c | 3 +- src/output/ascii.c | 6 +- src/output/cairo-fsm.c | 3 +- src/output/cairo-pager.c | 23 +------ src/output/chart-item.c | 20 ++++-- src/output/driver.c | 50 +++++--------- src/output/group-item.c | 51 +++++++++----- src/output/group-item.h | 10 ++- src/output/message-item.c | 30 +++++--- src/output/output-item-provider.h | 13 +++- src/output/output-item.c | 45 +++++++++--- src/output/output-item.h | 23 ++++--- src/output/page-eject-item.c | 15 +++- src/output/page-setup-item.c | 15 +++- src/output/spv/spv-output.c | 3 +- src/output/table-item.c | 30 +++++--- src/output/text-item.c | 107 ++++++++++++++++++++++------- src/output/text-item.h | 12 ++-- src/ui/gui/psppire-output-view.c | 49 ++----------- src/ui/gui/psppire-window.c | 3 +- utilities/pspp-output.c | 11 ++- 27 files changed, 335 insertions(+), 209 deletions(-) diff --git a/src/language/command.c b/src/language/command.c index 2fa05ad742..de20cb3caa 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -199,7 +199,7 @@ do_parse_command (struct lexer *lexer, goto finish; } group_open_item_submit (group_open_item_create_nocopy ( - utf8_to_title (command->name))); + utf8_to_title (command->name), NULL)); opened = true; if (command->function == NULL) diff --git a/src/language/data-io/print-space.c b/src/language/data-io/print-space.c index 555cdfa405..60eee4ce81 100644 --- a/src/language/data-io/print-space.c +++ b/src/language/data-io/print-space.c @@ -134,7 +134,7 @@ print_space_trns_proc (void *t_, struct ccase **c, while (n--) if (trns->writer == NULL) - text_item_submit (text_item_create (TEXT_ITEM_LOG, "")); + text_item_submit (text_item_create (TEXT_ITEM_LOG, "", NULL)); else dfm_put_record (trns->writer, " ", 1); /* XXX */ diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index 4a767dc3dc..7111c03c65 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -564,7 +564,8 @@ print_text_flush_records (struct print_trns *trns, struct u8_line *line, if (trns->writer == NULL) text_item_submit (text_item_create (TEXT_ITEM_LOG, - ds_cstr (&line->s) + 1)); + ds_cstr (&line->s) + 1, + NULL)); else { size_t len = ds_length (&line->s); diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index 8d2468ab7b..820a481271 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -1444,7 +1444,8 @@ lex_source_get__ (const struct lex_source *src_) /* Submit the line as syntax. */ text_item_submit (text_item_create_nocopy (TEXT_ITEM_SYNTAX, - xmemdup0 (line, copy_len))); + xmemdup0 (line, copy_len), + NULL)); src->journal_pos += line_len; } diff --git a/src/language/stats/reliability.c b/src/language/stats/reliability.c index 7b73f8a47e..b8dc10b90f 100644 --- a/src/language/stats/reliability.c +++ b/src/language/stats/reliability.c @@ -522,8 +522,10 @@ do_reliability (struct casereader *input, struct dataset *ds, alpha (s->n_items, s->sum_of_variances, s->variance_of_sums); } - text_item_submit (text_item_create_format (TEXT_ITEM_TITLE, _("Scale: %s"), - ds_cstr (&rel->scale_name))); + text_item_submit (text_item_create_nocopy ( + TEXT_ITEM_TITLE, + xasprintf (_("Scale: %s"), ds_cstr (&rel->scale_name)), + NULL)); case_processing_summary (n_valid, n_missing, dataset_dict (ds)); } diff --git a/src/language/utilities/echo.c b/src/language/utilities/echo.c index 3f31e335f6..861fcf88bb 100644 --- a/src/language/utilities/echo.c +++ b/src/language/utilities/echo.c @@ -24,6 +24,9 @@ #include "gl/xalloc.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + /* Echos a string to the output stream */ int cmd_echo (struct lexer *lexer, struct dataset *ds UNUSED) @@ -31,7 +34,8 @@ cmd_echo (struct lexer *lexer, struct dataset *ds UNUSED) if (!lex_force_string (lexer)) return CMD_FAILURE; - text_item_submit (text_item_create (TEXT_ITEM_LOG, lex_tokcstr (lexer))); + text_item_submit (text_item_create (TEXT_ITEM_LOG, lex_tokcstr (lexer), + _("Echo"))); lex_get (lexer); return CMD_SUCCESS; diff --git a/src/language/utilities/host.c b/src/language/utilities/host.c index 6298db2d8b..9d19620f7c 100644 --- a/src/language/utilities/host.c +++ b/src/language/utilities/host.c @@ -261,7 +261,8 @@ run_command (const char *command, struct timespec timeout) if (end > output && end[-1] == '\n') end[-1] = '\0'; - text_item_submit (text_item_create_nocopy (TEXT_ITEM_LOG, output)); + text_item_submit (text_item_create_nocopy (TEXT_ITEM_LOG, output, + xstrdup (_("Host Output")))); } free (locale_output); diff --git a/src/output/ascii.c b/src/output/ascii.c index 7fd2f5e876..55ccf5aefb 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -506,8 +506,10 @@ ascii_submit (struct output_driver *driver, { struct text_item *text_item; - text_item = text_item_create_format ( - TEXT_ITEM_LOG, _("See %s for a chart."), file_name); + text_item = text_item_create_nocopy ( + TEXT_ITEM_LOG, + xasprintf (_("See %s for a chart."), file_name), + NULL); ascii_submit (driver, &text_item->output_item); text_item_unref (text_item); diff --git a/src/output/cairo-fsm.c b/src/output/cairo-fsm.c index 6988d3f76c..1241dbd77a 100644 --- a/src/output/cairo-fsm.c +++ b/src/output/cairo-fsm.c @@ -988,7 +988,8 @@ xr_fsm_create (const struct output_item *item_, item = table_item_super ( text_item_to_table_item ( text_item_create (TEXT_ITEM_TITLE, - to_group_open_item (item_)->command_name))); + to_group_open_item (item_)->command_name, + NULL))); } else NOT_REACHED (); diff --git a/src/output/cairo-pager.c b/src/output/cairo-pager.c index 1ab481f0c3..e87ec32524 100644 --- a/src/output/cairo-pager.c +++ b/src/output/cairo-pager.c @@ -451,27 +451,8 @@ xr_pager_run (struct xr_pager *p) } p->n_opens = 0; - const char *text; - if (is_table_item (p->item)) - { - const struct table_item_text *title - = table_item_get_title (to_table_item (p->item)); - text = title ? title->content : "Table"; - } - else if (is_chart_item (p->item)) - { - const char *title - = chart_item_get_title (to_chart_item (p->item)); - text = title ? title : "Chart"; - } - else - text = (is_page_eject_item (p->item) ? "Page Break" - : is_page_setup_item (p->item) ? "Page Setup" - : is_message_item (p->item) ? "Message" - : is_text_item (p->item) ? "Text" - : NULL); - if (text) - add_outline (p->cr, parent_group_id, text, attrs, 0); + add_outline (p->cr, parent_group_id, + output_item_get_label (p->item), attrs, 0); free (attrs); } free (dest_name); diff --git a/src/output/chart-item.c b/src/output/chart-item.c index f4b19a2f27..3b3761372e 100644 --- a/src/output/chart-item.c +++ b/src/output/chart-item.c @@ -29,6 +29,9 @@ #include "gl/xalloc.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + /* Initializes ITEM as a chart item of the specified CLASS. The new chart item initially has the specified TITLE, which may be NULL if no title is yet available. The caller retains ownership of TITLE. @@ -40,9 +43,11 @@ void chart_item_init (struct chart_item *item, const struct chart_item_class *class, const char *title) { - output_item_init (&item->output_item, &chart_item_class); - item->class = class; - item->title = title != NULL ? xstrdup (title) : NULL; + *item = (struct chart_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&chart_item_class), + .class = class, + .title = title ? xstrdup (title) : NULL + }; } /* Returns ITEM's title, which is a null pointer if no title has been set. */ @@ -73,6 +78,13 @@ chart_item_submit (struct chart_item *item) output_submit (&item->output_item); } +static const char * +chart_item_get_label (const struct output_item *output_item) +{ + const struct chart_item *item = to_chart_item (output_item); + return item->title ? item->title : _("Chart"); +} + static void chart_item_destroy (struct output_item *output_item) { @@ -84,6 +96,6 @@ chart_item_destroy (struct output_item *output_item) const struct output_item_class chart_item_class = { - "chart", + chart_item_get_label, chart_item_destroy, }; diff --git a/src/output/driver.c b/src/output/driver.c index cf0a535f3c..be60cb2746 100644 --- a/src/output/driver.c +++ b/src/output/driver.c @@ -54,8 +54,7 @@ struct output_engine { struct ll ll; /* Node for this engine. */ struct llx_list drivers; /* Contains "struct output_driver"s. */ - struct string deferred_text; /* Output text being accumulated. */ - enum text_item_type deferred_type; /* Type of text being accumulated. */ + struct text_item *deferred_text; /* Output text being accumulated. */ char *command_name; /* Name of command being processed. */ char *title, *subtitle; /* Components of page title. */ @@ -101,7 +100,6 @@ output_engine_push (void) struct output_engine *e = xzalloc (sizeof (*e)); llx_init (&e->drivers); - ds_init_empty (&e->deferred_text); string_map_init (&e->heading_vars); @@ -124,7 +122,7 @@ output_engine_pop (void) struct output_driver *d = llx_pop_head (&e->drivers, &llx_malloc_mgr); output_driver_destroy (d); } - ds_destroy (&e->deferred_text); + text_item_unref (e->deferred_text); free (e->command_name); free (e->title); free (e->subtitle); @@ -180,40 +178,30 @@ output_submit__ (struct output_engine *e, struct output_item *item) static void flush_deferred_text (struct output_engine *e) { - if (!ds_is_empty (&e->deferred_text)) + struct text_item *deferred_text = e->deferred_text; + if (deferred_text) { - char *text = ds_steal_cstr (&e->deferred_text); - output_submit__ (e, text_item_super (text_item_create_nocopy ( - e->deferred_type, text))); + e->deferred_text = NULL; + output_submit__ (e, text_item_super (deferred_text)); } } static bool -defer_text (struct output_engine *e, struct output_item *item) +defer_text (struct output_engine *e, struct output_item *output_item) { - if (!is_text_item (item)) + if (!is_text_item (output_item)) return false; - struct text_item *text_item = to_text_item (item); - if (text_item->markup) /* XXX */ - return false; - - enum text_item_type type = text_item_get_type (text_item); - if (type != TEXT_ITEM_SYNTAX && type != TEXT_ITEM_LOG) - return false; - - if (!ds_is_empty (&e->deferred_text) && e->deferred_type != type) - flush_deferred_text (e); - - e->deferred_type = type; - - if (!ds_is_empty (&e->deferred_text)) - ds_put_byte (&e->deferred_text, '\n'); - - const char *text = text_item_get_text (text_item); - ds_put_cstr (&e->deferred_text, text); - output_item_unref (item); - + struct text_item *text = to_text_item (output_item); + if (!e->deferred_text) + e->deferred_text = text_item_unshare (text); + else if (text_item_append (e->deferred_text, text)) + text_item_unref (text); + else + { + flush_deferred_text (e); + e->deferred_text = text_item_unshare (text); + } return true; } @@ -326,7 +314,7 @@ output_set_title__ (struct output_engine *e, char **dst, const char *src) : e->subtitle ? xstrdup (e->subtitle) : xzalloc (1)); text_item_submit (text_item_create_nocopy (TEXT_ITEM_PAGE_TITLE, - page_title)); + page_title, NULL)); } void diff --git a/src/output/group-item.c b/src/output/group-item.c index 34ca63eab3..3bfb44cd09 100644 --- a/src/output/group-item.c +++ b/src/output/group-item.c @@ -20,27 +20,32 @@ #include +#include "libpspp/compiler.h" #include "output/driver.h" #include "output/output-item-provider.h" #include "gl/xalloc.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + struct group_open_item * -group_open_item_create (const char *command_name) +group_open_item_create (const char *command_name, const char *label) { return group_open_item_create_nocopy ( - command_name ? xstrdup (command_name) : NULL); + command_name ? xstrdup (command_name) : NULL, + label ? xstrdup (label) : NULL); } struct group_open_item * -group_open_item_create_nocopy (char *command_name) +group_open_item_create_nocopy (char *command_name, char *label) { - struct group_open_item *item; - - item = xmalloc (sizeof *item); - output_item_init (&item->output_item, &group_open_item_class); - item->command_name = command_name; - + struct group_open_item *item = xmalloc (sizeof *item); + *item = (struct group_open_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&group_open_item_class), + .output_item.label = label, + .command_name = command_name, + }; return item; } @@ -52,6 +57,14 @@ group_open_item_submit (struct group_open_item *item) output_submit (&item->output_item); } +static const char * +group_open_item_get_label (const struct output_item *output_item) +{ + struct group_open_item *item = to_group_open_item (output_item); + + return item->command_name ? item->command_name : _("Group"); +} + static void group_open_item_destroy (struct output_item *output_item) { @@ -63,18 +76,17 @@ group_open_item_destroy (struct output_item *output_item) const struct output_item_class group_open_item_class = { - "group_open", + group_open_item_get_label, group_open_item_destroy, }; struct group_close_item * group_close_item_create (void) { - struct group_close_item *item; - - item = xmalloc (sizeof *item); - output_item_init (&item->output_item, &group_close_item_class); - + struct group_close_item *item = xmalloc (sizeof *item); + *item = (struct group_close_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&group_close_item_class), + }; return item; } @@ -86,6 +98,13 @@ group_close_item_submit (struct group_close_item *item) output_submit (&item->output_item); } +static const char * +group_close_item_get_label (const struct output_item *output_item UNUSED) +{ + /* Not marked for translation: user should never see it. */ + return "Group Close"; +} + static void group_close_item_destroy (struct output_item *output_item) { @@ -96,6 +115,6 @@ group_close_item_destroy (struct output_item *output_item) const struct output_item_class group_close_item_class = { - "group_close", + group_close_item_get_label, group_close_item_destroy, }; diff --git a/src/output/group-item.h b/src/output/group-item.h index 3633b14bf5..61593632cd 100644 --- a/src/output/group-item.h +++ b/src/output/group-item.h @@ -29,11 +29,17 @@ struct group_open_item { struct output_item output_item; + + /* Locale-invariant name of the command that produced the enclosed output. + May be NULL if the group doesn't enclose a particular command's + output. */ char *command_name; }; -struct group_open_item *group_open_item_create (const char *command_name); -struct group_open_item *group_open_item_create_nocopy (char *command_name); +struct group_open_item *group_open_item_create (const char *command_name, + const char *label); +struct group_open_item *group_open_item_create_nocopy (char *command_name, + char *label); /* A group_close item. */ struct group_close_item diff --git a/src/output/message-item.c b/src/output/message-item.c index ddfcc3f42e..e834d5a7b2 100644 --- a/src/output/message-item.c +++ b/src/output/message-item.c @@ -20,6 +20,7 @@ #include +#include "libpspp/i18n.h" #include "libpspp/message.h" #include "output/driver.h" #include "output/output-item-provider.h" @@ -27,15 +28,17 @@ #include "gl/xalloc.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + struct message_item * message_item_create (const struct msg *msg) { - struct message_item *item; - - item = xmalloc (sizeof *msg); - output_item_init (&item->output_item, &message_item_class); - item->msg = msg_dup (msg); - + struct message_item *item = xmalloc (sizeof *msg); + *item = (struct message_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&message_item_class), + .msg = msg_dup (msg) + }; return item; } @@ -49,11 +52,22 @@ struct text_item * message_item_to_text_item (struct message_item *message_item) { struct text_item *text_item = text_item_create_nocopy ( - TEXT_ITEM_LOG, msg_to_string (message_item_get_msg (message_item))); + TEXT_ITEM_LOG, + msg_to_string (message_item_get_msg (message_item)), + xstrdup (output_item_get_label (message_item_super (message_item)))); message_item_unref (message_item); return text_item; } +static const char * +message_item_get_label (const struct output_item *output_item) +{ + const struct message_item *item = to_message_item (output_item); + return (item->msg->severity == MSG_S_ERROR ? _("Error") + : item->msg->severity == MSG_S_WARNING ? _("Warning") + : _("Note")); +} + static void message_item_destroy (struct output_item *output_item) { @@ -72,6 +86,6 @@ message_item_submit (struct message_item *item) const struct output_item_class message_item_class = { - "message", + message_item_get_label, message_item_destroy, }; diff --git a/src/output/output-item-provider.h b/src/output/output-item-provider.h index aa2584bef4..7517996119 100644 --- a/src/output/output-item-provider.h +++ b/src/output/output-item-provider.h @@ -25,13 +25,22 @@ instance of output_item. */ struct output_item_class { - const char *name; + /* Returns the localized label to use for ITEM. This is only called when + ITEM does not have an explicitly set label, that is, when 'item->label' + is NULL. */ + const char *(*get_label) (const struct output_item *item); /* Destroys and frees ITEM. Called when output_item_unref() drops ITEM's reference count to 0. */ void (*destroy) (struct output_item *item); }; -void output_item_init (struct output_item *, const struct output_item_class *); +#define OUTPUT_ITEM_INITIALIZER(CLASS) { .class = CLASS, .ref_cnt = 1 } +#define OUTPUT_ITEM_CLONE_INITIALIZER(SRC) \ + { \ + .class = (SRC)->class, \ + .ref_cnt = 1, \ + .label = (SRC)->label ? xstrdup ((SRC)->label) : NULL, \ + } #endif /* output/output-item-provider.h */ diff --git a/src/output/output-item.c b/src/output/output-item.c index dd4e70c2ee..860678b25f 100644 --- a/src/output/output-item.c +++ b/src/output/output-item.c @@ -25,6 +25,8 @@ #include "libpspp/cast.h" #include "gl/xalloc.h" + +#include "gettext.h" /* Increases ITEM's reference count, indicating that it has an additional owner. An output item that is shared among multiple owners must not be @@ -46,7 +48,11 @@ output_item_unref (struct output_item *item) { assert (item->ref_cnt > 0); if (--item->ref_cnt == 0) - item->class->destroy (item); + { + char *label = item->label; + item->class->destroy (item); + free (label); + } } } @@ -57,17 +63,34 @@ output_item_is_shared (const struct output_item *item) { return item->ref_cnt > 1; } - -/* Initializes ITEM as an output item of the specified CLASS, initially with a - reference count of 1. - An output item is an abstract class, that is, a plain output_item is not - useful on its own. Thus, this function is normally called from the - initialization function of some subclass of output_item. */ +/* Returns the label for ITEM, which the caller must not modify or free. */ +const char * +output_item_get_label (const struct output_item *item) +{ + return item->label ? item->label : item->class->get_label (item); +} + +/* Sets the label for ITEM to LABEL. The caller retains ownership of LABEL. + If LABEL is nonnull, it overrides any previously set label and the default + label. If LABEL is null, ITEM will now use its default label. + + ITEM must not be shared. */ +void +output_item_set_label (struct output_item *item, const char *label) +{ + output_item_set_label_nocopy (item, label ? xstrdup (label) : NULL); +} + +/* Sets the label for ITEM to LABEL, transferring ownership of LABEL to ITEM. + If LABEL is nonnull, it overrides any previously set label and the default + label. If LABEL is null, ITEM will now use its default label. + + ITEM must not be shared. */ void -output_item_init (struct output_item *item, - const struct output_item_class *class) +output_item_set_label_nocopy (struct output_item *item, char *label) { - item->class = class; - item->ref_cnt = 1; + assert (!output_item_is_shared (item)); + free (item->label); + item->label = label; } diff --git a/src/output/output-item.h b/src/output/output-item.h index 13a5c34a74..b522df4c90 100644 --- a/src/output/output-item.h +++ b/src/output/output-item.h @@ -19,16 +19,8 @@ /* Output items. - An output item is a self-contained chunk of output. The - following kinds of output items currently exist: - - - Tables (see output/table-item.h). - - - Charts (see output/chart-item.h). - - - Text strings (see output/text-item.h). - - - Messages (see output/message-item.h). + An output item is a self-contained chunk of output. Several kinds of output + items exist. See *-item.h for details. */ #include @@ -43,10 +35,21 @@ struct output_item indicated by a reference count greater than 1. When this is the case, the output item must not be modified. */ int ref_cnt; + + /* The localized label for the item that appears in the outline pane in the + PSPPIRE output viewer and in PDF outlines. This is NULL if no label has + been explicitly set. + + Use output_item_get_label() to read an item's label. */ + char *label; }; struct output_item *output_item_ref (const struct output_item *); void output_item_unref (struct output_item *); bool output_item_is_shared (const struct output_item *); +const char *output_item_get_label (const struct output_item *); +void output_item_set_label (struct output_item *, const char *); +void output_item_set_label_nocopy (struct output_item *, char *); + #endif /* output/output-item.h */ diff --git a/src/output/page-eject-item.c b/src/output/page-eject-item.c index 5d108f9890..85bde8c959 100644 --- a/src/output/page-eject-item.c +++ b/src/output/page-eject-item.c @@ -25,11 +25,16 @@ #include "gl/xalloc.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + struct page_eject_item * page_eject_item_create (void) { struct page_eject_item *item = xmalloc (sizeof *item); - output_item_init (&item->output_item, &page_eject_item_class); + *item = (struct page_eject_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&page_eject_item_class), + }; return item; } @@ -41,6 +46,12 @@ page_eject_item_submit (struct page_eject_item *item) output_submit (&item->output_item); } +static const char * +page_eject_item_get_label (const struct output_item *output_item UNUSED) +{ + return _("Page Break"); +} + static void page_eject_item_destroy (struct output_item *output_item) { @@ -49,6 +60,6 @@ page_eject_item_destroy (struct output_item *output_item) const struct output_item_class page_eject_item_class = { - "page_eject", + page_eject_item_get_label, page_eject_item_destroy, }; diff --git a/src/output/page-setup-item.c b/src/output/page-setup-item.c index 45cf8c977f..7be1c2c43b 100644 --- a/src/output/page-setup-item.c +++ b/src/output/page-setup-item.c @@ -102,8 +102,10 @@ struct page_setup_item * page_setup_item_create (const struct page_setup *ps) { struct page_setup_item *item = xmalloc (sizeof *item); - output_item_init (&item->output_item, &page_setup_item_class); - item->page_setup = page_setup_clone (ps); + *item = (struct page_setup_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&page_setup_item_class), + .page_setup = page_setup_clone (ps), + }; return item; } @@ -115,6 +117,13 @@ page_setup_item_submit (struct page_setup_item *item) output_submit (&item->output_item); } +static const char * +page_setup_item_get_label (const struct output_item *output_item UNUSED) +{ + /* Not marked for translation: user should never see it. */ + return "Page Setup"; +} + static void page_setup_item_destroy (struct output_item *output_item) { @@ -125,6 +134,6 @@ page_setup_item_destroy (struct output_item *output_item) const struct output_item_class page_setup_item_class = { - "page_setup", + page_setup_item_get_label, page_setup_item_destroy, }; diff --git a/src/output/spv/spv-output.c b/src/output/spv/spv-output.c index f83ff4542b..cb4964a7f1 100644 --- a/src/output/spv/spv-output.c +++ b/src/output/spv/spv-output.c @@ -35,7 +35,8 @@ spv_text_submit (const struct spv_item *in) const struct pivot_value *value = spv_item_get_text (in); char *text = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT, SETTINGS_VALUE_SHOW_DEFAULT); - struct text_item *item = text_item_create_nocopy (type, text); + char *label = in->label ? xstrdup (in->label) : NULL; + struct text_item *item = text_item_create_nocopy (type, text, label); const struct font_style *font = value->font_style; if (font) { diff --git a/src/output/table-item.c b/src/output/table-item.c index 9355a77a11..1b17c320a6 100644 --- a/src/output/table-item.c +++ b/src/output/table-item.c @@ -29,6 +29,9 @@ #include "gl/xalloc.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + struct table_item_text * table_item_text_create (const char *content) { @@ -78,7 +81,7 @@ table_item_layer_copy (struct table_item_layer *dst, src->n_footnotes * sizeof *src->footnotes); dst->n_footnotes = src->n_footnotes; } - + void table_item_layer_uninit (struct table_item_layer *layer) { @@ -127,13 +130,13 @@ table_item_create (struct table *table, const char *title, const char *caption, const char *notes) { struct table_item *item = xmalloc (sizeof *item); - output_item_init (&item->output_item, &table_item_class); - item->table = table; - item->title = table_item_text_create (title); - item->layers = NULL; - item->caption = table_item_text_create (caption); - item->notes = notes ? xstrdup (notes) : NULL; - item->pt = NULL; + *item = (struct table_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&table_item_class), + .table = table, + .title = table_item_text_create (title), + .caption = table_item_text_create (caption), + .notes = notes ? xstrdup (notes) : NULL, + }; return item; } @@ -238,6 +241,15 @@ table_item_submit (struct table_item *table_item) output_submit (&table_item->output_item); } +static const char * +table_item_get_label (const struct output_item *output_item) +{ + const struct table_item *item = to_table_item (output_item); + return (item->title && item->title->content + ? item->title->content + : _("Table")); +} + static void table_item_destroy (struct output_item *output_item) { @@ -253,6 +265,6 @@ table_item_destroy (struct output_item *output_item) const struct output_item_class table_item_class = { - "table", + table_item_get_label, table_item_destroy, }; diff --git a/src/output/text-item.c b/src/output/text-item.c index 8c7f0dc51a..55319e9ef6 100644 --- a/src/output/text-item.c +++ b/src/output/text-item.c @@ -34,6 +34,7 @@ #include "gettext.h" #define _(msgid) gettext (msgid) +#define N_(msgid) msgid const char * text_item_type_to_string (enum text_item_type type) @@ -55,40 +56,31 @@ text_item_type_to_string (enum text_item_type type) } } -/* Creates and returns a new text item containing TEXT and the specified TYPE. - The new text item takes ownership of TEXT. */ +/* Creates and returns a new text item containing TEXT and the specified TYPE + and LABEL. The new text item takes ownership of TEXT and LABEL. If LABEL + is NULL, uses the default label for TYPE. */ struct text_item * -text_item_create_nocopy (enum text_item_type type, char *text) +text_item_create_nocopy (enum text_item_type type, char *text, char *label) { struct text_item *item = xzalloc (sizeof *item); - output_item_init (&item->output_item, &text_item_class); - item->text = text; - item->type = type; + *item = (struct text_item) { + .output_item = OUTPUT_ITEM_INITIALIZER (&text_item_class), + .output_item.label = label, + .text = text, + .type = type, + }; return item; } /* Creates and returns a new text item containing a copy of TEXT and the - specified TYPE. The caller retains ownership of TEXT. */ -struct text_item * -text_item_create (enum text_item_type type, const char *text) -{ - return text_item_create_nocopy (type, xstrdup (text)); -} - -/* Creates and returns a new text item containing a copy of FORMAT, which is - formatted as if by printf(), and the specified TYPE. The caller retains - ownership of FORMAT. */ + specified TYPE and LABEL. The caller retains ownership of TEXT and LABEL. + If LABEL is null, uses a default label for TYPE. */ struct text_item * -text_item_create_format (enum text_item_type type, const char *format, ...) +text_item_create (enum text_item_type type, const char *text, + const char *label) { - struct text_item *item; - va_list args; - - va_start (args, format); - item = text_item_create_nocopy (type, xvasprintf (format, args)); - va_end (args); - - return item; + return text_item_create_nocopy (type, xstrdup (text), + label ? xstrdup (label) : NULL); } /* Returns ITEM's type. */ @@ -113,6 +105,62 @@ text_item_submit (struct text_item *item) output_submit (&item->output_item); } +struct text_item * +text_item_unshare (struct text_item *old) +{ + assert (old->output_item.ref_cnt > 0); + if (!text_item_is_shared (old)) + return old; + text_item_unref (old); + + struct text_item *new = xmalloc (sizeof *new); + *new = (struct text_item) { + .output_item = OUTPUT_ITEM_CLONE_INITIALIZER (&old->output_item), + .text = xstrdup (old->text), + .type = old->type, + .bold = old->bold, + .italic = old->italic, + .underline = old->underline, + .markup = old->markup, + .typeface = old->typeface ? xstrdup (old->typeface) : NULL, + .size = old->size + }; + return new; +} + +/* Attempts to append the text in SRC to DST. If successful, returns true, + otherwise false. + + Only TEXT_ITEM_SYNTAX and TEXT_ITEM_LOG items can be combined, and not with + each other. + + DST must not be shared. */ +bool +text_item_append (struct text_item *dst, const struct text_item *src) +{ + assert (!text_item_is_shared (dst)); + if (dst->type != src->type + || (dst->type != TEXT_ITEM_SYNTAX && dst->type != TEXT_ITEM_LOG) + || strcmp (output_item_get_label (&dst->output_item), + output_item_get_label (&src->output_item)) + || dst->bold != src->bold + || dst->italic != src->italic + || dst->underline != src->underline + || dst->markup + || src->markup + || strcmp (dst->typeface ? dst->typeface : "", + src->typeface ? src->typeface : "") + || dst->size != src->size) + return false; + else + { + char *new_text = xasprintf ("%s\n%s", dst->text, src->text); + free (dst->text); + dst->text = new_text; + return true; + } +} + struct table_item * text_item_to_table_item (struct text_item *text_item) { @@ -142,6 +190,13 @@ text_item_to_table_item (struct text_item *text_item) return table_item; } +static const char * +text_item_get_label (const struct output_item *output_item) +{ + const struct text_item *item = to_text_item (output_item); + return text_item_type_to_string (item->type); +} + static void text_item_destroy (struct output_item *output_item) { @@ -153,6 +208,6 @@ text_item_destroy (struct output_item *output_item) const struct output_item_class text_item_class = { - "text", + text_item_get_label, text_item_destroy, }; diff --git a/src/output/text-item.h b/src/output/text-item.h index 554d478f74..28e2457a2c 100644 --- a/src/output/text-item.h +++ b/src/output/text-item.h @@ -50,15 +50,17 @@ struct text_item int size; }; -struct text_item *text_item_create (enum text_item_type, const char *text); -struct text_item *text_item_create_nocopy (enum text_item_type, char *text); -struct text_item *text_item_create_format (enum text_item_type, - const char *format, ...) - PRINTF_FORMAT (2, 3); +struct text_item *text_item_create (enum text_item_type, + const char *text, const char *label); +struct text_item *text_item_create_nocopy (enum text_item_type, + char *text, char *label); enum text_item_type text_item_get_type (const struct text_item *); const char *text_item_get_text (const struct text_item *); +struct text_item *text_item_unshare (struct text_item *); +bool text_item_append (struct text_item *dst, const struct text_item *src); + struct table_item *text_item_to_table_item (struct text_item *); /* This boilerplate for text_item, a subclass of output_item, was diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c index 3e9151f608..cc00a05bda 100644 --- a/src/ui/gui/psppire-output-view.c +++ b/src/ui/gui/psppire-output-view.c @@ -84,9 +84,9 @@ struct psppire_output_view enum { - COL_NAME, /* Table name. */ + COL_LABEL, /* Output item label. */ COL_ADDR, /* Pointer to the table */ - COL_Y, /* Y position of top of name. */ + COL_Y, /* Y position of top of object. */ N_COLS }; @@ -405,7 +405,6 @@ psppire_output_view_put (struct psppire_output_view *view, { struct output_view_item *view_item; GtkWidget *drawing_area; - struct string name; int tw, th; if (is_group_close_item (item)) @@ -473,8 +472,6 @@ psppire_output_view_put (struct psppire_output_view *view, GtkTreeStore *store = GTK_TREE_STORE ( gtk_tree_view_get_model (view->overview)); - ds_init_empty (&name); - /* Create a new node in the tree and puts a reference to it in 'iter'. */ GtkTreeIter iter; GtkTreeIter parent; @@ -493,45 +490,11 @@ psppire_output_view_put (struct psppire_output_view *view, &iter); } - ds_clear (&name); - if (is_text_item (item)) - { - const struct text_item *text_item = to_text_item (item); - ds_put_cstr (&name, text_item_type_to_string ( - text_item_get_type (text_item))); - } - else if (is_message_item (item)) - { - const struct message_item *msg_item = to_message_item (item); - const struct msg *msg = message_item_get_msg (msg_item); - ds_put_format (&name, "%s: %s", _("Message"), - msg_severity_to_string (msg->severity)); - } - else if (is_table_item (item)) - { - const struct table_item_text *title - = table_item_get_title (to_table_item (item)); - if (title != NULL) - ds_put_format (&name, "Table: %s", title->content); - else - ds_put_cstr (&name, "Table"); - } - else if (is_chart_item (item)) - { - const char *s = chart_item_get_title (to_chart_item (item)); - if (s != NULL) - ds_put_format (&name, "Chart: %s", s); - else - ds_put_cstr (&name, "Chart"); - } - else if (is_group_open_item (item)) - ds_put_cstr (&name, to_group_open_item (item)->command_name); gtk_tree_store_set (store, &iter, - COL_NAME, ds_cstr (&name), + COL_LABEL, output_item_get_label (item), COL_ADDR, item, - COL_Y, (view->y), + COL_Y, view->y, -1); - ds_destroy (&name); GtkTreePath *path = gtk_tree_model_get_path ( GTK_TREE_MODEL (store), &iter); @@ -877,7 +840,7 @@ psppire_output_view_new (GtkLayout *output, GtkTreeView *overview) model = GTK_TREE_MODEL (gtk_tree_store_new ( N_COLS, - G_TYPE_STRING, /* COL_NAME */ + G_TYPE_STRING, /* COL_LABEL */ G_TYPE_POINTER, /* COL_ADDR */ G_TYPE_LONG)); /* COL_Y */ gtk_tree_view_set_model (overview, model); @@ -887,7 +850,7 @@ psppire_output_view_new (GtkLayout *output, GtkTreeView *overview) gtk_tree_view_append_column (GTK_TREE_VIEW (overview), column); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, renderer, TRUE); - gtk_tree_view_column_add_attribute (column, renderer, "text", COL_NAME); + gtk_tree_view_column_add_attribute (column, renderer, "text", COL_LABEL); g_signal_connect (GTK_TREE_VIEW (overview), "row-activated", G_CALLBACK (on_row_activate), view); diff --git a/src/ui/gui/psppire-window.c b/src/ui/gui/psppire-window.c index 99da30fa3e..fe4119dd37 100644 --- a/src/ui/gui/psppire-window.c +++ b/src/ui/gui/psppire-window.c @@ -766,7 +766,8 @@ dump_heading_transition (const struct spv_item *old, group_close_item_submit (group_close_item_create ()); for (size_t i = common; i < new_path.n; i++) group_open_item_submit (group_open_item_create ( - new_path.nodes[i]->command_id)); + new_path.nodes[i]->command_id, + new_path.nodes[i]->label)); free_path (&old_path); free_path (&new_path); diff --git a/utilities/pspp-output.c b/utilities/pspp-output.c index 2a8c83ffd5..a5ad14fb01 100644 --- a/utilities/pspp-output.c +++ b/utilities/pspp-output.c @@ -95,10 +95,14 @@ dump_item (const struct spv_item *item) { const char *x = item->xml_member; const char *b = item->bin_member; + + /* The strings below are not marked for translation because they are only + useful to developers. */ char *s = (x && b - ? xasprintf (_("%s and %s:"), x, b) + ? xasprintf ("%s and %s:", x, b) : xasprintf ("%s:", x ? x : b)); - text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s)); + text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s, + xstrdup ("Member Names"))); } switch (spv_item_get_type (item)) @@ -271,7 +275,8 @@ dump_heading_transition (const struct spv_item *old, group_close_item_submit (group_close_item_create ()); for (size_t i = common; i < new_path.n; i++) group_open_item_submit (group_open_item_create ( - new_path.nodes[i]->command_id)); + new_path.nodes[i]->command_id, + new_path.nodes[i]->label)); free_path (&old_path); free_path (&new_path); -- 2.30.2