1 /* ide-terminal-popover.c 2 * 3 * Copyright 2019 Christian Hergert <chergert@redhat.com> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 * SPDX-License-Identifier: GPL-3.0-or-later 19 */ 20 21 #define G_LOG_DOMAIN "ide-terminal-popover" 22 23 #include "config.h" 24 25 #include <dazzle.h> 26 #include <libide-foundry.h> 27 #include <libide-gui.h> 28 29 #include "ide-terminal-popover.h" 30 #include "ide-terminal-popover-row.h" 31 32 struct _IdeTerminalPopover 33 { 34 GtkPopover parent_instance; 35 36 DzlListModelFilter *filter; 37 gchar *selected; 38 39 /* Template widgets */ 40 GtkSearchEntry *search_entry; 41 GtkListBox *list_box; 42 }; 43 44 G_DEFINE_FINAL_TYPE (IdeTerminalPopover, ide_terminal_popover, GTK_TYPE_POPOVER) 45 46 static void 47 ide_terminal_popover_update_selected_cb (GtkWidget *widget, 48 gpointer user_data) 49 { 50 IdeTerminalPopoverRow *row = (IdeTerminalPopoverRow *)widget; 51 IdeRuntime *runtime = user_data; 52 gboolean selected; 53 54 g_assert (IDE_IS_TERMINAL_POPOVER_ROW (row)); 55 g_assert (IDE_IS_RUNTIME (runtime)); 56 57 selected = runtime == ide_terminal_popover_row_get_runtime (row); 58 ide_terminal_popover_row_set_selected (row, selected); 59 } 60 61 static void 62 ide_terminal_popover_row_activated_cb (IdeTerminalPopover *self, 63 IdeTerminalPopoverRow *row, 64 GtkListBox *list_box) 65 { 66 IdeRuntime *runtime; 67 68 g_assert (IDE_IS_TERMINAL_POPOVER (self)); 69 g_assert (IDE_IS_TERMINAL_POPOVER_ROW (row)); 70 g_assert (GTK_IS_LIST_BOX (list_box)); 71 72 runtime = ide_terminal_popover_row_get_runtime (row); 73 74 g_free (self->selected); 75 self->selected = g_strdup (ide_runtime_get_id (runtime)); 76 77 gtk_container_foreach (GTK_CONTAINER (self->list_box), 78 ide_terminal_popover_update_selected_cb, 79 runtime); 80 } 81 82 static GtkWidget * 83 ide_terminal_popover_create_row_cb (gpointer item, 84 gpointer user_data) 85 { 86 IdeRuntime *runtime = item; 87 IdeTerminalPopover *self = user_data; 88 GtkWidget *row = ide_terminal_popover_row_new (runtime); 89 90 if (ide_str_equal0 (ide_runtime_get_id (runtime), self->selected)) 91 ide_terminal_popover_row_set_selected (IDE_TERMINAL_POPOVER_ROW (row), TRUE); 92 else 93 ide_terminal_popover_row_set_selected (IDE_TERMINAL_POPOVER_ROW (row), FALSE); 94 95 return row; 96 } 97 98 static gboolean 99 ide_terminal_popover_filter_func (GObject *item, 100 gpointer user_data) 101 { 102 DzlPatternSpec *spec = user_data; 103 IdeRuntime *runtime = IDE_RUNTIME (item); 104 const gchar *str; 105 106 str = ide_runtime_get_id (runtime); 107 if (dzl_pattern_spec_match (spec, str)) 108 return TRUE; 109 110 str = ide_runtime_get_category (runtime); 111 if (dzl_pattern_spec_match (spec, str)) 112 return TRUE; 113 114 str = ide_runtime_get_display_name (runtime); 115 if (dzl_pattern_spec_match (spec, str)) 116 return TRUE; 117 118 return FALSE; 119 } 120 121 static void 122 ide_terminal_popover_search_changed_cb (IdeTerminalPopover *self, 123 GtkSearchEntry *entry) 124 { 125 const gchar *text; 126 127 g_assert (IDE_IS_TERMINAL_POPOVER (self)); 128 g_assert (GTK_IS_SEARCH_ENTRY (entry)); 129 130 if (self->filter == NULL) 131 return; 132 133 text = gtk_entry_get_text (GTK_ENTRY (entry)); 134 if (ide_str_empty0 (text)) 135 text = NULL; 136 137 dzl_list_model_filter_set_filter_func (self->filter, 138 ide_terminal_popover_filter_func, 139 dzl_pattern_spec_new (text), 140 (GDestroyNotify) dzl_pattern_spec_unref); 141 } 142 143 static void 144 ide_terminal_popover_context_set_cb (GtkWidget *widget, 145 IdeContext *context) 146 { 147 IdeTerminalPopover *self = (IdeTerminalPopover *)widget; 148 IdeRuntimeManager *runtime_manager; 149 150 g_assert (IDE_IS_TERMINAL_POPOVER (self)); 151 g_assert (!context || IDE_IS_CONTEXT (context)); 152 153 if (context == NULL) 154 return; 155 156 runtime_manager = ide_runtime_manager_from_context (context); 157 158 if (ide_context_has_project (context)) 159 { 160 IdeConfigManager *config_manager; 161 IdeConfig *config; 162 163 config_manager = ide_config_manager_from_context (context); 164 config = ide_config_manager_get_current (config_manager); 165 166 if (config != NULL) 167 { 168 g_free (self->selected); 169 self->selected = g_strdup (ide_config_get_runtime_id (config)); 170 } 171 } 172 173 g_clear_object (&self->filter); 174 self->filter = dzl_list_model_filter_new (G_LIST_MODEL (runtime_manager)); 175 176 gtk_list_box_bind_model (self->list_box, 177 G_LIST_MODEL (self->filter), 178 ide_terminal_popover_create_row_cb, 179 self, NULL); 180 } 181 182 static void 183 ide_terminal_popover_class_init (IdeTerminalPopoverClass *klass) 184 { 185 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); 186 187 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libide-terminal/ui/ide-terminal-popover.ui"); 188 gtk_widget_class_bind_template_child (widget_class, IdeTerminalPopover, list_box); 189 gtk_widget_class_bind_template_child (widget_class, IdeTerminalPopover, search_entry); 190 } 191 192 static void 193 ide_terminal_popover_init (IdeTerminalPopover *self) 194 { 195 gtk_widget_init_template (GTK_WIDGET (self)); 196 197 self->selected = g_strdup ("host"); 198 199 ide_widget_set_context_handler (self, ide_terminal_popover_context_set_cb); 200 201 g_signal_connect_object (self->search_entry, 202 "changed", 203 G_CALLBACK (ide_terminal_popover_search_changed_cb), 204 self, 205 G_CONNECT_SWAPPED); 206 207 g_signal_connect_object (self->list_box, 208 "row-activated", 209 G_CALLBACK (ide_terminal_popover_row_activated_cb), 210 self, 211 G_CONNECT_SWAPPED); 212 } 213 214 GtkWidget * 215 ide_terminal_popover_new (void) 216 { 217 return g_object_new (IDE_TYPE_TERMINAL_POPOVER, NULL); 218 } 219 220 /** 221 * ide_terminal_popover_get_runtime: 222 * @self: a #IdeTerminalPopover 223 * 224 * Returns: (transfer none): an #IdeRuntime or %NULL 225 * 226 * Since: 3.32 227 */ 228 IdeRuntime * 229 ide_terminal_popover_get_runtime (IdeTerminalPopover *self) 230 { 231 IdeRuntimeManager *runtime_manager; 232 IdeContext *context; 233 234 g_return_val_if_fail (IDE_IS_TERMINAL_POPOVER (self), NULL); 235 236 if (self->selected != NULL && 237 (context = ide_widget_get_context (GTK_WIDGET (self))) && 238 (runtime_manager = ide_runtime_manager_from_context (context))) 239 return ide_runtime_manager_get_runtime (runtime_manager, self->selected); 240 241 return NULL; 242 } 243