[gnome-boxes/wip/text-editor] WIP
- From: Felipe Borges <felipeborges src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-boxes/wip/text-editor] WIP
- Date: Mon, 3 Aug 2020 15:28:27 +0000 (UTC)
commit 7d6468addc04c82cee254a20c51fef14ddfe2a07
Author: Felipe Borges <felipeborges gnome org>
Date: Mon Aug 3 10:51:31 2020 +0200
WIP
data/gnome-boxes.gresource.xml | 1 +
data/ui/properties-toolbar.ui | 86 ++++++++++++++++++++++++++++++++++-
data/ui/properties-window.ui | 10 +++++
data/ui/text-editor.ui | 31 +++++++++++++
src/libvirt-machine-properties.vala | 7 +++
src/meson.build | 2 +
src/properties-toolbar.vala | 15 ++++++-
src/properties-window.vala | 12 ++++-
src/text-editor.vala | 90 +++++++++++++++++++++++++++++++++++++
src/vm-configurator.vala | 10 ++++-
10 files changed, 259 insertions(+), 5 deletions(-)
---
diff --git a/data/gnome-boxes.gresource.xml b/data/gnome-boxes.gresource.xml
index 3fe6f967..4ff7643d 100644
--- a/data/gnome-boxes.gresource.xml
+++ b/data/gnome-boxes.gresource.xml
@@ -35,6 +35,7 @@
<file preprocess="xml-stripblanks">ui/shared-folders.ui</file>
<file preprocess="xml-stripblanks">ui/shared-folder-popover.ui</file>
<file preprocess="xml-stripblanks">ui/snapshot-list-row.ui</file>
+ <file preprocess="xml-stripblanks">ui/text-editor.ui</file>
<file preprocess="xml-stripblanks">ui/topbar.ui</file>
<file preprocess="xml-stripblanks">ui/transfer-info-row.ui</file>
<file preprocess="xml-stripblanks">ui/transfer-popover.ui</file>
diff --git a/data/ui/properties-toolbar.ui b/data/ui/properties-toolbar.ui
index 3d096ba3..592d7e50 100644
--- a/data/ui/properties-toolbar.ui
+++ b/data/ui/properties-toolbar.ui
@@ -55,13 +55,13 @@
</style>
<child internal-child="accessible">
- <object class="AtkObject" id="a11y-button6">
+ <object class="AtkObject">
<property name="accessible-name" translatable="yes">Back</property>
</object>
</child>
<child>
- <object class="GtkImage" id="back_image2">
+ <object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
@@ -98,6 +98,88 @@
</packing>
</child>
+ <!-- Text Editor page -->
+ <child>
+ <object class="GtkHeaderBar" id="text_editor">
+ <property name="visible">True</property>
+ <property name="show-close-button">True</property>
+ <style>
+ <class name="titlebar"/>
+ </style>
+
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <signal name="clicked" handler="on_troubleshooting_back_clicked"/>
+ <style>
+ <class name="image-button"/>
+ </style>
+
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-button6">
+ <property name="accessible-name" translatable="yes">Back</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkImage" id="back_image2">
+ <property name="visible">True</property>
+ <property name="icon-name">go-previous-symbolic</property>
+ </object>
+ </child>
+ </object>
+
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="revert_button">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <signal name="clicked" handler="on_revert_changes_clicked"/>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">document-revert-symbolic</property>
+ </object>
+ </child>
+ </object>
+
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="save_button">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <property name="label" translatable="yes">_Save</property>
+ <signal name="clicked" handler="on_text_editor_save_clicked"/>
+ <style>
+ <class name="text-button"/>
+ </style>
+ </object>
+
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ </object>
+
+ <packing>
+ <property name="name">text_editor</property>
+ </packing>
+ </child>
+
<!-- File chooser page -->
<child>
<object class="GtkHeaderBar" id="file_chooser">
diff --git a/data/ui/properties-window.ui b/data/ui/properties-window.ui
index f8e2dd1e..4b459eef 100644
--- a/data/ui/properties-window.ui
+++ b/data/ui/properties-window.ui
@@ -70,6 +70,16 @@
</packing>
</child>
+ <child>
+ <object class="BoxesTextEditor" id="text_editor">
+ <property name="visible">True</property>
+ </object>
+
+ <packing>
+ <property name="name">text_editor</property>
+ </packing>
+ </child>
+
<child>
<object class="GtkBox">
<property name="visible">True</property>
diff --git a/data/ui/text-editor.ui b/data/ui/text-editor.ui
new file mode 100644
index 00000000..be34f3d5
--- /dev/null
+++ b/data/ui/text-editor.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.9 -->
+ <template class="BoxesTextEditor" parent="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="vexpand">True</property>
+ <property name="no-show-all">True</property>
+ <property name="min-content-width">640</property>
+ <property name="min-content-height">480</property>
+ <property name="margin-top">10</property>
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="margin-bottom">10</property>
+
+ <child>
+ <object class="GtkSourceView" id="view">
+ <property name="visible">True</property>
+ <property name="editable">True</property>
+ <property name="auto-indent">True</property>
+ <property name="indent-on-tab">True</property>
+ <property name="insert-spaces-instead-of-tabs">True</property>
+ <property name="monospace">True</property>
+ <property name="show-line-marks">True</property>
+ <property name="show-line-numbers">True</property>
+ <property name="background-pattern">grid</property>
+ <property name="wrap-mode">word</property>
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/libvirt-machine-properties.vala b/src/libvirt-machine-properties.vala
index eabdaa4d..4661bd2b 100644
--- a/src/libvirt-machine-properties.vala
+++ b/src/libvirt-machine-properties.vala
@@ -383,6 +383,13 @@ private void add_system_props_buttons (ref List<Boxes.Property> list) {
machine.window.props_window.show_troubleshoot_log (log);
});
+ var edit_button = new Gtk.Button.with_mnemonic (_("Edit XML"));
+ edit_button.halign = Gtk.Align.END;
+ grid.attach (edit_button, 2, 0, 1, 1);
+ edit_button.clicked.connect (() => {
+ machine.window.props_window.show_editor_view (machine);
+ });
+
var prop = add_property (ref list, null, grid);
ulong flushed_id = 0;
flushed_id = prop.flushed.connect (() => {
diff --git a/src/meson.build b/src/meson.build
index 3d4302af..440341f6 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -90,6 +90,7 @@ vala_sources = [
'selection-toolbar.vala',
'shared-folders.vala',
'spice-display.vala',
+ 'text-editor.vala',
'transfer-info-row.vala',
'transfer-popover.vala',
'troubleshoot-view.vala',
@@ -140,6 +141,7 @@ dependencies = [
dependency ('libvirt-gobject-1.0', version: '>= 3.0.0'),
dependency ('libxml-2.0', version: '>= 2.7.8'),
dependency ('spice-client-gtk-3.0', version: '>= 0.32'),
+ dependency ('gtksourceview-4'),
dependency ('tracker-sparql-2.0'),
dependency ('vte-2.91', version: '>= 0.40.2'),
dependency ('webkit2gtk-4.0', version: '>= 2.26.0'),
diff --git a/src/properties-toolbar.vala b/src/properties-toolbar.vala
index 6d15cfa3..a2f15d9a 100644
--- a/src/properties-toolbar.vala
+++ b/src/properties-toolbar.vala
@@ -16,6 +16,9 @@
[GtkChild]
public Gtk.HeaderBar main;
+ [GtkChild]
+ public Gtk.HeaderBar text_editor;
+
[GtkChild]
public Gtk.Button troubleshooting_back_button;
@@ -48,7 +51,7 @@ public void click_back_button () {
}
[GtkCallback]
- private void on_troubleshooting_back_clicked () requires (page == PropsWindowPage.TROUBLESHOOTING_LOG) {
+ private void on_troubleshooting_back_clicked () requires (page == PropsWindowPage.TROUBLESHOOTING_LOG ||
page == PropsWindowPage.TEXT_EDITOR) {
props_window.page = PropsWindowPage.MAIN;
}
@@ -57,6 +60,16 @@ private void on_copy_clipboard_clicked () requires (page == PropsWindowPage.TROU
props_window.copy_troubleshoot_log_to_clipboard ();
}
+ [GtkCallback]
+ private void on_revert_changes_clicked () requires (page == PropsWindowPage.TEXT_EDITOR) {
+ props_window.text_editor.revert_to_original ();
+ }
+
+ [GtkCallback]
+ private void on_text_editor_save_clicked () {
+ props_window.text_editor.save ();
+ }
+
[GtkCallback]
private void on_title_entry_changed () {
window.current_item.name = title_entry.text;
diff --git a/src/properties-window.vala b/src/properties-window.vala
index f920a72e..46f02ec1 100644
--- a/src/properties-window.vala
+++ b/src/properties-window.vala
@@ -5,13 +5,14 @@
MAIN,
TROUBLESHOOTING_LOG,
FILE_CHOOSER,
+ TEXT_EDITOR,
}
public delegate void Boxes.FileChosenFunc (string path);
[GtkTemplate (ui = "/org/gnome/Boxes/ui/properties-window.ui")]
private class Boxes.PropertiesWindow: Gtk.Window, Boxes.UI {
- public const string[] page_names = { "main", "troubleshoot_log", "file_chooser" };
+ public const string[] page_names = { "main", "troubleshoot_log", "file_chooser", "text_editor" };
public UIState previous_ui_state { get; protected set; }
public UIState ui_state { get; protected set; }
@@ -33,6 +34,8 @@
public Properties properties;
[GtkChild]
public TroubleshootLog troubleshoot_log;
+ [GtkChild]
+ public TextEditor text_editor;
public Gtk.FileChooserNative file_chooser;
[GtkChild]
@@ -65,6 +68,13 @@ public void show_troubleshoot_log (string log) {
page = PropsWindowPage.TROUBLESHOOTING_LOG;
}
+ public void show_editor_view (LibvirtMachine machine) {
+ page = PropsWindowPage.TEXT_EDITOR;
+ text_editor.setup (machine);
+
+ topbar.text_editor.set_title (machine.name);
+ }
+
public void show_file_chooser (owned FileChosenFunc file_chosen_func) {
page = PropsWindowPage.FILE_CHOOSER;
var res = file_chooser.run ();
diff --git a/src/text-editor.vala b/src/text-editor.vala
new file mode 100644
index 00000000..d2a7ae87
--- /dev/null
+++ b/src/text-editor.vala
@@ -0,0 +1,90 @@
+// This file is part of GNOME Boxes. License: LGPLv2+
+using Gtk;
+
+[GtkTemplate (ui = "/org/gnome/Boxes/ui/text-editor.ui")]
+private class Boxes.TextEditor: Gtk.ScrolledWindow {
+ private const string BOXES_NS = "boxes";
+ private const string BOXES_NS_URI = "https://wiki.gnome.org/Apps/Boxes/edited";
+ private const string MANUALLY_EDITED_XML = "<edited>%u</edited>";
+ private const string FILE_SUFFIX = ".original.xml";
+
+ [GtkChild]
+ private Gtk.SourceView view;
+
+ private LibvirtMachine machine;
+
+ public void setup (LibvirtMachine machine) {
+ this.machine = machine;
+
+ var buffer = new Gtk.SourceBuffer (null);
+ buffer.language = Gtk.SourceLanguageManager.get_default ().get_language ("xml");
+ view.buffer = buffer;
+
+ try {
+ var config = machine.domain.get_config (GVir.DomainXMLFlags.NONE);
+ buffer.set_text (config.to_xml ());
+ } catch (GLib.Error error) {
+ warning ("Failed to load machine configuration: %s", error.message);
+ }
+ }
+
+ public async void save () {
+ GVirConfig.Domain? config = null;
+ try {
+ config = machine.domain.get_config (GVir.DomainXMLFlags.NONE);
+ } catch (GLib.Error error) {
+ warning ("Failed to load machine configuration: %s", error.message);
+ return;
+ }
+
+ var saved = yield save_original_config (config);
+
+ var xml = view.buffer.text;
+ GVirConfig.Domain? custom_config = null;
+ try {
+ custom_config = new GVirConfig.Domain.from_xml (xml);
+ } catch (GLib.Error error) {
+ warning ("Failed to save changes!\n");
+ }
+
+ add_metadata (custom_config);
+
+ machine.domain.set_config (custom_config);
+ }
+
+ private void add_metadata (GVirConfig.Domain config) {
+ string edited_xml = MANUALLY_EDITED_XML.printf (1);
+
+ try {
+ config.set_custom_xml (edited_xml, "edited", BOXES_NS_URI);
+ } catch (GLib.Error error) {
+ warning ("Failed to save custom XML: %s", error.message);
+ }
+ }
+
+ private async bool save_original_config (GVirConfig.Domain config) {
+ var old_config_path = get_user_pkgconfig (config.get_name () + FILE_SUFFIX);
+
+ return FileUtils.set_contents (old_config_path, config.to_xml (), -1);
+ }
+
+ public async void revert_to_original () {
+ var original_config_path = get_user_pkgconfig (machine.domain_config.get_name () + FILE_SUFFIX);
+
+ string data;
+ FileUtils.get_contents (original_config_path, out data);
+ if (data == null) {
+ warning ("Failed to load original config");
+ return;
+ }
+
+ try {
+ var config = new GVirConfig.Domain.from_xml (data);
+ machine.domain.set_config (config);
+
+ view.buffer.text = data;
+ } catch (GLib.Error error) {
+ warning ("Failed to load old configurations %s", error.message);
+ }
+ }
+}
diff --git a/src/vm-configurator.vala b/src/vm-configurator.vala
index 7679cdc5..7d026586 100644
--- a/src/vm-configurator.vala
+++ b/src/vm-configurator.vala
@@ -254,6 +254,10 @@ public static async void update_existing_domain (Domain domain,
if (!boxes_created_domain (domain))
return;
+ if (boxes_edited_domain (domain)) {
+ return;
+ }
+
try {
var cpu = domain.get_cpu ();
if (cpu != null &&
@@ -513,7 +517,7 @@ private static StoragePermissions get_default_permissions () {
return null;
}
- private static string? get_custom_xml_node (Domain domain, string node_name) {
+ public static string? get_custom_xml_node (Domain domain, string node_name) {
var ns_uri = BOXES_NS_URI;
var xml = domain.get_custom_xml (ns_uri);
if (xml == null) {
@@ -557,6 +561,10 @@ private static bool boxes_created_domain (Domain domain) {
return (xml != null);
}
+ private static bool boxes_edited_domain (Domain domain) {
+ return (get_custom_xml_node (domain, "edited") != null);
+ }
+
private static void update_custom_xml (Domain domain,
InstallerMedia? install_media,
uint num_reboots = 0,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]