[gnome-builder/wip/gtk4-port] plugins/shellcmd: more work on editing shell commands
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/gtk4-port] plugins/shellcmd: more work on editing shell commands
- Date: Sat, 11 Jun 2022 08:10:36 +0000 (UTC)
commit 09aa6833fe279537aa4061d10a850b9647ba7676
Author: Christian Hergert <chergert redhat com>
Date: Sat Jun 11 00:53:04 2022 -0700
plugins/shellcmd: more work on editing shell commands
This is just a lot of UI scaffolding as things are not wired up yet.
src/plugins/shellcmd/gbp-shellcmd-command-dialog.c | 219 +++++++++++++++++++++
src/plugins/shellcmd/gbp-shellcmd-command-dialog.h | 37 ++++
.../shellcmd/gbp-shellcmd-command-dialog.ui | 172 ++++++++++++++++
.../shellcmd/gbp-shellcmd-preferences-addin.c | 53 +++--
src/plugins/shellcmd/meson.build | 1 +
src/plugins/shellcmd/shellcmd.gresource.xml | 1 +
6 files changed, 452 insertions(+), 31 deletions(-)
---
diff --git a/src/plugins/shellcmd/gbp-shellcmd-command-dialog.c
b/src/plugins/shellcmd/gbp-shellcmd-command-dialog.c
new file mode 100644
index 000000000..13d26b8fd
--- /dev/null
+++ b/src/plugins/shellcmd/gbp-shellcmd-command-dialog.c
@@ -0,0 +1,219 @@
+/* gbp-shellcmd-command-dialog.c
+ *
+ * Copyright 2022 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 "gbp-shellcmd-command-dialog"
+
+#include "config.h"
+
+#include <libide-gtk.h>
+
+#include "gbp-shellcmd-command-dialog.h"
+
+struct _GbpShellcmdCommandDialog
+{
+ AdwWindow parent_instance;
+
+ GbpShellcmdRunCommand *command;
+
+ GtkStringList *envvars;
+ GtkListBox *envvars_list_box;
+};
+
+enum {
+ PROP_0,
+ PROP_COMMAND,
+ N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (GbpShellcmdCommandDialog, gbp_shellcmd_command_dialog, ADW_TYPE_WINDOW)
+
+static GParamSpec *properties [N_PROPS];
+static GtkWidget *
+create_envvar_row_cb (gpointer item,
+ gpointer user_data)
+{
+ GtkStringObject *obj = item;
+ const char *str = gtk_string_object_get_string (obj);
+ AdwActionRow *row;
+ GtkButton *button;
+
+ row = g_object_new (ADW_TYPE_ACTION_ROW,
+ "title", str,
+ "title-selectable", TRUE,
+ NULL);
+ button = g_object_new (GTK_TYPE_BUTTON,
+ "icon-name", "list-remove-symbolic",
+ "css-classes", IDE_STRV_INIT ("flat", "circular"),
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+ adw_action_row_add_suffix (row, GTK_WIDGET (button));
+
+ return GTK_WIDGET (row);
+}
+
+static void
+on_env_entry_changed_cb (GbpShellcmdCommandDialog *self,
+ IdeEntryPopover *popover)
+{
+ gboolean valid = FALSE;
+ const char *text;
+ const char *eq;
+
+ g_assert (GBP_IS_SHELLCMD_COMMAND_DIALOG (self));
+ g_assert (IDE_IS_ENTRY_POPOVER (popover));
+
+ text = ide_entry_popover_get_text (popover);
+ eq = strchr (text, '=');
+
+ if (eq != NULL && eq != text)
+ {
+ for (const char *iter = text; iter < eq; iter = g_utf8_next_char (iter))
+ {
+ gunichar ch = g_utf8_get_char (iter);
+
+ if (!g_unichar_isalnum (ch) && ch != '_')
+ goto failure;
+ }
+
+ if (g_ascii_isalpha (*text))
+ valid = TRUE;
+ }
+
+failure:
+ ide_entry_popover_set_ready (popover, valid);
+}
+
+static void
+on_env_entry_activate_cb (GbpShellcmdCommandDialog *self,
+ const char *text,
+ IdeEntryPopover *popover)
+{
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_SHELLCMD_COMMAND_DIALOG (self));
+ g_assert (IDE_IS_ENTRY_POPOVER (popover));
+ g_assert (GTK_IS_STRING_LIST (self->envvars));
+
+ gtk_string_list_append (self->envvars, text);
+ ide_entry_popover_set_text (popover, "");
+
+ IDE_EXIT;
+}
+
+static void
+gbp_shellcmd_command_dialog_dispose (GObject *object)
+{
+ GbpShellcmdCommandDialog *self = (GbpShellcmdCommandDialog *)object;
+
+ g_clear_object (&self->command);
+
+ G_OBJECT_CLASS (gbp_shellcmd_command_dialog_parent_class)->dispose (object);
+}
+
+static void
+gbp_shellcmd_command_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpShellcmdCommandDialog *self = GBP_SHELLCMD_COMMAND_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_COMMAND:
+ g_value_set_object (value, self->command);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_shellcmd_command_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbpShellcmdCommandDialog *self = GBP_SHELLCMD_COMMAND_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_COMMAND:
+ self->command = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_shellcmd_command_dialog_class_init (GbpShellcmdCommandDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gbp_shellcmd_command_dialog_dispose;
+ object_class->get_property = gbp_shellcmd_command_dialog_get_property;
+ object_class->set_property = gbp_shellcmd_command_dialog_set_property;
+
+ properties [PROP_COMMAND] =
+ g_param_spec_object ("command", NULL, NULL,
+ GBP_TYPE_SHELLCMD_RUN_COMMAND,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/plugins/shellcmd/gbp-shellcmd-command-dialog.ui");
+ gtk_widget_class_bind_template_child (widget_class, GbpShellcmdCommandDialog, envvars);
+ gtk_widget_class_bind_template_child (widget_class, GbpShellcmdCommandDialog, envvars_list_box);
+ gtk_widget_class_bind_template_callback (widget_class, on_env_entry_changed_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_env_entry_activate_cb);
+}
+
+static void
+gbp_shellcmd_command_dialog_init (GbpShellcmdCommandDialog *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+#if DEVELOPMENT_BUILD
+ gtk_widget_add_css_class (GTK_WIDGET (self), "devel");
+#endif
+
+ gtk_list_box_bind_model (self->envvars_list_box,
+ G_LIST_MODEL (self->envvars),
+ create_envvar_row_cb,
+ NULL, NULL);
+ ide_gtk_widget_hide_when_empty (GTK_WIDGET (self->envvars_list_box),
+ G_LIST_MODEL (self->envvars));
+}
+
+GbpShellcmdCommandDialog *
+gbp_shellcmd_command_dialog_new (GbpShellcmdRunCommand *command)
+{
+ g_return_val_if_fail (GBP_IS_SHELLCMD_RUN_COMMAND (command), NULL);
+
+ return g_object_new (GBP_TYPE_SHELLCMD_COMMAND_DIALOG,
+ "command", command,
+ NULL);
+}
diff --git a/src/plugins/shellcmd/gbp-shellcmd-command-dialog.h
b/src/plugins/shellcmd/gbp-shellcmd-command-dialog.h
new file mode 100644
index 000000000..f7765bae8
--- /dev/null
+++ b/src/plugins/shellcmd/gbp-shellcmd-command-dialog.h
@@ -0,0 +1,37 @@
+/* gbp-shellcmd-command-dialog.h
+ *
+ * Copyright 2022 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
+ */
+
+#pragma once
+
+#include <adwaita.h>
+
+#include <libide-foundry.h>
+
+#include "gbp-shellcmd-run-command.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SHELLCMD_COMMAND_DIALOG (gbp_shellcmd_command_dialog_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpShellcmdCommandDialog, gbp_shellcmd_command_dialog, GBP, SHELLCMD_COMMAND_DIALOG,
AdwWindow)
+
+GbpShellcmdCommandDialog *gbp_shellcmd_command_dialog_new (GbpShellcmdRunCommand *command);
+
+G_END_DECLS
diff --git a/src/plugins/shellcmd/gbp-shellcmd-command-dialog.ui
b/src/plugins/shellcmd/gbp-shellcmd-command-dialog.ui
new file mode 100644
index 000000000..890a038f9
--- /dev/null
+++ b/src/plugins/shellcmd/gbp-shellcmd-command-dialog.ui
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GbpShellcmdCommandDialog" parent="AdwWindow">
+ <property name="default-width">650</property>
+ <property name="default-height">650</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="AdwHeaderBar">
+ <property name="show-start-title-buttons">false</property>
+ <property name="show-end-title-buttons">false</property>
+ <child type="start">
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use-underline">true</property>
+ <property name="width-request">100</property>
+ <property name="action-name">window.close</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkButton" id="save">
+ <property name="label" translatable="yes">_Apply</property>
+ <property name="use-underline">true</property>
+ <property name="width-request">100</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesPage">
+ <property name="vexpand">true</property>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="AdwEntryRow" id="display_name">
+ <property name="title" translatable="yes">Name</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="AdwEntryRow" id="command">
+ <property name="title" translatable="yes">Command</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="AdwEntryRow" id="location">
+ <property name="title" translatable="yes">Location</property>
+ <child type="suffix">
+ <object class="GtkButton">
+ <property name="valign">center</property>
+ <property name="icon-name">folder-symbolic</property>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">The command will be run from this location.
Use <tt>$BUILDDIR</tt>, <tt>$SRCDIR</tt>, or <tt>$HOME</tt> for a
relative path.</property>
+ <property name="use-markup">true</property>
+ <property name="margin-top">12</property>
+ <property name="wrap">true</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="caption"/>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="AdwActionRow" id="shortcut">
+ <property name="title" translatable="yes">Keyboard Shortcut</property>
+ <property name="icon-name">preferences-desktop-keyboard-shortcuts-symbolic</property>
+ <child type="suffix">
+ <object class="GtkShortcutsShortcut">
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <property name="title" translatable="yes">Environment</property>
+ <property name="header-suffix">
+ <object class="GtkMenuButton">
+ <style>
+ <class name="flat"/>
+ </style>
+ <property name="direction">left</property>
+ <property name="icon-name">list-add-symbolic</property>
+ <property name="popover">
+ <object class="IdeEntryPopover">
+ <property name="title" translatable="yes">Add Environment Variable</property>
+ <property name="button-text" translatable="yes">_Add</property>
+ <signal name="changed" handler="on_env_entry_changed_cb" swapped="true"
object="GbpShellcmdCommandDialog"/>
+ <signal name="activate" handler="on_env_entry_activate_cb" swapped="true"
object="GbpShellcmdCommandDialog"/>
+ </object>
+ </property>
+ </object>
+ </property>
+ <child>
+ <object class="GtkListBox" id="envvars_list_box">
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="boxed-list"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="margin-top">6</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">6</property>
+ <style>
+ <class name="toolbar"/>
+ </style>
+ <child>
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Delete Command</property>
+ <property name="halign">end</property>
+ <property name="hexpand">true</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkSizeGroup">
+ <property name="mode">horizontal</property>
+ <widgets>
+ <widget name="save"/>
+ <widget name="cancel"/>
+ </widgets>
+ </object>
+ <object class="GtkStringList" id="envvars">
+ </object>
+</interface>
diff --git a/src/plugins/shellcmd/gbp-shellcmd-preferences-addin.c
b/src/plugins/shellcmd/gbp-shellcmd-preferences-addin.c
index 847546ce2..c055ab0a4 100644
--- a/src/plugins/shellcmd/gbp-shellcmd-preferences-addin.c
+++ b/src/plugins/shellcmd/gbp-shellcmd-preferences-addin.c
@@ -26,6 +26,7 @@
#include <libide-gui.h>
+#include "gbp-shellcmd-command-dialog.h"
#include "gbp-shellcmd-command-model.h"
#include "gbp-shellcmd-preferences-addin.h"
#include "gbp-shellcmd-run-command.h"
@@ -49,31 +50,6 @@ argv_to_string (GBinding *binding,
return TRUE;
}
-static void
-on_items_changed_cb (GListModel *model,
- guint removed,
- guint added,
- GtkWidget *widget)
-{
- gboolean was_visible = gtk_widget_get_visible (widget);
- gboolean is_visible = added > 0 || g_list_model_get_n_items (model) > 0;
-
- if (was_visible != is_visible)
- gtk_widget_set_visible (widget, is_visible);
-}
-
-static void
-bind_visibility_to_nonempty (GtkWidget *widget,
- GListModel *model)
-{
- gtk_widget_set_visible (widget, g_list_model_get_n_items (model) > 0);
- g_signal_connect_object (model,
- "items-changed",
- G_CALLBACK (on_items_changed_cb),
- widget,
- 0);
-}
-
static GtkWidget *
gbp_shellcmd_preferences_addin_create_row_cb (gpointer item,
gpointer item_data)
@@ -108,7 +84,9 @@ on_row_activated_cb (GtkListBox *list_box,
AdwActionRow *row,
IdePreferencesWindow *window)
{
+ g_autoptr(GbpShellcmdRunCommand) new_command = NULL;
GbpShellcmdRunCommand *command;
+ GbpShellcmdCommandDialog *dialog;
IDE_ENTRY;
@@ -117,17 +95,30 @@ on_row_activated_cb (GtkListBox *list_box,
g_assert (IDE_IS_PREFERENCES_WINDOW (window));
command = g_object_get_data (G_OBJECT (row), "COMMAND");
+
g_assert (!command || GBP_IS_SHELLCMD_RUN_COMMAND (command));
if (command == NULL)
{
- /* TODO: create new command */
- }
- else
- {
- /* TODO: edit existing command */
+ IdePreferencesMode mode = ide_preferences_window_get_mode (window);
+ IdeContext *context = ide_preferences_window_get_context (window);
+ g_autofree char *settings_path = NULL;
+
+ if (mode == IDE_PREFERENCES_MODE_PROJECT)
+ new_command = gbp_shellcmd_run_command_create (context);
+ else
+ new_command = gbp_shellcmd_run_command_create (NULL);
+
+ command = new_command;
}
+ dialog = gbp_shellcmd_command_dialog_new (command);
+ gtk_window_set_title (GTK_WINDOW (dialog),
+ new_command ? _("Create Command") : _("Edit Command"));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (dialog));
+
IDE_EXIT;
}
@@ -209,7 +200,7 @@ handle_shellcmd_list (const char *page_name,
gbp_shellcmd_preferences_addin_create_row_cb,
NULL, NULL);
adw_preferences_group_add (group, GTK_WIDGET (list_box));
- bind_visibility_to_nonempty (GTK_WIDGET (list_box), G_LIST_MODEL (model));
+ ide_gtk_widget_hide_when_empty (GTK_WIDGET (list_box), G_LIST_MODEL (model));
g_signal_connect_object (list_box,
"row-activated",
G_CALLBACK (on_row_activated_cb),
diff --git a/src/plugins/shellcmd/meson.build b/src/plugins/shellcmd/meson.build
index c56bfd5b6..0476d6297 100644
--- a/src/plugins/shellcmd/meson.build
+++ b/src/plugins/shellcmd/meson.build
@@ -2,6 +2,7 @@ if get_option('plugin_shellcmd')
plugins_sources += files([
'shellcmd-plugin.c',
+ 'gbp-shellcmd-command-dialog.c',
'gbp-shellcmd-command-model.c',
'gbp-shellcmd-preferences-addin.c',
'gbp-shellcmd-run-command.c',
diff --git a/src/plugins/shellcmd/shellcmd.gresource.xml b/src/plugins/shellcmd/shellcmd.gresource.xml
index 4af547c31..9a01bc34d 100644
--- a/src/plugins/shellcmd/shellcmd.gresource.xml
+++ b/src/plugins/shellcmd/shellcmd.gresource.xml
@@ -2,5 +2,6 @@
<gresources>
<gresource prefix="/plugins/shellcmd">
<file>shellcmd.plugin</file>
+ <file preprocess="xml-stripblanks">gbp-shellcmd-command-dialog.ui</file>
</gresource>
</gresources>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]