[gnome-software/wip/hughsie/banner-editor-ids: 4/4] Support a few defined CSS IDs when setting up the feature tile
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/banner-editor-ids: 4/4] Support a few defined CSS IDs when setting up the feature tile
- Date: Mon, 15 May 2017 18:59:10 +0000 (UTC)
commit 3bfc60cd5f5e11d632b9583e48d33e789c5de65b
Author: Richard Hughes <richard hughsie com>
Date: Mon May 15 19:57:56 2017 +0100
Support a few defined CSS IDs when setting up the feature tile
src/gs-common.c | 111 ++++++++++++++++++++++++++++++++++++++++++++--
src/gs-common.h | 2 +
src/gs-editor.c | 37 +++++++++++++++-
src/gs-feature-tile.c | 14 +++++-
src/gs-popular-tile.c | 5 +-
src/gs-self-test.c | 71 ++++++++++++++++++++++++++++++
src/gs-summary-tile.c | 5 +-
src/gs-upgrade-banner.c | 5 +-
src/meson.build | 30 +++++++++++++
9 files changed, 266 insertions(+), 14 deletions(-)
---
diff --git a/src/gs-common.c b/src/gs-common.c
index 1ec2afd..26cad26 100644
--- a/src/gs-common.c
+++ b/src/gs-common.c
@@ -386,12 +386,9 @@ gs_utils_widget_set_css_simple (GtkWidget *widget, const gchar *css)
}
void
-gs_utils_widget_set_css_app (GsApp *app,
- GtkWidget *widget,
- const gchar *metadata_css)
+gs_utils_widget_set_css_app (GsApp *app, GtkWidget *widget, const gchar *css)
{
GPtrArray *key_colors;
- const gchar *css;
guint i;
g_autofree gchar *class_name = NULL;
g_autoptr(GString) css_str = NULL;
@@ -400,7 +397,6 @@ gs_utils_widget_set_css_app (GsApp *app,
g_return_if_fail (GS_IS_APP (app));
/* invalid */
- css = gs_app_get_metadata_item (app, metadata_css);
if (css == NULL) {
gs_utils_widget_set_css_simple (widget, css);
return;
@@ -434,6 +430,111 @@ gs_utils_widget_set_css_app (GsApp *app,
}
static void
+_cleanup_string (GString *str)
+{
+ /* remove leading newlines */
+ while (g_str_has_prefix (str->str, "\n") || g_str_has_prefix (str->str, " "))
+ g_string_erase (str, 0, 1);
+
+ /* remove trailing newlines */
+ while (g_str_has_suffix (str->str, "\n") || g_str_has_suffix (str->str, " "))
+ g_string_truncate (str, str->len - 1);
+}
+
+/**
+ * gs_utils_parse_css_ids:
+ * @css: CSS markup
+ * @error: A #GError, or %NULL
+ *
+ * Splits up some CSS into the different IDs. If the CSS is ID-less then
+ * it is handled fine and added to an empty key.
+ *
+ * Returns: a #GHashTable or %NULL for error
+ */
+GHashTable *
+gs_utils_parse_css_ids (const gchar *css, GError **error)
+{
+ g_autoptr(GHashTable) results = NULL;
+ g_auto(GStrv) parts = NULL;
+
+ /* no data */
+ results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ if (css == NULL || css[0] == '\0')
+ return g_steal_pointer (&results);
+
+ /* old style, no IDs */
+ if (!g_str_has_prefix (css, "#")) {
+ g_hash_table_insert (results, g_strdup (""), g_strdup (css));
+ return g_steal_pointer (&results);
+ }
+
+ /* split up CSS into ID chunks, e.g.
+ *
+ * #tile {border-radius: 0;}
+ * #name {color: white;}
+ */
+ parts = g_strsplit (css + 1, "\n#", -1);
+ for (guint i = 0; parts[i] != NULL; i++) {
+ g_autoptr(GString) current_css = NULL;
+ g_autoptr(GString) current_key = NULL;
+ for (guint j = 1; parts[i][j] != '\0'; j++) {
+ const gchar ch = parts[i][j];
+ if (ch == '{') {
+ if (current_key != NULL || current_css != NULL) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "invalid '{'");
+ return NULL;
+ }
+ current_key = g_string_new_len (parts[i], j);
+ current_css = g_string_new (NULL);
+ _cleanup_string (current_key);
+
+ /* already added */
+ if (g_hash_table_lookup (results, current_key->str) != NULL) {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "duplicate ID '%s'",
+ current_key->str);
+ return NULL;
+ }
+ continue;
+ }
+ if (ch == '}') {
+ if (current_key == NULL || current_css == NULL) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "invalid '}'");
+ return NULL;
+ }
+ _cleanup_string (current_css);
+ g_hash_table_insert (results,
+ g_string_free (current_key, FALSE),
+ g_string_free (current_css, FALSE));
+ current_key = NULL;
+ current_css = NULL;
+ continue;
+ }
+ if (current_css != NULL)
+ g_string_append_c (current_css, ch);
+ }
+ if (current_key != NULL || current_css != NULL) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "missing '}'");
+ return NULL;
+ }
+ }
+
+ /* success */
+ return g_steal_pointer (&results);
+}
+
+static void
do_not_expand (GtkWidget *child, gpointer data)
{
gtk_container_child_set (GTK_CONTAINER (gtk_widget_get_parent (child)),
diff --git a/src/gs-common.h b/src/gs-common.h
index b33b8f3..0d02e53 100644
--- a/src/gs-common.h
+++ b/src/gs-common.h
@@ -60,6 +60,8 @@ gchar *gs_utils_build_unique_id_kind (AsAppKind kind,
const gchar *id);
gboolean gs_utils_list_has_app_fuzzy (GsAppList *list,
GsApp *app);
+GHashTable *gs_utils_parse_css_ids (const gchar *css,
+ GError **error);
G_END_DECLS
diff --git a/src/gs-editor.c b/src/gs-editor.c
index d8f7f45..6c896af 100644
--- a/src/gs-editor.c
+++ b/src/gs-editor.c
@@ -89,7 +89,7 @@ gs_design_css_parsing_error_cb (GtkCssProvider *provider,
}
static gboolean
-gs_design_validate_css (GsEditor *self, const gchar *css, GError **error)
+gs_design_validate_css_part (GsEditor *self, const gchar *css, GError **error)
{
GsDesignErrorHelper helper;
g_autofree gchar *css_new = NULL;
@@ -122,6 +122,41 @@ gs_design_validate_css (GsEditor *self, const gchar *css, GError **error)
return *(helper.error) == NULL;
}
+static gboolean
+gs_design_validate_css (GsEditor *self, const gchar *css, GError **error)
+{
+ const gchar *tmp;
+ g_autoptr(GHashTable) ids = NULL;
+ g_autoptr(GList) keys = NULL;
+
+ /* check each CSS ID */
+ ids = gs_utils_parse_css_ids (css, error);
+ if (ids == NULL)
+ return FALSE;
+ keys = g_hash_table_get_keys (ids);
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *id = l->data;
+ g_warning ("%s", id);
+ if (g_strcmp0 (id, "") != 0 &&
+ g_strcmp0 (id, "tile") != 0 &&
+ g_strcmp0 (id, "name") != 0 &&
+ g_strcmp0 (id, "summary") != 0) {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "Invalid CSS ID '%s'",
+ id);
+ return FALSE;
+ }
+ tmp = g_hash_table_lookup (ids, id);
+ if (!gs_design_validate_css_part (self, tmp, error))
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
static void
gs_editor_refine_app_pixbuf (GsApp *app)
{
diff --git a/src/gs-feature-tile.c b/src/gs-feature-tile.c
index dfda13e..4876048 100644
--- a/src/gs-feature-tile.c
+++ b/src/gs-feature-tile.c
@@ -50,7 +50,9 @@ app_state_changed_idle (gpointer user_data)
{
GsFeatureTile *tile = GS_FEATURE_TILE (user_data);
AtkObject *accessible;
+ const gchar *css;
g_autofree gchar *name = NULL;
+ g_autoptr(GHashTable) ids = NULL;
/* nothing set yet */
if (tile->app == NULL)
@@ -61,8 +63,16 @@ app_state_changed_idle (gpointer user_data)
gtk_label_set_label (GTK_LABEL (tile->subtitle), gs_app_get_summary (tile->app));
/* perhaps set custom css */
- gs_utils_widget_set_css_app (tile->app, GTK_WIDGET (tile),
- "GnomeSoftware::FeatureTile-css");
+ css = gs_app_get_metadata_item (tile->app, "GnomeSoftware::FeatureTile-css");
+ ids = gs_utils_parse_css_ids (css, NULL);
+ css = g_hash_table_lookup (ids, "tile");
+ if (css == NULL)
+ css = g_hash_table_lookup (ids, "");
+ gs_utils_widget_set_css_app (tile->app, GTK_WIDGET (tile), css);
+ gs_utils_widget_set_css_simple (tile->title,
+ g_hash_table_lookup (ids, "name"));
+ gs_utils_widget_set_css_simple (tile->subtitle,
+ g_hash_table_lookup (ids, "summary"));
accessible = gtk_widget_get_accessible (GTK_WIDGET (tile));
diff --git a/src/gs-popular-tile.c b/src/gs-popular-tile.c
index 272c538..1047e6d 100644
--- a/src/gs-popular-tile.c
+++ b/src/gs-popular-tile.c
@@ -97,6 +97,7 @@ static void
gs_popular_tile_set_app (GsAppTile *app_tile, GsApp *app)
{
GsPopularTile *tile = GS_POPULAR_TILE (app_tile);
+ const gchar *css;
g_return_if_fail (GS_IS_APP (app) || app == NULL);
@@ -125,8 +126,8 @@ gs_popular_tile_set_app (GsAppTile *app_tile, GsApp *app)
app_state_changed (tile->app, NULL, tile);
/* perhaps set custom css */
- gs_utils_widget_set_css_app (app, GTK_WIDGET (tile),
- "GnomeSoftware::PopularTile-css");
+ css = gs_app_get_metadata_item (app, "GnomeSoftware::PopularTile-css");
+ gs_utils_widget_set_css_app (app, GTK_WIDGET (tile), css);
if (gs_app_get_pixbuf (tile->app) != NULL) {
gs_image_set_from_pixbuf (GTK_IMAGE (tile->image), gs_app_get_pixbuf (tile->app));
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
new file mode 100644
index 0000000..52bc4d7
--- /dev/null
+++ b/src/gs-self-test.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "gnome-software-private.h"
+
+#include "gs-common.h"
+#include "gs-test.h"
+
+static void
+gs_common_func (void)
+{
+ const gchar *css;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GHashTable) hash1 = NULL;
+ g_autoptr(GHashTable) hash2 = NULL;
+
+ /* hash, no IDs */
+ hash1 = gs_utils_parse_css_ids ("border: 0;", &error);
+ g_assert_no_error (error);
+ g_assert (hash1 != NULL);
+ css = g_hash_table_lookup (hash1, "");
+ g_assert_cmpstr (css, ==, "border: 0;");
+
+ /* hash IDs */
+ hash2 = gs_utils_parse_css_ids ("#tile{\nborder: 0;}\n#name {color: white;\n}", &error);
+ g_assert_no_error (error);
+ g_assert (hash2 != NULL);
+ css = g_hash_table_lookup (hash2, "");
+ g_assert_cmpstr (css, ==, NULL);
+ css = g_hash_table_lookup (hash2, "tile");
+ g_assert_cmpstr (css, ==, "border: 0;");
+ css = g_hash_table_lookup (hash2, "name");
+ g_assert_cmpstr (css, ==, "color: white;");
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+ g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+
+ /* only critical and error are fatal */
+ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+
+ /* tests go here */
+ g_test_add_func ("/gnome-software/src/common", gs_common_func);
+
+ return g_test_run ();
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-summary-tile.c b/src/gs-summary-tile.c
index 2fd6f90..4162953 100644
--- a/src/gs-summary-tile.c
+++ b/src/gs-summary-tile.c
@@ -115,6 +115,7 @@ gs_summary_tile_set_app (GsAppTile *app_tile, GsApp *app)
{
const GdkPixbuf *pixbuf;
GsSummaryTile *tile = GS_SUMMARY_TILE (app_tile);
+ const gchar *css;
g_autofree gchar *text = NULL;
g_return_if_fail (GS_IS_APP (app) || app == NULL);
@@ -150,8 +151,8 @@ gs_summary_tile_set_app (GsAppTile *app_tile, GsApp *app)
gtk_label_set_label (GTK_LABEL (tile->name), gs_app_get_name (app));
/* perhaps set custom css */
- gs_utils_widget_set_css_app (app, GTK_WIDGET (tile),
- "GnomeSoftware::AppTile-css");
+ css = gs_app_get_metadata_item (app, "GnomeSoftware::AppTile-css");
+ gs_utils_widget_set_css_app (app, GTK_WIDGET (tile), css);
/* some kinds have boring summaries */
switch (gs_app_get_kind (app)) {
diff --git a/src/gs-upgrade-banner.c b/src/gs-upgrade-banner.c
index c343013..4080f4a 100644
--- a/src/gs-upgrade-banner.c
+++ b/src/gs-upgrade-banner.c
@@ -207,6 +207,7 @@ void
gs_upgrade_banner_set_app (GsUpgradeBanner *self, GsApp *app)
{
GsUpgradeBannerPrivate *priv = gs_upgrade_banner_get_instance_private (self);
+ const gchar *css;
g_return_if_fail (GS_IS_UPGRADE_BANNER (self));
g_return_if_fail (GS_IS_APP (app) || app == NULL);
@@ -226,8 +227,8 @@ gs_upgrade_banner_set_app (GsUpgradeBanner *self, GsApp *app)
G_CALLBACK (app_progress_changed), self);
/* perhaps set custom css */
- gs_utils_widget_set_css_app (app, priv->box_upgrades,
- "GnomeSoftware::UpgradeBanner-css");
+ css = gs_app_get_metadata_item (app, "GnomeSoftware::UpgradeBanner-css");
+ gs_utils_widget_set_css_app (app, priv->box_upgrades, css);
gs_upgrade_banner_refresh (self);
}
diff --git a/src/meson.build b/src/meson.build
index a7c29d0..153e126 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -263,3 +263,33 @@ if get_option('enable-packagekit')
configuration : conf
)
endif
+
+if get_option('enable-tests')
+ cargs += ['-DTESTDATADIR="' + join_paths(meson.current_source_dir(), '..', 'data') + '"']
+ e = executable(
+ 'gs-self-test-src',
+ sources : [
+ 'gs-common.c',
+ 'gs-self-test.c',
+ ],
+ include_directories : [
+ include_directories('..'),
+ include_directories('../lib'),
+ ],
+ dependencies : [
+ appstream_glib,
+ gio_unix,
+ gmodule,
+ gtk,
+ json_glib,
+ libm,
+ libsecret,
+ libsoup,
+ ],
+ link_with : [
+ libgnomesoftware
+ ],
+ c_args : cargs
+ )
+ test('gs-self-test-src', e)
+endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]