Merge branch 'master' into 'master'

New JoinGroupchat/StartChat Dialog

See merge request gajim/gajim!161
This commit is contained in:
Philipp Hörist 2017-12-05 16:52:52 +01:00
commit 1ebcbac58a
28 changed files with 1128 additions and 852 deletions

View file

@ -19,8 +19,6 @@ by D-Bus.
.El
.Ss account_info Aq account
Gets detailed info on a account
.Ss add_contact Ao jid Ac Bq account
Adds contact to roster
.Ss change_avatar Ao picture Ac Bq account
Change the avatar
.Ss change_status Bo status Bc Bo message Bc Bq account
@ -35,18 +33,12 @@ Returns current status (the global one unless account is specified)
Returns current status message (the global one unless account is specified)
.Ss get_unread_msgs_number
Returns number of unread messages
.Ss handle_uri Ao uri Ac Bo account Bc Bq message
Handle a xmpp:/ uri
.Ss help Bq command
Shows a help on specific command
.Ss join_room Ao room Ac Bo nick Bc Bo password Bc Bq account
Join a MUC room
.Ss list_accounts
Prints a list of registered accounts
.Ss list_contacts Bq account
Prints a list of all contacts in the roster. Each contact appears on a separate line
.Ss open_chat Ao jid Ac Bo account Bc Bq message
Shows the chat dialog so that you can send messages to a contact
.Ss prefs_del Aq key
Deletes a preference item
.Ss prefs_list
@ -71,8 +63,6 @@ Sends custom XML
Changes the priority of account or accounts
.Ss show_next_pending_event
Pops up a window with the next pending event
.Ss start_chat Aq account
Opens 'Start Chat' dialog
.Ss toggle_ipython
Shows or hides the ipython window
.Ss toggle_roster_appearance

View file

@ -9,5 +9,4 @@ TryExec=gajim-remote
StartupNotify=false
Terminal=false
Type=Application
MimeType=x-scheme-handler/xmpp;
NoDisplay=true

View file

@ -13,3 +13,4 @@ StartupNotify=true
StartupWMClass=Gajim
Terminal=false
Type=Application
MimeType=x-scheme-handler/xmpp;

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
@ -43,6 +44,11 @@ class AppActions():
def __init__(self, application: Gtk.Application):
self.application = application
# General Actions
def on_add_contact_jid(self, action, param):
dialogs.AddNewContactWindow(None, param.get_string())
# Application Menu Actions
def on_preferences(self, action, param):
@ -74,6 +80,12 @@ class AppActions():
def on_quit(self, action, param):
interface.roster.on_quit_request()
def on_new_chat(self, action, param):
if 'start_chat' in app.interface.instances:
app.interface.instances['start_chat'].present()
else:
app.interface.instances['start_chat'] = dialogs.StartChatDialog()
# Accounts Actions
def on_profile(self, action, param):
@ -116,20 +128,14 @@ 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())
def on_new_chat(self, action, param):
dialogs.NewChatDialog(param.get_string())
def on_single_message(self, action, param):
dialogs.SingleMessageWindow(param.get_string(), action='send')

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

@ -411,6 +411,16 @@ def get_uf_show(show, use_mnemonic = False):
uf_show = Q_('?contact has status:Has errors')
return uf_show
def get_css_show_color(show):
if show in ('online', 'chat', 'invisible'):
return 'status-online'
elif show in ('offline', 'not in roster', 'requested'):
return None
elif show in ('xa', 'dnd'):
return 'status-dnd'
elif show in ('away'):
return 'status-away'
def get_uf_sub(sub):
if sub == 'none':
uf_sub = Q_('?Subscription we already have:None')

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

@ -28,15 +28,6 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="start_chat_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">_Start Chat...</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="join_group_chat_menuitem">
<property name="visible">True</property>

View file

@ -72,6 +72,11 @@
<attribute name="action">app.accounts</attribute>
<attribute name="accel">&lt;Primary&gt;&lt;Shift&gt;A</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Start Chat</attribute>
<attribute name="action">app.start-chat</attribute>
<attribute name="accel">&lt;Primary&gt;N</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Bookmarks</attribute>
<attribute name="action">app.bookmarks</attribute>

