model: Add visibility field

This field can be used to communicate the visibility of the
panel from a static context (i.e. without any instances of
a CcPanel nor any access to CcShell).
This commit is contained in:
Georges Basile Stavracas Neto 2018-04-08 19:10:25 -03:00
parent 489a7ae5dd
commit a78cbe3963
6 changed files with 246 additions and 63 deletions

View file

@ -18,20 +18,24 @@
* Author: Georges Basile Stavracas Neto <gbsneto@gnome.org>
*/
#define G_LOG_DOMAIN "cc-panel-list"
#include <string.h>
#include "cc-debug.h"
#include "cc-panel-list.h"
#include "cc-util.h"
typedef struct
{
GtkWidget *row;
GtkWidget *description_label;
CcPanelCategory category;
gchar *id;
gchar *name;
gchar *description;
gchar **keywords;
GtkWidget *row;
GtkWidget *description_label;
CcPanelCategory category;
gchar *id;
gchar *name;
gchar *description;
gchar **keywords;
CcPanelVisibility visibility;
} RowData;
struct _CcPanelList
@ -106,6 +110,49 @@ get_listbox_from_view (CcPanelList *self,
}
}
static GtkWidget *
get_listbox_from_category (CcPanelList *self,
CcPanelCategory category)
{
switch (category)
{
case CC_CATEGORY_DEVICES:
return self->devices_listbox;
break;
case CC_CATEGORY_DETAILS:
return self->details_listbox;
break;
default:
return self->main_listbox;
break;
}
return NULL;
}
static void
activate_row_below (CcPanelList *self,
RowData *data)
{
GtkListBoxRow *next_row;
GtkListBox *listbox;
guint row_index;
row_index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (data->row));
listbox = GTK_LIST_BOX (get_listbox_from_category (self, data->category));
next_row = gtk_list_box_get_row_at_index (listbox, row_index + 1);
/* Try the previous one if the current is invalid */
if (!next_row || next_row == self->devices_row || next_row == self->details_row)
next_row = gtk_list_box_get_row_at_index (listbox, row_index - 1);
if (next_row)
g_signal_emit_by_name (next_row, "activate");
}
static CcPanelListView
get_view_from_listbox (CcPanelList *self,
GtkWidget *listbox)
@ -159,12 +206,13 @@ row_data_free (RowData *data)
}
static RowData*
row_data_new (CcPanelCategory category,
const gchar *id,
const gchar *name,
const gchar *description,
gchar **keywords,
const gchar *icon)
row_data_new (CcPanelCategory category,
const gchar *id,
const gchar *name,
const gchar *description,
gchar **keywords,
const gchar *icon,
CcPanelVisibility visibility)
{
GtkWidget *label, *grid, *image;
RowData *data;
@ -222,6 +270,9 @@ row_data_new (CcPanelCategory category,
g_object_set_data_full (G_OBJECT (data->row), "data", data, (GDestroyNotify) row_data_free);
data->visibility = visibility;
gtk_widget_set_visible (data->row, visibility == CC_PANEL_VISIBLE);
return data;
}
@ -766,18 +817,21 @@ cc_panel_list_activate (CcPanelList *self)
{
GtkListBoxRow *row;
GtkWidget *listbox;
guint i = 0;
CC_ENTRY;
g_return_val_if_fail (CC_IS_PANEL_LIST (self), FALSE);
listbox = get_listbox_from_view (self, self->view);
if (self->view == CC_PANEL_LIST_SEARCH)
row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (listbox), 0);
else
row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (listbox), 0);
/* Select the first visible row */
do
row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (listbox), i++);
while (row && !gtk_widget_get_visible (GTK_WIDGET (row)));
/* If the row is valid, activate it */
if (row)
if (row && !gtk_list_box_row_is_selected (row))
{
gtk_list_box_select_row (GTK_LIST_BOX (listbox), row);
gtk_widget_grab_focus (GTK_WIDGET (row));
@ -785,7 +839,7 @@ cc_panel_list_activate (CcPanelList *self)
g_signal_emit_by_name (row, "activate");
}
return row != NULL;
CC_RETURN (row != NULL);
}
const gchar*
@ -865,13 +919,14 @@ cc_panel_list_set_view (CcPanelList *self,
}
void
cc_panel_list_add_panel (CcPanelList *self,
CcPanelCategory category,
const gchar *id,
const gchar *title,
const gchar *description,
gchar **keywords,
const gchar *icon)
cc_panel_list_add_panel (CcPanelList *self,
CcPanelCategory category,
const gchar *id,
const gchar *title,
const gchar *description,
gchar **keywords,
const gchar *icon,
CcPanelVisibility visibility)
{
GtkWidget *listbox;
RowData *data, *search_data;
@ -879,27 +934,13 @@ cc_panel_list_add_panel (CcPanelList *self,
g_return_if_fail (CC_IS_PANEL_LIST (self));
/* Add the panel to the proper listbox */
data = row_data_new (category, id, title, description, keywords, icon);
switch (category)
{
case CC_CATEGORY_DEVICES:
listbox = self->devices_listbox;
break;
case CC_CATEGORY_DETAILS:
listbox = self->details_listbox;
break;
default:
listbox = self->main_listbox;
break;
}
data = row_data_new (category, id, title, description, keywords, icon, visibility);
listbox = get_listbox_from_category (self, category);
gtk_container_add (GTK_CONTAINER (listbox), data->row);
/* And add to the search listbox too */
search_data = row_data_new (category, id, title, description, keywords, icon);
search_data = row_data_new (category, id, title, description, keywords, icon, visibility);
gtk_container_add (GTK_CONTAINER (self->search_listbox), search_data->row);
g_hash_table_insert (self->id_to_data, data->id, data);
@ -925,8 +966,19 @@ cc_panel_list_set_active_panel (CcPanelList *self,
g_assert (data != NULL);
/* Stop if row is supposed to be always hidden */
if (data->visibility == CC_PANEL_HIDDEN)
{
g_debug ("Panel '%s' is always hidden, stopping.", id);
cc_panel_list_activate (self);
return;
}
listbox = gtk_widget_get_parent (data->row);
/* The row might be hidden now, so make sure it's visible */
gtk_widget_show (data->row);
gtk_list_box_select_row (GTK_LIST_BOX (listbox), GTK_LIST_BOX_ROW (data->row));
gtk_widget_grab_focus (data->row);
@ -937,3 +989,38 @@ cc_panel_list_set_active_panel (CcPanelList *self,
g_signal_emit_by_name (data->row, "activate");
}
/**
* cc_panel_list_set_panel_visibility:
* @self: a #CcPanelList
* @id: the id of the panel
* @visibility: visibility of panel with @id
*
* Sets the visibility of panel with @id. @id must be a valid
* id with a corresponding panel.
*/
void
cc_panel_list_set_panel_visibility (CcPanelList *self,
const gchar *id,
CcPanelVisibility visibility)
{
RowData *data;
g_return_if_fail (CC_IS_PANEL_LIST (self));
data = g_hash_table_lookup (self->id_to_data, id);
g_assert (data != NULL);
data->visibility = visibility;
/* If this is the currently selected row, and the panel can't be displayed
* (i.e. visibility != VISIBLE), then select the next possible row */
if (gtk_list_box_row_is_selected (GTK_LIST_BOX_ROW (data->row)) &&
visibility != CC_PANEL_VISIBLE)
{
activate_row_below (self, data);
}
gtk_widget_set_visible (data->row, visibility == CC_PANEL_VISIBLE);
}

View file

@ -60,11 +60,16 @@ void cc_panel_list_add_panel (CcPanelList
const gchar *title,
const gchar *description,
gchar **keywords,
const gchar *icon);
const gchar *icon,
CcPanelVisibility visibility);
void cc_panel_list_set_active_panel (CcPanelList *self,
const gchar *id);
void cc_panel_list_set_panel_visibility (CcPanelList *self,
const gchar *id,
CcPanelVisibility visibility);
G_END_DECLS
#endif /* CC_PANEL_LIST_H */

View file

@ -36,6 +36,20 @@
G_DECLARE_DERIVABLE_TYPE (CcPanel, cc_panel, CC, PANEL, GtkBin)
/**
* CcPanelVisibility:
*
* @CC_PANEL_HIDDEN: Panel is hidden from search and sidebar, and not reachable.
* @CC_PANEL_VISIBLE_IN_SEARCH: Panel is hidden from main view, but can be accessed from search.
* @CC_PANEL_VISIBLE: Panel is visible everywhere.
*/
typedef enum
{
CC_PANEL_HIDDEN,
CC_PANEL_VISIBLE_IN_SEARCH,
CC_PANEL_VISIBLE,
} CcPanelVisibility;
/* cc-shell.h requires CcPanel, so make sure it is defined first */
#include "cc-shell.h"

View file

@ -254,8 +254,8 @@ cc_shell_model_class_init (CcShellModelClass *klass)
static void
cc_shell_model_init (CcShellModel *self)
{
GType types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_APP_INFO, G_TYPE_STRING,
G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_STRV};
GType types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_APP_INFO, G_TYPE_STRING, G_TYPE_UINT,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_STRV, G_TYPE_UINT };
gtk_list_store_set_column_types (GTK_LIST_STORE (self),
N_COLS, types);
@ -318,6 +318,7 @@ cc_shell_model_add_item (CcShellModel *model,
COL_CASEFOLDED_DESCRIPTION, casefolded_description,
COL_GICON, icon,
COL_KEYWORDS, keywords,
COL_VISIBILITY, CC_PANEL_VISIBLE,
-1);
g_free (casefolded_name);
@ -399,3 +400,43 @@ cc_shell_model_set_sort_terms (CcShellModel *self,
self,
NULL);
}
void
cc_shell_model_set_panel_visibility (CcShellModel *self,
const gchar *id,
CcPanelVisibility visibility)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean valid;
g_return_if_fail (CC_IS_SHELL_MODEL (self));
model = GTK_TREE_MODEL (self);
/* Find the iter for the panel with the given id */
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid)
{
g_autofree gchar *item_id = NULL;
gtk_tree_model_get (model, &iter, COL_ID, &item_id, -1);
/* Found the iter */
if (g_str_equal (id, item_id))
break;
/* If not found, continue */
valid = gtk_tree_model_iter_next (model, &iter);
}
/* If we don't find any panel with the given id, we'll iterate until
* valid == FALSE, so we can use this variable to determine if the
* panel was found or not. It is a programming error to try to set
* the visibility of a non-existant panel.
*/
g_assert (valid);
gtk_list_store_set (GTK_LIST_STORE (self), &iter, COL_VISIBILITY, visibility, -1);
}

