gem-graph-client/libide/greeter/ide-greeter-row.c

380 lines
11 KiB
C

/* ide-greeter-row.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "ide-greeter-row"
#include "config.h"
#include <glib/gi18n.h>
#include <libide-projects.h>
#include <stdlib.h>
#include "ide-project-info-private.h"
#include "ide-greeter-row.h"
typedef struct
{
IdeProjectInfo *project_info;
/* Template Widgets */
GtkCheckButton *check_button;
GtkLabel *title;
GtkLabel *subtitle;
GtkImage *image;
GtkBox *tags;
} IdeGreeterRowPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (IdeGreeterRow, ide_greeter_row, GTK_TYPE_LIST_BOX_ROW)
enum {
PROP_0,
PROP_PROJECT_INFO,
PROP_SELECTED,
N_PROPS
};
enum {
TAG_NONE,
TAG_BUILD_SYSTEM,
TAG_LANGUAGE,
};
static GParamSpec *properties [N_PROPS];
static GHashTable *icon_name_map;
/**
* ide_greeter_row_new:
*
* Create a new #IdeGreeterRow.
*
* Returns: (transfer full): a newly created #IdeGreeterRow
*/
IdeGreeterRow *
ide_greeter_row_new (void)
{
return g_object_new (IDE_TYPE_GREETER_ROW, NULL);
}
static void
ide_greeter_row_get_preferred_width (GtkWidget *widget,
gint *min_width,
gint *nat_width)
{
*min_width = 600;
*nat_width = 600;
}
static void
ide_greeter_row_finalize (GObject *object)
{
IdeGreeterRow *self = (IdeGreeterRow *)object;
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
g_clear_object (&priv->project_info);
G_OBJECT_CLASS (ide_greeter_row_parent_class)->finalize (object);
}
static void
ide_greeter_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
IdeGreeterRow *self = IDE_GREETER_ROW (object);
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
switch (prop_id)
{
case PROP_PROJECT_INFO:
g_value_set_object (value, ide_greeter_row_get_project_info (self));
break;
case PROP_SELECTED:
g_value_set_boolean (value,
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->check_button)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_greeter_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
IdeGreeterRow *self = IDE_GREETER_ROW (object);
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
switch (prop_id)
{
case PROP_PROJECT_INFO:
ide_greeter_row_set_project_info (self, g_value_get_object (value));
break;
case PROP_SELECTED:
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check_button),
g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_greeter_row_class_init (IdeGreeterRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = ide_greeter_row_finalize;
object_class->get_property = ide_greeter_row_get_property;
object_class->set_property = ide_greeter_row_set_property;
widget_class->get_preferred_width = ide_greeter_row_get_preferred_width;
/**
* IdeGreeterRow:project-info:
*
* The "project-info" property contains information about the project
* to be displayed.
*
* Since: 3.32
*/
properties [PROP_PROJECT_INFO] =
g_param_spec_object ("project-info",
"Project Info",
"Project Info",
IDE_TYPE_PROJECT_INFO,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_SELECTED] =
g_param_spec_boolean ("selected",
"Selected",
"If the row is selected",
FALSE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/ide-greeter-row.ui");
gtk_widget_class_bind_template_child_private (widget_class, IdeGreeterRow, check_button);
gtk_widget_class_bind_template_child_private (widget_class, IdeGreeterRow, image);
gtk_widget_class_bind_template_child_private (widget_class, IdeGreeterRow, subtitle);
gtk_widget_class_bind_template_child_private (widget_class, IdeGreeterRow, tags);
gtk_widget_class_bind_template_child_private (widget_class, IdeGreeterRow, title);
#define ADD(a,b) g_hash_table_insert(icon_name_map, (gpointer)a, (gpointer)b)
icon_name_map = g_hash_table_new (g_str_hash, g_str_equal);
ADD ("python", "text-x-python-symbolic");
ADD ("c", "text-x-csrc-symbolic");
ADD ("c++", "text-x-cpp-symbolic");
ADD ("css", "text-x-css-symbolic");
ADD ("html", "text-x-html-symbolic");
ADD ("ruby", "text-x-ruby-symbolic");
ADD ("rust", "text-x-rust-symbolic");
ADD ("javascript", "text-x-javascript-symbolic");
ADD ("vala", "text-x-vala-symbolic");
ADD ("xml", "text-x-xml-symbolic");
#undef ADD
}
static void
ide_greeter_row_init (IdeGreeterRow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
ide_greeter_row_clear (IdeGreeterRow *self)
{
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
g_assert (IDE_IS_GREETER_ROW (self));
g_object_set (priv->image, "icon-name", NULL, NULL);
gtk_label_set_label (priv->title, NULL);
gtk_label_set_label (priv->subtitle, NULL);
gtk_container_foreach (GTK_CONTAINER (priv->tags),
(GtkCallback)gtk_widget_destroy,
NULL);
}
/**
* ide_greeter_row_get_project_info:
* @self: an #IdeGreeterRow
*
* Gets the #IdeGreeterRow:project-info property.
*
* Returns: (transfer none) (nullable): an #IdeProjectInfo or %NULL
*
* Since: 3.32
*/
IdeProjectInfo *
ide_greeter_row_get_project_info (IdeGreeterRow *self)
{
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
g_return_val_if_fail (IDE_IS_GREETER_ROW (self), NULL);
return priv->project_info;
}
static gint
compare_language (gconstpointer a,
gconstpointer b)
{
return g_utf8_collate (*(gchar **)a, *(gchar **)b);
}
static gboolean
ignore_build_system (const gchar *str)
{
/* Handle translated and untranslated strings */
return ide_str_empty0 (str) ||
g_str_equal (str, "Directory") ||
g_str_equal (str, "Fallback") ||
g_str_equal (str, _("Directory")) ||
g_str_equal (str, _("Fallback"));
}
void
ide_greeter_row_set_project_info (IdeGreeterRow *self,
IdeProjectInfo *project_info)
{
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
g_return_if_fail (IDE_IS_GREETER_ROW (self));
g_return_if_fail (!project_info || IDE_IS_PROJECT_INFO (project_info));
if (g_set_object (&priv->project_info, project_info))
{
ide_greeter_row_clear (self);
if (project_info != NULL)
{
g_autofree gchar *collapsed = NULL;
g_auto(GStrv) languages = g_strdupv ((gchar **)ide_project_info_get_languages (project_info));
const gchar *name = ide_project_info_get_name (project_info);
const gchar *build_system = ide_project_info_get_build_system_name (project_info);
GFile *directory = _ide_project_info_get_real_directory (project_info);
const gchar *desc = ide_project_info_get_description (project_info);
GIcon *icon = ide_project_info_get_icon (project_info);
g_autoptr(GPtrArray) parts = g_ptr_array_new ();
if (!ide_str_empty0 (desc))
gtk_widget_set_tooltip_text (GTK_WIDGET (self), desc);
if (directory != NULL)
{
if ((collapsed = ide_path_collapse (g_file_peek_path (directory))))
desc = collapsed;
}
gtk_label_set_label (priv->title, name);
gtk_label_set_label (priv->subtitle, desc);
if (languages != NULL)
{
for (guint i = 0; languages[i] != NULL; i++)
g_ptr_array_add (parts, g_strstrip (languages[i]));
}
/* Sort before build system is added */
g_ptr_array_sort (parts, compare_language);
if (!ignore_build_system (build_system))
g_ptr_array_insert (parts, 0, (gchar *)build_system);
for (guint i = 0; i < parts->len; i++)
{
const gchar *key = g_ptr_array_index (parts, i);
DzlPillBox *tag;
tag = g_object_new (DZL_TYPE_PILL_BOX,
"visible", TRUE,
"label", key,
NULL);
gtk_container_add (GTK_CONTAINER (priv->tags), GTK_WIDGET (tag));
}
if (icon != NULL)
g_object_set (priv->image,
"pixel-size", 32,
"gicon", icon,
"visible", icon != NULL,
NULL);
}
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROJECT_INFO]);
}
}
/**
* ide_greeter_row_get_search_text:
* @self: a #IdeGreeterRow
*
* Gets a new string containing the search text for the greeter row.
*
* Returns: (transfer full) (nullable): a string or %NULL
*
* Since: 3.32
*/
gchar *
ide_greeter_row_get_search_text (IdeGreeterRow *self)
{
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
GString *str;
g_return_val_if_fail (IDE_IS_GREETER_ROW (self), NULL);
str = g_string_new (NULL);
g_string_append_printf (str, "%s ", gtk_label_get_text (priv->title) ?: "");
g_string_append_printf (str, "%s ", gtk_label_get_text (priv->subtitle) ?: "");
return g_string_free (g_steal_pointer (&str), FALSE);
}
gboolean
ide_greeter_row_get_selection_mode (IdeGreeterRow *self)
{
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
g_return_val_if_fail (IDE_IS_GREETER_ROW (self), FALSE);
return gtk_widget_get_visible (GTK_WIDGET (priv->check_button));
}
void
ide_greeter_row_set_selection_mode (IdeGreeterRow *self,
gboolean selection_mode)
{
IdeGreeterRowPrivate *priv = ide_greeter_row_get_instance_private (self);
g_return_if_fail (IDE_IS_GREETER_ROW (self));
gtk_widget_set_visible (GTK_WIDGET (priv->check_button), selection_mode);
}