Daniel Brötzmann pushed to branch mainwindow at gajim / gajim
Commits: 6b18f004 by wurstsalat at 2021-09-11T02:13:55+02:00 AddContact: Use assistant
- - - - -
3 changed files:
- + gajim/data/gui/add_contact.ui - − gajim/data/gui/add_new_contact_window.ui - gajim/gtk/add_contact.py
Changes:
===================================== gajim/data/gui/add_contact.ui ===================================== @@ -0,0 +1,349 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface> + <requires lib="gtk+" version="3.24"/> + <object class="GtkListStore" id="account_liststore"> + <columns> + <!-- column-name id --> + <column type="gchararray"/> + <!-- column-name label --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkBox" id="address_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">center</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-bottom">12</property> + <property name="label" translatable="yes">Add Contact</property> + <style> + <class name="large-header"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="account_box"> + <property name="can-focus">False</property> + <property name="no-show-all">True</property> + <property name="halign">center</property> + <property name="margin-bottom">12</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">Please choose an account</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="account_combo"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="model">account_liststore</property> + <property name="id-column">0</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext3"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">Please enter an XMPP address</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="address_entry"> + <property name="width-request">250</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="activates-default">True</property> + <property name="placeholder-text" translatable="yes">XMPP Address…</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <!-- n-columns=2 n-rows=5 --> + <object class="GtkGrid" id="contact_grid"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">center</property> + <property name="row-spacing">6</property> + <property name="column-spacing">12</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-bottom">12</property> + <property name="label" translatable="yes">Add Contact</property> + <style> + <class name="large-header"/> + </style> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">end</property> + <property name="label" translatable="yes">Publish Status</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">4</property> + </packing> + </child> + <child> + <object class="GtkSwitch" id="status_switch"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="halign">start</property> + <property name="active">True</property> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">4</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">end</property> + <property name="label" translatable="yes">Group</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">3</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="group_combo"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="has-entry">True</property> + <child internal-child="entry"> + <object class="GtkEntry"> + <property name="can-focus">True</property> + <property name="placeholder-text" translatable="yes">Choose a group…</property> + </object> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">end</property> + <property name="label" translatable="yes">Message</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="message_entry"> + <property name="width-request">275</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="placeholder-text" translatable="yes">Say hi to your new contact…</property> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="contact_info_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text" translatable="yes">Show Contact Infos</property> + <property name="halign">center</property> + <property name="margin-bottom">6</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">user-info-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">1</property> + <property name="width">2</property> + </packing> + </child> + </object> + <object class="GtkBox" id="gateway_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">center</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-bottom">12</property> + <property name="label" translatable="yes">Service Gateway</property> + <style> + <class name="large-header"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">center</property> + <property name="margin-bottom">6</property> + <property name="spacing">12</property> + <child> + <object class="GtkImage" id="gateway_image"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon_size">6</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="gateway_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="wrap">True</property> + <style> + <class name="bold16"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">center</property> + <property name="spacing">12</property> + <child> + <object class="GtkButton" id="register_button"> + <property name="label" translatable="yes">Register</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="command_button"> + <property name="label" translatable="yes">Command</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> +</interface>
===================================== gajim/data/gui/add_new_contact_window.ui deleted ===================================== @@ -1,492 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.36.0 --> -<interface> - <requires lib="gtk+" version="3.22"/> - <object class="GtkListStore" id="account_liststore"> - <columns> - <!-- column-name id --> - <column type="gchararray"/> - <!-- column-name label --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkListStore" id="groups_liststore"> - <columns> - <!-- column-name item --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkTextBuffer" id="message_textbuffer"> - <property name="text" translatable="yes">I would like to add you to my contact list.</property> - <signal name="end-user-action" handler="on_message_textbuffer_changed" swapped="no"/> - </object> - <object class="GtkListStore" id="protocol"> - <columns> - <!-- column-name label --> - <column type="gchararray"/> - <!-- column-name icon --> - <column type="gchararray"/> - <!-- column-name agent --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkListStore" id="protocol_jid"> - <columns> - <!-- column-name item --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkBox" id="add_contact_box"> - <property name="width_request">400</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="border_width">18</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkLabel" id="prompt_label"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="halign">center</property> - <property name="margin_top">18</property> - <property name="use_markup">True</property> - <property name="justify">center</property> - <property name="wrap">True</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkGrid"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - <child> - <object class="GtkLabel" id="uid_label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">_XMPP Address</property> - <property name="use_underline">True</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="nickname_label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">_Nickname</property> - <property name="use_underline">True</property> - <property name="xalign">0.5</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">3</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="group_label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">_Group</property> - <property name="use_underline">True</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">4</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="uid_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <property name="activates_default">True</property> - <property name="placeholder_text">user@example.org</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="nickname_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <property name="activates_default">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">3</property> - <property name="width">2</property> - </packing> - </child> - <child> - <object class="GtkComboBoxText" id="group_comboboxentry"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="hexpand">True</property> - <property name="has_entry">True</property> - <child internal-child="entry"> - <object class="GtkEntry" id="comboboxtext-entry"> - <property name="can_focus">True</property> - <property name="activates_default">True</property> - <property name="placeholder_text" translatable="yes">Choose or type new group name</property> - </object> - </child> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">4</property> - <property name="width">2</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="account_label"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="halign">end</property> - <property name="margin_bottom">12</property> - <property name="label" translatable="yes">A_ccount</property> - <property name="use_underline">True</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="protocol_label"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="halign">end</property> - <property name="label" translatable="yes">_Protocol</property> - <property name="use_underline">True</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">12</property> - <child> - <object class="GtkComboBox" id="protocol_combobox"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="model">protocol</property> - <signal name="changed" handler="on_protocol_combobox_changed" swapped="no"/> - <child> - <object class="GtkCellRendererPixbuf"/> - <attributes> - <attribute name="icon-name">1</attribute> - </attributes> - </child> - <child> - <object class="GtkCellRendererText"> - <property name="xpad">5</property> - </object> - <attributes> - <attribute name="text">0</attribute> - </attributes> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkComboBox" id="protocol_jid_combobox"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="model">protocol_jid</property> - <signal name="changed" handler="on_protocol_jid_combobox_changed" swapped="no"/> - <child> - <object class="GtkCellRendererText" id="cellrenderertext2"/> - <attributes> - <attribute name="text">0</attribute> - </attributes> - </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">1</property> - <property name="top_attach">1</property> - <property name="width">2</property> - </packing> - </child> - <child> - <object class="GtkComboBox" id="account_combobox"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="margin_bottom">12</property> - <property name="model">account_liststore</property> - <property name="entry_text_column">1</property> - <property name="id_column">0</property> - <signal name="changed" handler="on_account_combobox_changed" swapped="no"/> - <child> - <object class="GtkCellRendererText" id="cellrenderertext3"/> - <attributes> - <attribute name="text">1</attribute> - </attributes> - </child> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - <property name="width">2</property> - </packing> - </child> - <child> - <object class="GtkButton" id="show_contact_info_button"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="tooltip_text" translatable="yes">Query Contact Info</property> - <signal name="clicked" handler="on_show_contact_info_button_clicked" swapped="no"/> - <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">user-info-symbolic</property> - </object> - </child> - </object> - <packing> - <property name="left_attach">2</property> - <property name="top_attach">2</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="padding">18</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="auto_authorize_checkbutton"> - <property name="label" translatable="yes">A_llow contact to view my status</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="no_show_all">True</property> - <property name="halign">start</property> - <property name="use_underline">True</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">4</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="message_scrolledwindow"> - <property name="height_request">60</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="no_show_all">True</property> - <property name="margin_top">18</property> - <property name="shadow_type">etched-in</property> - <property name="min_content_height">5</property> - <child> - <object class="GtkTextView" id="message_textview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="wrap_mode">word</property> - <property name="left_margin">6</property> - <property name="right_margin">6</property> - <property name="top_margin">6</property> - <property name="bottom_margin">6</property> - <property name="buffer">message_textbuffer</property> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> - <child> - <object class="GtkRevealer" id="save_message_revealer"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="transition_type">crossfade</property> - <child> - <object class="GtkCheckButton" id="save_message_checkbutton"> - <property name="label" translatable="yes">_Save subscription message</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="halign">start</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">5</property> - </packing> - </child> - <child> - <object class="GtkBox" id="register_hbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="spacing">6</property> - <child> - <object class="GtkLabel" id="label224"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">You have to register with this transport -to be able to add a contact from this -protocol. Click on Register button to -proceed.</property> - <property name="wrap">True</property> - <property name="xalign">0</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="register_button"> - <property name="label" translatable="yes">_Register</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="halign">center</property> - <property name="valign">center</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_register_button_clicked" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="padding">18</property> - <property name="position">7</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="connected_label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">You must be connected to the transport to be able -to add a contact from this protocol.</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">8</property> - </packing> - </child> - <child> - <object class="GtkButtonBox" id="hbuttonbox1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="margin_top">18</property> - <property name="spacing">12</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="cancel_button"> - <property name="label" translatable="yes">_Cancel</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_cancel_button_clicked" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="add_button"> - <property name="label" translatable="yes">_Add</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_add_button_clicked" swapped="no"/> - <style> - <class name="suggested-action"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">9</property> - </packing> - </child> - </object> -</interface>
===================================== gajim/gtk/add_contact.py ===================================== @@ -12,490 +12,418 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
-from gi.repository import Gdk +import logging + from gi.repository import Gtk
+from nbxmpp.errors import is_error + from gajim.common import app -from gajim.common import ged -from gajim.common import helpers +from gajim.common.helpers import get_subscription_request_msg +from gajim.common.helpers import validate_jid from gajim.common.i18n import _ +from gajim.common.modules.util import as_task
+from .adhoc import AdHocCommand +from .assistant import Assistant +from .assistant import Page +from .assistant import ErrorPage +from .groupchat_info import GroupChatInfoScrolled from .service_registration import ServiceRegistration -from .dialogs import ErrorDialog from .util import get_builder -from .util import EventHelper from .util import open_window
+log = logging.getLogger('gajim.gui.add_contact')
-class AddContact(Gtk.ApplicationWindow, EventHelper):
- uid_labels = {'jabber': _('XMPP Address'), - 'gadu-gadu': _('GG Number'), - 'icq': _('ICQ Number')} +class AddContact(Assistant): + def __init__(self, account=None, jid=None, nick=None): + Assistant.__init__(self) + self.account = account + self._jid = jid + self._nick = nick
- def __init__(self, account=None, jid=None, nick=None, group=None): - Gtk.ApplicationWindow.__init__(self) - EventHelper.__init__(self) - self.set_application(app.app) - self.set_type_hint(Gdk.WindowTypeHint.DIALOG) - self.set_position(Gtk.WindowPosition.CENTER) - self.set_show_menubar(False) - self.set_resizable(False) - self.set_title(_('Add Contact')) + self._result = None
- self.connect_after('key-press-event', self._on_key_press) + self.add_button('next', _('Next'), complete=True, + css_class='suggested-action') + self.add_button('back', _('Back')) + self.add_button('add', _('Add Contact'), + css_class='suggested-action') + self.add_button('join', _('Join…'), + css_class='suggested-action')
- self.account = account - self._group = group - self.adding_jid = False + self.add_pages({ + 'address': Address(account, jid), + 'error': Error(), + 'contact': Contact(), + 'groupchat': GroupChat(), + 'gateway': Gateway(), + })
- if jid is not None: - jid = app.get_jid_without_resource(str(jid)) + progress = self.add_default_page('progress') + progress.set_title(_('Gathering information…')) + progress.set_text(_('Trying to gather information on this address…'))
- # fill accounts with active accounts - accounts = app.get_enabled_accounts_with_labels() + self.connect('button-clicked', self._on_button_clicked)
- if not accounts: + self.show_all() + + def _on_button_clicked(self, _assistant, button_name): + page = self.get_current_page() + + if button_name == 'next': + self._start_disco() return
- if not account: - self.account = accounts[0][0] - - self._ui = get_builder('add_new_contact_window.ui') - self.add(self._ui.add_contact_box) - self._ui.connect_signals(self) - - self.subscription_table = [ - self._ui.uid_label, self._ui.uid_entry, - self._ui.show_contact_info_button, - self._ui.nickname_label, self._ui.nickname_entry, - self._ui.group_label, self._ui.group_comboboxentry - ] - - self._ui.add_button.grab_default() - - self.agents = {'jabber': []} - self.gateway_prompt = {} - # types to which we are not subscribed but account has an agent for it - self.available_types = [] - for acct in accounts: - for j in app.contacts.get_jid_list(acct[0]): - if app.jid_is_transport(j): - type_ = app.get_transport_name_from_jid(j, False) - if not type_: - continue - if type_ in self.agents: - self.agents[type_].append(j) - else: - self.agents[type_] = [j] - self.gateway_prompt[j] = {'desc': None, 'prompt': None} - # Now add the one to which we can register - for acct in accounts: - for type_ in app.connections[acct[0]].available_transports: - if type_ in self.agents: - continue - self.agents[type_] = [] - for jid_ in app.connections[acct[0]].available_transports[type_]: - if jid_ not in self.agents[type_]: - self.agents[type_].append(jid_) - self.gateway_prompt[jid_] = {'desc': None, - 'prompt': None} - self.available_types.append(type_) - - uf_type = {'jabber': 'XMPP', 'gadu-gadu': 'Gadu Gadu', 'icq': 'ICQ'} - # Jabber as first - liststore = self._ui.protocol_combobox.get_model() - liststore.append(['XMPP', 'xmpp', 'jabber']) - for type_ in self.agents: - if type_ == 'jabber': - continue - if type_ in uf_type: - liststore.append([uf_type[type_], type_ + '-online', type_]) - else: - liststore.append([type_, type_ + '-online', type_]) - - if account: - for service in self.agents[type_]: - con = app.connections[account] - con.get_module('Gateway').request_gateway_prompt(service) - self._ui.protocol_combobox.set_active(0) - self._ui.auto_authorize_checkbutton.show() - - if jid: - self.jid_escaped = True - type_ = app.get_transport_name_from_jid(jid) - if not type_: - type_ = 'jabber' - if type_ == 'jabber': - self._ui.uid_entry.set_text(jid) - transport = None + if button_name == 'back': + self.show_page('address', + Gtk.StackTransitionType.SLIDE_RIGHT) + self.get_page('address').focus() + return + + if button_name == 'add': + client = app.get_client(self.account) + if page == 'contact': + data = self.get_page('contact').get_subscription_data() + client.get_module('Presence').subscribe( + self._result.jid, + msg=data['message'], + groups=data['groups'], + auto_auth=data['auto_auth']) else: - uid, transport = app.get_name_and_server_from_jid(jid) - self._ui.uid_entry.set_text(uid.replace('%', '@', 1)) - - self._ui.show_contact_info_button.set_sensitive(True) - - # set protocol_combobox - model = self._ui.protocol_combobox.get_model() - iter_ = model.get_iter_first() - i = 0 - while iter_: - if model[iter_][2] == type_: - self._ui.protocol_combobox.set_active(i) - break - iter_ = model.iter_next(iter_) - i += 1 - - # set protocol_jid_combobox - self._ui.protocol_jid_combobox.set_active(0) - model = self._ui.protocol_jid_combobox.get_model() - iter_ = model.get_iter_first() - i = 0 - while iter_: - if model[iter_][0] == transport: - self._ui.protocol_jid_combobox.set_active(i) - break - iter_ = model.iter_next(iter_) - i += 1 - if nick: - self._ui.nickname_entry.set_text(nick) - self._ui.nickname_entry.grab_focus() + client.get_module('Presence').subscribe( + self._result.jid, + name=self._result.gateway_name, + auto_auth=True) + app.window.show_account_page(self.account) + self.destroy() + return + + if button_name == 'join': + _, jid = self.get_page('address').get_account_and_jid() + open_window('GroupchatJoin', account=self.account, jid=jid) + self.destroy() + + def _start_disco(self): + self._result = None + self.show_page('progress', Gtk.StackTransitionType.SLIDE_LEFT) + + account, jid = self.get_page('address').get_account_and_jid() + self._disco_info(account, jid) + + @as_task + def _disco_info(self, account, address): + _task = yield + + client = app.get_client(account) + + result = yield client.get_module('Discovery').disco_info(address) + if is_error(result): + self._process_error(account, result) + raise result + + log.info('Disco Info received: %s', address) + self._process_info(account, result) + + def _process_error(self, account, result): + log.debug('Error received: %s', result) + self._result = result + + if result.condition == 'service-unavailable': + # It seems to be a contact + self.get_page('contact').prepare(account, result) + self.show_page('contact', Gtk.StackTransitionType.SLIDE_LEFT) else: - self.jid_escaped = False - self._ui.uid_entry.grab_focus() + self.get_page('error').set_text(result.get_text()) + self.show_page('error', Gtk.StackTransitionType.SLIDE_LEFT) + + def _process_info(self, account, result): + log.debug('Info received: %s', result) + self._result = result + + if result.is_muc: + for identity in result.identities: + if identity.type == 'irc' and result.jid.is_domain: + self.get_page('gateway').prepare(account, result) + self.show_page( + 'gateway', Gtk.StackTransitionType.SLIDE_LEFT) + return + + self.get_page('groupchat').prepare(account, result) + self.show_page('groupchat', Gtk.StackTransitionType.SLIDE_LEFT) + return + + if result.is_gateway: + self.get_page('gateway').prepare(account, result) + self.show_page('gateway', Gtk.StackTransitionType.SLIDE_LEFT) + return + + if result.has_category('client'): + self.get_page('contact').prepare(account, result) + self.show_page('contact', Gtk.StackTransitionType.SLIDE_LEFT) + + +class Address(Page): + def __init__(self, account, jid): + Page.__init__(self) + self.title = _('Add Contact') + + self._account = account + self._jid = jid
- self._update_groups() + self._client = None
+ self._ui = get_builder('add_contact.ui') + self.add(self._ui.address_box) + + self._ui.account_combo.connect('changed', self._on_account_changed) + self._ui.address_entry.connect('changed', self._set_complete) + + accounts = app.get_enabled_accounts_with_labels() if len(accounts) > 1: - liststore = self._ui.account_combobox.get_model() + liststore = self._ui.account_combo.get_model() for acc in accounts: liststore.append(acc) + self._ui.account_box.show()
- self._ui.account_combobox.set_active_id(self.account) - self._ui.account_label.show() - self._ui.account_combobox.show() + if self._account is not None: + self._client = app.get_client(self._account) + self._ui.account_combo.set_active_id(self._account)
- if len(self.agents) > 1: - self._ui.protocol_label.show() - self._ui.protocol_combobox.show() + if self._jid is not None: + self._ui.address_entry.set_text(self._jid)
- if self.account: - message_buffer = self._ui.message_textview.get_buffer() - msg = helpers.from_one_line(helpers.get_subscription_request_msg( - self.account)) - message_buffer.set_text(msg) + self._set_complete()
- self._ui.uid_entry.connect('changed', self.on_uid_entry_changed) self.show_all()
- self.register_events([ - ('gateway-prompt-received', ged.GUI1, self._nec_gateway_prompt_received), - ('presence-received', ged.GUI1, self._nec_presence_received), - ]) - - def _update_groups(self): - self._ui.group_comboboxentry.get_model().clear() - index = 0 - client = app.get_client(self.account) - for item in client.get_module('Roster').get_groups(): - self._ui.group_comboboxentry.append_text(item) - if item == self._group: - self._ui.group_comboboxentry.set_active(index) - index += 1 - - def on_uid_entry_changed(self, widget): - is_empty = bool(not self._ui.uid_entry.get_text() == '') - self._ui.show_contact_info_button.set_sensitive(is_empty) - - def on_show_contact_info_button_clicked(self, _widget): - """ - Ask for vCard - """ - jid = self._ui.uid_entry.get_text().strip() - client = app.get_client(self.account) - contact = client.get_module('Contacts').get_contact(jid) - open_window('ContactInfo', account=self.account, contact=contact) - - def on_register_button_clicked(self, widget): - model = self._ui.protocol_jid_combobox.get_model() - row = self._ui.protocol_jid_combobox.get_active() - jid = model[row][0] - ServiceRegistration(self.account, jid) - - def _on_key_press(self, widget, event): - if event.keyval == Gdk.KEY_Escape: - self.destroy() + def get_visible_buttons(self): + return ['next']
- def on_cancel_button_clicked(self, widget): - """ - When Cancel button is clicked - """ - self.destroy() - - def on_message_textbuffer_changed(self, widget): - self._ui.save_message_revealer.show() - self._ui.save_message_revealer.set_reveal_child(True) - - def on_add_button_clicked(self, widget): - """ - When Subscribe button is clicked - """ - jid = self._ui.uid_entry.get_text().strip() - if not jid: - ErrorDialog( - _('%s Missing') % self._ui.uid_label.get_text(), - (_('You must supply the %s of the new contact.') % - self._ui.uid_label.get_text()) - ) - return + def get_default_button(self): + return 'next'
- model = self._ui.protocol_combobox.get_model() - row = self._ui.protocol_combobox.get_active_iter() - type_ = model[row][2] - if type_ != 'jabber': - model = self._ui.protocol_jid_combobox.get_model() - row = self._ui.protocol_jid_combobox.get_active() - transport = model[row][0] - if self.account and not self.jid_escaped: - self.adding_jid = (jid, transport, type_) - con = app.connections[self.account] - con.get_module('Gateway').request_gateway_prompt(transport, jid) - else: - jid = jid.replace('@', '%') + '@' + transport - self._add_jid(jid, type_) - else: - self._add_jid(jid, type_) + def get_account_and_jid(self): + return self._account, self._ui.address_entry.get_text()
- def _add_jid(self, jid, type_): - # check if jid is conform to RFC and stringprep it - try: - jid = helpers.parse_jid(jid) - except helpers.InvalidFormat as s: - pritext = _('Invalid User ID') - ErrorDialog(pritext, str(s)) - return + def focus(self): + self._ui.address_entry.grab_focus()
- # No resource in jid - if jid.find('/') >= 0: - pritext = _('Invalid User ID') - ErrorDialog(pritext, _('The user ID must not contain a resource.')) - return + def _on_account_changed(self, combobox): + account = combobox.get_active_id() + self._account = account + self._set_complete() + + def _show_icon(self, show): + icon = 'dialog-warning-symbolic' if show else None + self._ui.address_entry.set_icon_from_icon_name( + Gtk.EntryIconPosition.SECONDARY, icon)
- if jid == app.get_jid_from_account(self.account): - pritext = _('Invalid User ID') - ErrorDialog(pritext, _('You cannot add yourself to your contact list.')) + def _set_complete(self, *args): + if self._account is None: + self.complete = False + self.update_page_complete() return
- if not app.account_is_available(self.account): - ErrorDialog( - _('Account Offline'), - _('Your account must be online to add new contacts.') - ) + address = self._ui.address_entry.get_text() + is_self = bool(address == app.get_jid_from_account(self._account)) + if is_self: + self._show_icon(True) + self._ui.address_entry.set_icon_tooltip_text( + Gtk.EntryIconPosition.SECONDARY, + _('You cannot add yourself to your contact list.')) + self.complete = False + self.update_page_complete() return
- nickname = self._ui.nickname_entry.get_text() or '' - # get value of account combobox, if account was not specified - if not self.account: - model = self._ui.account_combobox.get_model() - index = self._ui.account_combobox.get_active() - self.account = model[index][1] - - # Check if jid is already in roster - if jid in app.contacts.get_jid_list(self.account): - c = app.contacts.get_first_contact_from_jid(self.account, jid) - if _('Not in contact list') not in c.groups and c.sub in ('both', 'to'): - ErrorDialog( - _('Contact Already in Contact List'), - _('This contact is already in your contact list.')) + client = app.get_client(self._account) + for contact in client.get_module('Roster').iter_contacts(): + if address == str(contact.jid): + self._show_icon(True) + self._ui.address_entry.set_icon_tooltip_text( + Gtk.EntryIconPosition.SECONDARY, + _('%s is already in your contact list') % address) + self.complete = False + self.update_page_complete() return
- if type_ == 'jabber': - message_buffer = self._ui.message_textview.get_buffer() - start_iter = message_buffer.get_start_iter() - end_iter = message_buffer.get_end_iter() - message = message_buffer.get_text(start_iter, end_iter, True) - if self._ui.save_message_checkbutton.get_active(): - msg = helpers.to_one_line(message) - app.settings.set_account_setting(self.account, - 'subscription_request_msg', - msg) - else: - message = '' - group = self._ui.group_comboboxentry.get_child().get_text() - groups = [] - if group: - groups = [group] - auto_auth = self._ui.auto_authorize_checkbutton.get_active() - - client = app.get_client(self.account) - client.get_module('Presence').subscribe(jid, - message, - nickname, - groups=groups, - auto_auth=auto_auth) - - self.destroy() - - def on_account_combobox_changed(self, widget): - account = widget.get_active_id() - message_buffer = self._ui.message_textview.get_buffer() - message_buffer.set_text(helpers.get_subscription_request_msg(account)) - self.account = account - self._update_groups() + self.complete = self._validate_address(address) + self.update_page_complete()
- def on_protocol_jid_combobox_changed(self, widget): - model = widget.get_model() - iter_ = widget.get_active_iter() - if not iter_: - return - jid_ = model[iter_][0] - model = self._ui.protocol_combobox.get_model() - iter_ = self._ui.protocol_combobox.get_active_iter() - type_ = model[iter_][2] - - desc = None - if self.agents[type_] and jid_ in self.gateway_prompt: - desc = self.gateway_prompt[jid_]['desc'] - - if desc: - self._ui.prompt_label.set_markup(desc) - self._ui.prompt_label.show() - else: - self._ui.prompt_label.hide() - - prompt = None - if self.agents[type_] and jid_ in self.gateway_prompt: - prompt = self.gateway_prompt[jid_]['prompt'] - if not prompt: - if type_ in self.uid_labels: - prompt = self.uid_labels[type_] - else: - prompt = _('User ID:') - self._ui.uid_label.set_text(prompt) - - def on_protocol_combobox_changed(self, widget): - model = widget.get_model() - iter_ = widget.get_active_iter() - type_ = model[iter_][2] - model = self._ui.protocol_jid_combobox.get_model() - model.clear() - if self.agents[type_]: - for jid_ in self.agents[type_]: - model.append([jid_]) - self._ui.protocol_jid_combobox.set_active(0) - desc = None - if self.agents[type_]: - jid_ = self.agents[type_][0] - if jid_ in self.gateway_prompt: - desc = self.gateway_prompt[jid_]['desc'] - - if desc: - self._ui.prompt_label.set_markup(desc) - self._ui.prompt_label.show() - else: - self._ui.prompt_label.hide() + def _validate_address(self, address): + if not address: + self._show_icon(False) + return False
- if len(self.agents[type_]) > 1: - self._ui.protocol_jid_combobox.show() - else: - self._ui.protocol_jid_combobox.hide() - prompt = None - if self.agents[type_]: - jid_ = self.agents[type_][0] - if jid_ in self.gateway_prompt: - prompt = self.gateway_prompt[jid_]['prompt'] - if not prompt: - if type_ in self.uid_labels: - prompt = self.uid_labels[type_] - else: - prompt = _('User ID:') - self._ui.uid_label.set_text(prompt) + try: + jid = validate_jid(address) + if jid.resource: + raise ValueError + except ValueError: + self._show_icon(True) + self._ui.address_entry.set_icon_tooltip_text( + Gtk.EntryIconPosition.SECONDARY, _('Invalid Address')) + return False + + self._show_icon(False) + return True + + +class Error(ErrorPage): + def __init__(self): + ErrorPage.__init__(self) + self.set_title(_('Add Contact')) + self.set_heading(_('An Error Occurred'))
- if type_ == 'jabber': - self._ui.message_scrolledwindow.show() - self._ui.save_message_checkbutton.show() - else: - self._ui.message_scrolledwindow.hide() - self._ui.save_message_checkbutton.hide() - if type_ in self.available_types: - self._ui.register_hbox.show() - self._ui.auto_authorize_checkbutton.hide() - self._ui.connected_label.hide() - self._subscription_table_hide() - self._ui.add_button.set_sensitive(False) + def get_visible_buttons(self): + return ['back'] + + def get_default_button(self): + return 'back' + + +class Contact(Page): + def __init__(self): + Page.__init__(self) + self.title = _('Add Contact') + + self._result = None + self._account = None + self._contact = None + + self._ui = get_builder('add_contact.ui') + self.add(self._ui.contact_grid) + + self._ui.contact_info_button.connect('clicked', self._on_info_clicked) + + self.show_all() + + def get_visible_buttons(self): + if self._contact.is_in_roster: + return ['back'] + return ['back', 'add'] + + def get_default_button(self): + return 'add' + + def prepare(self, account, result): + self._result = result + self._account = account + + client = app.get_client(account) + self._contact = client.get_module('Contacts').get_contact(result.jid) + + self._update_groups(account) + self._ui.message_entry.set_text(get_subscription_request_msg(account)) + self._ui.contact_grid.set_sensitive(True) + + def _update_groups(self, account): + self._ui.group_combo.get_model().clear() + client = app.get_client(account) + for group in client.get_module('Roster').get_groups(): + self._ui.group_combo.append_text(group) + + def _on_info_clicked(self, _button): + open_window( + 'ContactInfo', account=self._account, contact=self._contact) + + def get_subscription_data(self): + group = self._ui.group_combo.get_child().get_text() + groups = [group] if group else [] + return { + 'message': self._ui.message_entry.get_text(), + 'groups': groups, + 'auto_auth': self._ui.status_switch.get_active(), + } + + +class Gateway(Page): + def __init__(self): + Page.__init__(self) + self.title = _('Service Gateway') + + self._account = None + self._result = None + + self._ui = get_builder('add_contact.ui') + self.add(self._ui.gateway_box) + + self._ui.register_button.connect('clicked', self._on_register_clicked) + self._ui.command_button.connect('clicked', self._on_command_clicked) + + self.show_all() + + def get_visible_buttons(self): + return ['back', 'add'] + + def get_default_button(self): + return 'add' + + def prepare(self, account, result): + self._account = account + self._result = result + + icon_name = None + if result.is_gateway: + if result.gateway_type == 'sms': + icon_name = 'gajim-agent-sms' + if result.gateway_type == 'irc': + icon_name = 'gajim-agent-irc' + self._ui.gateway_image.set_from_icon_name( + icon_name, Gtk.IconSize.DIALOG) + self._ui.gateway_label.set_text(_('%(name)s (%(type)s)') % { + 'name': result.gateway_name, + 'type': result.gateway_type.upper()}) else: - self._ui.register_hbox.hide() - if type_ != 'jabber': - model = self._ui.protocol_jid_combobox.get_model() - row = self._ui.protocol_jid_combobox.get_active() - jid = model[row][0] - contact = app.contacts.get_first_contact_from_jid( - self.account, jid) - if contact is None or contact.show in ('offline', 'error'): - self._subscription_table_hide() - self._ui.connected_label.show() - self._ui.add_button.set_sensitive(False) - self._ui.auto_authorize_checkbutton.hide() - return - self._subscription_table_show() - self._ui.auto_authorize_checkbutton.show() - self._ui.connected_label.hide() - self._ui.add_button.set_sensitive(True) - - def transport_signed_in(self, jid): - model = self._ui.protocol_jid_combobox.get_model() - row = self._ui.protocol_jid_combobox.get_active() - _jid = model[row][0] - if _jid == jid: - self._ui.register_hbox.hide() - self._ui.connected_label.hide() - self._subscription_table_show() - self._ui.auto_authorize_checkbutton.show() - self._ui.add_button.set_sensitive(True) - - def transport_signed_out(self, jid): - model = self._ui.protocol_jid_combobox.get_model() - row = self._ui.protocol_jid_combobox.get_active() - _jid = model[row][0] - if _jid == jid: - self._subscription_table_hide() - self._ui.auto_authorize_checkbutton.hide() - self._ui.connected_label.show() - self._ui.add_button.set_sensitive(False) - - def _nec_presence_received(self, obj): - if app.jid_is_transport(obj.jid): - if obj.old_show == 0 and obj.new_show > 1: - self.transport_signed_in(obj.jid) - elif obj.old_show > 1 and obj.new_show == 0: - self.transport_signed_out(obj.jid) - - def _nec_gateway_prompt_received(self, obj): - if self.adding_jid: - jid, transport, type_ = self.adding_jid - if obj.stanza.getError(): - ErrorDialog( - _('Error while adding transport contact'), - _('This error occurred while adding a contact for transport ' - '%(transport)s:\n\n%(error)s') % { - 'transport': transport, - 'error': obj.stanza.getErrorMsg()}) - return - if obj.prompt_jid: - self._add_jid(obj.prompt_jid, type_) - else: - jid = jid.replace('@', '%') + '@' + transport - self._add_jid(jid, type_) - elif obj.jid in self.gateway_prompt: - if obj.desc: - self.gateway_prompt[obj.jid]['desc'] = obj.desc - if obj.prompt: - self.gateway_prompt[obj.jid]['prompt'] = obj.prompt - - def _subscription_table_hide(self): - for widget in self.subscription_table: - widget.hide() - - def _subscription_table_show(self): - for widget in self.subscription_table: - widget.show() + for identity in result.identities: + identity_name = identity.name + identity_type = identity.type + if identity.type == 'sms': + icon_name = 'gajim-agent-sms' + if identity.type == 'irc': + icon_name = 'gajim-agent-irc' + self._ui.gateway_image.set_from_icon_name( + icon_name, Gtk.IconSize.DIALOG) + self._ui.gateway_label.set_text(_('%(name)s (%(type)s)') % { + 'name': identity_name, + 'type': identity_type.upper()}) + + def _on_register_clicked(self, _button): + ServiceRegistration(self._account, self._result.jid) + + def _on_command_clicked(self, _button): + AdHocCommand(self._account, self._result.jid) + + +class GroupChat(Page): + def __init__(self): + Page.__init__(self) + self.title = _('Join Group Chat?') + + self._result = None + + heading = Gtk.Label(label=_('Join Group Chat?')) + heading.get_style_context().add_class('large-header') + heading.set_max_width_chars(30) + heading.set_line_wrap(True) + heading.set_halign(Gtk.Align.CENTER) + heading.set_justify(Gtk.Justification.CENTER) + self.pack_start(heading, False, True, 0) + + self._info_box = GroupChatInfoScrolled(options={'minimal': True}) + self.pack_start(self._info_box, True, True, 0) + + self.show_all() + + def get_visible_buttons(self): + return ['back', 'join'] + + def get_default_button(self): + return 'join' + + def prepare(self, account, result): + self._result = result + + self._info_box.set_account(account) + self._info_box.set_from_disco_info(result)
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/6b18f00423b0212328067af0777053aa5...