View file

@ -1,302 +1,340 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.20.1 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkImage" id="image1">
<requires lib="gtk+" version="3.20"/>
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-find</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
<object class="GtkWindow" id="join_groupchat_window">
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="title" translatable="yes">Join Group Chat</property>
<property name="resizable">False</property>
<property name="type_hint">dialog</property>
<signal name="destroy" handler="on_join_groupchat_window_destroy" swapped="no"/>
<signal name="key-press-event" handler="on_join_groupchat_window_key_press_event" swapped="no"/>
<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="GtkBox" id="box1">
<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="orientation">vertical</property>
<property name="spacing">12</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="GtkGrid" id="grid1">
<object class="GtkButton">
<property name="label">gtk-cancel</property>
<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="GtkEntry" id="room_jid_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="activates_default">True</property>
<signal name="changed" handler="on_required_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</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="label" translatable="yes">Account</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="account_combobox">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<signal name="changed" handler="on_account_combobox_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label225">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Recently:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="recently_combobox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_recently_combobox_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label142">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Nickname:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</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="activates_default">True</property>
<signal name="changed" handler="on_required_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label143">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Room:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Server:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label145">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="activates_default">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="bookmark_checkbutton">
<property name="label" translatable="yes">_Bookmark this room</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_bookmark_checkbutton_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="auto_join_checkbutton">
<property name="label" translatable="yes">Join this room _automatically when I connect</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkComboBoxText" id="server_comboboxtext">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="has_entry">True</property>
<child internal-child="entry">
<object class="GtkEntry" id="comboboxtext-entry">
<property name="can_focus">True</property>
<signal name="changed" handler="on_server_entry_changed" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="browse_rooms_button">
<property name="label" translatable="yes">Bro_wse Rooms</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image1</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_browse_rooms_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</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">4</property>
</packing>
</child>
<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">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<object class="GtkButton" id="join_button">
<property name="label" translatable="yes">Join</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label">gtk-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_stock">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="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="has_default">True</property>
<property name="receives_default">False</property>
<property name="image">image2</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_join_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<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">False</property>
<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

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkBox" id="box">
<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="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="is_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="listbox">
<property name="name">StartChatListBox</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">browse</property>
<property name="activate_on_single_click">False</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

View file

