mirror of https://github.com/GNOME/gimp.git
app: display the release notes as a GtkListBox instead of text.
What it means is that we will be a bit strict over our <release> formatting which will have to always be a <p> introduction followed by a list of items. This is what gimp_appstream_to_pango_markups() expects. Since so far, this is how all our <release> tags were formatted anyway, this is not too much of a problem. Note that I keep the less strict gimp_appstream_to_pango_markup() and use it for extension's appstream description as we will have no control over these. The main reason for this new rule and new display of our release notes is that I am going to add the ability to click independent release items so that people can get "blinking" indications of what changed when relevant.
This commit is contained in:
parent
83a3130688
commit
3011795407
|
@ -75,9 +75,15 @@ typedef struct
|
|||
const gchar *lang;
|
||||
GString *original;
|
||||
gint foreign_level;
|
||||
|
||||
gchar **introduction;
|
||||
GList **release_items;
|
||||
} ParseState;
|
||||
|
||||
|
||||
static gchar * gimp_appstream_parse (const gchar *as_text,
|
||||
gchar **introduction,
|
||||
GList **release_items);
|
||||
static void appstream_text_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
|
@ -955,49 +961,19 @@ gimp_ascii_strtod (const gchar *nptr,
|
|||
gchar *
|
||||
gimp_appstream_to_pango_markup (const gchar *as_text)
|
||||
{
|
||||
static const GMarkupParser appstream_text_parser =
|
||||
{
|
||||
appstream_text_start_element,
|
||||
appstream_text_end_element,
|
||||
appstream_text_characters,
|
||||
NULL, /* passthrough */
|
||||
NULL /* error */
|
||||
};
|
||||
|
||||
GimpXmlParser *xml_parser;
|
||||
gchar *markup = NULL;
|
||||
GError *error = NULL;
|
||||
ParseState state;
|
||||
|
||||
state.level = 0;
|
||||
state.foreign_level = -1;
|
||||
state.text = g_string_new (NULL);
|
||||
state.numbered_list = FALSE;
|
||||
state.unnumbered_list = FALSE;
|
||||
state.lang = g_getenv ("LANGUAGE");
|
||||
state.original = NULL;
|
||||
|
||||
xml_parser = gimp_xml_parser_new (&appstream_text_parser, &state);
|
||||
if (as_text &&
|
||||
! gimp_xml_parser_parse_buffer (xml_parser, as_text, -1, &error))
|
||||
{
|
||||
g_printerr ("%s: %s\n", G_STRFUNC, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* Append possibly last original text without proper localization. */
|
||||
if (state.original)
|
||||
{
|
||||
g_string_append (state.text, state.original->str);
|
||||
g_string_free (state.original, TRUE);
|
||||
}
|
||||
|
||||
markup = g_string_free (state.text, FALSE);
|
||||
gimp_xml_parser_free (xml_parser);
|
||||
|
||||
return markup;
|
||||
return gimp_appstream_parse (as_text, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_appstream_to_pango_markups (const gchar *as_text,
|
||||
gchar **introduction,
|
||||
GList **release_items)
|
||||
{
|
||||
gchar * markup;
|
||||
|
||||
markup = gimp_appstream_parse (as_text, introduction, release_items);
|
||||
g_free (markup);
|
||||
}
|
||||
|
||||
gint
|
||||
gimp_g_list_compare (GList *list1,
|
||||
|
@ -1308,6 +1284,61 @@ gimp_create_image_from_buffer (Gimp *gimp,
|
|||
|
||||
/* Private functions */
|
||||
|
||||
|
||||
static gchar *
|
||||
gimp_appstream_parse (const gchar *as_text,
|
||||
gchar **introduction,
|
||||
GList **release_items)
|
||||
{
|
||||
static const GMarkupParser appstream_text_parser =
|
||||
{
|
||||
appstream_text_start_element,
|
||||
appstream_text_end_element,
|
||||
appstream_text_characters,
|
||||
NULL, /* passthrough */
|
||||
NULL /* error */
|
||||
};
|
||||
|
||||
GimpXmlParser *xml_parser;
|
||||
gchar *markup = NULL;
|
||||
GError *error = NULL;
|
||||
ParseState state;
|
||||
|
||||
state.level = 0;
|
||||
state.foreign_level = -1;
|
||||
state.text = g_string_new (NULL);
|
||||
state.list_num = 0;
|
||||
state.numbered_list = FALSE;
|
||||
state.unnumbered_list = FALSE;
|
||||
state.lang = g_getenv ("LANGUAGE");
|
||||
state.original = NULL;
|
||||
state.introduction = introduction;
|
||||
state.release_items = release_items;
|
||||
|
||||
xml_parser = gimp_xml_parser_new (&appstream_text_parser, &state);
|
||||
if (as_text &&
|
||||
! gimp_xml_parser_parse_buffer (xml_parser, as_text, -1, &error))
|
||||
{
|
||||
g_printerr ("%s: %s\n", G_STRFUNC, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* Append possibly last original text without proper localization. */
|
||||
if (state.original)
|
||||
{
|
||||
g_string_append (state.text, state.original->str);
|
||||
g_string_free (state.original, TRUE);
|
||||
}
|
||||
|
||||
if (release_items)
|
||||
*release_items = g_list_reverse (*release_items);
|
||||
|
||||
markup = g_string_free (state.text, FALSE);
|
||||
gimp_xml_parser_free (xml_parser);
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
static void
|
||||
appstream_text_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
|
@ -1367,6 +1398,7 @@ appstream_text_start_element (GMarkupParseContext *context,
|
|||
else if (g_strcmp0 (element_name, "ul") == 0)
|
||||
{
|
||||
state->unnumbered_list = TRUE;
|
||||
state->list_num = 0;
|
||||
}
|
||||
else if (g_strcmp0 (element_name, "ol") == 0)
|
||||
{
|
||||
|
@ -1407,6 +1439,10 @@ appstream_text_end_element (GMarkupParseContext *context,
|
|||
{
|
||||
if (state->foreign_level < 0)
|
||||
{
|
||||
if (state->introduction &&
|
||||
*state->introduction == NULL)
|
||||
*state->introduction = g_strdup (state->original ? state->original->str : state->text->str);
|
||||
|
||||
if (state->original)
|
||||
g_string_append (state->original, "\n\n");
|
||||
else
|
||||
|
@ -1440,8 +1476,24 @@ appstream_text_characters (GMarkupParseContext *context,
|
|||
{
|
||||
ParseState *state = user_data;
|
||||
|
||||
if (state->foreign_level < 0)
|
||||
if (state->foreign_level < 0 && text_len > 0)
|
||||
{
|
||||
if (state->list_num > 0 && state->release_items)
|
||||
{
|
||||
GList **items = state->release_items;
|
||||
|
||||
if (state->list_num == g_list_length (*(state->release_items)))
|
||||
{
|
||||
gchar *tmp = (*items)->data;
|
||||
|
||||
(*items)->data = g_strconcat (tmp, text, NULL);
|
||||
g_free (tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
*items = g_list_prepend (*items, g_strdup (text));
|
||||
}
|
||||
}
|
||||
if (state->original)
|
||||
g_string_append (state->original, text);
|
||||
else
|
||||
|
|
|
@ -102,6 +102,9 @@ gboolean gimp_ascii_strtod (const gchar *nptr,
|
|||
gdouble *result);
|
||||
|
||||
gchar * gimp_appstream_to_pango_markup (const gchar *as_text);
|
||||
void gimp_appstream_to_pango_markups (const gchar *as_text,
|
||||
gchar **introduction,
|
||||
GList **release_items);
|
||||
|
||||
gint gimp_g_list_compare (GList *list1,
|
||||
GList *list2);
|
||||
|
|
|
@ -74,15 +74,15 @@ welcome_dialog_create (Gimp *gimp)
|
|||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *image;
|
||||
GtkWidget *listbox;
|
||||
GtkWidget *widget;
|
||||
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter iter;
|
||||
|
||||
gchar *release_link;
|
||||
gchar *appdata_path;
|
||||
gchar *title;
|
||||
gchar *markup;
|
||||
gchar *release_introduction = NULL;
|
||||
GList *release_items = NULL;
|
||||
gchar *tmp;
|
||||
|
||||
gint row;
|
||||
|
@ -344,26 +344,55 @@ welcome_dialog_create (Gimp *gimp)
|
|||
|
||||
/* Release note contents. */
|
||||
|
||||
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scrolled_window);
|
||||
gimp_appstream_to_pango_markups (release_notes,
|
||||
&release_introduction,
|
||||
&release_items);
|
||||
if (release_introduction)
|
||||
{
|
||||
widget = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (widget), release_introduction);
|
||||
gtk_label_set_max_width_chars (GTK_LABEL (widget), 70);
|
||||
gtk_label_set_selectable (GTK_LABEL (widget), FALSE);
|
||||
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
|
||||
gtk_widget_show (widget);
|
||||
|
||||
widget = gtk_text_view_new ();
|
||||
gtk_widget_set_vexpand (widget, TRUE);
|
||||
gtk_widget_set_hexpand (widget, TRUE);
|
||||
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (widget), GTK_WRAP_WORD_CHAR);
|
||||
gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), FALSE);
|
||||
gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (widget), FALSE);
|
||||
gtk_text_view_set_justification (GTK_TEXT_VIEW (widget), GTK_JUSTIFY_LEFT);
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
|
||||
gtk_text_buffer_get_start_iter (buffer, &iter);
|
||||
g_free (release_introduction);
|
||||
}
|
||||
|
||||
markup = gimp_appstream_to_pango_markup (release_notes);
|
||||
gtk_text_buffer_insert_markup (buffer, &iter, markup, -1);
|
||||
g_free (markup);
|
||||
if (release_items)
|
||||
{
|
||||
GList *item;
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
|
||||
gtk_widget_show (widget);
|
||||
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scrolled_window);
|
||||
|
||||
listbox = gtk_list_box_new ();
|
||||
|
||||
for (item = release_items; item; item = item->next)
|
||||
{
|
||||
GtkWidget *row;
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
widget = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (widget), item->data);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
|
||||
gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
|
||||
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
|
||||
gtk_widget_set_halign (widget, GTK_ALIGN_START);
|
||||
gtk_label_set_xalign (GTK_LABEL (widget), 0.0);
|
||||
gtk_container_add (GTK_CONTAINER (row), widget);
|
||||
|
||||
gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1);
|
||||
gtk_widget_show_all (row);
|
||||
}
|
||||
gtk_container_add (GTK_CONTAINER (scrolled_window), listbox);
|
||||
gtk_widget_show (listbox);
|
||||
|
||||
g_list_free_full (release_items, g_free);
|
||||
}
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
|
Loading…
Reference in New Issue