[gnome-shell] extensionPrefs: Use template for preference dialog



commit 2b517e352d717b8ee630fef17739ed522897fd44
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri Mar 6 01:03:45 2020 +0100

    extensionPrefs: Use template for preference dialog
    
    The dialog that contains the extension's preference widget has become
    fairly complex over time, mostly due to the error handling.
    
    It therefore makes sense to move it to a template, just like we did
    for the main application window and extension rows.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1106

 js/extensionPrefs/data/css/application.css         |   3 +
 .../data/org.gnome.Extensions.data.gresource.xml   |   1 +
 .../data/ui/extension-prefs-dialog.ui              | 197 ++++++++++++
 js/extensionPrefs/js/main.js                       | 339 ++++++---------------
 po/POTFILES.in                                     |   1 +
 5 files changed, 303 insertions(+), 238 deletions(-)
---
diff --git a/js/extensionPrefs/data/css/application.css b/js/extensionPrefs/data/css/application.css
index 37105d0819..5641c5d232 100644
--- a/js/extensionPrefs/data/css/application.css
+++ b/js/extensionPrefs/data/css/application.css
@@ -9,3 +9,6 @@
 }
 
 image.warning { color: @warning_color; }
+
+.expander-frame > * { border-top-width: 0; }
+.expander-toolbar { border: 0 solid @borders; border-top-width: 1px; }
diff --git a/js/extensionPrefs/data/org.gnome.Extensions.data.gresource.xml 
b/js/extensionPrefs/data/org.gnome.Extensions.data.gresource.xml
index 659c03ffc8..de65e08233 100644
--- a/js/extensionPrefs/data/org.gnome.Extensions.data.gresource.xml
+++ b/js/extensionPrefs/data/org.gnome.Extensions.data.gresource.xml
@@ -5,6 +5,7 @@
 
     <file>dbus-interfaces/org.gnome.Shell.Extensions.xml</file>
 
+    <file>ui/extension-prefs-dialog.ui</file>
     <file>ui/extension-row.ui</file>
     <file>ui/extensions-window.ui</file>
   </gresource>