View file

@ -20,6 +20,8 @@
#pragma once
#include "cc-panel.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
@ -50,6 +52,7 @@ enum
COL_CASEFOLDED_DESCRIPTION,
COL_GICON,
COL_KEYWORDS,
COL_VISIBILITY,
N_COLS
};
@ -57,19 +60,23 @@ enum
CcShellModel* cc_shell_model_new (void);
void cc_shell_model_add_item (CcShellModel *model,
CcPanelCategory category,
GAppInfo *appinfo,
const char *id);
void cc_shell_model_add_item (CcShellModel *model,
CcPanelCategory category,
GAppInfo *appinfo,
const char *id);
gboolean cc_shell_model_has_panel (CcShellModel *model,
const char *id);
gboolean cc_shell_model_has_panel (CcShellModel *model,
const char *id);
gboolean cc_shell_model_iter_matches_search (CcShellModel *model,
GtkTreeIter *iter,
const char *term);
gboolean cc_shell_model_iter_matches_search (CcShellModel *model,
GtkTreeIter *iter,
const char *term);
void cc_shell_model_set_sort_terms (CcShellModel *model,
GStrv terms);
void cc_shell_model_set_sort_terms (CcShellModel *model,
GStrv terms);
void cc_shell_model_set_panel_visibility (CcShellModel *self,
const gchar *id,
CcPanelVisibility visible);
G_END_DECLS

