summaryrefslogtreecommitdiffstats
path: root/src/gs-repos-section.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gs-repos-section.c')
-rw-r--r--src/gs-repos-section.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/gs-repos-section.c b/src/gs-repos-section.c
new file mode 100644
index 0000000..3e5d684
--- /dev/null
+++ b/src/gs-repos-section.c
@@ -0,0 +1,201 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * Copyright (C) 2021 Red Hat <www.redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include "gs-repo-row.h"
+#include "gs-repos-section.h"
+
+struct _GsReposSection
+{
+ AdwPreferencesGroup parent_instance;
+ GtkWidget *title;
+ GtkListBox *list;
+ gchar *sort_key;
+ gboolean always_allow_enable_disable;
+};
+
+G_DEFINE_TYPE (GsReposSection, gs_repos_section, ADW_TYPE_PREFERENCES_GROUP)
+
+enum {
+ SIGNAL_REMOVE_CLICKED,
+ SIGNAL_SWITCH_CLICKED,
+ SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+static void
+repo_remove_clicked_cb (GsRepoRow *row,
+ GsReposSection *section)
+{
+ g_signal_emit (section, signals[SIGNAL_REMOVE_CLICKED], 0, row);
+}
+
+static void
+repo_switch_clicked_cb (GsRepoRow *row,
+ GsReposSection *section)
+{
+ g_signal_emit (section, signals[SIGNAL_SWITCH_CLICKED], 0, row);
+}
+
+static void
+gs_repos_section_row_activated_cb (GtkListBox *box,
+ GtkListBoxRow *row,
+ gpointer user_data)
+{
+ GsReposSection *section = user_data;
+ g_return_if_fail (GS_IS_REPOS_SECTION (section));
+ gs_repo_row_emit_switch_clicked (GS_REPO_ROW (row));
+}
+
+static gchar *
+_get_app_sort_key (GsApp *app)
+{
+ if (gs_app_get_name (app) != NULL)
+ return gs_utils_sort_key (gs_app_get_name (app));
+
+ return NULL;
+}
+
+static gint
+_list_sort_func (GtkListBoxRow *a, GtkListBoxRow *b, gpointer user_data)
+{
+ GsApp *a1 = gs_repo_row_get_repo (GS_REPO_ROW (a));
+ GsApp *a2 = gs_repo_row_get_repo (GS_REPO_ROW (b));
+ g_autofree gchar *key1 = _get_app_sort_key (a1);
+ g_autofree gchar *key2 = _get_app_sort_key (a2);
+
+ return g_strcmp0 (key1, key2);
+}
+
+static void
+gs_repos_section_finalize (GObject *object)
+{
+ GsReposSection *self = GS_REPOS_SECTION (object);
+
+ g_free (self->sort_key);
+
+ G_OBJECT_CLASS (gs_repos_section_parent_class)->finalize (object);
+}
+
+static void
+gs_repos_section_class_init (GsReposSectionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gs_repos_section_finalize;
+
+ signals [SIGNAL_REMOVE_CLICKED] =
+ g_signal_new ("remove-clicked",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GS_TYPE_REPO_ROW);
+
+ signals [SIGNAL_SWITCH_CLICKED] =
+ g_signal_new ("switch-clicked",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GS_TYPE_REPO_ROW);
+}
+
+static void
+gs_repos_section_init (GsReposSection *self)
+{
+ GtkStyleContext *style_context;
+
+ self->list = GTK_LIST_BOX (gtk_list_box_new ());
+ g_object_set (G_OBJECT (self->list),
+ "visible", TRUE,
+ "selection-mode", GTK_SELECTION_NONE,
+ NULL);
+ gtk_list_box_set_sort_func (self->list, _list_sort_func, self, NULL);
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (self->list));
+ gtk_style_context_add_class (style_context, "boxed-list");
+
+ adw_preferences_group_add (ADW_PREFERENCES_GROUP (self), GTK_WIDGET (self->list));
+
+ g_signal_connect (self->list, "row-activated",
+ G_CALLBACK (gs_repos_section_row_activated_cb), self);
+}
+
+/*
+ * gs_repos_section_new:
+ * @always_allow_enable_disable: always allow enable/disable of the repos in this section
+ *
+ * Creates a new #GsReposSection. @always_allow_enable_disable is passed to each
+ * #GsRepoRow.
+ *
+ * The @always_allow_enable_disable, when %TRUE, means that every repo in this section
+ * can be enabled/disabled by the user, if supported by the related plugin, regardless
+ * of the other heuristics, which can avoid the repo enable/disable.
+ *
+ * Returns: (transfer full): a newly created #GsReposSection
+ */
+GtkWidget *
+gs_repos_section_new (gboolean always_allow_enable_disable)
+{
+ GsReposSection *self;
+
+ self = g_object_new (GS_TYPE_REPOS_SECTION, NULL);
+
+ self->always_allow_enable_disable = always_allow_enable_disable;
+
+ return GTK_WIDGET (self);
+}
+
+void
+gs_repos_section_add_repo (GsReposSection *self,
+ GsApp *repo)
+{
+ GtkWidget *row;
+
+ g_return_if_fail (GS_IS_REPOS_SECTION (self));
+ g_return_if_fail (GS_IS_APP (repo));
+
+ /* Derive the sort key from the repository. All repositories of the same kind
+ should have set the same sort key. It's because there's no other way to provide
+ the section sort key by the plugin without breaking the abstraction. */
+ if (!self->sort_key)
+ self->sort_key = g_strdup (gs_app_get_metadata_item (repo, "GnomeSoftware::SortKey"));
+
+ row = gs_repo_row_new (repo, self->always_allow_enable_disable);
+
+ g_signal_connect (row, "remove-clicked",
+ G_CALLBACK (repo_remove_clicked_cb), self);
+ g_signal_connect (row, "switch-clicked",
+ G_CALLBACK (repo_switch_clicked_cb), self);
+
+ gtk_list_box_prepend (self->list, row);
+ gtk_widget_show (row);
+}
+
+const gchar *
+gs_repos_section_get_sort_key (GsReposSection *self)
+{
+ g_return_val_if_fail (GS_IS_REPOS_SECTION (self), NULL);
+
+ return self->sort_key;
+}
+
+void
+gs_repos_section_set_sort_key (GsReposSection *self,
+ const gchar *sort_key)
+{
+ g_return_if_fail (GS_IS_REPOS_SECTION (self));
+
+ if (g_strcmp0 (sort_key, self->sort_key) != 0) {
+ g_free (self->sort_key);
+ self->sort_key = g_strdup (sort_key);
+ }
+}