[geary/wip/problem-report-logs: 14/23] Convert ProblemReportDialog to use Inspector views
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/problem-report-logs: 14/23] Convert ProblemReportDialog to use Inspector views
- Date: Fri, 5 Jul 2019 03:09:46 +0000 (UTC)
commit 6f650622194ad5154bf1bdd5e2ef0c0251083620
Author: Michael Gratton <mike vee net>
Date: Thu Jul 4 13:30:42 2019 +1000
Convert ProblemReportDialog to use Inspector views
Aside from the code re-use, this allows including log files in problem
reports.
.../components-inspector-error-view.vala | 75 ++++++
src/client/components/main-window-info-bar.vala | 12 +-
.../dialogs/dialogs-problem-details-dialog.vala | 265 ++++++++++++++++-----
src/client/meson.build | 1 +
src/meson.build | 1 +
ui/components-inspector-error-view.ui | 95 ++++++++
ui/org.gnome.Geary.gresource.xml | 1 +
ui/problem-details-dialog.ui | 157 +++++-------
8 files changed, 444 insertions(+), 163 deletions(-)
---
diff --git a/src/client/components/components-inspector-error-view.vala
b/src/client/components/components-inspector-error-view.vala
new file mode 100644
index 00000000..2850701a
--- /dev/null
+++ b/src/client/components/components-inspector-error-view.vala
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * A view that displays information about an application error.
+ */
+[GtkTemplate (ui = "/org/gnome/Geary/components-inspector-error-view.ui")]
+public class Components.InspectorErrorView : Gtk.Grid {
+
+
+ [GtkChild]
+ private Gtk.TextView problem_text;
+
+ private string details;
+
+
+ public InspectorErrorView(Geary.ErrorContext error,
+ Geary.AccountInformation? account,
+ Geary.ServiceInformation? service) {
+ this.details = format_problem(error, account, service);
+ this.problem_text.buffer.text = this.details;
+ }
+
+ public void save(GLib.DataOutputStream out, GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ out.put_string(this.details, cancellable);
+ }
+
+ private string format_problem(Geary.ErrorContext error,
+ Geary.AccountInformation? account,
+ Geary.ServiceInformation? service) {
+ StringBuilder details = new StringBuilder();
+ if (account != null) {
+ details.append_printf(
+ "Account id: %s\n",
+ account.id
+ );
+ details.append_printf(
+ "Account provider: %s\n",
+ account.service_provider.to_string()
+ );
+ }
+ if (service != null) {
+ details.append_printf(
+ "Service type: %s\n",
+ service.protocol.to_string()
+ );
+ details.append_printf(
+ "Service host: %s\n",
+ service.host
+ );
+ }
+ if (error == null) {
+ details.append("No error reported");
+ } else {
+ details.append_printf(
+ "Error type: %s\n", error.format_error_type()
+ );
+ details.append_printf(
+ "Message: %s\n", error.thrown.message
+ );
+ details.append("Back trace:\n");
+ foreach (Geary.ErrorContext.StackFrame frame in
+ error.backtrace) {
+ details.append_printf(" - %s\n", frame.to_string());
+ }
+ }
+ return details.str;
+ }
+
+}
diff --git a/src/client/components/main-window-info-bar.vala b/src/client/components/main-window-info-bar.vala
index 1084c71e..11ee77ce 100644
--- a/src/client/components/main-window-info-bar.vala
+++ b/src/client/components/main-window-info-bar.vala
@@ -123,9 +123,17 @@ public class MainWindowInfoBar : Gtk.InfoBar {
}
private void show_details() {
+ Geary.ServiceProblemReport? service_report =
+ this.report as Geary.ServiceProblemReport;
+ Geary.AccountProblemReport? account_report =
+ this.report as Geary.AccountProblemReport;
+
Dialogs.ProblemDetailsDialog dialog =
- new Dialogs.ProblemDetailsDialog.for_problem_report(
- get_toplevel() as Gtk.Window, this.report
+ new Dialogs.ProblemDetailsDialog(
+ get_toplevel() as MainWindow,
+ this.report.error,
+ account_report != null ? account_report.account : null,
+ service_report != null ? service_report.service : null
);
dialog.run();
dialog.destroy();
diff --git a/src/client/dialogs/dialogs-problem-details-dialog.vala
b/src/client/dialogs/dialogs-problem-details-dialog.vala
index 32bb55d1..8716217f 100644
--- a/src/client/dialogs/dialogs-problem-details-dialog.vala
+++ b/src/client/dialogs/dialogs-problem-details-dialog.vala
@@ -9,18 +9,46 @@
* Displays technical details when a problem has been reported.
*/
[GtkTemplate (ui = "/org/gnome/Geary/problem-details-dialog.ui")]
-public class Dialogs.ProblemDetailsDialog : Gtk.Dialog {
+public class Dialogs.ProblemDetailsDialog : Hdy.Dialog {
+ private const string ACTION_CLOSE = "problem-details-close";
+ private const string ACTION_SEARCH_TOGGLE = "toggle-search";
+ private const string ACTION_SEARCH_ACTIVATE = "activate-search";
+
+ private const ActionEntry[] action_entries = {
+ {GearyApplication.ACTION_CLOSE, on_close },
+ {GearyApplication.ACTION_COPY, on_copy_clicked },
+ {ACTION_CLOSE, on_close },
+ {ACTION_SEARCH_TOGGLE, on_logs_search_toggled, null, "false" },
+ {ACTION_SEARCH_ACTIVATE, on_logs_search_activated },
+ };
+
+ public static void add_window_accelerators(GearyApplication app) {
+ app.add_window_accelerators(ACTION_CLOSE, { "Escape" } );
+ app.add_window_accelerators(ACTION_SEARCH_ACTIVATE, { "<Ctrl>F" } );
+ }
+
+
+ [GtkChild]
+ private Gtk.Stack stack;
+
+ [GtkChild]
+ private Gtk.Button copy_button;
+
+ [GtkChild]
+ private Gtk.ToggleButton search_button;
+
+ private Components.InspectorErrorView error_pane;
+ private Components.InspectorLogView log_pane;
+ private Components.InspectorSystemView system_pane;
+
private Geary.ErrorContext error;
private Geary.AccountInformation? account;
private Geary.ServiceInformation? service;
- [GtkChild]
- private Gtk.TextView detail_text;
-
- public ProblemDetailsDialog(Gtk.Window parent,
+ public ProblemDetailsDialog(MainWindow parent,
Geary.ErrorContext error,
Geary.AccountInformation? account,
Geary.ServiceInformation? service) {
@@ -28,84 +56,191 @@ public class Dialogs.ProblemDetailsDialog : Gtk.Dialog {
transient_for: parent,
use_header_bar: 1
);
- set_default_size(600, -1);
+ set_default_size(600, 400);
this.error = error;
this.account = account;
this.service = service;
- this.detail_text.buffer.text = format_details();
- }
+ GLib.SimpleActionGroup actions = new GLib.SimpleActionGroup();
+ actions.add_action_entries(ProblemDetailsDialog.action_entries, this);
+ insert_action_group("win", actions);
+
+ this.error_pane = new Components.InspectorErrorView(
+ error, account, service
+ );
- public ProblemDetailsDialog.for_problem_report(Gtk.Window parent,
- Geary.ProblemReport report) {
- Geary.ServiceProblemReport? service_report =
- report as Geary.ServiceProblemReport;
- Geary.AccountProblemReport? account_report =
- report as Geary.AccountProblemReport;
- this(
- parent,
- report.error,
- account_report != null ? account_report.account : null,
- service_report != null ? service_report.service : null
+ this.log_pane = new Components.InspectorLogView(
+ parent.application.config, null
);
+ this.log_pane.load();
+ this.log_pane.record_selection_changed.connect(
+ on_logs_selection_changed
+ );
+
+ this.system_pane = new Components.InspectorSystemView(
+ parent.application
+ );
+
+ /// Translators: Title for problem report dialog error
+ /// information pane
+ this.stack.add_titled(this.error_pane, "error_pane", _("Details"));
+ /// Translators: Title for problem report dialog logs pane
+ this.stack.add_titled(this.log_pane, "log_pane", _("Logs"));
+ /// Translators: Title for problem report system information
+ /// pane
+ this.stack.add_titled(this.system_pane, "system_pane", _("System"));
}
- private string format_details() {
- StringBuilder details = new StringBuilder();
-
- Gtk.ApplicationWindow? parent =
- this.get_toplevel() as Gtk.ApplicationWindow;
- GearyApplication? app = (parent != null)
- ? parent.application as GearyApplication
- : null;
- if (app != null) {
- foreach (GearyApplication.RuntimeDetail? detail
- in app.get_runtime_information()) {
- details.append_printf("%s: %s", detail.name, detail.value);
- }
+ public override bool key_press_event(Gdk.EventKey event) {
+ bool ret = Gdk.EVENT_PROPAGATE;
+
+ if (this.log_pane.search_mode_enabled &&
+ event.keyval == Gdk.Key.Escape) {
+ // Manually deactivate search so the button stays in sync
+ this.search_button.set_active(false);
+ ret = Gdk.EVENT_STOP;
}
- if (this.account != null) {
- details.append_printf(
- "Account id: %s\n",
- this.account.id
- );
- details.append_printf(
- "Account provider: %s\n",
- this.account.service_provider.to_string()
- );
+
+ if (ret == Gdk.EVENT_PROPAGATE &&
+ this.log_pane.search_mode_enabled) {
+ // Ensure <Space> and others are passed to the search
+ // entry before getting used as an accelerator.
+ ret = this.log_pane.handle_key_press(event);
}
- if (this.service != null) {
- details.append_printf(
- "Service type: %s\n",
- this.service.protocol.to_string()
- );
- details.append_printf(
- "Service host: %s\n",
- this.service.host
- );
+
+ if (ret == Gdk.EVENT_PROPAGATE) {
+ ret = base.key_press_event(event);
}
- if (this.error == null) {
- details.append("No error reported");
- } else {
- details.append_printf(
- "Error type: %s\n", this.error.format_error_type()
- );
- details.append_printf(
- "Message: %s\n", this.error.thrown.message
- );
- details.append("Back trace:\n");
- foreach (Geary.ErrorContext.StackFrame frame in
- this.error.backtrace) {
- details.append_printf(" - %s\n", frame.to_string());
+
+ if (ret == Gdk.EVENT_PROPAGATE &&
+ !this.log_pane.search_mode_enabled) {
+ // Nothing has handled the event yet, and search is not
+ // active, so see if we want to activate it now.
+ ret = this.log_pane.handle_key_press(event);
+ if (ret == Gdk.EVENT_STOP) {
+ this.search_button.set_active(true);
}
}
- return details.str;
+
+ return ret;
+ }
+
+ private async void save(string path,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ GLib.File dest = GLib.File.new_for_path(path);
+ GLib.FileIOStream dest_io = yield dest.replace_readwrite_async(
+ null,
+ false,
+ GLib.FileCreateFlags.NONE,
+ GLib.Priority.DEFAULT,
+ cancellable
+ );
+ GLib.DataOutputStream out = new GLib.DataOutputStream(
+ new GLib.BufferedOutputStream(dest_io.get_output_stream())
+ );
+
+ this.error_pane.save(@out, cancellable);
+ out.put_byte('\n');
+ out.put_byte('\n');
+ this.system_pane.save(@out, cancellable);
+ out.put_byte('\n');
+ out.put_byte('\n');
+ this.log_pane.save(@out, true, cancellable);
+
+ yield out.close_async();
+ yield dest_io.close_async();
+ }
+
+ private void update_ui() {
+ bool logs_visible = this.stack.visible_child == this.log_pane;
+ uint logs_selected = this.log_pane.count_selected_records();
+ this.copy_button.set_sensitive(!logs_visible || logs_selected > 0);
+ this.search_button.set_visible(logs_visible);
}
[GtkCallback]
+ private void on_visible_child_changed() {
+ update_ui();
+ }
+
private void on_copy_clicked() {
- get_clipboard(Gdk.SELECTION_CLIPBOARD).set_text(format_details(), -1);
+ GLib.MemoryOutputStream bytes = new GLib.MemoryOutputStream.resizable();
+ GLib.DataOutputStream out = new GLib.DataOutputStream(bytes);
+ try {
+ if (this.stack.visible_child == this.error_pane) {
+ this.error_pane.save(@out, null);
+ } else if (this.stack.visible_child == this.log_pane) {
+ this.log_pane.save(@out, false, null);
+ } else if (this.stack.visible_child == this.system_pane) {
+ this.system_pane.save(@out, null);
+ }
+
+ // Ensure the data is a valid string
+ out.put_byte(0, null);
+ } catch (GLib.Error err) {
+ warning(
+ "Error saving inspector data for clipboard: %s",
+ err.message
+ );
+ }
+
+ string clipboard_value = (string) bytes.get_data();
+ if (!Geary.String.is_empty(clipboard_value)) {
+ get_clipboard(Gdk.SELECTION_CLIPBOARD).set_text(clipboard_value, -1);
+ }
+ }
+
+ [GtkCallback]
+ private void on_save_as_clicked() {
+ Gtk.FileChooserNative chooser = new Gtk.FileChooserNative(
+ _("Save As"),
+ this,
+ Gtk.FileChooserAction.SAVE,
+ _("Save As"),
+ _("Cancel")
+ );
+ chooser.set_current_name(
+ new GLib.DateTime.now_local().format(
+ "Geary Problem Report - %F %T.txt"
+ )
+ );
+
+ if (chooser.run() == Gtk.ResponseType.ACCEPT) {
+ this.save.begin(
+ chooser.get_filename(),
+ null,
+ (obj, res) => {
+ try {
+ this.save.end(res);
+ } catch (GLib.Error err) {
+ warning(
+ "Failed to save problem report data: %s", err.message
+ );
+ }
+ }
+ );
+ }
+ }
+
+ private void on_logs_selection_changed() {
+ update_ui();
+ }
+
+ private void on_logs_search_toggled(GLib.SimpleAction action,
+ GLib.Variant? param) {
+ bool enabled = !((bool) action.state);
+ this.log_pane.search_mode_enabled = enabled;
+ action.set_state(enabled);
+ }
+
+ private void on_logs_search_activated() {
+ this.search_button.set_active(true);
+ }
+
+ private void on_close() {
+ destroy();
}
}
diff --git a/src/client/meson.build b/src/client/meson.build
index 95aab1e3..7f1a1df7 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -24,6 +24,7 @@ geary_client_vala_sources = files(
'components/client-web-view.vala',
'components/components-inspector.vala',
+ 'components/components-inspector-error-view.vala',
'components/components-inspector-log-view.vala',
'components/components-inspector-system-view.vala',
'components/components-placeholder-pane.vala',
diff --git a/src/meson.build b/src/meson.build
index 5ef921fd..31894cb3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -80,6 +80,7 @@ geary_bin_dependencies = [
gmime,
goa,
gtk,
+ libhandy,
libmath,
libsoup,
webkit2gtk,
diff --git a/ui/components-inspector-error-view.ui b/ui/components-inspector-error-view.ui
new file mode 100644
index 00000000..140f8ee5
--- /dev/null
+++ b/ui/components-inspector-error-view.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <requires lib="libhandy" version="0.0"/>
+ <template class="ComponentsInspectorErrorView" parent="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="HdyColumn">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">16</property>
+ <property name="margin_right">16</property>
+ <property name="margin_top">32</property>
+ <property name="margin_bottom">32</property>
+ <property name="maximum_width">500</property>
+ <property name="linear_growth_width">1</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">start</property>
+ <property name="valign">baseline</property>
+ <property name="margin_bottom">12</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">If the problem is serious or persists, please copy
and send these details to the <a href="https://wiki.gnome.org/Apps/Geary/Contact">mailing
list</a> or file a <a href="https://wiki.gnome.org/Apps/Geary/ReportingABug">new bug
report</a>.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">baseline</property>
+ <property name="label" translatable="yes">Details:</property>
+ <property name="track_visited_links">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="problem_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="editable">False</property>
+ <property name="wrap_mode">none</property>
+ <property name="left_margin">6</property>
+ <property name="right_margin">6</property>
+ <property name="top_margin">6</property>
+ <property name="bottom_margin">6</property>
+ <property name="cursor_visible">False</property>
+ <property name="monospace">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </template>
+</interface>
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
index 1065416e..1883b4cd 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -11,6 +11,7 @@
<file compressed="true">client-web-view.js</file>
<file compressed="true">client-web-view-allow-remote-images.js</file>
<file compressed="true" preprocess="xml-stripblanks">components-inspector.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">components-inspector-error-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-inspector-log-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-inspector-system-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-placeholder-pane.ui</file>
diff --git a/ui/problem-details-dialog.ui b/ui/problem-details-dialog.ui
index 0e7d2b88..6497cc6b 100644
--- a/ui/problem-details-dialog.ui
+++ b/ui/problem-details-dialog.ui
@@ -2,10 +2,9 @@
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
- <template class="DialogsProblemDetailsDialog" parent="GtkDialog">
+ <requires lib="libhandy" version="0.0"/>
+ <template class="DialogsProblemDetailsDialog" parent="HdyDialog">
<property name="can_focus">False</property>
- <property name="modal">True</property>
- <property name="type_hint">dialog</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
@@ -13,123 +12,89 @@
<property name="title" translatable="yes" comments="Dialog title for displaying technical details of
a problem. Same as the button that invokes it.">Details</property>
<property name="show_close_button">True</property>
<child>
- <object class="GtkButton">
- <property name="label" translatable="yes" comments="Button label for copying technical
information to the clipboard">Copy to Clipboard</property>
+ <object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <property name="tooltip_text" translatable="yes" comments="Button tooltip for copying technical
information to the clipboard">Copy technical details to clipboard for pasting into an email or bug
report</property>
- <signal name="clicked" handler="on_copy_clicked" swapped="no"/>
- <style>
- <class name="suggested-action"/>
- </style>
+ <property name="tooltip_text" translatable="yes" comments="Tooltip for problem report
button">Search for matching log entries</property>
+ <property name="action_name">win.toggle-search</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">edit-find-symbolic</property>
+ </object>
+ </child>
</object>
<packing>
- <property name="pack_type">end</property>
+ <property name="position">1</property>
</packing>
</child>
- </object>
- </child>
- <child internal-child="vbox">
- <object class="GtkBox">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">2</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox">
+ <child type="title">
+ <object class="GtkStackSwitcher">
+ <property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="layout_style">end</property>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
+ <property name="stack">stack</property>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
</child>
<child>
- <object class="GtkGrid" id="problem_details">
+ <object class="GtkButton" id="save_as_button">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">12</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="valign">baseline</property>
- <property name="margin_bottom">12</property>
- <property name="hexpand">True</property>
- <property name="label" translatable="yes">If the problem is serious or persists, please copy
and send these details to the <a href="https://wiki.gnome.org/Apps/Geary/Contact">mailing
list</a> or file a <a href="https://wiki.gnome.org/Apps/Geary/ReportingABug">new bug
report</a>.</property>
- <property name="use_markup">True</property>
- <property name="wrap">True</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" comments="Tooltip for problem report
button">Save logs entries and details</property>
+ <signal name="clicked" handler="on_save_as_clicked" swapped="no"/>
<child>
- <object class="GtkLabel">
+ <object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="valign">baseline</property>
- <property name="label" translatable="yes">Details:</property>
- <property name="track_visited_links">False</property>
+ <property name="icon_name">document-save-as-symbolic</property>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
</child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="copy_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" comments="Tooltip for problem report
button">Copy to clipboard</property>
+ <property name="action_name">win.copy</property>
<child>
- <object class="GtkScrolledWindow">
- <property name="width_request">600</property>
- <property name="height_request">200</property>
+ <object class="GtkImage">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTextView" id="detail_text">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="editable">False</property>
- <property name="wrap_mode">word</property>
- <property name="left_margin">6</property>
- <property name="right_margin">6</property>
- <property name="top_margin">6</property>
- <property name="bottom_margin">6</property>
- <property name="cursor_visible">False</property>
- <property name="monospace">True</property>
- </object>
- </child>
+ <property name="can_focus">False</property>
+ <property name="icon_name">edit-copy-symbolic</property>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- </packing>
</child>
</object>
<packing>
- <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="border_width">0</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <signal name="notify::visible-child" handler="on_visible_child_changed" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]