View file

@ -162,11 +162,12 @@ get_symbolic_icon_name_from_g_icon (GIcon *gicon)
}
static gboolean
activate_panel (CcWindow *self,
const gchar *id,
GVariant *parameters,
const gchar *name,
GIcon *gicon)
activate_panel (CcWindow *self,
const gchar *id,
GVariant *parameters,
const gchar *name,
GIcon *gicon,
CcPanelVisibility visibility)
{
g_autoptr (GTimer) timer = NULL;
GtkWidget *box, *title_widget;
@ -175,6 +176,9 @@ activate_panel (CcWindow *self,
if (!id)
return FALSE;
if (visibility == CC_PANEL_HIDDEN)
return FALSE;
timer = g_timer_new ();
g_settings_set_string (self->settings, "last-panel", id);
@ -283,6 +287,23 @@ update_list_title (CcWindow *self)
gtk_header_bar_set_title (GTK_HEADER_BAR (self->header), title);
}
static void
on_row_changed_cb (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
CcWindow *self)
{
g_autofree gchar *id = NULL;
CcPanelVisibility visibility;
gtk_tree_model_get (model, iter,
COL_ID, &id,
COL_VISIBILITY, &visibility,
-1);
cc_panel_list_set_panel_visibility (CC_PANEL_LIST (self->panel_list), id, visibility);
}
static void
setup_model (CcWindow *shell)
{
@ -309,6 +330,7 @@ setup_model (CcWindow *shell)
g_autofree gchar *id = NULL;
g_autofree gchar *icon_name = NULL;
g_autofree GStrv keywords = NULL;
CcPanelVisibility visibility;
gtk_tree_model_get (model, &iter,
COL_CATEGORY, &category,
@ -317,6 +339,7 @@ setup_model (CcWindow *shell)
COL_ID, &id,
COL_NAME, &name,
COL_KEYWORDS, &keywords,
COL_VISIBILITY, &visibility,
-1);
icon_name = get_symbolic_icon_name_from_g_icon (icon);
@ -327,10 +350,14 @@ setup_model (CcWindow *shell)
name,
description,
keywords,
icon_name);
icon_name,
visibility);
valid = gtk_tree_model_iter_next (model, &iter);
}
/* React to visibility changes */
g_signal_connect_object (model, "row-changed", G_CALLBACK (on_row_changed_cb), shell, 0);
}
@ -343,6 +370,7 @@ set_active_panel_from_id (CcShell *shell,
{
g_autoptr(GIcon) gicon = NULL;
g_autofree gchar *name = NULL;
CcPanelVisibility visibility;
GtkTreeIter iter;
GtkWidget *old_panel;
CcWindow *self;
@ -372,6 +400,7 @@ set_active_panel_from_id (CcShell *shell,
COL_NAME, &name,
COL_GICON, &gicon,
COL_ID, &id,
COL_VISIBILITY, &visibility,
-1);
if (id && strcmp (id, start_id) == 0)