@ -86,4 +86,16 @@ popover#EmoticonPopover flowboxchild { padding-top: 5px; padding-bottom: 5px; }
background-color: @theme_unfocused_bg_color;
color: @theme_text_color; }
/* StartChatListBox */
#StartChatListBox > row { border-bottom: 1px solid; border-color: @theme_unfocused_bg_color; }
#StartChatListBox > row:last-child { border-bottom: 0px}
#StartChatListBox > row.activatable:active { box-shadow: none; }
#StartChatListBox > row { padding: 10px 20px 10px 10px; }
#StartChatListBox > row:not(.activatable) label { color: @insensitive_fg_color }
/* Text style */
.bold16 { font-size: 16px; font-weight: bold; }
.status-away { color: #ff8533;}
.status-dnd { color: #e62e00;}
.status-online { color: #66bf10;}

View file

@ -38,6 +38,7 @@ from gi.repository import GLib
import os
import nbxmpp
import time
import locale
from gajim import gtkgui_helpers
from gajim import vcard
@ -61,6 +62,8 @@ from gajim.common import app
from gajim.common import helpers
from gajim.common import i18n
from gajim.common import dataforms
from gajim.common.const import AvatarSize
from gajim.common.caps_cache import muc_caps_cache
from gajim.common.exceptions import GajimGeneralException
from gajim.common.connection_handlers_events import MessageOutgoingEvent
@ -2350,199 +2353,233 @@ class SubscriptionRequestWindow:
gtkgui_helpers.popup_emoticons_under_button(menu, widget,
self.window.get_window())
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'))
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
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)
@ -2552,9 +2589,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:
@ -2563,9 +2600,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.\
@ -2573,99 +2610,14 @@ 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
def on_server_entry_changed(self, widget):
if not widget.get_text():
self.browse_button.set_sensitive(False)
else:
self.browse_button.set_sensitive(True)
def on_cancel_button_clicked(self, widget):
"""
When Cancel button is clicked
"""
self.window.destroy()
def on_bookmark_checkbutton_toggled(self, widget):
auto_join_checkbutton = self.xml.get_object('auto_join_checkbutton')
if widget.get_active():
auto_join_checkbutton.set_sensitive(True)
else:
auto_join_checkbutton.set_sensitive(False)
def on_join_button_clicked(self, widget):
"""
When Join button is clicked
"""
if not self.account:
ErrorDialog(_('Invalid Account'),
_('You have to choose an account from which you want to join the '
'groupchat.'))
return
nickname = self._nickname_entry.get_text()
server = self.server_comboboxtext.get_child().get_text()
room = self._room_jid_entry.get_text().strip()
room_jid = room + '@' + server
password = self._password_entry.get_text()
try:
nickname = helpers.parse_resource(nickname)
except Exception:
ErrorDialog(_('Invalid Nickname'),
_('The nickname contains invalid characters.'))
return
user, server, resource = helpers.decompose_jid(room_jid)
if not user or not server or resource:
ErrorDialog(_('Invalid group chat JID'),
_('Please enter the group chat JID as room@server.'))
return
try:
room_jid = helpers.parse_jid(room_jid)
except Exception:
ErrorDialog(_('Invalid group chat JID'),
_('The group chat JID contains invalid characters.'))
return
if app.contacts.get_contact(self.account, room_jid) and \
not app.contacts.get_contact(self.account, room_jid).is_groupchat():
ErrorDialog(_('This is not a group chat'),
_('%(room_jid)s is already in your roster. Please check if '
'%(room_jid)s is a correct group chat name. If it is, delete '
'it from your roster and try joining the group chat again.') % \
{'room_jid': room_jid, 'room_jid': room_jid})
return
full_jid = room_jid + '/' + nickname
if full_jid in self.recently_groupchat:
self.recently_groupchat.remove(full_jid)
self.recently_groupchat.insert(0, full_jid)
if len(self.recently_groupchat) > 10:
self.recently_groupchat = self.recently_groupchat[0:10]
app.config.set('recently_groupchat',
' '.join(self.recently_groupchat))
if self.xml.get_object('bookmark_checkbutton').get_active():
if self.xml.get_object('auto_join_checkbutton').get_active():
autojoin = '1'
else:
autojoin = '0'
# Add as bookmark, with autojoin and not minimized
name = app.get_nick_from_jid(room_jid)
app.interface.add_gc_bookmark(self.account, name, room_jid,
autojoin, autojoin, password, nickname)
if self.automatic:
app.automatic_rooms[self.account][room_jid] = self.automatic
app.interface.join_gc_room(self.account, room_jid, nickname, password)
self.window.destroy()
class SynchroniseSelectAccountDialog:
def __init__(self, account):
# 'account' can be None if we are about to create our first one
@ -2807,59 +2759,323 @@ class SynchroniseSelectContactsDialog:
iter_ = model.iter_next(iter_)
self.dialog.destroy()
class NewChatDialog(InputDialog):
def __init__(self, account):
self.account = account
class StartChatDialog(Gtk.ApplicationWindow):
def __init__(self):
# Must be before ApplicationWindow.__init__
# or we get our own window
active_window = app.app.get_active_window()
if len(app.connections) > 1:
title = _('Start Chat with account %s') % account
Gtk.ApplicationWindow.__init__(self)
self.set_name('StartChatDialog')
self.set_application(app.app)
mode = app.config.get('one_message_window') != 'always_with_roster'
if active_window == app.interface.roster.window and mode:
self.set_position(Gtk.WindowPosition.CENTER)
else:
title = _('Start Chat')
prompt_text = _('Fill in the nickname or the JID of the contact you '
'would like\nto send a chat message to:')
InputDialog.__init__(self, title, prompt_text, is_modal=False)
self.input_entry.set_placeholder_text(_('Nickname / JID'))
self.set_transient_for(active_window)
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
self.set_show_menubar(False)
self.set_title(_('Start new Conversation'))
self.set_default_size(-1, 400)
self.completion_dict = {}
liststore = gtkgui_helpers.get_completion_liststore(self.input_entry)
self.completion_dict = helpers.get_contact_dict_for_account(account)
# add all contacts to the model
keys = sorted(self.completion_dict.keys())
for jid in keys:
contact = self.completion_dict[jid]
img = app.interface.jabber_state_images['16'][contact.show]
liststore.append((img.get_pixbuf(), jid))
self.builder = gtkgui_helpers.get_gtk_builder(
'start_chat_dialog.ui')
self.listbox = self.builder.get_object('listbox')
self.search_entry = self.builder.get_object('search_entry')
self.box = self.builder.get_object('box')
self.ok_handler = self.new_chat_response
okbutton = self.xml.get_object('okbutton')
okbutton.connect('clicked', self.on_okbutton_clicked)
cancelbutton = self.xml.get_object('cancelbutton')
cancelbutton.connect('clicked', self.on_cancelbutton_clicked)
self.dialog.set_transient_for(app.interface.roster.window)
self.dialog.show_all()
self.add(self.box)
def new_chat_response(self, jid):
"""
Called when ok button is clicked
"""
if app.connections[self.account].connected <= 1:
#if offline or connecting
ErrorDialog(_('Connection not available'),
_('Please make sure you are connected with "%s".') % self.account)
return
self.new_contact_row_visible = False
self.new_contact_rows = {}
self.new_groupchat_rows = {}
self.accounts = app.connections.keys()
self.add_contacts()
self.add_groupchats()
if jid in self.completion_dict:
jid = self.completion_dict[jid].jid
self.search_entry.connect('search-changed',
self._on_search_changed)
self.search_entry.connect('next-match',
self._select_new_match, 'next')
self.search_entry.connect('previous-match',
self._select_new_match, 'prev')
self.search_entry.connect('stop-search',
lambda *args: self.search_entry.set_text(''))
self.listbox.set_filter_func(self._filter_func, None)
self.listbox.set_sort_func(self._sort_func, None)
self.listbox.connect('row-activated', self._on_row_activated)
self.connect('key-press-event', self._on_key_press)
self.connect('destroy', self._destroy)
self.select_first_row()
self.show_all()
def add_contacts(self):
show_account = len(self.accounts) > 1
for account in self.accounts:
self.new_contact_rows[account] = None
for jid in app.contacts.get_jid_list(account):
contact = app.contacts.get_contact_with_highest_priority(
account, jid)
if contact.is_groupchat():
continue
row = ContactRow(account, contact, jid,
contact.get_shown_name(), show_account)
self.listbox.add(row)
def add_groupchats(self):
show_account = len(self.accounts) > 1
for account in self.accounts:
self.new_groupchat_rows[account] = None
bookmarks = app.connections[account].bookmarks
groupchats = {}
for bookmark in bookmarks:
groupchats[bookmark['jid']] = bookmark['name']
for jid in app.contacts.get_gc_list(account):
if jid in groupchats:
continue
groupchats[jid] = None
for jid in groupchats:
name = groupchats[jid]
if name is None:
name = app.get_nick_from_jid(groupchats[jid])
row = ContactRow(account, None, jid, name,
show_account, True)
self.listbox.add(row)
def _on_row_activated(self, listbox, row):
row = row.get_child()
self._start_new_chat(row)
def _on_key_press(self, widget, event):
if event.keyval in (Gdk.KEY_Down, Gdk.KEY_Tab):
self.search_entry.emit('next-match')
return True
elif (event.state == Gdk.ModifierType.SHIFT_MASK and
event.keyval == Gdk.KEY_ISO_Left_Tab):
self.search_entry.emit('previous-match')
return True
elif event.keyval == Gdk.KEY_Up:
self.search_entry.emit('previous-match')
return True
elif event.keyval == Gdk.KEY_Escape:
if self.search_entry.get_text() != '':
self.search_entry.emit('stop-search')
else:
self.destroy()
return True
elif event.keyval == Gdk.KEY_Return:
row = self.listbox.get_selected_row()
if row is not None:
row.emit('activate')
return True
else:
self.search_entry.grab_focus_without_selecting()
def _start_new_chat(self, row):
if row.new:
if not app.account_is_connected(row.account):
ErrorDialog(
_('You are not connected to the server'),
_('You can not start a new conversation'
' unless you are connected.'),
transient_for=self)
return
try:
jid = helpers.parse_jid(jid)
helpers.parse_jid(row.jid)
except helpers.InvalidFormat as e:
ErrorDialog(_('Invalid JID'), str(e))
ErrorDialog(_('Invalid JID'), str(e), transient_for=self)
return
except:
ErrorDialog(_('Invalid JID'), _('Unable to parse "%s".') % jid)
if row.groupchat:
app.interface.join_gc_minimal(row.account, row.jid)
else:
app.interface.new_chat_from_jid(row.account, row.jid)
self.destroy()
def _on_search_changed(self, entry):
search_text = entry.get_text()
if '@' in search_text:
self._add_new_jid_row()
self._update_new_jid_rows(search_text)
else:
self._remove_new_jid_row()
self.listbox.invalidate_filter()
def _add_new_jid_row(self):
if self.new_contact_row_visible:
return
for account in self.new_contact_rows:
show_account = len(self.accounts) > 1
row = ContactRow(account, None, '', None, show_account)
self.new_contact_rows[account] = row
group_row = ContactRow(account, None, '', None, show_account, True)
self.new_groupchat_rows[account] = group_row
self.listbox.add(row)
self.listbox.add(group_row)
row.get_parent().show_all()
self.new_contact_row_visible = True
def _remove_new_jid_row(self):
if not self.new_contact_row_visible:
return
for account in self.new_contact_rows:
self.listbox.remove(self.new_contact_rows[account].get_parent())
self.listbox.remove(self.new_groupchat_rows[account].get_parent())
self.new_contact_row_visible = False
def _update_new_jid_rows(self, search_text):
for account in self.new_contact_rows:
self.new_contact_rows[account].update_jid(search_text)
self.new_groupchat_rows[account].update_jid(search_text)
def _select_new_match(self, entry, direction):
selected_row = self.listbox.get_selected_row()
index = selected_row.get_index()
if direction == 'next':
index += 1
else:
index -= 1
while True:
new_selected_row = self.listbox.get_row_at_index(index)
if new_selected_row is None:
return
app.interface.new_chat_from_jid(self.account, jid)
if new_selected_row.get_child_visible():
self.listbox.select_row(new_selected_row)
new_selected_row.grab_focus()
return
if direction == 'next':
index += 1
else:
index -= 1
def select_first_row(self):
first_row = self.listbox.get_row_at_y(0)
self.listbox.select_row(first_row)
def _filter_func(self, row, user_data):
search_text = self.search_entry.get_text().lower()
search_text_list = search_text.split()
row_text = row.get_child().get_search_text().lower()
for text in search_text_list:
if text not in row_text:
GLib.timeout_add(50, self.select_first_row)
return
GLib.timeout_add(50, self.select_first_row)
return True
@staticmethod
def _sort_func(row1, row2, user_data):
name1 = row1.get_child().get_search_text()
name2 = row2.get_child().get_search_text()
account1 = row1.get_child().account
account2 = row2.get_child().account
is_groupchat1 = row1.get_child().groupchat
is_groupchat2 = row2.get_child().groupchat
new1 = row1.get_child().new
new2 = row2.get_child().new
result = locale.strcoll(account1.lower(), account2.lower())
if result != 0:
return result
if new1 != new2:
return 1 if new1 else -1
if is_groupchat1 != is_groupchat2:
return 1 if is_groupchat1 else -1
return locale.strcoll(name1.lower(), name2.lower())
@staticmethod
def _destroy(*args):
del app.interface.instances['start_chat']
class ContactRow(Gtk.Grid):
def __init__(self, account, contact, jid, name, show_account,
groupchat=False):
Gtk.Grid.__init__(self)
self.set_column_spacing(12)
self.set_size_request(260, -1)
self.account = account
self.account_label = app.config.get_per(
'accounts', account, 'account_label') or account
self.show_account = show_account
self.jid = jid
self.contact = contact
self.name = name
self.groupchat = groupchat
self.new = jid == ''
if self.groupchat:
if self.new:
muc_image = app.interface.jabber_state_images['32']['muc_inactive']
else:
muc_image = app.interface.jabber_state_images['32']['muc_active']
image = Gtk.Image.new_from_pixbuf(muc_image.get_pixbuf())
else:
avatar = app.contacts.get_avatar(account, jid, AvatarSize.ROSTER)
if avatar is None:
image = Gtk.Image.new_from_icon_name(
'avatar-default', Gtk.IconSize.DND)
else:
image = Gtk.Image.new_from_pixbuf(avatar)
self.add(image)
middle_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
middle_box.set_hexpand(True)
if self.name is None:
if self.groupchat:
self.name = _('New Groupchat')
else:
self.name = _('New Contact')
self.name_label = Gtk.Label(self.name)
self.name_label.set_halign(Gtk.Align.START)
self.name_label.get_style_context().add_class('bold16')
status = contact.show if contact else 'offline'
css_class = helpers.get_css_show_color(status)
if css_class is not None:
self.name_label.get_style_context().add_class(css_class)
middle_box.add(self.name_label)
self.jid_label = Gtk.Label(jid)
self.jid_label.set_halign(Gtk.Align.START)
middle_box.add(self.jid_label)
self.add(middle_box)
if show_account:
account_label = Gtk.Label(self.account_label)
account_label.set_halign(Gtk.Align.START)
account_label.set_valign(Gtk.Align.START)
right_box = Gtk.Box()
right_box.set_vexpand(True)
right_box.add(account_label)
self.add(right_box)
self.show_all()
def update_jid(self, jid):
self.jid = jid
self.jid_label.set_text(jid)
def get_search_text(self):
if self.contact is None and not self.groupchat:
return self.jid
if self.show_account:
return '%s %s %s' % (self.name, self.jid, self.account_label)
return '%s %s' % (self.name, self.jid)
class ChangePasswordDialog:
def __init__(self, account, on_response, transient_for=None):
@ -4476,16 +4692,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,
@ -4828,7 +5041,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,28 @@ 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)
elif cmd == 'roster':
self.activate_action('add-contact', GLib.Variant('s', jid))
elif cmd == 'message':
from gajim.common import app
accounts = list(app.connections.keys())
if not accounts:
continue
if len(accounts) == 1:
app.interface.new_chat_from_jid(accounts[0], jid)
else:
self.activate_action('start-chat')
start_chat_window = app.interface.instances['start_chat']
start_chat_window.search_entry.set_text(jid)
def do_shutdown(self, *args):
Gtk.Application.do_shutdown(self)
# Shutdown GUI and save config
@ -274,10 +295,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):
@ -301,7 +318,6 @@ class GajimApplication(Gtk.Application):
self.account_actions = [
('-start-single-chat', action.on_single_message, 'online', 's'),
('-start-chat', action.on_new_chat, 'online', 's'),
('-join-groupchat', action.on_join_gc, 'online', 's'),
('-add-contact', action.on_add_contact, 'online', 's'),
('-services', action.on_service_disco, 'online', 's'),
@ -342,6 +358,7 @@ class GajimApplication(Gtk.Application):
('accounts', action.on_accounts),
('add-account', action.on_add_account),
('manage-proxies', action.on_manage_proxies),
('start-chat', action.on_new_chat),
('bookmarks', action.on_manage_bookmarks),
('history-manager', action.on_history_manager),
('preferences', action.on_preferences),
@ -355,6 +372,10 @@ class GajimApplication(Gtk.Application):
('faq', action.on_faq),
]
act = Gio.SimpleAction.new('add-contact', GLib.VariantType.new('s'))
act.connect("activate", action.on_add_contact_jid)
self.add_action(act)
for action in self.general_actions:
action_name, func = action
act = Gio.SimpleAction.new(action_name, None)

