Rewrite GroupchatConfig dialog
- Complete rewrite of the dialog - Use new DataFormWidget
This commit is contained in:
parent
e615a8e2e3
commit
61a791d67c
|
@ -193,6 +193,16 @@ class SyncThreshold(IntEnum):
|
|||
return str(self.value)
|
||||
|
||||
|
||||
class MUCUser(IntEnum):
|
||||
JID = 0
|
||||
NICK = 1
|
||||
REASON = 1
|
||||
NICK_OR_REASON = 1
|
||||
ROLE = 2
|
||||
AFFILIATION = 3
|
||||
AFFILIATION_TEXT = 4
|
||||
|
||||
|
||||
ACTIVITIES = {
|
||||
'doing_chores': {
|
||||
'category': _('Doing Chores'),
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
import time
|
||||
import logging
|
||||
import weakref
|
||||
|
||||
import nbxmpp
|
||||
|
||||
|
@ -187,28 +188,40 @@ class MUC:
|
|||
item = iq.setQuery()
|
||||
for jid in users_dict:
|
||||
affiliation = users_dict[jid].get('affiliation')
|
||||
reason = users_dict[jid].get('reason') or None
|
||||
reason = users_dict[jid].get('reason')
|
||||
nick = users_dict[jid].get('nick')
|
||||
item_tag = item.addChild('item', {'jid': jid,
|
||||
'affiliation': affiliation})
|
||||
if reason is not None:
|
||||
item_tag.setTagData('reason', reason)
|
||||
|
||||
if nick is not None:
|
||||
item_tag.setAttr('nick', nick)
|
||||
log.info('Set affiliation for %s: %s', room_jid, users_dict)
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
iq, self._default_response, {})
|
||||
|
||||
def get_affiliation(self, room_jid, affiliation):
|
||||
def get_affiliation(self, room_jid, affiliation, success_cb, error_cb):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
iq = nbxmpp.Iq(typ='get', to=room_jid, queryNS=nbxmpp.NS_MUC_ADMIN)
|
||||
item = iq.setQuery().setTag('item')
|
||||
item.setAttr('affiliation', affiliation)
|
||||
log.info('Get affiliation %s for %s', affiliation, room_jid)
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
iq, self._affiliation_received)
|
||||
|
||||
def _affiliation_received(self, stanza):
|
||||
weak_success_cb = weakref.WeakMethod(success_cb)
|
||||
weak_error_cb = weakref.WeakMethod(error_cb)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
iq, self._affiliation_received, {'affiliation': affiliation,
|
||||
'success_cb': weak_success_cb,
|
||||
'error_cb': weak_error_cb})
|
||||
|
||||
def _affiliation_received(self, _con, stanza, affiliation,
|
||||
success_cb, error_cb):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
log.info('Error: %s', stanza.getError())
|
||||
if error_cb() is not None:
|
||||
error_cb()(affiliation, stanza.getError())
|
||||
return
|
||||
|
||||
room_jid = stanza.getFrom().getStripped()
|
||||
|
@ -222,8 +235,8 @@ class MUC:
|
|||
log.warning('Invalid JID: %s, ignoring it',
|
||||
item.getAttr('jid'))
|
||||
continue
|
||||
affiliation = item.getAttr('affiliation')
|
||||
users_dict[jid] = {'affiliation': affiliation}
|
||||
|
||||
users_dict[jid] = {}
|
||||
if item.has_attr('nick'):
|
||||
users_dict[jid]['nick'] = item.getAttr('nick')
|
||||
if item.has_attr('role'):
|
||||
|
@ -231,9 +244,12 @@ class MUC:
|
|||
reason = item.getTagData('reason')
|
||||
if reason:
|
||||
users_dict[jid]['reason'] = reason
|
||||
log.info('Affiliations received from %s: %s', room_jid, users_dict)
|
||||
app.nec.push_incoming_event(MucAdminReceivedEvent(
|
||||
None, conn=self._con, room_jid=room_jid, users_dict=users_dict))
|
||||
|
||||
log.info('%s affiliations received from %s: %s',
|
||||
affiliation, room_jid, users_dict)
|
||||
|
||||
if success_cb() is not None:
|
||||
success_cb()(self._account, room_jid, affiliation, users_dict)
|
||||
|
||||
def set_role(self, room_jid, nick, role, reason=''):
|
||||
if not app.account_is_connected(self._account):
|
||||
|
@ -423,10 +439,6 @@ class GcDeclineReceived(NetworkIncomingEvent):
|
|||
name = 'gc-decline-received'
|
||||
|
||||
|
||||
class MucAdminReceivedEvent(NetworkIncomingEvent):
|
||||
name = 'muc-admin-received'
|
||||
|
||||
|
||||
class MucOwnerReceivedEvent(NetworkIncomingEvent):
|
||||
name = 'muc-owner-received'
|
||||
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkListStore" id="affiliation_store">
|
||||
<columns>
|
||||
<!-- column-name jabberid -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name nickname -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name role -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name affiliation -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name affiliation-text -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name editable-affiliation -->
|
||||
<column type="gboolean"/>
|
||||
<!-- column-name editable-jid -->
|
||||
<column type="gboolean"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkListStore" id="combo_store">
|
||||
<columns>
|
||||
<!-- column-name affiliation -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name affiliation-text -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Owner</col>
|
||||
<col id="1">owner</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Admin</col>
|
||||
<col id="1">admin</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Member</col>
|
||||
<col id="1">member</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkPopover" id="info_popover">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="margin_top">12</property>
|
||||
<property name="margin_bottom">12</property>
|
||||
<property name="label" translatable="yes"><b>Jabber-ID</b>
|
||||
&lt;user@domain/resource&gt; (only that resource matches)
|
||||
&lt;user@domain&gt; (any resource matches)
|
||||
&lt;domain/resource&gt; (only that resource matches)
|
||||
&lt;domain&gt; (the domain itself matches, as does any user@domain or domain/resource)
|
||||
</property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="outcast_store">
|
||||
<columns>
|
||||
<!-- column-name jabberid -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name reason -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name dummy -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name affiliation -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name dummy1 -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name dummy2 -->
|
||||
<column type="gboolean"/>
|
||||
<!-- column-name editable-jid -->
|
||||
<column type="gboolean"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<property name="name">GroupchatConfig</property>
|
||||
<property name="width_request">700</property>
|
||||
<property name="height_request">500</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="treeview_buttonbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="vexpand">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="popover">info_popover</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">dialog-information-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</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="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">Only Admins and Owners can modify the affiliation</property>
|
||||
<property name="halign">start</property>
|
||||
<signal name="clicked" handler="_on_add" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">list-add-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="remove_button">
|
||||
<property name="label" translatable="yes">Remove</property>
|
||||
<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">Only Admins and Owners can modify the affiliation</property>
|
||||
<signal name="clicked" handler="_on_remove" swapped="no"/>
|
||||
<style>
|
||||
<class name="destructive-action"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</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="GtkButtonBox" id="close_ok_button_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<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>
|
||||
<signal name="clicked" handler="_on_cancel" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<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>
|
||||
<signal name="clicked" handler="_on_ok" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="transition_duration">300</property>
|
||||
<property name="transition_type">crossfade</property>
|
||||
<signal name="notify::visible-child-name" handler="_on_switch_page" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkGrid" id="config_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</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="name">config</property>
|
||||
<property name="title" translatable="yes">Configuration</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="affiliation_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">affiliation_store</property>
|
||||
<property name="search_column">0</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection">
|
||||
<property name="mode">multiple</property>
|
||||
<signal name="changed" handler="_on_selection_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="title">Jabber-ID</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="placeholder_text">user@example.org</property>
|
||||
<signal name="edited" handler="_on_jid_edited" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="editable">6</attribute>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="reserved_name_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="title" translatable="yes">Reserved Name</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<signal name="edited" handler="_on_nick_edited" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="editable">6</attribute>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="role_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="min_width">100</property>
|
||||
<property name="title" translatable="yes">Role</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">2</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="min_width">120</property>
|
||||
<property name="title" translatable="yes">Affiliation</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">3</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererCombo">
|
||||
<property name="has_entry">False</property>
|
||||
<property name="model">combo_store</property>
|
||||
<property name="text_column">0</property>
|
||||
<signal name="changed" handler="_on_affiliation_changed" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="editable">5</attribute>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="margin-12"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">affiliation</property>
|
||||
<property name="title" translatable="yes">Affiliations</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="outcast_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">outcast_store</property>
|
||||
<property name="search_column">0</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection">
|
||||
<property name="mode">multiple</property>
|
||||
<signal name="changed" handler="_on_selection_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="title">Jabber-ID</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="placeholder_text">user@example.org</property>
|
||||
<signal name="edited" handler="_on_outcast_jid_edited" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="editable">6</attribute>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="min_width">250</property>
|
||||
<property name="title" translatable="yes">Reason</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="placeholder_text">spam</property>
|
||||
<signal name="edited" handler="_on_reason_edited" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="editable">6</attribute>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="margin-12"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">outcast</property>
|
||||
<property name="title" translatable="yes">Ban List</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackSidebar">
|
||||
<property name="width_request">140</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="height">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
|
@ -146,6 +146,14 @@ list.settings > row > box {
|
|||
#StartChatListBox > row { padding: 10px 20px 10px 10px; }
|
||||
#StartChatListBox > row:not(.activatable) label { color: @insensitive_fg_color }
|
||||
|
||||
/* GroupchatConfig */
|
||||
#GroupchatConfig buttonbox { margin: 0px 12px 12px 12px; }
|
||||
#GroupchatConfig stack { border-bottom: 1px solid; border-color: @borders;}
|
||||
#GroupchatConfig stacksidebar > scrolledwindow {
|
||||
background-color:@theme_base_color;
|
||||
border-bottom: 1px solid;
|
||||
border-color: @borders;}
|
||||
|
||||
/* Popover Treeview */
|
||||
.popover_treeview { border-radius: 3px; background-color: @theme_bg_color; }
|
||||
.popover_treeview { padding: 6px; }
|
||||
|
@ -211,6 +219,7 @@ list.settings > row > box {
|
|||
|
||||
/* Padding/Margins */
|
||||
.margin-top6 { margin-top: 6px; }
|
||||
.margin-12 { margin: 12px; }
|
||||
|
||||
/* Treeview */
|
||||
treeview.space { padding: 6px; }
|
||||
|
|
|
@ -728,18 +728,21 @@ class GroupchatControl(ChatControlBase):
|
|||
_('You may also enter an alternate venue:'), ok_handler=on_ok,
|
||||
transient_for=self.parent_win.window)
|
||||
|
||||
def _on_configure_room(self, action, param):
|
||||
c = app.contacts.get_gc_contact(
|
||||
def _on_configure_room(self, _action, _param):
|
||||
contact = app.contacts.get_gc_contact(
|
||||
self.account, self.room_jid, self.nick)
|
||||
if c.affiliation == 'owner':
|
||||
if contact.affiliation == 'owner':
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').request_config(self.room_jid)
|
||||
elif c.affiliation == 'admin':
|
||||
if self.room_jid not in app.interface.instances[self.account][
|
||||
'gc_config']:
|
||||
app.interface.instances[self.account]['gc_config'][
|
||||
self.room_jid] = GroupchatConfig(self.account,
|
||||
self.room_jid)
|
||||
elif contact.affiliation == 'admin':
|
||||
win = app.get_app_window(
|
||||
'GroupchatConfig', self.account, self.room_jid)
|
||||
if win is not None:
|
||||
win.present()
|
||||
else:
|
||||
GroupchatConfig(self.account,
|
||||
self.room_jid,
|
||||
contact.affiliation)
|
||||
|
||||
def _on_bookmark_room(self, action, param):
|
||||
"""
|
||||
|
|
|
@ -12,237 +12,365 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
|
||||
import nbxmpp
|
||||
from gi.repository import Gtk
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common.i18n import _
|
||||
from gajim.common.const import MUCUser
|
||||
from gajim.common.caps_cache import muc_caps_cache
|
||||
|
||||
from gajim import dataforms_widget
|
||||
|
||||
from gajim.gtk.dialogs import ErrorDialog
|
||||
from gajim.gtk.dataform import DataFormWidget
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.dialogs import InputDialog
|
||||
|
||||
log = logging.getLogger('gajim.gtk.groupchat_config')
|
||||
|
||||
|
||||
class GroupchatConfig:
|
||||
def __init__(self, account, room_jid, form=None):
|
||||
class GroupchatConfig(Gtk.ApplicationWindow):
|
||||
def __init__(self, account, jid, own_affiliation, form=None):
|
||||
Gtk.ApplicationWindow.__init__(self)
|
||||
self.set_application(app.app)
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.set_show_menubar(False)
|
||||
self.set_title(_('Group Chat Configuration'))
|
||||
|
||||
self.account = account
|
||||
self.room_jid = room_jid
|
||||
self.form = form
|
||||
self.remove_button = {}
|
||||
self.affiliation_treeview = {}
|
||||
self.start_users_dict = {} # list at the beginning
|
||||
self.affiliation_labels = {
|
||||
'outcast': _('Ban List'),
|
||||
'member': _('Member List'),
|
||||
'owner': _('Owner List'),
|
||||
'admin':_('Administrator List')
|
||||
}
|
||||
self.jid = jid
|
||||
self._own_affiliation = own_affiliation
|
||||
|
||||
self._ui = get_builder('data_form_window.ui', ['data_form_window'])
|
||||
self.window = self._ui.data_form_window
|
||||
self.window.set_transient_for(app.interface.roster.window)
|
||||
self._ui = get_builder('groupchat_config.ui')
|
||||
self.add(self._ui.grid)
|
||||
|
||||
if self.form:
|
||||
self.data_form_widget = dataforms_widget.DataFormWidget(self.form)
|
||||
# hide scrollbar of this data_form_widget, we already have in this
|
||||
# widget
|
||||
sw = self.data_form_widget.xml.get_object(
|
||||
'single_form_scrolledwindow')
|
||||
sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER)
|
||||
if self.form.title:
|
||||
self._ui.title_label.set_text(self.form.title)
|
||||
else:
|
||||
self._ui.title_hseparator.set_no_show_all(True)
|
||||
self._ui.title_hseparator.hide()
|
||||
# Activate Add button only for Admins and Owners
|
||||
if self._own_affiliation in ('admin', 'owner'):
|
||||
self._ui.add_button.set_sensitive(True)
|
||||
self._ui.add_button.set_tooltip_text('')
|
||||
|
||||
self.data_form_widget.show()
|
||||
self._ui.config_vbox.pack_start(self.data_form_widget, True, True, 0)
|
||||
else:
|
||||
self._ui.title_label.set_no_show_all(True)
|
||||
self._ui.title_label.hide()
|
||||
self._ui.title_hseparator.set_no_show_all(True)
|
||||
self._ui.title_hseparator.hide()
|
||||
self._ui.config_hseparator.set_no_show_all(True)
|
||||
self._ui.config_hseparator.hide()
|
||||
visible = muc_caps_cache.supports(jid, nbxmpp.NS_REGISTER)
|
||||
self._ui.reserved_name_column.set_visible(visible)
|
||||
|
||||
# Draw the edit affiliation list things
|
||||
add_on_vbox = self._ui.add_on_vbox
|
||||
self._form = form
|
||||
self._affiliations = {}
|
||||
self._new_affiliations = {}
|
||||
|
||||
for affiliation in self.affiliation_labels:
|
||||
self.start_users_dict[affiliation] = {}
|
||||
hbox = Gtk.HBox(spacing=5)
|
||||
add_on_vbox.pack_start(hbox, False, True, 0)
|
||||
|
||||
label = Gtk.Label(label=self.affiliation_labels[affiliation])
|
||||
hbox.pack_start(label, False, True, 0)
|
||||
|
||||
bb = Gtk.HButtonBox()
|
||||
bb.set_layout(Gtk.ButtonBoxStyle.END)
|
||||
bb.set_spacing(5)
|
||||
hbox.pack_start(bb, True, True, 0)
|
||||
add_button = Gtk.Button(stock=Gtk.STOCK_ADD)
|
||||
add_button.connect(
|
||||
'clicked', self.on_add_button_clicked, affiliation)
|
||||
bb.pack_start(add_button, True, True, 0)
|
||||
self.remove_button[affiliation] = Gtk.Button(stock=Gtk.STOCK_REMOVE)
|
||||
self.remove_button[affiliation].set_sensitive(False)
|
||||
self.remove_button[affiliation].connect(
|
||||
'clicked', self.on_remove_button_clicked, affiliation)
|
||||
bb.pack_start(self.remove_button[affiliation], True, True, 0)
|
||||
|
||||
# jid, reason, nick, role
|
||||
liststore = Gtk.ListStore(str, str, str, str)
|
||||
self.affiliation_treeview[affiliation] = Gtk.TreeView(liststore)
|
||||
self.affiliation_treeview[affiliation].get_selection().set_mode(
|
||||
Gtk.SelectionMode.MULTIPLE)
|
||||
self.affiliation_treeview[affiliation].connect(
|
||||
'cursor-changed',
|
||||
self.on_affiliation_treeview_cursor_changed,
|
||||
affiliation)
|
||||
renderer = Gtk.CellRendererText()
|
||||
col = Gtk.TreeViewColumn(_('JID'), renderer)
|
||||
col.add_attribute(renderer, 'text', 0)
|
||||
col.set_resizable(True)
|
||||
col.set_sort_column_id(0)
|
||||
self.affiliation_treeview[affiliation].append_column(col)
|
||||
|
||||
if affiliation == 'outcast':
|
||||
renderer = Gtk.CellRendererText()
|
||||
renderer.set_property('editable', True)
|
||||
renderer.connect('edited', self.on_cell_edited)
|
||||
col = Gtk.TreeViewColumn(_('Reason'), renderer)
|
||||
col.add_attribute(renderer, 'text', 1)
|
||||
col.set_resizable(True)
|
||||
col.set_sort_column_id(1)
|
||||
self.affiliation_treeview[affiliation].append_column(col)
|
||||
elif affiliation == 'member':
|
||||
renderer = Gtk.CellRendererText()
|
||||
col = Gtk.TreeViewColumn(_('Nick'), renderer)
|
||||
col.add_attribute(renderer, 'text', 2)
|
||||
col.set_resizable(True)
|
||||
col.set_sort_column_id(2)
|
||||
self.affiliation_treeview[affiliation].append_column(col)
|
||||
renderer = Gtk.CellRendererText()
|
||||
col = Gtk.TreeViewColumn(_('Role'), renderer)
|
||||
col.add_attribute(renderer, 'text', 3)
|
||||
col.set_resizable(True)
|
||||
col.set_sort_column_id(3)
|
||||
self.affiliation_treeview[affiliation].append_column(col)
|
||||
|
||||
sw = Gtk.ScrolledWindow()
|
||||
sw.add(self.affiliation_treeview[affiliation])
|
||||
add_on_vbox.pack_start(sw, True, True, 0)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').get_affiliation(self.room_jid, affiliation)
|
||||
for affiliation in ('owner', 'admin', 'member', 'outcast'):
|
||||
con.get_module('MUC').get_affiliation(
|
||||
self.jid,
|
||||
affiliation,
|
||||
self._on_affiliations_received,
|
||||
self._on_affiliations_error)
|
||||
|
||||
if form is not None:
|
||||
self._ui.stack.set_visible_child_name('config')
|
||||
self._data_form_widget = DataFormWidget(form)
|
||||
self._ui.config_grid.add(self._data_form_widget)
|
||||
# self._ui.stack.set_visible_child_name('affiliation')
|
||||
else:
|
||||
self._ui.stack.get_child_by_name('config').hide()
|
||||
self._ui.stack.get_child_by_name('config').set_no_show_all(True)
|
||||
self._ui.stack.set_visible_child_name('affiliation')
|
||||
|
||||
self._ui.connect_signals(self)
|
||||
self.window.connect('delete-event', self.on_cancel_button_clicked)
|
||||
self.window.show_all()
|
||||
self.show_all()
|
||||
self._ui.stack.notify('visible-child-name')
|
||||
|
||||
def on_cancel_button_clicked(self, *args):
|
||||
if self.form:
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').cancel_config(self.room_jid)
|
||||
self.window.destroy()
|
||||
def _get_current_treeview(self):
|
||||
page_name = self._ui.stack.get_visible_child_name()
|
||||
return getattr(self._ui, '%s_treeview' % page_name)
|
||||
|
||||
def on_cell_edited(self, _cell, path, new_text):
|
||||
model = self.affiliation_treeview['outcast'].get_model()
|
||||
new_text = new_text
|
||||
iter_ = model.get_iter(path)
|
||||
model[iter_][1] = new_text
|
||||
|
||||
def on_add_button_clicked(self, _widget, affiliation):
|
||||
if affiliation == 'outcast':
|
||||
title = _('Banning…')
|
||||
#You can move '\n' before user@domain if that line is TOO BIG
|
||||
prompt = _('<b>Whom do you want to ban?</b>\n\n')
|
||||
elif affiliation == 'member':
|
||||
title = _('Adding Member…')
|
||||
prompt = _('<b>Whom do you want to make a member?</b>\n\n')
|
||||
elif affiliation == 'owner':
|
||||
title = _('Adding Owner…')
|
||||
prompt = _('<b>Whom do you want to make an owner?</b>\n\n')
|
||||
def _on_add(self, *args):
|
||||
page_name = self._ui.stack.get_visible_child_name()
|
||||
if page_name == 'outcast':
|
||||
affiliation_edit, jid_edit = self._allowed_to_edit('outcast')
|
||||
text = None
|
||||
affiliation = 'outcast'
|
||||
else:
|
||||
title = _('Adding Administrator…')
|
||||
prompt = _('<b>Whom do you want to make an administrator?</b>\n\n')
|
||||
prompt += _(
|
||||
'Can be one of the following:\n'
|
||||
'1. user@domain/resource (only that resource matches).\n'
|
||||
'2. user@domain (any resource matches).\n'
|
||||
'3. domain/resource (only that resource matches).\n'
|
||||
'4. domain (the domain itself matches, as does any user@domain,\n'
|
||||
'domain/resource, or address containing a subdomain).')
|
||||
affiliation_edit, jid_edit = self._allowed_to_edit('member')
|
||||
text = _('Member')
|
||||
affiliation = 'member'
|
||||
|
||||
def on_ok(jid):
|
||||
if not jid:
|
||||
return
|
||||
model = self.affiliation_treeview[affiliation].get_model()
|
||||
model.append((jid, '', '', ''))
|
||||
InputDialog(title, prompt, ok_handler=on_ok)
|
||||
treeview = self._get_current_treeview()
|
||||
treeview.get_model().append([None,
|
||||
None,
|
||||
None,
|
||||
affiliation,
|
||||
text,
|
||||
affiliation_edit,
|
||||
jid_edit])
|
||||
|
||||
def on_remove_button_clicked(self, _widget, affiliation):
|
||||
selection = self.affiliation_treeview[affiliation].get_selection()
|
||||
model, paths = selection.get_selected_rows()
|
||||
row_refs = []
|
||||
# Scroll to added row
|
||||
row = treeview.get_model()[-1]
|
||||
treeview.scroll_to_cell(row.path, None, False, 0, 0)
|
||||
treeview.get_selection().unselect_all()
|
||||
treeview.get_selection().select_path(row.path)
|
||||
|
||||
def _on_remove(self, *args):
|
||||
treeview = self._get_current_treeview()
|
||||
model, paths = treeview.get_selection().get_selected_rows()
|
||||
|
||||
owner_count = self._get_owner_count()
|
||||
references = []
|
||||
for path in paths:
|
||||
row_refs.append(Gtk.TreeRowReference.new(model, path))
|
||||
for row_ref in row_refs:
|
||||
path = row_ref.get_path()
|
||||
iter_ = model.get_iter(path)
|
||||
if model[path][MUCUser.AFFILIATION] == 'owner':
|
||||
if owner_count < 2:
|
||||
# There must be at least one owner
|
||||
ErrorDialog(_('Error'),
|
||||
_('A Group Chat needs at least one Owner'))
|
||||
return
|
||||
owner_count -= 1
|
||||
references.append(Gtk.TreeRowReference.new(model, path))
|
||||
|
||||
for ref in references:
|
||||
iter_ = model.get_iter(ref.get_path())
|
||||
model.remove(iter_)
|
||||
self.remove_button[affiliation].set_sensitive(False)
|
||||
|
||||
def on_affiliation_treeview_cursor_changed(self, _widget, affiliation):
|
||||
self.remove_button[affiliation].set_sensitive(True)
|
||||
def _on_jid_edited(self, _renderer, path, new_text):
|
||||
old_text = self._ui.affiliation_store[path][MUCUser.JID]
|
||||
if new_text == old_text:
|
||||
return
|
||||
|
||||
def affiliation_list_received(self, users_dict):
|
||||
"""
|
||||
Fill the affiliation treeview
|
||||
"""
|
||||
for jid in users_dict:
|
||||
affiliation = users_dict[jid]['affiliation']
|
||||
if affiliation not in self.affiliation_labels.keys():
|
||||
# Unknown affiliation or 'none' affiliation, do not show it
|
||||
if self._jid_exists(new_text):
|
||||
self._raise_error()
|
||||
return
|
||||
|
||||
self._ui.affiliation_store[path][MUCUser.JID] = new_text
|
||||
|
||||
def _on_outcast_jid_edited(self, _renderer, path, new_text):
|
||||
old_text = self._ui.outcast_store[path][MUCUser.JID]
|
||||
if new_text == old_text:
|
||||
return
|
||||
|
||||
if self._jid_exists(new_text):
|
||||
self._raise_error()
|
||||
return
|
||||
|
||||
self._ui.outcast_store[path][MUCUser.JID] = new_text
|
||||
self._ui.outcast_store[path][MUCUser.AFFILIATION] = 'outcast'
|
||||
|
||||
def _on_nick_edited(self, _renderer, path, new_text):
|
||||
self._ui.affiliation_store[path][MUCUser.NICK] = new_text
|
||||
|
||||
def _on_reason_edited(self, _renderer, path, new_text):
|
||||
self._ui.outcast_store[path][MUCUser.REASON] = new_text
|
||||
|
||||
def _on_affiliation_changed(self, cell_renderer_combo,
|
||||
path_string, new_iter):
|
||||
combo_store = cell_renderer_combo.get_property('model')
|
||||
affiliation_text = combo_store.get_value(new_iter, 0)
|
||||
affiliation = combo_store.get_value(new_iter, 1)
|
||||
|
||||
store = self._ui.affiliation_treeview.get_model()
|
||||
|
||||
store[path_string][MUCUser.AFFILIATION] = affiliation
|
||||
store[path_string][MUCUser.AFFILIATION_TEXT] = affiliation_text
|
||||
|
||||
def _on_selection_changed(self, tree_selection):
|
||||
sensitive = bool(tree_selection.count_selected_rows())
|
||||
selected_affiliations = self._get_selected_affiliations(tree_selection)
|
||||
self._set_remove_button_state(sensitive, selected_affiliations)
|
||||
|
||||
def _jid_exists(self, jid):
|
||||
stores = [self._ui.affiliation_store, self._ui.outcast_store]
|
||||
|
||||
for store in stores:
|
||||
for row in store:
|
||||
if row[MUCUser.JID] == jid:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _get_selected_affiliations(tree_selection):
|
||||
model, paths = tree_selection.get_selected_rows()
|
||||
selected_affiliations = set()
|
||||
for path in paths:
|
||||
selected_affiliations.add(model[path][MUCUser.AFFILIATION])
|
||||
return selected_affiliations
|
||||
|
||||
def _on_switch_page(self, stack, _pspec):
|
||||
page_name = stack.get_visible_child_name()
|
||||
self._set_button_box_state(page_name)
|
||||
if page_name == 'config':
|
||||
return
|
||||
|
||||
treeview = getattr(self._ui, '%s_treeview' % page_name)
|
||||
sensitive = bool(treeview.get_selection().count_selected_rows())
|
||||
|
||||
selected_affiliations = self._get_selected_affiliations(
|
||||
treeview.get_selection())
|
||||
self._set_remove_button_state(sensitive, selected_affiliations)
|
||||
|
||||
def _set_button_box_state(self, page_name):
|
||||
affiliation = self._own_affiliation in ('admin', 'owner')
|
||||
page = page_name != 'config'
|
||||
self._ui.treeview_buttonbox.set_visible(affiliation and page)
|
||||
|
||||
def _set_remove_button_state(self, sensitive, selected_affiliations):
|
||||
if self._own_affiliation not in ('admin', 'owner'):
|
||||
self._ui.remove_button.set_sensitive(False)
|
||||
return
|
||||
|
||||
self._ui.remove_button.set_tooltip_text('')
|
||||
|
||||
if not sensitive:
|
||||
self._ui.remove_button.set_sensitive(False)
|
||||
return
|
||||
|
||||
if self._own_affiliation == 'owner':
|
||||
self._ui.remove_button.set_sensitive(True)
|
||||
return
|
||||
|
||||
if set(['owner', 'admin']).intersection(selected_affiliations):
|
||||
self._ui.remove_button.set_sensitive(False)
|
||||
self._ui.remove_button.set_tooltip_text(
|
||||
_('You are not allowed to modify the affiliation '
|
||||
'of Admins and Owners'))
|
||||
return
|
||||
|
||||
self._ui.remove_button.set_sensitive(True)
|
||||
|
||||
def _get_owner_count(self):
|
||||
owner_count = 0
|
||||
for row in self._ui.affiliation_store:
|
||||
if row[MUCUser.AFFILIATION] == 'owner':
|
||||
owner_count += 1
|
||||
return owner_count
|
||||
|
||||
def _allowed_to_edit(self, affiliation):
|
||||
if self._own_affiliation == 'owner':
|
||||
return True, True
|
||||
|
||||
if self._own_affiliation == 'admin':
|
||||
if affiliation in ('admin', 'owner'):
|
||||
return False, False
|
||||
return False, True
|
||||
return False, False
|
||||
|
||||
def _on_ok(self, *args):
|
||||
if self._own_affiliation in ('admin', 'owner'):
|
||||
self._set_affiliations()
|
||||
|
||||
if self._form is not None and self._own_affiliation == 'owner':
|
||||
form = self._data_form_widget.get_submit_form()
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').set_config(self.jid, form)
|
||||
self.destroy()
|
||||
|
||||
def _get_diff(self):
|
||||
stores = [self._ui.affiliation_store, self._ui.outcast_store]
|
||||
|
||||
self._new_affiliations = {}
|
||||
for store in stores:
|
||||
for row in store:
|
||||
if not row[MUCUser.JID]:
|
||||
# Ignore empty JID field
|
||||
continue
|
||||
self.start_users_dict[affiliation][jid] = users_dict[jid]
|
||||
tv = self.affiliation_treeview[affiliation]
|
||||
model = tv.get_model()
|
||||
reason = users_dict[jid].get('reason', '')
|
||||
nick = users_dict[jid].get('nick', '')
|
||||
role = users_dict[jid].get('role', '')
|
||||
model.append((jid, reason, nick, role))
|
||||
|
||||
def on_data_form_window_destroy(self, _widget):
|
||||
del app.interface.instances[self.account]['gc_config'][self.room_jid]
|
||||
attr = 'nick'
|
||||
if row[MUCUser.AFFILIATION] == 'outcast':
|
||||
attr = 'reason'
|
||||
|
||||
def on_ok_button_clicked(self, _widget):
|
||||
if self.form:
|
||||
form = self.data_form_widget.data_form
|
||||
self._new_affiliations[row[MUCUser.JID]] = {
|
||||
'affiliation': row[MUCUser.AFFILIATION],
|
||||
attr: row[MUCUser.NICK_OR_REASON]}
|
||||
|
||||
old_jids = set(self._affiliations.keys())
|
||||
new_jids = set(self._new_affiliations.keys())
|
||||
remove = old_jids - new_jids
|
||||
add = new_jids - old_jids
|
||||
modified = new_jids - remove - add
|
||||
|
||||
return add, remove, modified
|
||||
|
||||
def _on_cancel(self, *args):
|
||||
if self._form and self._own_affiliation == 'owner':
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').set_config(self.room_jid, form)
|
||||
for affiliation in self.affiliation_labels:
|
||||
users_dict = {}
|
||||
actual_jid_list = []
|
||||
model = self.affiliation_treeview[affiliation].get_model()
|
||||
iter_ = model.get_iter_first()
|
||||
# add new jid
|
||||
while iter_:
|
||||
jid = model[iter_][0]
|
||||
actual_jid_list.append(jid)
|
||||
if jid not in self.start_users_dict[affiliation] or \
|
||||
(affiliation == 'outcast' and 'reason' in self.start_users_dict[
|
||||
affiliation][jid] and self.start_users_dict[affiliation][jid]\
|
||||
['reason'] != model[iter_][1]):
|
||||
users_dict[jid] = {'affiliation': affiliation}
|
||||
con.get_module('MUC').cancel_config(self.jid)
|
||||
self.destroy()
|
||||
|
||||
def _set_affiliations(self):
|
||||
add, remove, modified = self._get_diff()
|
||||
|
||||
diff_dict = {}
|
||||
for jid in add:
|
||||
diff_dict[jid] = self._new_affiliations[jid]
|
||||
|
||||
for jid in remove:
|
||||
diff_dict[jid] = {'affiliation': 'none'}
|
||||
|
||||
for jid in modified:
|
||||
if self._new_affiliations[jid] == self._affiliations[jid]:
|
||||
# Not modified
|
||||
continue
|
||||
|
||||
diff_dict[jid] = self._new_affiliations[jid]
|
||||
if self._new_affiliations[jid]['affiliation'] == 'outcast':
|
||||
# New affiliation is outcast, check if the reason changed.
|
||||
# In case the affiliation was 'admin', 'owner' or 'member'
|
||||
# before, there is no reason.
|
||||
new_reason = self._new_affiliations[jid]['reason']
|
||||
old_reason = self._affiliations[jid].get('reason')
|
||||
if new_reason == old_reason:
|
||||
diff_dict[jid].pop('reason', None)
|
||||
|
||||
else:
|
||||
# New affiliation is not outcast, check if the nick has changed.
|
||||
# In case the affiliation was 'outcast' there is no nick.
|
||||
new_nick = self._new_affiliations[jid]['nick']
|
||||
old_nick = self._affiliations[jid].get('nick')
|
||||
if new_nick == old_nick:
|
||||
diff_dict[jid].pop('nick', None)
|
||||
|
||||
if not diff_dict:
|
||||
# No changes were made
|
||||
return
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').set_affiliation(self.jid, diff_dict)
|
||||
|
||||
def _on_affiliations_error(self, affiliation, error):
|
||||
log.info('Error while requesting %s affiliations: %s',
|
||||
affiliation, error)
|
||||
|
||||
def _on_affiliations_received(self, _account, _room_jid,
|
||||
affiliation, users):
|
||||
|
||||
if affiliation == 'outcast':
|
||||
users_dict[jid]['reason'] = model[iter_][1]
|
||||
iter_ = model.iter_next(iter_)
|
||||
# remove removed one
|
||||
for jid in self.start_users_dict[affiliation]:
|
||||
if jid not in actual_jid_list:
|
||||
users_dict[jid] = {'affiliation': 'none'}
|
||||
if users_dict:
|
||||
con = app.connections[self.account]
|
||||
con.get_module('MUC').set_affiliation(
|
||||
self.room_jid, users_dict)
|
||||
self.window.destroy()
|
||||
self._ui.stack.get_child_by_name('outcast').show()
|
||||
|
||||
for jid, attrs in users.items():
|
||||
affiliation_edit, jid_edit = self._allowed_to_edit(affiliation)
|
||||
if affiliation == 'outcast':
|
||||
reason = attrs.get('reason')
|
||||
self._ui.outcast_store.append(
|
||||
[jid,
|
||||
reason,
|
||||
None,
|
||||
affiliation,
|
||||
None,
|
||||
affiliation_edit,
|
||||
jid_edit])
|
||||
self._affiliations[jid] = {'affiliation': affiliation,
|
||||
'reason': reason}
|
||||
else:
|
||||
nick = attrs.get('nick')
|
||||
role = attrs.get('role')
|
||||
self._ui.affiliation_store.append(
|
||||
[jid,
|
||||
nick,
|
||||
role,
|
||||
affiliation,
|
||||
_(affiliation.capitalize()),
|
||||
affiliation_edit,
|
||||
jid_edit])
|
||||
self._affiliations[jid] = {'affiliation': affiliation,
|
||||
'nick': nick}
|
||||
if role is not None:
|
||||
self._ui.role_column.set_visible(True)
|
||||
|
||||
@staticmethod
|
||||
def _raise_error():
|
||||
ErrorDialog(_('Error'),
|
||||
_('An entry with this Jabber-ID already exists'))
|
||||
|
|
|
@ -601,16 +601,12 @@ class Interface:
|
|||
_('%(jid)s has been invited in this room') % {
|
||||
'jid': jid}, graphics=False)
|
||||
del app.automatic_rooms[account][obj.jid]
|
||||
elif obj.jid not in self.instances[account]['gc_config']:
|
||||
self.instances[account]['gc_config'][obj.jid] = \
|
||||
GroupchatConfig(account, obj.jid, obj.dataform)
|
||||
|
||||
def handle_event_gc_affiliation(self, obj):
|
||||
#('GC_AFFILIATION', account, (room_jid, users_dict))
|
||||
account = obj.conn.name
|
||||
if obj.room_jid in self.instances[account]['gc_config']:
|
||||
self.instances[account]['gc_config'][obj.room_jid].\
|
||||
affiliation_list_received(obj.users_dict)
|
||||
else:
|
||||
win = app.get_app_window('GroupchatConfig', account, obj.jid)
|
||||
if win is not None:
|
||||
win.present()
|
||||
else:
|
||||
GroupchatConfig(account, obj.jid, 'owner', obj.dataform)
|
||||
|
||||
def handle_event_gc_decline(self, obj):
|
||||
gc_control = self.msg_win_mgr.get_gc_control(obj.room_jid, obj.account)
|
||||
|
@ -1531,7 +1527,6 @@ class Interface:
|
|||
'message-not-sent': [self.handle_event_msgnotsent],
|
||||
'message-sent': [self.handle_event_msgsent],
|
||||
'metacontacts-received': [self.handle_event_metacontacts],
|
||||
'muc-admin-received': [self.handle_event_gc_affiliation],
|
||||
'muc-owner-received': [self.handle_event_gc_config],
|
||||
'oauth2-credentials-required': [self.handle_oauth2_credentials],
|
||||
'our-show': [self.handle_event_status],
|
||||
|
|
Loading…
Reference in New Issue