summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2016-07-04 14:15:44 +0200
committerLubomir Rintel <lkundrak@v3.sk>2016-07-25 14:02:08 +0200
commit13eea21c6f1291f43c26f0b4f5170f9629cb4219 (patch)
treea1c2cd8f72d165ec26c5a47725ed04ccba6ee46c
parent65c662d08b34d486d4d567424ccf623cda72389e (diff)
downloadnetwork-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.ui889
-rw-r--r--src/connection-editor/page-team-port.c530
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