View file

@ -125,18 +125,6 @@ class GajimRemote:
' "sync with global status" option set'), False)
]
],
'open_chat': [
_('Shows the chat dialog so that you can send messages to a contact'),
[
('jid', _('JID of the contact that you want to chat with'),
True),
(Q_('?CLI:account'), _('if specified, contact is taken from the '
'contact list of this account'), False),
(Q_('?CLI:message'),
_('message content. The account must be specified or ""'),
False)
]
],
'send_chat_message': [
_('Sends new chat message to a contact in the roster. Both OpenPGP key '
'and account are optional. If you want to set only \'account\', '
@ -225,13 +213,6 @@ class GajimRemote:
]
],
'add_contact': [
_('Adds contact to roster'),
[
(_('jid'), _('JID of the contact'), True),
(Q_('?CLI:account'), _('Adds new contact to this account'), False)
]
],
'get_status': [
_('Returns current status (the global one unless account is specified)'),
@ -251,12 +232,7 @@ class GajimRemote:
_('Returns number of unread messages'),
[ ]
],
'start_chat': [
_('Opens \'Start Chat\' dialog'),
[
(Q_('?CLI:account'), _('Starts chat, using this account'), True)
]
],
'send_xml': [
_('Sends custom XML'),
[
@ -275,25 +251,7 @@ class GajimRemote:
False)
]
],
'handle_uri': [
_('Handle a xmpp:/ URI'),
[
(Q_('?CLI:uri'), _('URI to handle'), True),
(Q_('?CLI:account'), _('Account in which you want to handle it'),
False),
(Q_('?CLI:message'), _('Message content'), False)
]
],
'join_room': [
_('Join a MUC room'),
[
(Q_('?CLI:room'), _('Room JID'), True),
(Q_('?CLI:nick'), _('Nickname to use'), False),
(Q_('?CLI:password'), _('Password to enter the room'), False),
(Q_('?CLI:account'), _('Account from which you want to enter the '
'room'), False)
]
],
'check_gajim_running': [
_('Check if Gajim is running'),
[]
@ -317,8 +275,6 @@ class GajimRemote:
else:
print(self.compose_help().encode(PREFERRED_ENCODING))
sys.exit(0)
if self.command == 'handle_uri':
self.handle_uri()
if self.command == 'check_gajim_running':
print(self.check_gajim_running())
sys.exit(0)
@ -342,10 +298,8 @@ class GajimRemote:
Print retrieved result to the output
"""
if res is not None:
if self.command in ('open_chat', 'send_chat_message',
'send_single_message', 'start_chat'):
if self.command in ('send_message', 'send_single_message'):
self.argv_len -= 2
if self.command in ('send_chat_message', 'send_single_message'):
self.argv_len -= 2
if res is False:
if self.argv_len < 4:
@ -533,66 +487,6 @@ class GajimRemote:
# add empty string for missing args
self.arguments += ['']*(len(args)-i)
def handle_uri(self):
if len(sys.argv) < 3:
send_error(_('No URI given'))
if not sys.argv[2].startswith('xmpp:'):
send_error(_('Wrong URI'))
sys.argv[2] = sys.argv[2][5:]
uri = sys.argv[2]
if not '?' in uri:
self.command = sys.argv[1] = 'open_chat'
return
jid, args = uri.split('?', 1)
try:
jid = urllib.parse.unquote(jid)
except UnicodeDecodeError:
pass
args = args.split(';')
action = None
options = {}
if args:
action = args[0]
for arg in args[1:]:
opt = arg.split('=', 1)
if len(opt) != 2:
continue
options[opt[0]] = opt[1]
if action == 'message':
self.command = sys.argv[1] = 'open_chat'
sys.argv[2] = jid
if 'body' in options:
# Open chat window and paste the text in the input message
# dialog
message = options['body']
try:
message = urllib.parse.unquote(message)
except UnicodeDecodeError:
pass
if len(sys.argv) == 4:
# jid in the sys.argv
sys.argv.append(message)
else:
sys.argv.append('')
sys.argv.append(message)
sys.argv[3] = ''
sys.argv[4] = message
return
sys.argv[2] = jid
if action == 'join':
self.command = sys.argv[1] = 'join_room'
# Move account parameter from position 3 to 5
sys.argv.append('')
sys.argv.append(sys.argv[3])
sys.argv[3] = ''
return
if action == 'roster':
# Add contact to roster
self.command = sys.argv[1] = 'add_contact'
return
sys.exit(0)
def call_remote_method(self):
"""
Calls self.method with arguments from sys.argv[2:]

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:
@ -2403,8 +2446,8 @@ class Interface:
pixbuf = None
try:
if size is not None:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
path, size, size)
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
path, size, size, False)
else:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
except GLib.GError as error:
@ -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