diff --git a/js/extensionPrefs/data/ui/extension-prefs-dialog.ui 
b/js/extensionPrefs/data/ui/extension-prefs-dialog.ui
new file mode 100644
index 0000000000..fc08eae3c2
--- /dev/null
+++ b/js/extensionPrefs/data/ui/extension-prefs-dialog.ui
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="ExtensionPrefsDialog" parent="GtkWindow">
+    <property name="default_width">600</property>
+    <property name="default_height">400</property>
+    <child type="titlebar">
+      <object class="GtkHeaderBar" id="headerBar">
+        <property name="visible">True</property>
+        <property name="show_close_button">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkStack" id="stack">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="visible">True</property>
+            <property name="hscrollbar_policy">never</property>
+            <property name="propagate_natural_height">True</property>
+            <child>
+              <object class="GtkViewport">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="margin">100</property>
+                    <property name="margin_bottom">60</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Something’s gone wrong</property>
+                        <attributes>
+                          <attribute name="scale" value="1.44"/> <!-- x-large -->
+                        </attributes>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">We’re very sorry, but there’s been a 
problem: the settings for this extension can’t be displayed. We recommend that you report the issue to the 
extension authors.</property>
+                        <property name="justify">center</property>
+                        <property name="wrap">True</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="margin_top">12</property>
+                        <child>
+                          <object class="GtkFrame" id="expander">
+                            <property name="visible">True</property>
+                            <property name="hexpand">True</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <object class="GtkEventBox">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkBox">
+                                    <property name="visible">True</property>
+                                    <property name="margin">12</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkImage" id="expanderArrow">
+                                        <property name="visible">True</property>
+                                        <property name="icon_name">pan-end-symbolic</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel">
+                                        <property name="visible">True</property>
+                                        <property name="label" translatable="yes">Technical 
Details</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkRevealer" id="revealer">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkFrame">
+                                <property name="visible">True</property>
+                                <property name="shadow_type">in</property>
+                                <style>
+                                  <class name="expander-frame"/>
+                                </style>
+                                <child>
+                                  <object class="GtkBox">
+                                    <property name="visible">True</property>
+                                    <property name="orientation">vertical</property>
+                                    <child>
+                                      <object class="GtkTextView" id="errorView">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="monospace">True</property>
+                                        <property name="editable">False</property>
+                                        <property name="wrap_mode">word</property>
+                                        <property name="left_margin">12</property>
+                                        <property name="right_margin">12</property>
+                                        <property name="top_margin">12</property>
+                                        <property name="bottom_margin">12</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkToolbar">
+                                        <property name="visible">True</property>
+                                        <style>
+                                          <class name="expander-toolbar"/>
+                                        </style>
+                                        <child>
+                                          <object class="GtkToolItem">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <object class="GtkButton">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="receives_default">True</property>
+                                                <property name="action_name">win.copy-error</property>
+                                                <style>
+                                                  <class name="flat"/>
+                                                  <class name="image-button"/>
+                                                </style>
+                                                <child>
+                                                  <object class="GtkImage">
+                                                    <property name="visible">True</property>
+                                                    <property name="icon_name">edit-copy-symbolic</property>
+                                                  </object>
+                                                </child>
+                                              </object>
+                                            </child>
+                                          </object>
+                                        </child>
+                                        <child>
+                                          <object class="GtkSeparatorToolItem">
+                                            <property name="visible">True</property>
+                                            <property name="draw">False</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">True</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkToolItem">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <object class="GtkButton" id="homeButton">
+                                                <property name="visible"
+                                                          bind-source="homeButton"
+                                                          bind-property="sensitive"
+                                                          bind-flags="sync-create"/>
+                                                <property name="label" translatable="yes">Homepage</property>
+                                                <property name="tooltip_text" translatable="yes">Visit 
extension homepage</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="receives_default">True</property>
+                                                <property name="no_show_all">True</property>
+                                                <property name="action_name">win.show-url</property>
+                                                <style>
+                                                  <class name="flat"/>
+                                                </style>
+                                              </object>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/js/extensionPrefs/js/main.js b/js/extensionPrefs/js/main.js
index d1da73a025..fd8c009593 100644
--- a/js/extensionPrefs/js/main.js
+++ b/js/extensionPrefs/js/main.js
@@ -191,31 +191,10 @@ var ExtensionsWindow = GObject.registerClass({
         if (!row || !row.hasPrefs)
             return false;
 
-        let widget;
-
-        try {
-            widget = row.prefsModule.buildPrefsWidget();
-        } catch (e) {
-            widget = this._buildErrorUI(row, e);
-        }
-
-        this._prefsDialog = new Gtk.Window({
-            application: this.application,
-            default_width: 600,
-            default_height: 400,
-            modal: this.visible,
-            type_hint: Gdk.WindowTypeHint.DIALOG,
-            window_position: Gtk.WindowPosition.CENTER,
-        });
-
-        this._prefsDialog.set_titlebar(new Gtk.HeaderBar({
-            show_close_button: true,
-            title: row.name,
-            visible: true,
-        }));
+        this._prefsDialog = new ExtensionPrefsDialog(row);
 
         if (this.visible)
-            this._prefsDialog.transient_for = this;
+            this._prefsDialog.set({ transient_for: this, modal: true });
 
         this._prefsDialog.connect('destroy', () => {
             this._prefsDialog = null;
@@ -224,7 +203,6 @@ var ExtensionsWindow = GObject.registerClass({
                 this.destroy();
         });
 
-        this._prefsDialog.add(widget);
         this._prefsDialog.show();
 
         return true;
@@ -266,121 +244,6 @@ var ExtensionsWindow = GObject.registerClass({
             });
     }
 
-    _buildErrorUI(row, exc) {
-        let scroll = new Gtk.ScrolledWindow({
-            hscrollbar_policy: Gtk.PolicyType.NEVER,
-            propagate_natural_height: true,
-        });
-
-        let box = new Gtk.Box({
-            orientation: Gtk.Orientation.VERTICAL,
-            spacing: 12,
-            margin: 100,
-            margin_bottom: 60,
-        });
-        scroll.add(box);
-
-        let label = new Gtk.Label({
-            label: '<span size="x-large">%s</span>'.format(_("Something’s gone wrong")),
-            use_markup: true,
-        });
-        label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
-        box.add(label);
-
-        label = new Gtk.Label({
-            label: _("We’re very sorry, but there’s been a problem: the settings for this extension can’t be 
displayed. We recommend that you report the issue to the extension authors."),
-            justify: Gtk.Justification.CENTER,
-            wrap: true,
-        });
-        box.add(label);
-
-        let expander = new Expander({
-            label: _("Technical Details"),
-            margin_top: 12,
-        });
-        box.add(expander);
-
-        let errortext = '%s\n\nStack trace:\n'.format(exc);
-        // Indent stack trace.
-        errortext +=
-            exc.stack.split('\n').map(line => '  %s'.format(line)).join('\n');
-
-        let buffer = new Gtk.TextBuffer({ text: errortext });
-        let textview = new Gtk.TextView({
-            buffer,
-            wrap_mode: Gtk.WrapMode.WORD,
-            monospace: true,
-            editable: false,
-            top_margin: 12,
-            bottom_margin: 12,
-            left_margin: 12,
-            right_margin: 12,
-        });
-
-        let toolbar = new Gtk.Toolbar();
-        let provider = new Gtk.CssProvider();
-        provider.load_from_data(`* {
-            border: 0 solid @borders;
-            border-top-width: 1px;
-        }`);
-        toolbar.get_style_context().add_provider(
-            provider,
-            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
-        );
-
-        let copyButton = new Gtk.ToolButton({
-            icon_name: 'edit-copy-symbolic',
-            tooltip_text: _("Copy Error"),
-        });
-        toolbar.add(copyButton);
-
-        copyButton.connect('clicked', w => {
-            let clipboard = Gtk.Clipboard.get_default(w.get_display());
-            // markdown for pasting in gitlab issues
-            let lines = [
-                'The settings of extension %s had an error:'.format(row.uuid),
-                '```', // '`' (xgettext throws up on odd number of backticks)
-                exc.toString(),
-                '```', // '`'
-                '',
-                'Stack trace:',
-                '```', // '`'
-                exc.stack.replace(/\n$/, ''), // stack without trailing newline
-                '```', // '`'
-                '',
-            ];
-            clipboard.set_text(lines.join('\n'), -1);
-        });
-
-        let spacing = new Gtk.SeparatorToolItem({ draw: false });
-        toolbar.add(spacing);
-        toolbar.child_set_property(spacing, "expand", true);
-
-        let urlButton = new Gtk.ToolButton({
-            label: _("Homepage"),
-            tooltip_text: _("Visit extension homepage"),
-            no_show_all: true,
-            visible: row.url !== '',
-        });
-        toolbar.add(urlButton);
-
-        urlButton.connect('clicked', w => {
-            let context = w.get_display().get_app_launch_context();
-            Gio.AppInfo.launch_default_for_uri(row.url, context);
-        });
-
-        let expandedBox = new Gtk.Box({
-            orientation: Gtk.Orientation.VERTICAL,
-        });
-        expandedBox.add(textview);
-        expandedBox.add(toolbar);
-
-        expander.add(expandedBox);
-
-        scroll.show_all();
-        return scroll;
-    }
-
     _sortList(row1, row2) {
         return row1.name.localeCompare(row2.name);
     }
@@ -504,105 +367,6 @@ var ExtensionsWindow = GObject.registerClass({
     }
 });
 
-var Expander = GObject.registerClass({
-    Properties: {
-        'label': GObject.ParamSpec.string(
-            'label', 'label', 'label',
-            GObject.ParamFlags.READWRITE,
-            null
-        ),
-    },
-}, class Expander extends Gtk.Box {
-    _init(params = {}) {
-        this._labelText = null;
-
-        super._init(Object.assign(params, {
-            orientation: Gtk.Orientation.VERTICAL,
-            spacing: 0,
-        }));
-
-        this._frame = new Gtk.Frame({
-            shadow_type: Gtk.ShadowType.IN,
-            hexpand: true,
-        });
-
-        let eventBox = new Gtk.EventBox();
-        this._frame.add(eventBox);
-
-        let hbox = new Gtk.Box({
-            spacing: 6,
-            margin: 12,
-        });
-        eventBox.add(hbox);
-
-        this._arrow = new Gtk.Image({
-            icon_name: 'pan-end-symbolic',
-        });
-        hbox.add(this._arrow);
-
-        this._label = new Gtk.Label({ label: this._labelText });
-        hbox.add(this._label);
-
-        this._revealer = new Gtk.Revealer();
-
-        this._childBin = new Gtk.Frame({
-            shadow_type: Gtk.ShadowType.IN,
-        });
-        this._revealer.add(this._childBin);
-
-        // Directly chain up to parent for internal children
-        super.add(this._frame);
-        super.add(this._revealer);
-
-        let provider = new Gtk.CssProvider();
-        provider.load_from_data('* { border-top-width: 0; }');
-        this._childBin.get_style_context().add_provider(
-            provider,
-            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
-        );
-
-        this._gesture = new Gtk.GestureMultiPress({
-            widget: this._frame,
-            button: 0,
-            exclusive: true,
-        });
-        this._gesture.connect('released', (gesture, nPress) => {
-            if (nPress == 1)
-                this._revealer.reveal_child = !this._revealer.reveal_child;
-        });
-        this._revealer.connect('notify::reveal-child', () => {
-            if (this._revealer.reveal_child)
-                this._arrow.icon_name = 'pan-down-symbolic';
-            else
-                this._arrow.icon_name = 'pan-end-symbolic';
-        });
-    }
-
-    get label() {
-        return this._labelText;
-    }
-
-    set label(text) {
-        if (this._labelText == text)
-            return;
-
-        if (this._label)
-            this._label.label = text;
-        this._labelText = text;
-        this.notify('label');
-    }
-
-    add(child) {
-        // set expanded child
-        this._childBin.get_children().forEach(c => {
-            this._childBin.remove(c);
-        });
-
-        if (child)
-            this._childBin.add(child);
-    }
-});
-
 var ExtensionRow = GObject.registerClass({
     GTypeName: 'ExtensionRow',
     Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
@@ -768,6 +532,105 @@ var ExtensionRow = GObject.registerClass({
     }
 });
 
+var ExtensionPrefsDialog = GObject.registerClass({
+    GTypeName: 'ExtensionPrefsDialog',
+    Template: 'resource:///org/gnome/Extensions/ui/extension-prefs-dialog.ui',
+    InternalChildren: [
+        'headerBar',
+        'stack',
+        'expander',
+        'expanderArrow',
+        'revealer',
+        'errorView',
+    ],
+}, class ExtensionPrefsDialog extends Gtk.Window {
+    _init(extension) {
+        super._init();
+
+        this._uuid = extension.uuid;
+        this._url = extension.url;
+
+        this._headerBar.title = extension.name;
+
+        this._actionGroup = new Gio.SimpleActionGroup();
+        this.insert_action_group('win', this._actionGroup);
+
+        this._initActions();
+
+        this._gesture = new Gtk.GestureMultiPress({
+            widget: this._expander,
+            button: 0,
+            exclusive: true,
+        });
+
+        this._gesture.connect('released', (gesture, nPress) => {
+            if (nPress === 1)
+                this._revealer.reveal_child = !this._revealer.reveal_child;
+        });
+
+        this._revealer.connect('notify::reveal-child', () => {
+            this._expanderArrow.icon_name = this._revealer.reveal_child
+                ? 'pan-down-symbolic'
+                : 'pan-end-symbolic';
+        });
+
+        try {
+            const widget = extension.prefsModule.buildPrefsWidget();
+            this._stack.add(widget);
+            this._stack.visible_child = widget;
+        } catch (e) {
+            this._setError(e);
+        }
+    }
+
+    _setError(exc) {
+        this._errorView.buffer.text = '%s\n\nStack trace:\n'.format(exc);
+        // Indent stack trace.
+        this._errorView.buffer.text +=
+            exc.stack.split('\n').map(line => '  %s'.format(line)).join('\n');
+
+        // markdown for pasting in gitlab issues
+        let lines = [
+            'The settings of extension %s had an error:'.format(this._uuid),
+            '```', // '`' (xgettext throws up on odd number of backticks)
+            exc.toString(),
+            '```', // '`'
+            '',
+            'Stack trace:',
+            '```', // '`'
+            exc.stack.replace(/\n$/, ''), // stack without trailing newline
+            '```', // '`'
+            '',
+        ];
+        this._errorMarkdown = lines.join('\n');
+        this._actionGroup.lookup('copy-error').enabled = true;
+    }
+
+    _initActions() {
+        let action;
+
+        action = new Gio.SimpleAction({
+            name: 'copy-error',
+            enabled: false,
+        });
+        action.connect('activate', () => {
+            const clipboard = Gtk.Clipboard.get_default(this.get_display());
+            clipboard.set_text(this._errorMarkdown, -1);
+        });
+        this._actionGroup.add_action(action);
+
+        action = new Gio.SimpleAction({
+            name: 'show-url',
+            enabled: this._url !== '',
+        });
+        action.connect('activate', () => {
+            Gio.AppInfo.launch_default_for_uri(this._url,
+                this.get_display().get_app_launch_context());
+        });
+        this._actionGroup.add_action(action);
+    }
+});
+
 function initEnvironment() {
     // Monkey-patch in a "global" object that fakes some Shell utilities
     // that ExtensionUtils depends on.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3a0c0a151d..ba8a5b13bd 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@ data/org.gnome.Shell.PortalHelper.desktop.in.in
 js/extensionPrefs/data/metainfo/org.gnome.Extensions.metainfo.xml.in
 js/extensionPrefs/data/org.gnome.Extensions.desktop.in.in
 js/extensionPrefs/js/main.js
+js/extensionPrefs/data/ui/extension-prefs-dialog.ui
 js/extensionPrefs/data/ui/extension-row.ui
 js/extensionPrefs/data/ui/extensions-window.ui
 js/gdm/authPrompt.js


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]