Convert ProblemReportDialog to use Inspector views
Aside from the code re-use, this allows including log files in problem reports.
This commit is contained in:
parent
2841cb0b66
commit
6f65062219
8 changed files with 450 additions and 169 deletions
75
src/client/components/components-inspector-error-view.vala
Normal file
75
src/client/components/components-inspector-error-view.vala
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
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.error_pane = new Components.InspectorErrorView(
|
||||
error, account, service
|
||||
);
|
||||
|
||||
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();
|
||||
public override bool key_press_event(Gdk.EventKey event) {
|
||||
bool ret = Gdk.EVENT_PROPAGATE;
|
||||
|
||||
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);
|
||||
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 (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 (ret == Gdk.EVENT_PROPAGATE) {
|
||||
ret = base.key_press_event(event);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 (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 (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());
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ geary_bin_dependencies = [
|
|||
gmime,
|
||||
goa,
|
||||
gtk,
|
||||
libhandy,
|
||||
libmath,
|
||||
libsoup,
|
||||
webkit2gtk,
|
||||
|
|
|
|||
95
ui/components-inspector-error-view.ui
Normal file
95
ui/components-inspector-error-view.ui
Normal file
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_as_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">Save logs entries and details</property>
|
||||
<signal name="clicked" handler="on_save_as_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-save-as-symbolic</property>
|
||||
</object>
|
||||
</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="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-copy-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<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>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</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="GtkStack" id="stack">
|
||||
<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>
|
||||
<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="width_request">600</property>
|
||||
<property name="height_request">200</property>
|
||||
<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>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<signal name="notify::visible-child" handler="on_visible_child_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue