Add new Join Groupchat dialog

- Complete rewrite of the old Groupchat dialog
- Has now a "minimal" mode, which is used if we have all infos for joining except the nickname and if we want to bookmark
- Handle xmpp uris received via command line
This commit is contained in:
Philipp Hörist 2017-11-25 15:33:54 +01:00
parent d814a42345
commit ace904573a
18 changed files with 724 additions and 298 deletions

View File

@ -18,14 +18,15 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
import sys
import os
from gi.repository import Gtk
from gajim.common import app
from gajim.common import helpers
from gajim.common.app import interface
from gajim.common.exceptions import GajimGeneralException
from gi.repository import Gtk
import sys
import os
from gajim import config
from gajim import dialogs
from gajim import features_window
@ -116,13 +117,10 @@ class AppActions():
'You cannot join a group chat while you are invisible'))
return
if 'join_gc' in interface.instances[account]:
interface.instances[account]['join_gc'].window.present()
interface.instances[account]['join_gc'].present()
else:
try:
interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account)
except GajimGeneralException:
pass
interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account, None)
def on_add_contact(self, action, param):
dialogs.AddNewContactWindow(param.get_string())

View File

@ -1601,15 +1601,13 @@ class ChatControl(ChatControlBase):
self._add_info_bar_message(markup, [b], file_props, Gtk.MessageType.ERROR)
def _on_accept_gc_invitation(self, widget, event):
try:
if event.is_continued:
app.interface.join_gc_room(self.account, event.room_jid,
app.nicks[self.account], event.password,
is_continued=True)
else:
dialogs.JoinGroupchatWindow(self.account, event.room_jid)
except GajimGeneralException:
pass
if event.is_continued:
app.interface.join_gc_room(self.account, event.room_jid,
app.nicks[self.account], event.password,
is_continued=True)
else:
app.interface.join_gc_minimal(self.account, event.room_jid)
app.events.remove_events(self.account, self.contact.jid, event=event)
def _on_cancel_gc_invitation(self, widget, event):

View File

@ -296,21 +296,12 @@ class StandardGroupChatCommands(CommandContainer):
'room_jid': self.room_jid}
@command(raw=True, empty=True)
@doc(_("Join a group chat given by a jid, optionally using given nickname"))
def join(self, jid, nick):
if not nick:
nick = self.nick
@doc(_("Join a group chat given by a jid"))
def join(self, jid):
if '@' not in jid:
jid = jid + '@' + app.get_server_from_jid(self.room_jid)
try:
app.interface.instances[self.account]['join_gc'].window.present()
except KeyError:
try:
dialogs.JoinGroupchatWindow(account=self.account, room_jid=jid, nick=nick)
except GajimGeneralException:
pass
app.interface.join_gc_minimal(self.account, room_jid=jid)
@command('part', 'close', raw=True, empty=True)
@doc(_("Leave the groupchat, optionally giving a reason, and close tab or window"))

View File

@ -33,6 +33,7 @@ import logging
import locale
import uuid
from distutils.version import LooseVersion as V
from collections import namedtuple
import gi
import nbxmpp
import hashlib
@ -81,6 +82,8 @@ PLUGINS_DIRS = [gajimpaths['PLUGINS_BASE'],
PLUGINS_CONFIG_DIR = gajimpaths['PLUGINS_CONFIG_DIR']
MY_CERT_DIR = gajimpaths['MY_CERT']
RecentGroupchat = namedtuple('RecentGroupchat', ['room', 'server', 'nickname'])
try:
LANG = locale.getdefaultlocale()[0] # en_US, fr_FR, el_GR etc..
except (ValueError, locale.Error):
@ -373,6 +376,16 @@ def get_number_of_connected_accounts(accounts_list = None):
connected_accounts = connected_accounts + 1
return connected_accounts
def get_connected_accounts():
"""
Returns a list of CONNECTED accounts
"""
account_list = []
for account in connections:
if account_is_connected(account):
account_list.append(account)
return account_list
def account_is_connected(account):
if account not in connections:
return False
@ -388,6 +401,11 @@ def zeroconf_is_connected():
return account_is_connected(ZEROCONF_ACC_NAME) and \
config.get_per('accounts', ZEROCONF_ACC_NAME, 'is_zeroconf')
def in_groupchat(account, room_jid):
if room_jid not in gc_connected[account]:
return False
return gc_connected[account][room_jid]
def get_number_of_securely_connected_accounts():
"""
Return the number of the accounts that are SSL/TLS connected
@ -495,6 +513,34 @@ def get_name_from_jid(account, jid):
actor = jid
return actor
def get_muc_domain(account):
return connections[account].muc_jid.get('jabber', None)
def get_recent_groupchats(account):
recent_groupchats = config.get_per(
'accounts', account, 'recent_groupchats').split()
recent_list = []
for groupchat in recent_groupchats:
jid = nbxmpp.JID(groupchat)
recent = RecentGroupchat(
jid.getNode(), jid.getDomain(), jid.getResource())
recent_list.append(recent)
return recent_list
def add_recent_groupchat(account, room_jid, nickname):
recent = config.get_per(
'accounts', account, 'recent_groupchats').split()
full_jid = room_jid + '/' + nickname
if full_jid in recent:
recent.remove(full_jid)
recent.insert(0, full_jid)
if len(recent) > 10:
recent = recent[0:9]
config_value = ' '.join(recent)
config.set_per(
'accounts', account, 'recent_groupchats', config_value)
def get_priority(account, show):
"""
Return the priority an account must have

View File

@ -472,6 +472,10 @@ class MucCapsCache:
if child.getNamespace() == nbxmpp.NS_DATA:
data.append(nbxmpp.DataForm(node=child))
if nbxmpp.NS_MUC not in features:
# Not a MUC, dont cache info
return
self.cache[jid] = self.DiscoInfo(identities, features, data)
def is_cached(self, jid):

View File

@ -174,7 +174,6 @@ class Config:
'history_window_x-position': [ opt_int, 0 ],
'history_window_y-position': [ opt_int, 0 ],
'latest_disco_addresses': [ opt_str, '' ],
'recently_groupchat': [ opt_str, '' ],
'time_stamp': [ opt_str, '[%X] ', _('This option let you customize timestamp that is printed in conversation. For exemple "[%H:%M] " will show "[hour:minute] ". See python doc on strftime for full documentation: http://docs.python.org/lib/module-time.html') ],
'before_nickname': [ opt_str, '', _('Characters that are printed before the nickname in conversations') ],
'after_nickname': [ opt_str, ':', _('Characters that are printed after the nickname in conversations') ],
@ -409,6 +408,7 @@ class Config:
'oauth2_client_id': [ opt_str, '0000000044077801', _('client_id for OAuth 2.0 authentication.')],
'oauth2_redirect_url': [ opt_str, 'https%3A%2F%2Fgajim.org%2Fmsnauth%2Findex.cgi', _('redirect_url for OAuth 2.0 authentication.')],
'opened_chat_controls': [opt_str, '', _('Space separated list of JIDs for which we want to re-open a chat window on next startup.')],
'recent_groupchats': [ opt_str, '' ],
}, {}),
'statusmsg': ({
'message': [ opt_str, '' ],

View File

@ -98,6 +98,9 @@ class ConnectionDisco:
self.disco_info_ids.append(id_)
def discoverMUC(self, jid, callback):
if muc_caps_cache.is_cached(jid):
callback()
return
disco_info = nbxmpp.Iq(typ='get', to=jid, queryNS=nbxmpp.NS_DISCO_INFO)
self.connection.SendAndCallForResponse(
disco_info, self.received_muc_info, {'callback': callback})

View File

@ -689,15 +689,9 @@ class ConversationTextview(GObject.GObject):
app.interface.new_chat_from_jid(self.account, jid)
def on_join_group_chat_menuitem_activate(self, widget, room_jid):
if 'join_gc' in app.interface.instances[self.account]:
instance = app.interface.instances[self.account]['join_gc']
instance.xml.get_object('room_jid_entry').set_text(room_jid)
app.interface.instances[self.account]['join_gc'].window.present()
else:
try:
dialogs.JoinGroupchatWindow(account=self.account, room_jid=room_jid)
except GajimGeneralException:
pass
# Remove ?join
room_jid = room_jid.split('?')[0]
app.interface.join_gc_minimal(self.account, room_jid)
def on_add_to_roster_activate(self, widget, jid):
dialogs.AddNewContactWindow(self.account, jid)
@ -805,7 +799,7 @@ class ConversationTextview(GObject.GObject):
if '?' in word:
(jid, action) = word.split('?')
if action == 'join':
self.on_join_group_chat_menuitem_activate(None, jid)
app.interface.join_gc_minimal(None, jid)
else:
self.on_start_chat_activate(None, jid)
else:

View File

@ -0,0 +1,340 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">18</property>
<property name="margin_right">18</property>
<property name="margin_top">18</property>
<property name="margin_bottom">18</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="jid_label">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">center</property>
<property name="margin_bottom">12</property>
<style>
<class name="bold16"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">3</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="bookmark_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Bookmark this Groupchat</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="margin_top">6</property>
<property name="active">True</property>
<signal name="notify::active" handler="_on_bookmark_activate" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">7</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="autojoin_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Join this Groupchat everytime Gajim is started</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="active">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">8</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">start</property>
<property name="valign">center</property>
<property name="margin_top">6</property>
<property name="label" translatable="yes">Bookmark</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Autojoin</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="account_combo">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="valign">center</property>
<signal name="changed" handler="_on_account_combo_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="nick_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="valign">center</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="GtkLabel" id="account_label">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Account</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Nickname</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="password_label">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Password</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password_entry">
<property name="can_focus">True</property>
<property name="no_show_all">True</property>
<property name="input_purpose">password</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="button_box">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="margin_top">18</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_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="join_button">
<property name="label" translatable="yes">Join</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="_on_join_clicked" swapped="no"/>
<style>
<class name="suggested-action"/>
</style>
</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">9</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="server_label">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Server</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="room_label">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Room</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="recent_label">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Recently</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="room_entry">
<property name="can_focus">True</property>
<property name="no_show_all">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="recent_combo">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<signal name="changed" handler="_on_recent_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="server_combo">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="has_entry">True</property>
<child internal-child="entry">
<object class="GtkEntry">
<property name="can_focus">True</property>
<property name="caps_lock_warning">False</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="search_button">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
<property name="tooltip_text" translatable="yes">Search the rooms on this server</property>
<signal name="clicked" handler="_on_search_clicked" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">system-search-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<object class="GtkHeaderBar" id="headerbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">Join Groupchat</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_clicked" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Join</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="_on_join_clicked" swapped="no"/>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

View File

@ -86,4 +86,6 @@ popover#EmoticonPopover flowboxchild { padding-top: 5px; padding-bottom: 5px; }
background-color: @theme_unfocused_bg_color;
color: @theme_text_color; }
/* Text style */
.bold16 { font-size: 16px; font-weight: bold; }

View File

@ -61,6 +61,7 @@ from gajim.common import app
from gajim.common import helpers
from gajim.common import i18n
from gajim.common import dataforms
from gajim.common.caps_cache import muc_caps_cache
from gajim.common.exceptions import GajimGeneralException
from gajim.common.connection_handlers_events import MessageOutgoingEvent
@ -2350,198 +2351,233 @@ class SubscriptionRequestWindow:
gtkgui_helpers.popup_emoticons_under_button(menu, widget,
self.window.get_window())
class JoinGroupchatWindow:
def __init__(self, account=None, room_jid='', nick='', password='',
automatic=False):
"""
Automatic is a dict like {'invities': []}. If automatic is not empty,
this means room must be automaticaly configured and when done, invities
must be automatically invited
"""
self.window_account = None
if account:
if room_jid != '' and room_jid in app.gc_connected[account] and \
app.gc_connected[account][room_jid]:
ErrorDialog(_('You are already in group chat %s') % room_jid)
raise GajimGeneralException('You are already in this group chat')
if nick == '':
nick = app.nicks[account]
if app.connections[account].connected < 2:
ErrorDialog(_('You are not connected to the server'),
_('You can not join a group chat unless you are connected.'))
raise GajimGeneralException('You must be connected to join a groupchat')
self.window_account = account
class JoinGroupchatWindow(Gtk.ApplicationWindow):
def __init__(self, account, room_jid, password=None, automatic=None):
Gtk.ApplicationWindow.__init__(self)
self.set_name('JoinGroupchat')
self.set_application(app.app)
self.set_show_menubar(False)
self.set_resizable(False)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_title(_('Join Groupchat'))
self.xml = gtkgui_helpers.get_gtk_builder('join_groupchat_window.ui')
account_label = self.xml.get_object('account_label')
account_combobox = self.xml.get_object('account_combobox')
account_label.set_no_show_all(False)
account_combobox.set_no_show_all(False)
liststore = Gtk.ListStore(str)
account_combobox.set_model(liststore)
cell = Gtk.CellRendererText()
account_combobox.pack_start(cell, True)
account_combobox.add_attribute(cell, 'text', 0)
account_combobox.set_active(-1)
# Add accounts, set current as active if it matches 'account'
for acct in [a for a in app.connections if \
app.account_is_connected(a)]:
if app.connections[acct].is_zeroconf:
continue
liststore.append([acct])
if account and account == acct:
account_combobox.set_active(liststore.iter_n_children(None)-1)
self.account = account
self.automatic = automatic
self._empty_required_widgets = []
self.window = self.xml.get_object('join_groupchat_window')
self.window.set_transient_for(app.interface.roster.window)
self._room_jid_entry = self.xml.get_object('room_jid_entry')
self._nickname_entry = self.xml.get_object('nickname_entry')
self._password_entry = self.xml.get_object('password_entry')
self.server_comboboxtext = self.xml.get_object('server_comboboxtext')
self._nickname_entry.set_text(nick)
if password:
self._password_entry.set_text(password)
self.xml.connect_signals(self)
title = None
if account:
# now add us to open windows
app.interface.instances[account]['join_gc'] = self
if len(app.connections) > 1:
title = _('Join Group Chat with account %s') % account
if title is None:
title = _('Join Group Chat')
self.window.set_title(title)
self.browse_button = self.xml.get_object('browse_rooms_button')
self.browse_button.set_sensitive(False)
self.recently_combobox = self.xml.get_object('recently_combobox')
liststore = Gtk.ListStore(str, str)
self.recently_combobox.set_model(liststore)
cell = Gtk.CellRendererText()
self.recently_combobox.pack_start(cell, True)
self.recently_combobox.add_attribute(cell, 'text', 0)
self.recently_groupchat = app.config.get('recently_groupchat').split()
server_list = []
# get the muc server of our server
if 'jabber' in app.connections[account].muc_jid:
server_list.append(app.connections[account].muc_jid['jabber'])
for g in self.recently_groupchat:
r_jid = app.get_jid_without_resource(g)
nick = app.get_resource_from_jid(g)
if nick:
show = '%(nick)s on %(room_jid)s' % {'nick': nick,
'room_jid': r_jid}
else:
show = r_jid
liststore.append([show, g])
server = app.get_server_from_jid(r_jid)
if server not in server_list and not server.startswith('irc'):
server_list.append(server)
for s in server_list:
self.server_comboboxtext.append_text(s)
self._set_room_jid(room_jid)
if len(self.recently_groupchat) == 0:
self.recently_combobox.set_sensitive(False)
elif room_jid == '':
self.recently_combobox.set_active(0)
self._room_jid_entry.select_region(0, -1)
elif room_jid != '':
self.xml.get_object('join_button').grab_focus()
if not self._room_jid_entry.get_text():
self._empty_required_widgets.append(self._room_jid_entry)
if not self._nickname_entry.get_text():
self._empty_required_widgets.append(self._nickname_entry)
if len(self._empty_required_widgets):
self.xml.get_object('join_button').set_sensitive(False)
if account and not app.connections[account].private_storage_supported:
self.xml.get_object('bookmark_checkbutton').set_sensitive(False)
self.password = password
self.requested_jid = None
app.ged.register_event_handler('agent-info-received', ged.GUI1,
self._nec_agent_info_received)
app.ged.register_event_handler('agent-info-error-received', ged.GUI1,
self._nec_agent_info_error_received)
self.room_jid = room_jid
self.account = account
self.minimal_mode = room_jid is not None
self.window.show_all()
glade_objects = ['grid', 'nick_entry', 'account_combo', 'jid_label',
'bookmark_switch', 'autojoin_switch', 'headerbar',
'account_label', 'password_entry', 'password_label',
'join_button', 'button_box', 'server_label',
'server_combo', 'recent_label', 'recent_combo',
'room_label', 'room_entry', 'search_button']
def on_join_groupchat_window_destroy(self, widget):
"""
Close window
"""
app.ged.remove_event_handler('agent-info-received', ged.GUI1,
self._nec_agent_info_received)
app.ged.register_event_handler('agent-info-error-received', ged.GUI1,
self._nec_agent_info_error_received)
if self.window_account and 'join_gc' in app.interface.instances[
self.window_account]:
# remove us from open windows
del app.interface.instances[self.window_account]['join_gc']
minimal_widgets = ['jid_label']
def on_join_groupchat_window_key_press_event(self, widget, event):
if event.keyval == Gdk.KEY_Escape: # ESCAPE
widget.destroy()
extended_widgets = ['server_label', 'server_combo', 'recent_label',
'recent_combo', 'room_label', 'room_entry',
'search_button']
self.builder = gtkgui_helpers.get_gtk_builder(
'join_groupchat_window.ui')
for obj in glade_objects:
setattr(self, obj, self.builder.get_object(obj))
def on_required_entry_changed(self, widget):
if not widget.get_text():
self._empty_required_widgets.append(widget)
self.xml.get_object('join_button').set_sensitive(False)
self.add(self.grid)
if os.environ.get('GTK_CSD', '1') == '1':
self.set_titlebar(self.headerbar)
else:
if widget in self._empty_required_widgets:
self._empty_required_widgets.remove(widget)
if not self._empty_required_widgets and self.account:
self.xml.get_object('join_button').set_sensitive(True)
text = self._room_jid_entry.get_text()
if widget == self._room_jid_entry and text.startswith('xmpp:'):
text = text[5:]
self._room_jid_entry.set_text(text)
if widget == self._room_jid_entry and '@' in text:
# Don't allow @ char in room entry
room_jid, server = text.split('@', 1)
self._room_jid_entry.set_text(room_jid)
if server:
if '?' in server:
server = server.split('?')[0]
self.server_comboboxtext.get_child().set_text(server)
self.server_comboboxtext.grab_focus()
self.button_box.show()
def on_account_combobox_changed(self, widget):
model = widget.get_model()
iter_ = widget.get_active_iter()
self.account = model[iter_][0]
self.on_required_entry_changed(self._nickname_entry)
# Show widgets depending on the mode the window is in
if self.minimal_mode:
for widget in minimal_widgets:
getattr(self, widget).show()
self.jid_label.set_text(room_jid)
else:
for widget in extended_widgets:
getattr(self, widget).show()
self._fill_recent_and_servers(account)
def _set_room_jid(self, full_jid):
room_jid, nick = app.get_room_and_nick_from_fjid(full_jid)
if account is None:
connected_accounts = app.get_connected_accounts()
for acc in connected_accounts:
self.account_combo.append_text(acc)
else:
connected_accounts = [account]
self.account_combo.append_text(account)
self.builder.connect_signals(self)
self.connect('key-press-event', self._on_key_press_event)
self.connect('destroy', self._on_destroy)
if not self.minimal_mode:
app.ged.register_event_handler('agent-info-received', ged.GUI1,
self._nec_agent_info_received)
app.ged.register_event_handler('agent-info-error-received', ged.GUI1,
self._nec_agent_info_error_received)
# Show account combobox if there is more than one account
if len(connected_accounts) > 1:
self.account_combo.show()
self.account_label.show()
# Select first account
self.account_combo.set_active(0)
if not self.minimal_mode:
self.recent_combo.set_active(0)
if self.password is not None:
self.password_entry.set_text(self.password)
# Set bookmark switch sensitive if server supports bookmarks
acc = self.account_combo.get_active_text()
if not app.connections[acc].private_storage_supported:
self.bookmark_switch.set_sensitive(False)
self.autojoin_switch.set_sensitive(False)
# Show password field if we are in extended mode or
# The MUC is passwordprotected
if not self.minimal_mode or muc_caps_cache.supports(
room_jid, 'muc_passwordprotected'):
self.password_entry.show()
self.password_label.show()
self.show_all()
def set_room(self, room_jid):
room, server = app.get_name_and_server_from_jid(room_jid)
self._room_jid_entry.set_text(room)
model = self.server_comboboxtext.get_model()
self.server_comboboxtext.get_child().set_text(server)
if nick:
self._nickname_entry.set_text(nick)
self.room_entry.set_text(room)
self.server_combo.get_child().set_text(server)
def on_recently_combobox_changed(self, widget):
model = widget.get_model()
iter_ = widget.get_active_iter()
full_jid = model[iter_][1]
self._set_room_jid(full_jid)
def _fill_recent_and_servers(self, account):
recent = app.get_recent_groupchats(account)
servers = []
for groupchat in recent:
text = '%s on %s@%s' % (groupchat.nickname,
groupchat.room,
groupchat.server)
self.recent_combo.append_text(text)
servers.append(groupchat.server)
def on_browse_rooms_button_clicked(self, widget):
server = self.server_comboboxtext.get_child().get_text()
for server in set(servers):
self.server_combo.append_text(server)
# Add own Server to ComboBox
muc_domain = app.get_muc_domain(account)
if muc_domain is not None:
self.server_combo.insert_text(0, muc_domain)
def _on_recent_changed(self, combo):
text = combo.get_active_text()
if text is None:
self.server_combo.set_active(0)
return
nickname, _, room_jid = text.split()
room, server = app.get_name_and_server_from_jid(room_jid)
self.room_entry.set_text(room)
self.nick_entry.set_text(nickname)
self.server_combo.get_child().set_text(server)
def _on_account_combo_changed(self, combo):
account = combo.get_active_text()
self.nick_entry.set_text(app.nicks[account])
def _on_key_press_event(self, widget, event):
if event.keyval == Gdk.KEY_Escape:
self.destroy()
if event.keyval == Gdk.KEY_Return:
self._on_join_clicked()
return True
def _on_join_clicked(self, *args):
account = self.account_combo.get_active_text()
nickname = self.nick_entry.get_text()
if not self.minimal_mode:
server = self.server_combo.get_active_text()
room = self.room_entry.get_text()
if room == '':
ErrorDialog(_('Invalid Room'),
_('Please choose a room'), transient_for=self)
return
self.room_jid = '%s@%s' % (room, server)
if app.in_groupchat(account, self.room_jid):
# If we already in the groupchat, join_gc_room will bring
# it to front
app.interface.join_gc_room(account, self.room_jid, nickname, '')
self.destroy()
return
if nickname == '':
ErrorDialog(_('Invalid Nickname'),
_('Please choose a nickname'), transient_for=self)
return
try:
helpers.parse_resource(nickname)
except helpers.InvalidFormat as error:
ErrorDialog(_('Invalid Nickname'), str(error), transient_for=self)
return
try:
helpers.parse_jid(self.room_jid)
except helpers.InvalidFormat as error:
ErrorDialog(_('Invalid JID'), str(error), transient_for=self)
return
if not app.account_is_connected(account):
ErrorDialog(
_('You are not connected to the server'),
_('You can not join a group chat unless you are connected.'),
transient_for=self)
return
password = self.password_entry.get_text()
self._add_bookmark(account, nickname, password)
app.add_recent_groupchat(account, self.room_jid, nickname)
if self.automatic:
app.automatic_rooms[self.account][self.room_jid] = self.automatic
app.interface.join_gc_room(account, self.room_jid, nickname, password)
self.destroy()
def _on_cancel_clicked(self, *args):
self.destroy()
def _on_bookmark_activate(self, switch, param):
self.autojoin_switch.set_sensitive(switch.get_active())
def _add_bookmark(self, account, nickname, password):
if not app.connections[account].private_storage_supported:
return
add_bookmark = self.bookmark_switch.get_active()
if not add_bookmark:
return
autojoin = int(self.autojoin_switch.get_active())
# Add as bookmark, with autojoin and not minimized
name = app.get_nick_from_jid(self.room_jid)
app.interface.add_gc_bookmark(
account, name, self.room_jid, autojoin, 0, password, nickname)
def _on_destroy(self, *args):
if not self.minimal_mode:
del app.interface.instances[self.account]['join_gc']
app.ged.remove_event_handler('agent-info-received', ged.GUI1,
self._nec_agent_info_received)
app.ged.remove_event_handler('agent-info-error-received', ged.GUI1,
self._nec_agent_info_error_received)
def _on_search_clicked(self, widget):
server = self.server_combo.get_active_text()
self.requested_jid = server
app.connections[self.account].discoverInfo(server)
@ -2551,9 +2587,9 @@ class JoinGroupchatWindow:
if obj.jid != self.requested_jid:
return
self.requested_jid = None
window = app.interface.instances[self.account]['join_gc'].window
ErrorDialog(_('Wrong server'), _('%s is not a groupchat server') % \
obj.jid, transient_for=window)
ErrorDialog(_('Wrong server'),
_('%s is not a groupchat server') % obj.jid,
transient_for=self)
def _nec_agent_info_received(self, obj):
if obj.conn.name != self.account:
@ -2562,9 +2598,9 @@ class JoinGroupchatWindow:
return
self.requested_jid = None
if nbxmpp.NS_MUC not in obj.features:
window = app.interface.instances[self.account]['join_gc'].window
ErrorDialog(_('Wrong server'), _('%s is not a groupchat server') % \
obj.jid, transient_for=window)
ErrorDialog(_('Wrong server'),
_('%s is not a groupchat server') % obj.jid,
transient_for=self)
return
if obj.jid in app.interface.instances[self.account]['disco']:
app.interface.instances[self.account]['disco'][obj.jid].window.\
@ -2572,10 +2608,11 @@ class JoinGroupchatWindow:
else:
try:
# Object will add itself to the window dict
import disco
disco.ServiceDiscoveryWindow(self.account, obj.jid,
from gajim.disco import ServiceDiscoveryWindow
ServiceDiscoveryWindow(
self.account, obj.jid,
initial_identities=[{'category': 'conference',
'type': 'text'}])
'type': 'text'}])
except GajimGeneralException:
pass
@ -4389,16 +4426,13 @@ class InvitationReceivedDialog:
sectext += '\n\n' + _('Do you want to accept the invitation?')
def on_yes(checked, text):
try:
if self.is_continued:
app.interface.join_gc_room(self.account, self.room_jid,
app.nicks[self.account], self.password,
is_continued=True)
else:
JoinGroupchatWindow(self.account, self.room_jid,
password=self.password)
except GajimGeneralException:
pass
if self.is_continued:
app.interface.join_gc_room(self.account, self.room_jid,
app.nicks[self.account], self.password,
is_continued=True)
else:
app.interface.join_gc_minimal(
self.account, self.room_jid, password=self.password)
def on_no(text):
app.connections[account].decline_invitation(self.room_jid,
@ -4741,7 +4775,7 @@ class TransformChatToMUC:
if 'jabber' in app.connections[account].muc_jid:
server_list.append(app.connections[account].muc_jid['jabber'])
# add servers or recently joined groupchats
recently_groupchat = app.config.get('recently_groupchat').split()
recently_groupchat = app.config.get_per('accounts', account, 'recent_groupchats').split()
for g in recently_groupchat:
server = app.get_server_from_jid(g)
if server not in server_list and not server.startswith('irc'):

View File

@ -1400,13 +1400,7 @@ class ToplevelAgentBrowser(AgentBrowser):
if not iter_:
return
service = model[iter_][0]
if 'join_gc' not in app.interface.instances[self.account]:
try:
dialogs.JoinGroupchatWindow(self.account, service)
except GajimGeneralException:
pass
else:
app.interface.instances[self.account]['join_gc'].window.present()
app.interface.join_gc_minimal(self.account, service)
def update_actions(self):
if self.execute_button:
@ -1810,14 +1804,11 @@ class MucBrowser(AgentBrowser):
return
service = model[iter_][0]
if 'join_gc' not in app.interface.instances[self.account]:
try:
dialogs.JoinGroupchatWindow(self.account, service)
except GajimGeneralException:
pass
app.interface.join_gc_minimal(self.account, service)
else:
app.interface.instances[self.account]['join_gc']._set_room_jid(
service)
app.interface.instances[self.account]['join_gc'].window.present()
app.interface.instances[self.account]['join_gc'].set_room(service)
app.interface.instances[self.account]['join_gc'].present()
self.window.destroy()
def update_actions(self):
sens = self.window.services_treeview.get_selection().count_selected_rows()

View File

@ -60,7 +60,8 @@ class GajimApplication(Gtk.Application):
'''Main class handling activation and command line.'''
def __init__(self):
Gtk.Application.__init__(self, application_id='org.gajim.Gajim')
Gtk.Application.__init__(self, application_id='org.gajim.Gajim',
flags=Gio.ApplicationFlags.HANDLES_OPEN)
self.add_main_option('version', ord('V'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
@ -89,13 +90,11 @@ class GajimApplication(Gtk.Application):
self.add_main_option('warnings', ord('w'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show all warnings'))
self.add_main_option(GLib.OPTION_REMAINING, 0, GLib.OptionFlags.HIDDEN,
GLib.OptionArg.STRING_ARRAY,
"")
self.connect('handle-local-options', self._handle_local_options)
self.connect('startup', self._startup)
self.connect('activate', self._activate)
self.connect('open', self._open)
self.profile = ''
self.config_path = None
@ -235,6 +234,15 @@ class GajimApplication(Gtk.Application):
from gajim import gui_menu_builder
gui_menu_builder.build_accounts_menu()
def _open(self, application, file, hint, *args):
for arg in file:
uri = arg.get_uri()
# remove xmpp:///
uri = uri[8:]
jid, cmd = uri.split('?')
if cmd == 'join':
self.interface.join_gc_minimal(None, jid)
def do_shutdown(self, *args):
Gtk.Application.do_shutdown(self)
# Shutdown GUI and save config
@ -274,10 +282,6 @@ class GajimApplication(Gtk.Application):
logging_helpers.set_loglevels(loglevel)
if options.contains('warnings'):
self.show_warnings()
if options.contains(GLib.OPTION_REMAINING):
unhandled = options.lookup_value(GLib.OPTION_REMAINING).get_strv()
print('Error: Unhandled arguments: %s' % unhandled)
return 0
return -1
def show_warnings(self):

View File

@ -101,6 +101,7 @@ from gajim import profile_window
from gajim import config
from threading import Thread
from gajim.common import ged
from gajim.common.caps_cache import muc_caps_cache
from gajim.common.configpaths import gajimpaths
config_filename = gajimpaths['CONFIG_FILE']
@ -1757,6 +1758,49 @@ class Interface:
tv = ctrl.conv_textview
tv.scroll_to_end_iter()
def join_gc_minimal(self, account, room_jid, password=None):
if account is not None:
if app.in_groupchat(account, room_jid):
# If we already in the groupchat, join_gc_room will bring
# it to front
app.interface.join_gc_room(account, room_jid, '', '')
return
for bookmark in app.connections[account].bookmarks:
if bookmark['jid'] != room_jid:
continue
app.interface.join_gc_room(
account, room_jid, bookmark['nick'], bookmark['password'])
return
try:
room_jid = helpers.parse_jid(room_jid)
except helpers.InvalidFormat:
dialogs.ErrorDialog('Invalid JID',
transient_for=app.app.get_active_window())
return
connected_accounts = app.get_connected_accounts()
if account is not None and account not in connected_accounts:
connected_accounts = None
if not connected_accounts:
dialogs.ErrorDialog(
_('You are not connected to the server'),
_('You can not join a group chat unless you are connected.'),
transient_for=app.app.get_active_window())
return
def _on_discover_result():
if not muc_caps_cache.is_cached(room_jid):
dialogs.ErrorDialog(_('JID is not a Groupchat'),
transient_for=app.app.get_active_window())
return
dialogs.JoinGroupchatWindow(account, room_jid, password=password)
disco_account = connected_accounts[0] if account is None else account
app.connections[disco_account].discoverMUC(
room_jid, _on_discover_result)
################################################################################
### Methods dealing with emoticons
################################################################################
@ -1953,8 +1997,6 @@ class Interface:
win.set_active_tab(gc_ctrl)
else:
self.roster.on_groupchat_maximized(None, room_jid, account)
dialogs.ErrorDialog(_('You are already in group chat %s') % \
room_jid)
return
invisible_show = app.SHOW_LIST.index('invisible')
@ -2130,6 +2172,7 @@ class Interface:
### Other Methods
################################################################################
@staticmethod
def change_awn_icon_status(status):
if not dbus_support.supported:
@ -2454,7 +2497,7 @@ class Interface:
self.roster.add_groupchat(jid, account)
def add_gc_bookmark(self, account, name, jid, autojoin, minimize, password,
nick):
nick):
"""
Add a bookmark for this account, sorted in bookmark list
"""
@ -2471,10 +2514,6 @@ class Interface:
# check for duplicate entry and respect alpha order
for bookmark in app.connections[account].bookmarks:
if bookmark['jid'] == bm['jid']:
dialogs.ErrorDialog(
_('Bookmark already set'),
_('Group Chat "%s" is already in your bookmarks.') % \
bm['jid'])
return
if bookmark['name'] > bm['name']:
place_found = True
@ -2486,10 +2525,6 @@ class Interface:
app.connections[account].bookmarks.append(bm)
app.connections[account].store_bookmarks()
gui_menu_builder.build_bookmark_menu(account)
dialogs.InformationDialog(
_('Bookmark has been added successfully'),
_('You can manage your bookmarks via Actions menu in your roster.'))
# does JID exist only within a groupchat?
def is_pm_contact(self, fjid, account):

View File

@ -915,10 +915,7 @@ class HtmlTextView(Gtk.TextView):
# app.interface.new_chat_from_jid(self.account, jid)
def on_join_group_chat_menuitem_activate(self, widget, room_jid):
try:
dialogs.JoinGroupchatWindow(room_jid=room_jid)
except GajimGeneralException:
pass
dialogs.JoinGroupchatWindow(None, room_jid)
def on_add_to_roster_activate(self, widget, jid):
dialogs.AddNewContactWindow(self.account, jid)

View File

@ -908,8 +908,6 @@ class SignalObject(dbus.service.Object):
return
if not nick:
nick = ''
app.interface.instances[account]['join_gc'] = \
JoinGroupchatWindow(account, room_jid, nick)
app.interface.join_gc_minimal(account, room_jid)
else:
app.interface.join_gc_room(account, room_jid, nick, password)

View File

@ -3091,15 +3091,11 @@ class RosterWindow:
if app.connections[account].muc_jid[type_]:
# create the room on this muc server
if 'join_gc' in app.interface.instances[account]:
app.interface.instances[account]['join_gc'].window.\
destroy()
try:
app.interface.instances[account]['join_gc'].destroy()
else:
app.interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account,
app.connections[account].muc_jid[type_],
automatic = {'invities': jid_list})
except GajimGeneralException:
continue
dialogs.JoinGroupchatWindow(
account, None, automatic={'invities': jid_list})
break
def on_invite_to_room(self, widget, list_, room_jid, room_account,
@ -3676,13 +3672,10 @@ class RosterWindow:
'invisible'))
return
if 'join_gc' in app.interface.instances[account]:
app.interface.instances[account]['join_gc'].window.present()
app.interface.instances[account]['join_gc'].present()
else:
try:
app.interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account)
except GajimGeneralException:
pass
app.interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account, None)
def on_new_chat_menuitem_activate(self, widget, account):
dialogs.NewChatDialog(account)

View File

@ -651,9 +651,7 @@ if dbus_support.supported:
if not account:
return
if not nick:
nick = ''
gajim.interface.instances[account]['join_gc'] = \
JoinGroupchatWindow(account, room_jid, nick)
gajim.interface.join_gc_minimal(account, room_jid)
else:
gajim.interface.join_gc_room(account, room_jid, nick, password)