@ -722,7 +722,6 @@ def get_account_menu(account):
('-join-groupchat', _('Join Group Chat')),
('-profile', _('Profile')),
('-services', _('Discover Services')),
('-start-chat', _('Start Chat...')),
('-start-single-chat', _('Send Single Message...')),
('Advanced', [
('-archive', _('Archiving Preferences')),

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

@ -35,7 +35,7 @@ import mimetypes
from gajim.common import app
from gajim.common import helpers
from time import time
from gajim.dialogs import AddNewContactWindow, NewChatDialog, JoinGroupchatWindow
from gajim.dialogs import AddNewContactWindow, JoinGroupchatWindow
from gajim.common import ged
from gajim.common.connection_handlers_events import MessageOutgoingEvent
from gajim.common.connection_handlers_events import GcMessageOutgoingEvent
@ -849,7 +849,7 @@ class SignalObject(dbus.service.Object):
if not account:
# error is shown in gajim-remote check_arguments(..)
return DBUS_BOOLEAN(False)
NewChatDialog(account)
app.app.activate_action('start-chat')
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
@ -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,16 +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
def on_new_chat_menuitem_activate(self, widget, account):
dialogs.NewChatDialog(account)
app.interface.instances[account]['join_gc'] = \
dialogs.JoinGroupchatWindow(account, None)
def on_show_transports_action(self, action, param):
app.config.set('show_transports_group', param.get_boolean())
@ -4934,7 +4924,6 @@ class RosterWindow:
account_context_menu = xml.get_object('account_context_menu')
status_menuitem = xml.get_object('status_menuitem')
start_chat_menuitem = xml.get_object('start_chat_menuitem')
join_group_chat_menuitem = xml.get_object(
'join_group_chat_menuitem')
add_contact_menuitem = xml.get_object('add_contact_menuitem')
@ -5022,9 +5011,6 @@ class RosterWindow:
execute_command_menuitem.connect('activate',
self.on_execute_command, contact, account)
start_chat_menuitem.connect('activate',
self.on_new_chat_menuitem_activate, account)
gc_sub_menu = Gtk.Menu() # gc is always a submenu
join_group_chat_menuitem.set_submenu(gc_sub_menu)
self.add_bookmarks_list(gc_sub_menu, account)
@ -5033,7 +5019,7 @@ class RosterWindow:
if app.connections[account].connected < 2:
for widget in (add_contact_menuitem, service_discovery_menuitem,
join_group_chat_menuitem, execute_command_menuitem,
pep_menuitem, start_chat_menuitem):
pep_menuitem):
widget.set_sensitive(False)
else:
xml = gtkgui_helpers.get_gtk_builder('zeroconf_context_menu.ui')

View file

@ -185,7 +185,7 @@ class StatusIcon:
dialogs.SingleMessageWindow(account, action='send')
def on_new_chat(self, widget, account):
dialogs.NewChatDialog(account)
app.app.activate_action('start-chat')
def make_menu(self, event_button, event_time):
"""

View file

@ -628,7 +628,7 @@ if dbus_support.supported:
if not account:
# error is shown in gajim-remote check_arguments(..)
return DBUS_BOOLEAN(False)
NewChatDialog(account)
app.app.activate_action('start-chat')
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
@ -651,16 +651,14 @@ 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)
from gajim.common import app
from gajim.common import helpers
from time import time
from gajim.dialogs import AddNewContactWindow, NewChatDialog, JoinGroupchatWindow
from gajim.dialogs import AddNewContactWindow, JoinGroupchatWindow
from gajim.plugins import GajimPlugin
from gajim.plugins.helpers import log_calls, log