diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2016-07-04 14:15:44 +0200 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2016-07-25 14:02:08 +0200 |
commit | 13eea21c6f1291f43c26f0b4f5170f9629cb4219 (patch) | |
tree | a1c2cd8f72d165ec26c5a47725ed04ccba6ee46c | |
parent | 65c662d08b34d486d4d567424ccf623cda72389e (diff) | |
download | network-manager-applet-lr/team.tar.gz |
editor/team-port: add UI controls for team port configurationlr/team
Editing raw JSON is still supported and kept in sync.
-rw-r--r-- | src/connection-editor/ce-page-team-port.ui | 889 | ||||
-rw-r--r-- | src/connection-editor/page-team-port.c | 530 |
2 files changed, 1370 insertions, 49 deletions
diff --git a/src/connection-editor/ce-page-team-port.ui b/src/connection-editor/ce-page-team-port.ui index 84d22b49..1f32fcb7 100644 --- a/src/connection-editor/ce-page-team-port.ui +++ b/src/connection-editor/ce-page-team-port.ui @@ -1,62 +1,879 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.4"/> <object class="GtkGrid" id="TeamPortPage"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> <property name="border_width">12</property> + <property name="row_spacing">8</property> <property name="column_spacing">12</property> - <property name="row_spacing">6</property> - <property name="column_homogeneous">True</property> <child> - <object class="GtkLabel" id="team_port_json_config_label"> + <object class="GtkButton" id="advanced_button"> <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">_JSON config:</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">end</property> + <property name="valign">end</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> <property name="use_underline">True</property> - <property name="mnemonic_widget">team_port_json_config</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-preferences</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Ad_vanced...</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> </object> <packing> <property name="left_attach">0</property> <property name="top_attach">0</property> + <property name="width">2</property> </packing> </child> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">in</property> - <property name="min_content_height">100</property> + </object> + <object class="GtkAdjustment" id="delay_down_adjustment"> + <property name="lower">-1</property> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="delay_up_adjustment"> + <property name="lower">-1</property> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="init_wait_adjustment"> + <property name="lower">-1</property> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="lacp_port_key_adjustment"> + <property name="lower">-1</property> + <property name="upper">4294967296</property> + <property name="value">-1</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="lacp_port_prio_adjustment"> + <property name="lower">-1</property> + <property name="upper">4294967296</property> + <property name="value">-1</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkListStore" id="link_watch_model"> + <columns> + <!-- column-name type --> + <column type="gchararray"/> + <!-- column-name name --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0">master</col> + <col id="1" translatable="yes">Set by master</col> + </row> + <row> + <col id="0">ethtool</col> + <col id="1" translatable="yes">Ethernet port state</col> + </row> + <row> + <col id="0">arp_ping</col> + <col id="1" translatable="yes">ARP (IPv4)</col> + </row> + <row> + <col id="0">nsna_ping</col> + <col id="1" translatable="yes">NDP (IPv6)</col> + </row> + </data> + </object> + <object class="GtkAdjustment" id="missed_max_adjustment"> + <property name="lower">-1</property> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="port_prio_adjustment"> + <property name="lower">-1</property> + <property name="upper">4294967296</property> + <property name="value">-1</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="queue_id_adjustment"> + <property name="lower">-1</property> + <property name="upper">4294967296</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="send_interval_adjustment"> + <property name="lower">-1</property> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkDialog" id="advanced_dialog"> + <property name="can_focus">False</property> + <property name="title" translatable="yes">Team Advanced Options</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="advanced_dialog_box"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="advanced_buttons"> + <property name="can_focus">False</property> + <property name="margin_left">6</property> + <property name="margin_right">6</property> + <property name="margin_top">6</property> + <property name="margin_bottom">6</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="advanced_cancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="advanced_ok"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> <child> - <object class="GtkTextView" id="team_port_json_config"> + <object class="GtkNotebook" id="advanced_notebook"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="hexpand">True</property> + <property name="margin_left">6</property> + <property name="margin_right">6</property> + <property name="margin_top">6</property> + <property name="margin_bottom">6</property> + <child> + <object class="GtkGrid" id="general_grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">start</property> + <property name="border_width">12</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + <child> + <object class="GtkLabel" id="queue_id_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Queue ID:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">queue_id</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="queue_id"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Number of bursts of unsolicited NAs and gratuitous ARP packets sent after port is enabled or disabled.</property> + <property name="hexpand">True</property> + <property name="secondary_icon_tooltip_text" translatable="yes">ID of queue which this port should be mapped to.</property> + <property name="adjustment">queue_id_adjustment</property> + <property name="value">-1</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">etched-out</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="port_prio_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Port priority:</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="port_sticky"> + <property name="label" translatable="yes">Port _sticky</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Validate received ARP packets on active ports. If this is not checked, all incoming ARP packets will be considered as a good reply.</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="port_prio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Value is positive number in milliseconds. Specifies an interval between bursts of notify-peer packets.</property> + <property name="hexpand">True</property> + <property name="secondary_icon_tooltip_text" translatable="yes">Port priority. The higher number means higher priority.</property> + <property name="adjustment">port_prio_adjustment</property> + <property name="value">-1</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Active-Backup runner options</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">etched-out</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="lacp_port_prio_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_LACP port priority:</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="lacp_port_key_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">LACP port _key:</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="lacp_port_prio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Number of bursts of multicast group rejoin requests sent after port is enabled or disabled.</property> + <property name="hexpand">True</property> + <property name="secondary_icon_tooltip_text" translatable="yes">Port priority according to LACP standard. The lower number means higher priority.</property> + <property name="adjustment">lacp_port_prio_adjustment</property> + <property name="value">-1</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="lacp_port_key"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Value is positive number in milliseconds. Specifies an interval between bursts of multicast group rejoin requests.</property> + <property name="hexpand">True</property> + <property name="secondary_icon_tooltip_text" translatable="yes">Port key according to LACP standard. It is only possible to aggregate ports with the same key.</property> + <property name="adjustment">lacp_port_key_adjustment</property> + <property name="value">-1</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">LACP runner options</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + <property name="width">2</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="general_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">General</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="link_watch_grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">start</property> + <property name="border_width">12</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="link_watcher_name_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Link watcher:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">link_watcher_name</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="delay_up_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Up delay:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">delay_up</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="delay_down_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Down delay:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">delay_down</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="send_interval_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">Send _interval:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">send_interval</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="init_wait_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">Delay _before first send:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">init_wait</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="missed_max_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Maximum missed replies:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">missed_max</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">5</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="source_host_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">_Source host:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">source_host</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">6</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="target_host_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes">_Target host:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">target_host</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">7</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="missed_max"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Maximum number of missed replies. If this number is exceeded, link is reported as down.</property> + <property name="hexpand">True</property> + <property name="adjustment">missed_max_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">5</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="source_host"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Hostname to be converted to IP address which will be filled into ARP request as source address.</property> + <property name="hexpand">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">6</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="target_host"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Hostname to be converted to IP address which will be filled into request as destination address.</property> + <property name="hexpand">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">7</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="validate_active"> + <property name="label" translatable="yes">Ignore invalid packets from _active ports</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Validate received ARP packets on active ports. If this is not checked, all incoming ARP packets will be considered as a good reply.</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">8</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="validate_inactive"> + <property name="label" translatable="yes">Ignore invalid packets from i_nactive ports</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Validate received ARP packets on inactive ports. If this is not checked, all incoming ARP packets will be considered as a good reply.</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">9</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="send_all"> + <property name="label" translatable="yes">S_end on inactive ports</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">By default, ARP requests are sent on active ports only. This option allows sending even on inactive ports.</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">10</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="delay_up_ms"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label">ms</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="delay_down_ms"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label">ms</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="send_interval_ms"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label">ms</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="init_wait_ms"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label">ms</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="delay_up"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">The delay between the link coming up and the runner being notified about it.</property> + <property name="hexpand">True</property> + <property name="adjustment">delay_up_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="delay_down"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">The delay between the link going down and the runner being notified about it.</property> + <property name="hexpand">True</property> + <property name="adjustment">delay_down_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="send_interval"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">The interval between requests being sent.</property> + <property name="hexpand">True</property> + <property name="adjustment">send_interval_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="init_wait"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">The delay between link watch initialization and the first request being sent.</property> + <property name="hexpand">False</property> + <property name="adjustment">init_wait_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="link_watcher_name"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">The link watcher to be used.</property> + <property name="hexpand">True</property> + <property name="model">link_watch_model</property> + <property name="active">0</property> + <property name="id_column">0</property> + <child> + <object class="GtkCellRendererText" id="link_watch_renderer"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="link_watch_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Link Watcher</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="json_grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="vexpand">True</property> + <property name="border_width">12</property> + <property name="row_spacing">8</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkButton" id="import_config_button"> + <property name="label" translatable="yes">Im_port team configuration from a file...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="hexpand">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <property name="min_content_height">100</property> + <child> + <object class="GtkTextView" id="team_port_json_config"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="monospace">True</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="team_port_json_config_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Edit _JSON configuration:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">team_port_json_config</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="json_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Raw Configuration</property> + </object> + <packing> + <property name="position">2</property> + <property name="tab_fill">False</property> + </packing> + </child> </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> </child> </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - <property name="width">2</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkButton" id="import_config_button"> - <property name="label" translatable="yes">_Import team configuration from a file...</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_underline">True</property> - <property name="hexpand">True</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - <property name="width">2</property> - <property name="height">1</property> - </packing> </child> + <action-widgets> + <action-widget response="-6">advanced_cancel</action-widget> + <action-widget response="-5">advanced_ok</action-widget> + </action-widgets> </object> </interface> diff --git a/src/connection-editor/page-team-port.c b/src/connection-editor/page-team-port.c index e033ccf8..a89d4ce5 100644 --- a/src/connection-editor/page-team-port.c +++ b/src/connection-editor/page-team-port.c @@ -15,11 +15,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright 2013 Jiri Pirko <jiri@resnulli.us> - * Copyright 2013 - 2014 Red Hat, Inc. + * Copyright 2013 - 2016 Red Hat, Inc. */ #include "nm-default.h" +#if WITH_JANSSON +#include <jansson.h> +#endif + #include <string.h> #include "page-team-port.h" @@ -33,8 +37,97 @@ typedef struct { GtkTextView *json_config_widget; GtkWidget *import_config_button; + + GtkButton *advanced_button; + GtkDialog *advanced_dialog; + GtkNotebook *advanced_notebook; + + /* General */ + GtkSpinButton *queue_id; + GtkSpinButton *port_prio; + GtkToggleButton *port_sticky; + GtkSpinButton *lacp_port_prio; + GtkSpinButton *lacp_port_key; + + /* Link Watch */ + GtkComboBox *link_watcher_name; + GtkSpinButton *delay_up; + GtkLabel *delay_up_label; + GtkLabel *delay_up_ms; + GtkSpinButton *delay_down; + GtkLabel *delay_down_label; + GtkLabel *delay_down_ms; + GtkSpinButton *send_interval; + GtkLabel *send_interval_label; + GtkLabel *send_interval_ms; + GtkSpinButton *init_wait; + GtkLabel *init_wait_label; + GtkLabel *init_wait_ms; + GtkSpinButton *missed_max; + GtkLabel *missed_max_label; + GtkEntry *source_host; + GtkLabel *source_host_label; + GtkEntry *target_host; + GtkLabel *target_host_label; + GtkToggleButton *validate_active; + GtkToggleButton *validate_inactive; + GtkToggleButton *send_all; } CEPageTeamPortPrivate; +/* Get string "type" from a combo box with a ["type", "name"] model. */ +static gchar * +get_combo_box (GtkComboBox *combo) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gchar *name; + + if (!gtk_combo_box_get_active_iter (combo, &iter)) + g_return_val_if_reached (NULL); + + model = gtk_combo_box_get_model (combo); + gtk_tree_model_get (model, &iter, 0, &name, -1); + + return name; +} + +#if WITH_JANSSON + +/* Set active item to "type" in a combo box with a ["type", "name"] model. */ +static gboolean +set_combo_box (GtkComboBox *combo, const gchar *value, GError **error) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean valid; + const gchar *name; + int i = 0; + + if (!value || !*value) { + gtk_combo_box_set_active (combo, 0); + return TRUE; + } + + model = gtk_combo_box_get_model (combo); + for (valid = gtk_tree_model_get_iter_first (model, &iter); + valid; + valid = gtk_tree_model_iter_next (model, &iter)) { + gtk_tree_model_get (model, &iter, 0, &name, -1); + if (strcmp (name, value) == 0) { + gtk_combo_box_set_active (combo, i); + return TRUE; + } + i++; + } + + g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, + "Value of \"%s\" is not known", value); + + return FALSE; +} + +#endif + static void team_port_private_init (CEPageTeamPort *self) { @@ -45,12 +138,51 @@ team_port_private_init (CEPageTeamPort *self) priv->json_config_widget = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "team_port_json_config")); priv->import_config_button = GTK_WIDGET (gtk_builder_get_object (builder, "import_config_button")); -} - -static void -json_config_changed (GObject *object, CEPageTeamPort *self) -{ - ce_page_changed (CE_PAGE (self)); + priv->advanced_button = GTK_BUTTON (gtk_builder_get_object (builder, "advanced_button")); + priv->advanced_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "advanced_dialog")); + gtk_window_set_modal (GTK_WINDOW (priv->advanced_dialog), TRUE); + priv->advanced_notebook = GTK_NOTEBOOK (gtk_builder_get_object (builder, "advanced_notebook")); + + /* General */ + priv->queue_id = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "queue_id")); + priv->port_prio = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "port_prio")); + priv->port_sticky = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "port_sticky")); + priv->lacp_port_prio = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "lacp_port_prio")); + priv->lacp_port_key = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "lacp_port_key")); + + /* Link Watcher */ + priv->link_watcher_name = GTK_COMBO_BOX (gtk_builder_get_object (builder, "link_watcher_name")); + priv->send_interval = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "send_interval")); + priv->send_interval_label = GTK_LABEL (gtk_builder_get_object (builder, "send_interval_label")); + priv->send_interval_ms = GTK_LABEL (gtk_builder_get_object (builder, "send_interval_ms")); + priv->init_wait = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "init_wait")); + priv->init_wait_label = GTK_LABEL (gtk_builder_get_object (builder, "init_wait_label")); + priv->init_wait_ms = GTK_LABEL (gtk_builder_get_object (builder, "init_wait_ms")); + priv->missed_max = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "missed_max")); + priv->missed_max_label = GTK_LABEL (gtk_builder_get_object (builder, "missed_max_label")); + priv->source_host = GTK_ENTRY (gtk_builder_get_object (builder, "source_host")); + priv->source_host_label = GTK_LABEL (gtk_builder_get_object (builder, "source_host_label")); + priv->target_host = GTK_ENTRY (gtk_builder_get_object (builder, "target_host")); + priv->target_host_label = GTK_LABEL (gtk_builder_get_object (builder, "target_host_label")); + priv->validate_active = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "validate_active")); + priv->validate_inactive = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "validate_inactive")); + priv->send_all = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "send_all")); + priv->delay_up = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "delay_up")); + priv->delay_up_label = GTK_LABEL (gtk_builder_get_object (builder, "delay_up_label")); + priv->delay_up_ms = GTK_LABEL (gtk_builder_get_object (builder, "delay_up_ms")); + priv->delay_down = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "delay_down")); + priv->delay_down_label = GTK_LABEL (gtk_builder_get_object (builder, "delay_down_label")); + priv->delay_down_ms = GTK_LABEL (gtk_builder_get_object (builder, "delay_down_ms")); + + ce_spin_default_val (priv->queue_id, -1); + ce_spin_default_val (priv->port_prio, -1); + ce_spin_default_val (priv->lacp_port_prio, -1); + ce_spin_default_val (priv->lacp_port_key, -1); + ce_spin_default_val (priv->send_interval, -1); + ce_spin_default_val (priv->init_wait, -1); + ce_spin_default_val (priv->missed_max, -1); + ce_spin_default_val (priv->delay_up, -1); + ce_spin_default_val (priv->delay_down, -1); } static void @@ -58,18 +190,18 @@ import_button_clicked_cb (GtkWidget *widget, CEPageTeamPort *self) { CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self); GtkWidget *dialog; - GtkWindow *toplevel; GtkTextBuffer *buffer; char *filename; char *buf = NULL; gsize buf_len; + GtkWidget *toplevel; - toplevel = GTK_WINDOW (gtk_widget_get_toplevel (widget)); - if (!gtk_widget_is_toplevel (GTK_WIDGET (toplevel))) - toplevel = NULL; + toplevel = gtk_widget_get_toplevel (CE_PAGE (self)->page); + g_return_if_fail (toplevel); + g_return_if_fail (gtk_widget_is_toplevel (toplevel)); dialog = gtk_file_chooser_dialog_new (_("Select file to import"), - toplevel, + GTK_WINDOW (toplevel), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, @@ -103,6 +235,376 @@ out: } static void +link_watcher_changed (GtkComboBox *combo, gpointer user_data) +{ + CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (user_data); + gchar *name; + + /* First hide everything and then show just what we need. */ + gtk_widget_hide (GTK_WIDGET (priv->delay_up)); + gtk_widget_hide (GTK_WIDGET (priv->delay_up_label)); + gtk_widget_hide (GTK_WIDGET (priv->delay_up_ms)); + gtk_widget_hide (GTK_WIDGET (priv->delay_down)); + gtk_widget_hide (GTK_WIDGET (priv->delay_down_label)); + gtk_widget_hide (GTK_WIDGET (priv->delay_down_ms)); + gtk_widget_hide (GTK_WIDGET (priv->send_interval)); + gtk_widget_hide (GTK_WIDGET (priv->send_interval_label)); + gtk_widget_hide (GTK_WIDGET (priv->send_interval_ms)); + gtk_widget_hide (GTK_WIDGET (priv->init_wait)); + gtk_widget_hide (GTK_WIDGET (priv->init_wait_label)); + gtk_widget_hide (GTK_WIDGET (priv->init_wait_ms)); + gtk_widget_hide (GTK_WIDGET (priv->missed_max)); + gtk_widget_hide (GTK_WIDGET (priv->missed_max_label)); + gtk_widget_hide (GTK_WIDGET (priv->source_host)); + gtk_widget_hide (GTK_WIDGET (priv->source_host_label)); + gtk_widget_hide (GTK_WIDGET (priv->target_host)); + gtk_widget_hide (GTK_WIDGET (priv->target_host_label)); + gtk_widget_hide (GTK_WIDGET (priv->validate_active)); + gtk_widget_hide (GTK_WIDGET (priv->validate_inactive)); + gtk_widget_hide (GTK_WIDGET (priv->send_all)); + + name = get_combo_box (combo); + if (g_strcmp0 (name, "master") == 0) { + /* Leave everything disabled. */ + } else if (g_strcmp0 (name, "ethtool") == 0) { + gtk_widget_show (GTK_WIDGET (priv->delay_up)); + gtk_widget_show (GTK_WIDGET (priv->delay_up_label)); + gtk_widget_show (GTK_WIDGET (priv->delay_up_ms)); + gtk_widget_show (GTK_WIDGET (priv->delay_down)); + gtk_widget_show (GTK_WIDGET (priv->delay_down_label)); + gtk_widget_show (GTK_WIDGET (priv->delay_down_ms)); + } else if (g_strcmp0 (name, "arp_ping") == 0) { + gtk_widget_show (GTK_WIDGET (priv->send_interval)); + gtk_widget_show (GTK_WIDGET (priv->send_interval_label)); + gtk_widget_show (GTK_WIDGET (priv->send_interval_ms)); + gtk_widget_show (GTK_WIDGET (priv->init_wait)); + gtk_widget_show (GTK_WIDGET (priv->init_wait_label)); + gtk_widget_show (GTK_WIDGET (priv->init_wait_ms)); + gtk_widget_show (GTK_WIDGET (priv->missed_max)); + gtk_widget_show (GTK_WIDGET (priv->missed_max_label)); + gtk_widget_show (GTK_WIDGET (priv->source_host)); + gtk_widget_show (GTK_WIDGET (priv->source_host_label)); + gtk_widget_show (GTK_WIDGET (priv->target_host)); + gtk_widget_show (GTK_WIDGET (priv->target_host_label)); + gtk_widget_show (GTK_WIDGET (priv->validate_active)); + gtk_widget_show (GTK_WIDGET (priv->validate_inactive)); + gtk_widget_show (GTK_WIDGET (priv->send_all)); + } else if (g_strcmp0 (name, "nsna_ping") == 0) { + gtk_widget_show (GTK_WIDGET (priv->send_interval)); + gtk_widget_show (GTK_WIDGET (priv->send_interval_label)); + gtk_widget_show (GTK_WIDGET (priv->send_interval_ms)); + gtk_widget_show (GTK_WIDGET (priv->init_wait)); + gtk_widget_show (GTK_WIDGET (priv->init_wait_label)); + gtk_widget_show (GTK_WIDGET (priv->init_wait_ms)); + gtk_widget_show (GTK_WIDGET (priv->missed_max)); + gtk_widget_show (GTK_WIDGET (priv->missed_max_label)); + gtk_widget_show (GTK_WIDGET (priv->target_host)); + gtk_widget_show (GTK_WIDGET (priv->target_host_label)); + } else { + g_return_if_reached (); + } + g_free (name); +} + +#if WITH_JANSSON + +static gboolean +json_to_dialog (CEPageTeamPort *self) +{ + CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self); + char *json_config; + json_t *json; + json_error_t json_error; + int ret; + gboolean success = TRUE; + GtkTextIter start, end; + GtkTextBuffer *buffer; + GError *error = NULL; + /* General */ + int queue_id = -1; + int port_prio = -1; + int port_sticky = FALSE; + int lacp_port_prio = -1; + int lacp_port_key = -1; + /* Link Watch */ + const char *link_watch_name = ""; + int link_watch_delay_up = -1; + int link_watch_delay_down = -1; + int link_watch_interval = -1; + int link_watch_init_wait = -1; + int link_watch_missed_max = -1; + const char *link_watch_source_host = ""; + const char *link_watch_target_host = ""; + int link_watch_validate_active = FALSE; + int link_watch_validate_inactive = FALSE; + int link_watch_send_always = FALSE; + + buffer = gtk_text_view_get_buffer (priv->json_config_widget); + gtk_text_buffer_get_iter_at_offset (buffer, &start, 0); + gtk_text_buffer_get_iter_at_offset (buffer, &end, -1); + json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); + + if (strcmp (json_config, "") == 0) { + /* Initial empty configuration */ + json = json_object (); + } else { + json = json_loads (json_config, 0, &json_error); + } + + if (!json) { + g_message ("Failed to parse JSON: %s on line %d", json_error.text, json_error.line); + success = FALSE; + } + + /* For simplicity, we proceed with json==NULL. The attempt to + * unpack will produce an error which we'll ignore. */ + g_free (json_config); + ret = json_unpack_ex (json, &json_error, 0, + "{" + " s?:i," + " s?:i," + " s?:b," + " s?:i," + " s?:i," + " s?:{s?:s, s?:i, s?:i, s?:i, s?:i, s?:i, s?:s, s?:s, s?:b, s?:b, s?:b !}" + "!}", + "queue_id", &queue_id, + "prio", &port_prio, + "sticky", &port_sticky, + "lacp_prio", &lacp_port_prio, + "lacp_key", &lacp_port_key, + "link_watch", + "name", &link_watch_name, + "delay_up", &link_watch_delay_up, + "delay_down", &link_watch_delay_down, + "interval", &link_watch_interval, + "init_wait", &link_watch_init_wait, + "missed_max", &link_watch_missed_max, + "source_host", &link_watch_source_host, + "target_host", &link_watch_target_host, + "validate_active", &link_watch_validate_active, + "validate_inactive", &link_watch_validate_inactive, + "send_always", &link_watch_send_always); + + if (success == TRUE && ret == -1) { + g_message ("Failed to parse JSON: %s on line %d", json_error.text, json_error.line); + success = FALSE; + } + + /* We proceed setting the form fields even in case we couldn't unpack. + * That way we'll get at least sensible default values. Editing will + * be disabled anyway. */ + gtk_spin_button_set_value (priv->queue_id, queue_id); + gtk_spin_button_set_value (priv->port_prio, port_prio); + gtk_toggle_button_set_active (priv->port_sticky, port_sticky); + gtk_spin_button_set_value (priv->lacp_port_prio, lacp_port_prio); + gtk_spin_button_set_value (priv->lacp_port_key, lacp_port_key); + if (!set_combo_box (priv->link_watcher_name, link_watch_name, &error)) { + g_message ("Cannot read link watcher name: %s", error->message); + g_clear_error (&error); + success = FALSE; + } + gtk_spin_button_set_value (priv->delay_up, link_watch_delay_up); + gtk_spin_button_set_value (priv->delay_down, link_watch_delay_down); + gtk_spin_button_set_value (priv->send_interval, link_watch_interval); + gtk_spin_button_set_value (priv->init_wait, link_watch_init_wait); + gtk_spin_button_set_value (priv->missed_max, link_watch_missed_max); + gtk_entry_set_text (priv->source_host, link_watch_source_host); + gtk_entry_set_text (priv->target_host, link_watch_target_host); + gtk_toggle_button_set_active (priv->validate_active, link_watch_validate_active); + gtk_toggle_button_set_active (priv->validate_inactive, link_watch_validate_inactive); + gtk_toggle_button_set_active (priv->send_all, link_watch_send_always); + + if (success) { + /* Enable editing. */ + gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0), 1); + gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 1), 1); + } + + json_decref (json); + return success; +} + +static void +maybe_set_str (json_t *json, const char *key, const char *str) +{ + if (str && *str) + json_object_set_new(json, key, json_string (str)); +} + +static void +maybe_set_int (json_t *json, const char *key, int num) +{ + if (num != -1) + json_object_set_new(json, key, json_integer (num)); +} + +static void +maybe_set_json (json_t *json, const char *key, json_t *val) +{ + if ( (json_is_object (val) && json_object_size (val)) + || (json_is_array (val) && json_array_size (val))) { + json_object_set_new (json, key, val); + } else { + json_decref (val); + } +} + +static void +maybe_set_true (json_t *json, const char *key, int set) +{ + if (set) + json_object_set_new(json, key, json_true ()); + else + json_object_set_new(json, key, json_false ()); +} + +static void +dialog_to_json (CEPageTeamPort *self) +{ + CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self); + json_t *json; + json_t *obj; + gchar *tmp; + char *json_config; + GtkTextBuffer *buffer; + + /* If the JSON is being edited, don't overwrite it. */ + if (!gtk_widget_get_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0))) + return; + + /* Disable editing via form, until converted back from JSON. */ + gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0), 0); + gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 1), 0); + + json = json_object (); + maybe_set_int (json, "queue_id", gtk_spin_button_get_value_as_int (priv->queue_id)); + maybe_set_int (json, "prio", gtk_spin_button_get_value_as_int (priv->port_prio)); + if (gtk_toggle_button_get_active (priv->port_sticky)) + json_object_set_new(json, "sticky", json_true ()); + maybe_set_int (json, "lacp_prio", gtk_spin_button_get_value_as_int (priv->lacp_port_prio)); + maybe_set_int (json, "lacp_key", gtk_spin_button_get_value_as_int (priv->lacp_port_key)); + + obj = json_object (); + tmp = get_combo_box (priv->link_watcher_name); + if (g_strcmp0 (tmp, "master") != 0) { + maybe_set_str (obj, "name", tmp); + if (g_strcmp0 (tmp, "ethtool") == 0) { + maybe_set_int (obj, "delay_up", gtk_spin_button_get_value (priv->delay_up)); + maybe_set_int (obj, "delay_down", gtk_spin_button_get_value (priv->delay_down)); + } else if (g_strcmp0 (tmp, "arp_ping") == 0) { + maybe_set_int (obj, "interval", gtk_spin_button_get_value (priv->send_interval)); + maybe_set_int (obj, "init_wait", gtk_spin_button_get_value (priv->init_wait)); + maybe_set_int (obj, "missed_max", gtk_spin_button_get_value (priv->missed_max)); + maybe_set_str (obj, "source_host", gtk_entry_get_text (priv->source_host)); + maybe_set_str (obj, "target_host", gtk_entry_get_text (priv->target_host)); + maybe_set_true (obj, "validate_active", gtk_toggle_button_get_active (priv->validate_active)); + maybe_set_true (obj, "validate_inactive", gtk_toggle_button_get_active (priv->validate_inactive)); + maybe_set_true (obj, "send_always", gtk_toggle_button_get_active (priv->send_all)); + } else if (g_strcmp0 (tmp, "nsna_ping") == 0) { + maybe_set_int (obj, "interval", gtk_spin_button_get_value (priv->send_interval)); + maybe_set_int (obj, "init_wait", gtk_spin_button_get_value (priv->init_wait)); + maybe_set_int (obj, "missed_max", gtk_spin_button_get_value (priv->missed_max)); + maybe_set_str (obj, "target_host", gtk_entry_get_text (priv->target_host)); + } else { + g_return_if_reached (); + } + } + maybe_set_json (json, "link_watch", obj); + g_free (tmp); + + json_config = json_dumps (json, JSON_INDENT (4)); + json_decref (json); + + buffer = gtk_text_view_get_buffer (priv->json_config_widget); + gtk_text_buffer_set_text (buffer, json_config, -1); + free (json_config); +} + +#else /* WITH_JANSSON */ + +static gboolean +json_to_dialog (CEPageTeamPort *self) +{ + return FALSE; +} + +static void +dialog_to_json (CEPageTeamPort *self) +{ +} + +#endif /* WITH_JANSSON */ + +static void +advanced_button_clicked_cb (GtkWidget *button, gpointer user_data) +{ + CEPageTeamPort *self = CE_PAGE_TEAM_PORT (user_data); + CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self); + NMSettingTeamPort *s_port = priv->setting; + GtkWidget *toplevel; + GtkTextBuffer *buffer; + GtkTextIter start, end; + char *json_config = NULL; + + toplevel = gtk_widget_get_toplevel (CE_PAGE (self)->page); + g_return_if_fail (toplevel); + gtk_window_set_transient_for (GTK_WINDOW (priv->advanced_dialog), GTK_WINDOW (toplevel)); + g_return_if_fail (gtk_widget_is_toplevel (toplevel)); + + /* Load in the JSON from settings to dialog. */ + buffer = gtk_text_view_get_buffer (priv->json_config_widget); + gtk_text_buffer_set_text (buffer, nm_setting_team_port_get_config (s_port) ?: "", -1); + + /* Fill in the form fields. */ + if (json_to_dialog (self)) { + gtk_notebook_set_current_page (priv->advanced_notebook, 0); + } else { + /* First disable the pages, so that potentially + * inconsistent changes are not propageated to JSON. */ + gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0), 0); + gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 1), 0); + gtk_notebook_set_current_page (priv->advanced_notebook, 2); + } + + link_watcher_changed (priv->link_watcher_name, self); + + if (gtk_dialog_run (priv->advanced_dialog) == GTK_RESPONSE_OK) { + dialog_to_json (self); + + /* Set the JSON from the dialog to setting. */ + gtk_text_buffer_get_iter_at_offset (buffer, &start, 0); + gtk_text_buffer_get_iter_at_offset (buffer, &end, -1); + json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); + + g_object_set (priv->setting, + NM_SETTING_TEAM_CONFIG, + g_strcmp0 (json_config, "") == 0 ? NULL : json_config, + NULL); + g_free (json_config); + ce_page_changed (CE_PAGE (self)); + } + gtk_widget_hide (GTK_WIDGET (priv->advanced_dialog)); +} + +static gboolean +switch_page (GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + gpointer user_data) +{ + CEPageTeamPort *self = CE_PAGE_TEAM_PORT (user_data); + + /* Keep the JSON and the form in sync if possible. */ + if (gtk_notebook_get_current_page (notebook) == 2) + json_to_dialog (self); + else if (page_num == 2) + dialog_to_json (self); + + return TRUE; +} + +static void populate_ui (CEPageTeamPort *self) { CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self); @@ -114,8 +616,10 @@ populate_ui (CEPageTeamPort *self) json_config = nm_setting_team_port_get_config (s_port); gtk_text_buffer_set_text (buffer, json_config ? json_config : "", -1); - g_signal_connect (buffer, "changed", G_CALLBACK (json_config_changed), self); g_signal_connect (priv->import_config_button, "clicked", G_CALLBACK (import_button_clicked_cb), self); + g_signal_connect (priv->link_watcher_name, "changed", G_CALLBACK (link_watcher_changed), self); + g_signal_connect (priv->advanced_button, "clicked", G_CALLBACK (advanced_button_clicked_cb), self); + g_signal_connect (priv->advanced_notebook, "switch-page", G_CALLBACK (switch_page), self); } static void |