Move some dialogs into gtk module
This commit is contained in:
parent
bff5f14b92
commit
3a3b5aff20
|
@ -6,7 +6,6 @@ from gajim.common import app
|
|||
from gajim import gtkgui_helpers
|
||||
from gajim import gui_menu_builder
|
||||
from gajim.common import passwords
|
||||
from gajim import dialogs
|
||||
from gajim import config
|
||||
from gajim.common import helpers
|
||||
from gajim.common import ged
|
||||
|
@ -14,6 +13,8 @@ from gajim.common.connection import Connection
|
|||
from gajim.common.zeroconf.connection_zeroconf import ConnectionZeroconf
|
||||
from gajim.options_dialog import OptionsDialog, OptionsBox
|
||||
from gajim.common.const import Option, OptionKind, OptionType
|
||||
from gajim.gtk import ConfirmationDialog
|
||||
from gajim.gtk import YesNoDialog
|
||||
|
||||
|
||||
class AccountsWindow(Gtk.ApplicationWindow):
|
||||
|
@ -143,7 +144,7 @@ class AccountsWindow(Gtk.ApplicationWindow):
|
|||
account, 'offline', _('Be right back.'))
|
||||
GLib.timeout_add(500, login, account, show_before, status_before)
|
||||
|
||||
dialogs.YesNoDialog(
|
||||
YesNoDialog(
|
||||
_('Relogin now?'),
|
||||
_('If you want all the changes to apply instantly, '
|
||||
'you must relogin.'),
|
||||
|
@ -197,7 +198,7 @@ class AccountsWindow(Gtk.ApplicationWindow):
|
|||
app.interface.instances[account]['remove_account'] = \
|
||||
config.RemoveAccountWindow(account)
|
||||
if win_opened:
|
||||
dialogs.ConfirmationDialog(
|
||||
ConfirmationDialog(
|
||||
_('You have opened chat in account %s') % account,
|
||||
_('All chat and groupchat windows will be closed. '
|
||||
'Do you want to continue?'),
|
||||
|
|
|
@ -33,7 +33,7 @@ from gajim.common import dataforms
|
|||
from gajim.common import ged
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import HigDialog
|
||||
from gajim import dataforms_widget
|
||||
|
||||
class CommandWindow:
|
||||
|
@ -322,7 +322,7 @@ class CommandWindow:
|
|||
dialog.destroy()
|
||||
cb()
|
||||
|
||||
dialog = dialogs.HigDialog(self.window, Gtk.MessageType.WARNING,
|
||||
dialog = HigDialog(self.window, Gtk.MessageType.WARNING,
|
||||
Gtk.ButtonsType.YES_NO, _('Cancel confirmation'),
|
||||
_('You are in process of executing command. Do you really want to '
|
||||
'cancel it?'), on_response_yes=on_yes)
|
||||
|
|
|
@ -28,14 +28,21 @@ import gajim.plugins.gui
|
|||
from gajim import history_window
|
||||
from gajim import disco
|
||||
from gajim.gtk.history_sync import HistorySyncAssistant
|
||||
from gajim.server_info import ServerInfoDialog
|
||||
from gajim.gtk.server_info import ServerInfoDialog
|
||||
from gajim.gtk.mam_preferences import MamPreferences
|
||||
from gajim.gtk import JoinGroupchatWindow
|
||||
from gajim.gtk import StartChatDialog
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
from gajim.gtk import SingleMessageWindow
|
||||
from gajim.gtk import XMLConsoleWindow
|
||||
from gajim.gtk import AboutDialog
|
||||
from gajim.gtk import PrivacyListsWindow
|
||||
|
||||
|
||||
# General Actions
|
||||
|
||||
def on_add_contact_jid(action, param):
|
||||
dialogs.AddNewContactWindow(None, param.get_string())
|
||||
AddNewContactWindow(None, param.get_string())
|
||||
|
||||
# Application Menu Actions
|
||||
|
||||
|
@ -79,7 +86,7 @@ def on_new_chat(action, param):
|
|||
if 'start_chat' in app.interface.instances:
|
||||
app.interface.instances['start_chat'].present()
|
||||
else:
|
||||
app.interface.instances['start_chat'] = dialogs.StartChatDialog()
|
||||
app.interface.instances['start_chat'] = StartChatDialog()
|
||||
|
||||
# Accounts Actions
|
||||
|
||||
|
@ -103,7 +110,7 @@ def on_send_server_message(action, param):
|
|||
account = param.get_string()
|
||||
server = app.config.get_per('accounts', account, 'hostname')
|
||||
server += '/announce/online'
|
||||
dialogs.SingleMessageWindow(account, server, 'send')
|
||||
SingleMessageWindow(account, server, 'send')
|
||||
|
||||
|
||||
def on_service_disco(action, param):
|
||||
|
@ -127,23 +134,23 @@ def on_join_gc(action, param):
|
|||
return
|
||||
else:
|
||||
account = param.get_string()
|
||||
window = app.get_app_window(dialogs.JoinGroupchatWindow)
|
||||
window = app.get_app_window(JoinGroupchatWindow)
|
||||
if window is None:
|
||||
dialogs.JoinGroupchatWindow(account, None)
|
||||
JoinGroupchatWindow(account, None)
|
||||
else:
|
||||
window.present()
|
||||
|
||||
|
||||
def on_add_contact(action, param):
|
||||
window = app.get_app_window(dialogs.AddNewContactWindow)
|
||||
window = app.get_app_window(AddNewContactWindow)
|
||||
if window is None:
|
||||
dialogs.AddNewContactWindow(param.get_string())
|
||||
AddNewContactWindow(param.get_string())
|
||||
else:
|
||||
window.present()
|
||||
|
||||
|
||||
def on_single_message(action, param):
|
||||
dialogs.SingleMessageWindow(param.get_string(), action='send')
|
||||
SingleMessageWindow(param.get_string(), action='send')
|
||||
|
||||
|
||||
def on_merge_accounts(action, param):
|
||||
|
@ -206,7 +213,7 @@ def on_privacy_lists(action, param):
|
|||
interface.instances[account]['privacy_lists'].window.present()
|
||||
else:
|
||||
interface.instances[account]['privacy_lists'] = \
|
||||
dialogs.PrivacyListsWindow(account)
|
||||
PrivacyListsWindow(account)
|
||||
|
||||
|
||||
def on_server_info(action, param):
|
||||
|
@ -224,7 +231,7 @@ def on_xml_console(action, param):
|
|||
interface.instances[account]['xml_console'].present()
|
||||
else:
|
||||
interface.instances[account]['xml_console'] = \
|
||||
dialogs.XMLConsoleWindow(account)
|
||||
XMLConsoleWindow(account)
|
||||
|
||||
|
||||
def on_manage_proxies(action, param):
|
||||
|
@ -241,14 +248,14 @@ def on_set_motd(action, param):
|
|||
account = param.get_string()
|
||||
server = app.config.get_per('accounts', account, 'hostname')
|
||||
server += '/announce/motd'
|
||||
dialogs.SingleMessageWindow(account, server, 'send')
|
||||
SingleMessageWindow(account, server, 'send')
|
||||
|
||||
|
||||
def on_update_motd(action, param):
|
||||
account = param.get_string()
|
||||
server = app.config.get_per('accounts', account, 'hostname')
|
||||
server += '/announce/motd/update'
|
||||
dialogs.SingleMessageWindow(account, server, 'send')
|
||||
SingleMessageWindow(account, server, 'send')
|
||||
|
||||
|
||||
def on_delete_motd(action, param):
|
||||
|
@ -279,7 +286,7 @@ def on_features(action, param):
|
|||
|
||||
|
||||
def on_about(action, param):
|
||||
dialogs.AboutDialog()
|
||||
AboutDialog()
|
||||
|
||||
# View Actions
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ from gajim import gtkgui_helpers
|
|||
from gajim import gui_menu_builder
|
||||
from gajim import message_control
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import ConfirmationDialog
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
|
@ -337,7 +339,7 @@ class ChatControl(ChatControlBase):
|
|||
'information-' + self.control_id).set_enabled(online)
|
||||
|
||||
def _on_add_to_roster(self, action, param):
|
||||
dialogs.AddNewContactWindow(self.account, self.contact.jid)
|
||||
AddNewContactWindow(self.account, self.contact.jid)
|
||||
|
||||
def _on_information(self, action, param):
|
||||
app.interface.roster.on_info(None, self.contact, self.account)
|
||||
|
@ -1208,7 +1210,7 @@ class ChatControl(ChatControlBase):
|
|||
def on_cancel():
|
||||
on_no(self)
|
||||
|
||||
dialogs.ConfirmationDialog(
|
||||
ConfirmationDialog(
|
||||
#%s is being replaced in the code with JID
|
||||
_('You just received a new message from "%s"') % \
|
||||
self.contact.jid,
|
||||
|
|
|
@ -37,7 +37,7 @@ from gi.repository import Gio
|
|||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import message_control
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import NonModalConfirmationDialog
|
||||
from gajim import history_window
|
||||
from gajim import notify
|
||||
import re
|
||||
|
@ -1160,7 +1160,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
prim_text = _('Really send file?')
|
||||
sec_text = _('If you send a file to %s, your real JID will '
|
||||
'be revealed.') % gc_contact.name
|
||||
dialog = dialogs.NonModalConfirmationDialog(prim_text,
|
||||
dialog = NonModalConfirmationDialog(prim_text,
|
||||
sec_text, on_response_ok=(_on_ok, gc_contact))
|
||||
dialog.popup()
|
||||
return
|
||||
|
|
|
@ -955,7 +955,7 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
|
|||
if self.msg_obj.form_node:
|
||||
# It could be a voice request. See
|
||||
# http://www.xmpp.org/extensions/xep-0045.html#voiceapprove
|
||||
from gajim.dialogs import SingleMessageWindow
|
||||
from gajim.gtk import SingleMessageWindow
|
||||
SingleMessageWindow(
|
||||
self.conn.name, self.fjid,
|
||||
action='receive', from_whom=self.fjid,
|
||||
|
|
|
@ -52,6 +52,12 @@ from gajim.gajim_themes_window import GajimThemesWindow
|
|||
from gajim.advanced_configuration_window import AdvancedConfigurationWindow
|
||||
from gajim import dataforms_widget
|
||||
from gajim import gui_menu_builder
|
||||
from gajim.gtk import AspellDictError
|
||||
from gajim.gtk import ConfirmationDialog
|
||||
from gajim.gtk import ConfirmationDialogDoubleRadio
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import InputDialog
|
||||
from gajim.gtk import WarningDialog
|
||||
|
||||
from gajim.common import helpers
|
||||
from gajim.common import app
|
||||
|
@ -653,7 +659,7 @@ class PreferencesWindow:
|
|||
if gspell_lang is None:
|
||||
gspell_lang = Gspell.language_get_default()
|
||||
if gspell_lang is None:
|
||||
dialogs.AspellDictError(lang)
|
||||
AspellDictError(lang)
|
||||
app.config.set('use_speller', False)
|
||||
widget.set_active(False)
|
||||
else:
|
||||
|
@ -1682,7 +1688,7 @@ class GroupchatConfigWindow:
|
|||
return
|
||||
model = self.affiliation_treeview[affiliation].get_model()
|
||||
model.append((jid, '', '', ''))
|
||||
dialogs.InputDialog(title, prompt, ok_handler=on_ok)
|
||||
InputDialog(title, prompt, ok_handler=on_ok)
|
||||
|
||||
def on_remove_button_clicked(self, widget, affiliation):
|
||||
selection = self.affiliation_treeview[affiliation].get_selection()
|
||||
|
@ -1785,7 +1791,7 @@ class RemoveAccountWindow:
|
|||
app.connections[self.account].change_status('offline', 'offline')
|
||||
if self.remove_and_unregister_radiobutton.get_active():
|
||||
if not self.account in app.connections:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Account is disabled'),
|
||||
_('To unregister from a server, account must be '
|
||||
'enabled.'),
|
||||
|
@ -1813,7 +1819,7 @@ class RemoveAccountWindow:
|
|||
|
||||
if self.account in app.connections and \
|
||||
app.connections[self.account].connected:
|
||||
dialogs.ConfirmationDialog(
|
||||
ConfirmationDialog(
|
||||
_('Account "%s" is connected to the server') % self.account,
|
||||
_('If you remove it, the connection will be lost.'),
|
||||
on_response_ok=remove,
|
||||
|
@ -1829,7 +1835,7 @@ class RemoveAccountWindow:
|
|||
# action of unregistration has failed, we don't remove the account
|
||||
# Error message is send by connect_and_auth()
|
||||
if not res:
|
||||
dialogs.ConfirmationDialogDoubleRadio(
|
||||
ConfirmationDialogDoubleRadio(
|
||||
_('Connection to server %s failed') % self.account,
|
||||
_('What would you like to do?'),
|
||||
_('Remove only from Gajim'),
|
||||
|
@ -2036,7 +2042,7 @@ class ManageBookmarksWindow:
|
|||
|
||||
if self.server_entry.get_text() == '' or \
|
||||
self.room_entry.get_text() == '':
|
||||
dialogs.ErrorDialog(_('This bookmark has invalid data'),
|
||||
ErrorDialog(_('This bookmark has invalid data'),
|
||||
_('Please be sure to fill out server and room fields or remove this'
|
||||
' bookmark.'))
|
||||
return False
|
||||
|
@ -2166,7 +2172,7 @@ class ManageBookmarksWindow:
|
|||
try:
|
||||
nick = helpers.parse_resource(nick)
|
||||
except helpers.InvalidFormat:
|
||||
dialogs.ErrorDialog(_('Invalid nickname'),
|
||||
ErrorDialog(_('Invalid nickname'),
|
||||
_('Character not allowed'), transient_for=self.window)
|
||||
self.nick_entry.set_text(model[iter_][6])
|
||||
return True
|
||||
|
@ -2182,7 +2188,7 @@ class ManageBookmarksWindow:
|
|||
if not server:
|
||||
return
|
||||
if '@' in server:
|
||||
dialogs.ErrorDialog(_('Invalid server'),
|
||||
ErrorDialog(_('Invalid server'),
|
||||
_('Character not allowed'), transient_for=self.window)
|
||||
widget.set_text(server.replace('@', ''))
|
||||
|
||||
|
@ -2193,7 +2199,7 @@ class ManageBookmarksWindow:
|
|||
try:
|
||||
room_jid = helpers.parse_jid(room_jid)
|
||||
except helpers.InvalidFormat as e:
|
||||
dialogs.ErrorDialog(_('Invalid server'),
|
||||
ErrorDialog(_('Invalid server'),
|
||||
_('Character not allowed'), transient_for=self.window)
|
||||
self.server_entry.set_text(model[iter_][2].split('@')[1])
|
||||
return True
|
||||
|
@ -2221,7 +2227,7 @@ class ManageBookmarksWindow:
|
|||
try:
|
||||
room_jid = helpers.parse_jid(room_jid)
|
||||
except helpers.InvalidFormat:
|
||||
dialogs.ErrorDialog(_('Invalid room'),
|
||||
ErrorDialog(_('Invalid room'),
|
||||
_('Character not allowed'), transient_for=self.window)
|
||||
return True
|
||||
model[iter_][2] = room_jid
|
||||
|
@ -2439,7 +2445,7 @@ class AccountCreationWizardWindow:
|
|||
pritext = _('Invalid username')
|
||||
sectext = _(
|
||||
'You must provide a username to configure this account.')
|
||||
dialogs.ErrorDialog(pritext, sectext)
|
||||
ErrorDialog(pritext, sectext)
|
||||
return
|
||||
server = self.xml.get_object('server_comboboxtext_entry').\
|
||||
get_text().strip()
|
||||
|
@ -2457,7 +2463,7 @@ class AccountCreationWizardWindow:
|
|||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat as s:
|
||||
pritext = _('Invalid JID')
|
||||
dialogs.ErrorDialog(pritext, str(s))
|
||||
ErrorDialog(pritext, str(s))
|
||||
return
|
||||
|
||||
self.account = server
|
||||
|
@ -2478,7 +2484,7 @@ class AccountCreationWizardWindow:
|
|||
get_text()
|
||||
|
||||
if not server:
|
||||
dialogs.ErrorDialog(_('Invalid server'),
|
||||
ErrorDialog(_('Invalid server'),
|
||||
_('Please provide a server on which you want to register.'))
|
||||
return
|
||||
self.account = server
|
||||
|
@ -2502,7 +2508,7 @@ class AccountCreationWizardWindow:
|
|||
try:
|
||||
custom_port = int(custom_port)
|
||||
except Exception:
|
||||
dialogs.ErrorDialog(_('Invalid entry'),
|
||||
ErrorDialog(_('Invalid entry'),
|
||||
_('Custom port must be a port number.'))
|
||||
return
|
||||
config['custom_port'] = custom_port
|
||||
|
@ -2535,7 +2541,7 @@ class AccountCreationWizardWindow:
|
|||
with open(my_ca_certs) as f:
|
||||
certs = f.read()
|
||||
if self.ssl_cert in certs:
|
||||
dialogs.ErrorDialog(_('Certificate Already in File'),
|
||||
ErrorDialog(_('Certificate Already in File'),
|
||||
_('This certificate is already in file %s, so it\'s '
|
||||
'not added again.') % my_ca_certs)
|
||||
else:
|
||||
|
@ -2766,7 +2772,7 @@ class AccountCreationWizardWindow:
|
|||
|
||||
def save_account(self, login, server, savepass, password, anonymous=False):
|
||||
if self.account in app.connections:
|
||||
dialogs.ErrorDialog(_('Account name is in use'),
|
||||
ErrorDialog(_('Account name is in use'),
|
||||
_('You already have an account using this name.'))
|
||||
return
|
||||
con = connection.Connection(self.account)
|
||||
|
@ -2899,7 +2905,7 @@ class ManagePEPServicesWindow:
|
|||
def node_not_removed(self, jid, node, msg):
|
||||
if jid != app.get_jid_from_account(self.account):
|
||||
return
|
||||
dialogs.WarningDialog(_('PEP node was not removed'),
|
||||
WarningDialog(_('PEP node was not removed'),
|
||||
_('PEP node %(node)s was not removed: %(message)s') % {'node': node,
|
||||
'message': msg})
|
||||
|
||||
|
|
|
@ -38,7 +38,11 @@ from gajim import dialogs
|
|||
import queue
|
||||
import urllib
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
from gajim.gtk import util
|
||||
from gajim.gtk.util import load_icon
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.util import get_cursor
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.common import i18n
|
||||
|
@ -164,11 +168,6 @@ class ConversationTextview(GObject.GObject):
|
|||
)
|
||||
)
|
||||
|
||||
MESSAGE_CORRECTED_PIXBUF = gtkgui_helpers.get_icon_pixmap(
|
||||
'document-edit-symbolic')
|
||||
MESSAGE_ENCRYPTED_PIXBUF = gtkgui_helpers.get_icon_pixmap(
|
||||
'channel-secure-croped-symbolic')
|
||||
|
||||
def __init__(self, account, used_in_history_window = False):
|
||||
"""
|
||||
If used_in_history_window is True, then we do not show Clear menuitem in
|
||||
|
@ -330,11 +329,11 @@ class ConversationTextview(GObject.GObject):
|
|||
if len(text) > 50:
|
||||
text = text[:47] + '…'
|
||||
tooltip.set_text(text)
|
||||
window.set_cursor(gtkgui_helpers.get_cursor('HAND2'))
|
||||
window.set_cursor(get_cursor('HAND2'))
|
||||
self.cursor_changed = True
|
||||
return True
|
||||
if tag_name in ('url', 'mail', 'xmpp', 'sth_at_sth'):
|
||||
window.set_cursor(gtkgui_helpers.get_cursor('HAND2'))
|
||||
window.set_cursor(get_cursor('HAND2'))
|
||||
self.cursor_changed = True
|
||||
return False
|
||||
try:
|
||||
|
@ -344,7 +343,7 @@ class ConversationTextview(GObject.GObject):
|
|||
except KeyError:
|
||||
pass
|
||||
if self.cursor_changed:
|
||||
window.set_cursor(gtkgui_helpers.get_cursor('XTERM'))
|
||||
window.set_cursor(get_cursor('XTERM'))
|
||||
self.cursor_changed = False
|
||||
return False
|
||||
|
||||
|
@ -370,7 +369,7 @@ class ConversationTextview(GObject.GObject):
|
|||
|
||||
def scroll_to_end(self, force=False):
|
||||
if self.autoscroll or force:
|
||||
gtkgui_helpers.scroll_to_end(self.tv.get_parent())
|
||||
util.scroll_to_end(self.tv.get_parent())
|
||||
|
||||
def correct_message(self, correct_id, kind, name):
|
||||
allowed = True
|
||||
|
@ -674,10 +673,10 @@ class ConversationTextview(GObject.GObject):
|
|||
app.interface.join_gc_minimal(self.account, room_jid)
|
||||
|
||||
def on_add_to_roster_activate(self, widget, jid):
|
||||
dialogs.AddNewContactWindow(self.account, jid)
|
||||
AddNewContactWindow(self.account, jid)
|
||||
|
||||
def make_link_menu(self, event, kind, text):
|
||||
xml = gtkgui_helpers.get_gtk_builder('chat_context_menu.ui')
|
||||
xml = get_builder('chat_context_menu.ui')
|
||||
menu = xml.get_object('chat_context_menu')
|
||||
childs = menu.get_children()
|
||||
if kind == 'url':
|
||||
|
@ -1142,8 +1141,9 @@ class ConversationTextview(GObject.GObject):
|
|||
self.print_time(text, kind, tim, simple, direction_mark,
|
||||
other_tags_for_time, iter_)
|
||||
|
||||
icon = load_icon('channel-secure-croped-symbolic', self.tv, pixbuf=True)
|
||||
if encrypted:
|
||||
buffer_.insert_pixbuf(iter_, self.MESSAGE_ENCRYPTED_PIXBUF)
|
||||
buffer_.insert_pixbuf(iter_, icon)
|
||||
|
||||
# If there's a displaymarking, print it here.
|
||||
if displaymarking:
|
||||
|
@ -1185,8 +1185,9 @@ class ConversationTextview(GObject.GObject):
|
|||
# Show Correction Icon
|
||||
buffer_.create_tag(tag_name=msg_stanza_id)
|
||||
buffer_.insert(iter_, ' ')
|
||||
icon = load_icon('document-edit-symbolic', self.tv, pixbuf=True)
|
||||
buffer_.insert_pixbuf(
|
||||
iter_, ConversationTextview.MESSAGE_CORRECTED_PIXBUF)
|
||||
iter_, icon)
|
||||
tag_start_iter = iter_.copy()
|
||||
tag_start_iter.backward_chars(2)
|
||||
buffer_.apply_tag_by_name(msg_stanza_id, tag_start_iter, iter_)
|
||||
|
|
|
@ -128,3 +128,8 @@ button.flat.link { padding: 0; border: 0; }
|
|||
/*SendFileDialog*/
|
||||
#SendFileDialog grid {padding: 12px}
|
||||
#SendFileDialog grid list { background-color: @theme_bg_color}
|
||||
|
||||
/*Icon colors*/
|
||||
.success-color { color: @success_color; }
|
||||
.error-color { color: @error_color; }
|
||||
.warning-color { color: @warning_color; }
|
||||
|
|
|
@ -22,8 +22,8 @@ from collections import namedtuple
|
|||
from gi.repository import GLib
|
||||
|
||||
from gajim.common.app import app
|
||||
from gajim.dialogs import ErrorDialog
|
||||
from gajim.dialogs import InformationDialog
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import InformationDialog
|
||||
|
||||
Message = namedtuple('Message', ['title', 'text', 'dialog'])
|
||||
|
||||
|
|
3186
gajim/dialogs.py
3186
gajim/dialogs.py
File diff suppressed because it is too large
Load Diff
|
@ -52,7 +52,8 @@ from gi.repository import Gdk
|
|||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import InformationDialog
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import groups
|
||||
from gajim import adhoc_commands
|
||||
|
@ -526,7 +527,7 @@ class ServiceDiscoveryWindow(object):
|
|||
|
||||
# Check connection
|
||||
if app.connections[account].connected < 2:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection, you can not browse available services'))
|
||||
raise RuntimeError('You must be connected to browse services')
|
||||
|
||||
|
@ -722,14 +723,14 @@ _('Without a connection, you can not browse available services'))
|
|||
if not self.address_comboboxtext:
|
||||
# We can't travel anywhere else.
|
||||
self.destroy()
|
||||
dialogs.ErrorDialog(_('The service could not be found'),
|
||||
ErrorDialog(_('The service could not be found'),
|
||||
_('There is no service at the address you entered, or it is '
|
||||
'not responding. Check the address and try again.'),
|
||||
transient_for=self.window)
|
||||
return
|
||||
klass = self.cache.get_browser(identities, features)
|
||||
if not klass:
|
||||
dialogs.ErrorDialog(_('The service is not browsable'),
|
||||
ErrorDialog(_('The service is not browsable'),
|
||||
_('This type of service does not contain any items to browse.'),
|
||||
transient_for=self.window)
|
||||
return
|
||||
|
@ -772,7 +773,7 @@ _('Without a connection, you can not browse available services'))
|
|||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat as s:
|
||||
pritext = _('Invalid Server Name')
|
||||
dialogs.ErrorDialog(pritext, str(s))
|
||||
ErrorDialog(pritext, str(s))
|
||||
return
|
||||
self.travel(jid, '')
|
||||
|
||||
|
@ -782,7 +783,7 @@ _('Without a connection, you can not browse available services'))
|
|||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat as s:
|
||||
pritext = _('Invalid Server Name')
|
||||
dialogs.ErrorDialog(pritext, str(s),
|
||||
ErrorDialog(pritext, str(s),
|
||||
transient_for=self.window)
|
||||
return
|
||||
if jid == self.jid: # jid has not changed
|
||||
|
@ -1081,7 +1082,7 @@ class AgentBrowser:
|
|||
if not self.window.address_comboboxtext:
|
||||
# We can't travel anywhere else.
|
||||
self.window.destroy()
|
||||
dialogs.ErrorDialog(_('The service is not browsable'),
|
||||
ErrorDialog(_('The service is not browsable'),
|
||||
_('This service does not contain any items to browse.'),
|
||||
transient_for=self.window.window)
|
||||
return
|
||||
|
@ -1772,7 +1773,7 @@ class MucBrowser(AgentBrowser):
|
|||
}
|
||||
|
||||
if room_jid in con.get_module('Bookmarks').bookmarks:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Bookmark already set'),
|
||||
_('Group Chat "%s" is already in your bookmarks.') % room_jid,
|
||||
transient_for=self.window.window)
|
||||
|
@ -1783,7 +1784,7 @@ class MucBrowser(AgentBrowser):
|
|||
|
||||
gui_menu_builder.build_bookmark_menu(self.account)
|
||||
|
||||
dialogs.InformationDialog(
|
||||
InformationDialog(
|
||||
_('Bookmark has been added successfully'),
|
||||
_('You can manage your bookmarks via Actions menu in your roster.'),
|
||||
transient_for=self.window.window)
|
||||
|
|
|
@ -36,7 +36,12 @@ from datetime import datetime
|
|||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import tooltips
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import HigDialog
|
||||
from gajim.gtk import InformationDialog
|
||||
from gajim.gtk import YesNoDialog
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import FTOverwriteConfirmationDialog
|
||||
from gajim.gtk import NonModalConfirmationDialog
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
|
@ -247,7 +252,7 @@ class FileTransfersWindow:
|
|||
sectext += recipient
|
||||
if file_props.type_ == 'r':
|
||||
sectext += '\n\t' + _('Saved in: %s') % file_path
|
||||
dialog = dialogs.HigDialog(app.interface.roster.window, Gtk.MessageType.INFO,
|
||||
dialog = HigDialog(app.interface.roster.window, Gtk.MessageType.INFO,
|
||||
Gtk.ButtonsType.NONE, _('File transfer completed'), sectext)
|
||||
if file_props.type_ == 'r':
|
||||
button = Gtk.Button.new_with_mnemonic(_('Open _Containing Folder'))
|
||||
|
@ -263,14 +268,14 @@ class FileTransfersWindow:
|
|||
"""
|
||||
Show error dialog to the recipient saying that transfer has been canceled
|
||||
"""
|
||||
dialogs.InformationDialog(_('File transfer cancelled'), _('Connection with peer cannot be established.'))
|
||||
InformationDialog(_('File transfer cancelled'), _('Connection with peer cannot be established.'))
|
||||
self.tree.get_selection().unselect_all()
|
||||
|
||||
def show_send_error(self, file_props):
|
||||
"""
|
||||
Show error dialog to the sender saying that transfer has been canceled
|
||||
"""
|
||||
dialogs.InformationDialog(_('File transfer cancelled'),
|
||||
InformationDialog(_('File transfer cancelled'),
|
||||
_('Connection with peer cannot be established.'))
|
||||
self.tree.get_selection().unselect_all()
|
||||
|
||||
|
@ -283,7 +288,7 @@ class FileTransfersWindow:
|
|||
sectext += '\n\t' + _('Recipient: %s') % jid
|
||||
if error_msg:
|
||||
sectext += '\n\t' + _('Error message: %s') % error_msg
|
||||
dialogs.ErrorDialog(_('File transfer stopped'), sectext)
|
||||
ErrorDialog(_('File transfer stopped'), sectext)
|
||||
self.tree.get_selection().unselect_all()
|
||||
|
||||
def show_hash_error(self, jid, file_props, account):
|
||||
|
@ -318,7 +323,7 @@ class FileTransfersWindow:
|
|||
file_name = os.path.basename(file_props.file_name)
|
||||
else:
|
||||
file_name = file_props.name
|
||||
dialogs.YesNoDialog(('File transfer error'),
|
||||
YesNoDialog(('File transfer error'),
|
||||
_('The file %(file)s has been received, but it seems to have '
|
||||
'been damaged along the way.\nDo you want to download it again?') % \
|
||||
{'file': file_name}, on_response_yes=(on_yes, jid, file_props,
|
||||
|
@ -335,7 +340,7 @@ class FileTransfersWindow:
|
|||
if gtkgui_helpers.file_is_locked(file_path):
|
||||
pritext = _('Gajim can not read this file')
|
||||
sextext = _('Another process is using this file.')
|
||||
dialogs.ErrorDialog(pritext, sextext)
|
||||
ErrorDialog(pritext, sextext)
|
||||
return
|
||||
|
||||
if isinstance(contact, str):
|
||||
|
@ -378,7 +383,7 @@ class FileTransfersWindow:
|
|||
if not os.access(file_path, os.W_OK):
|
||||
file_name = GLib.markup_escape_text(os.path.basename(
|
||||
file_path))
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Cannot overwrite existing file "%s"' % file_name),
|
||||
_('A file with this name already exists and you do not '
|
||||
'have permission to overwrite it.'))
|
||||
|
@ -395,7 +400,7 @@ class FileTransfersWindow:
|
|||
file_props.offset = dl_size
|
||||
self._start_receive(file_path, account, contact, file_props)
|
||||
|
||||
dialog = dialogs.FTOverwriteConfirmationDialog(
|
||||
dialog = FTOverwriteConfirmationDialog(
|
||||
_('This file already exists'), _('What do you want to do?'),
|
||||
propose_resume=not dl_finished, on_response=on_response)
|
||||
dialog.set_destroy_with_parent(True)
|
||||
|
@ -406,7 +411,7 @@ class FileTransfersWindow:
|
|||
# read-only bit is used to mark special folder under
|
||||
# windows, not to mark that a folder is read-only.
|
||||
# See ticket #3587
|
||||
dialogs.ErrorDialog(_('Directory "%s" is not writable') % \
|
||||
ErrorDialog(_('Directory "%s" is not writable') % \
|
||||
dirname, _('You do not have permission to create files '
|
||||
'in this directory.'))
|
||||
return
|
||||
|
@ -445,7 +450,7 @@ class FileTransfersWindow:
|
|||
def on_response_cancel(account, file_props):
|
||||
app.connections[account].send_file_rejection(file_props)
|
||||
|
||||
dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text,
|
||||
dialog = NonModalConfirmationDialog(prim_text, sec_text,
|
||||
on_response_ok=(on_response_ok, account, contact, file_props),
|
||||
on_response_cancel=(on_response_cancel, account, file_props))
|
||||
dialog.connect('delete-event', lambda widget, event:
|
||||
|
@ -674,10 +679,10 @@ class FileTransfersWindow:
|
|||
if os.path.isfile(file_path):
|
||||
stat = os.stat(file_path)
|
||||
else:
|
||||
dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path)
|
||||
ErrorDialog(_('Invalid File'), _('File: ') + file_path)
|
||||
return None
|
||||
if stat[6] == 0:
|
||||
dialogs.ErrorDialog(_('Invalid File'),
|
||||
ErrorDialog(_('Invalid File'),
|
||||
_('It is not possible to send empty files'))
|
||||
return None
|
||||
file_props = FilesProp.getNewFileProp(account,
|
||||
|
|
|
@ -25,15 +25,17 @@
|
|||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Pango
|
||||
from gajim import dialogs
|
||||
from gajim import gtkgui_helpers
|
||||
|
||||
from gajim.common import app
|
||||
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk.util import get_builder
|
||||
|
||||
|
||||
class GajimThemesWindow:
|
||||
|
||||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_gtk_builder('gajim_themes_window.ui')
|
||||
self.xml = get_builder('gajim_themes_window.ui')
|
||||
self.window = self.xml.get_object('gajim_themes_window')
|
||||
self.window.set_transient_for(app.interface.instances[
|
||||
'preferences'].window)
|
||||
|
@ -94,7 +96,7 @@ class GajimThemesWindow:
|
|||
if old_name == new_name:
|
||||
return
|
||||
if old_name == 'default':
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('You cannot make changes to the default theme'),
|
||||
_('Please create a new clean theme.'))
|
||||
return
|
||||
|
@ -183,7 +185,7 @@ class GajimThemesWindow:
|
|||
if not iter_:
|
||||
return
|
||||
if self.current_theme == app.config.get('roster_theme'):
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('You cannot delete your current theme'),
|
||||
_('Pick another theme to use first.'))
|
||||
return
|
||||
|
|
|
@ -41,11 +41,11 @@ from gajim import gtkgui_helpers
|
|||
from gajim import gui_menu_builder
|
||||
from gajim import message_control
|
||||
from gajim import tooltips
|
||||
from gajim import dialogs
|
||||
from gajim import config
|
||||
from gajim import vcard
|
||||
from gajim import dataforms_widget
|
||||
from gajim import adhoc_commands
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
from gajim.common.const import AvatarSize
|
||||
from gajim.common.caps_cache import muc_caps_cache
|
||||
import nbxmpp
|
||||
|
@ -63,6 +63,12 @@ from gajim.common import contacts
|
|||
from gajim.chat_control import ChatControl
|
||||
from gajim.chat_control_base import ChatControlBase
|
||||
from gajim.filechoosers import AvatarChooserDialog
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import InputTextDialog
|
||||
from gajim.gtk import ConfirmationDialogCheck
|
||||
from gajim.gtk import DoubleInputDialog
|
||||
from gajim.gtk import InputDialog
|
||||
from gajim.gtk import ChangeNickDialog
|
||||
|
||||
from gajim.command_system.implementation.hosts import PrivateChatCommands
|
||||
from gajim.command_system.implementation.hosts import GroupChatCommands
|
||||
|
@ -239,7 +245,7 @@ class PrivateChatControl(ChatControl):
|
|||
room, nick = app.get_room_and_nick_from_fjid(self.contact.jid)
|
||||
gc_contact = app.contacts.get_gc_contact(self.account, room, nick)
|
||||
if not gc_contact:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Sending private message failed'),
|
||||
#in second %s code replaces with nickname
|
||||
_('You are no longer in group chat "%(room)s" or '
|
||||
|
@ -646,7 +652,7 @@ class GroupchatControl(ChatControlBase):
|
|||
app.connections[self.account].send_gc_subject(
|
||||
self.room_jid, subject)
|
||||
|
||||
dialogs.InputTextDialog(_('Changing Subject'),
|
||||
InputTextDialog(_('Changing Subject'),
|
||||
_('Please specify the new subject:'), input_str=self.subject,
|
||||
ok_handler=on_ok, transient_for=self.parent_win.window)
|
||||
|
||||
|
@ -657,7 +663,7 @@ class GroupchatControl(ChatControlBase):
|
|||
title = _('Changing Nickname')
|
||||
prompt = _('Please specify the new nickname you want to use:')
|
||||
app.interface.instances['change_nick_dialog'] = \
|
||||
dialogs.ChangeNickDialog(self.account, self.room_jid, title,
|
||||
ChangeNickDialog(self.account, self.room_jid, title,
|
||||
prompt, change_nick=True, transient_for=self.parent_win.window)
|
||||
|
||||
def _on_disconnect(self, action, param):
|
||||
|
@ -672,7 +678,7 @@ class GroupchatControl(ChatControlBase):
|
|||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except Exception:
|
||||
dialogs.ErrorDialog(_('Invalid group chat JID'),
|
||||
ErrorDialog(_('Invalid group chat JID'),
|
||||
_('The group chat JID has not allowed characters.'))
|
||||
return
|
||||
app.connections[self.account].destroy_gc_room(
|
||||
|
@ -683,7 +689,7 @@ class GroupchatControl(ChatControlBase):
|
|||
self.force_non_minimizable = False
|
||||
|
||||
# Ask for a reason
|
||||
dialogs.DoubleInputDialog(_('Destroying %s') % '\u200E' + \
|
||||
DoubleInputDialog(_('Destroying %s') % '\u200E' + \
|
||||
self.room_jid, _('You are going to remove this room permanently.'
|
||||
'\nYou may specify a reason below:'),
|
||||
_('You may also enter an alternate venue:'), ok_handler=on_ok,
|
||||
|
@ -751,7 +757,7 @@ class GroupchatControl(ChatControlBase):
|
|||
def _on_accept(filename):
|
||||
sha = app.interface.save_avatar(filename, publish=True)
|
||||
if sha is None:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Could not load image'),
|
||||
transient_for=self.parent_win.window)
|
||||
return
|
||||
|
@ -2343,7 +2349,7 @@ class GroupchatControl(ChatControlBase):
|
|||
sectext = _('If you close this window, you will be disconnected '
|
||||
'from this group chat.')
|
||||
|
||||
dialogs.ConfirmationDialogCheck(pritext, sectext,
|
||||
ConfirmationDialogCheck(pritext, sectext,
|
||||
_('_Do not ask me again'), on_response_ok=on_ok,
|
||||
on_response_cancel=on_cancel,
|
||||
transient_for=self.parent_win.window)
|
||||
|
@ -2379,7 +2385,7 @@ class GroupchatControl(ChatControlBase):
|
|||
app.connections[self.account].send_gc_subject(self.room_jid,
|
||||
subject)
|
||||
|
||||
dialogs.InputTextDialog(_('Changing Subject'),
|
||||
InputTextDialog(_('Changing Subject'),
|
||||
_('Please specify the new subject:'), input_str=self.subject,
|
||||
ok_handler=on_ok, transient_for=self.parent_win.window)
|
||||
|
||||
|
@ -2560,7 +2566,7 @@ class GroupchatControl(ChatControlBase):
|
|||
'none', reason)
|
||||
|
||||
# ask for reason
|
||||
dialogs.InputDialog(_('Kicking %s') % nick,
|
||||
InputDialog(_('Kicking %s') % nick,
|
||||
_('You may specify a reason below:'), ok_handler=on_ok,
|
||||
transient_for=self.parent_win.window)
|
||||
|
||||
|
@ -2857,7 +2863,7 @@ class GroupchatControl(ChatControlBase):
|
|||
# to ban we know the real jid. so jid is not fakejid
|
||||
nick = app.get_nick_from_jid(jid)
|
||||
# ask for reason
|
||||
dialogs.InputDialog(_('Banning %s') % nick,
|
||||
InputDialog(_('Banning %s') % nick,
|
||||
_('You may specify a reason below:'), ok_handler=on_ok,
|
||||
transient_for=self.parent_win.window)
|
||||
|
||||
|
@ -2922,7 +2928,7 @@ class GroupchatControl(ChatControlBase):
|
|||
self._on_history_menuitem_activate(widget=widget, jid=jid)
|
||||
|
||||
def on_add_to_roster(self, widget, jid):
|
||||
dialogs.AddNewContactWindow(self.account, jid)
|
||||
AddNewContactWindow(self.account, jid)
|
||||
|
||||
def on_block(self, widget, nick):
|
||||
fjid = self.room_jid + '/' + nick
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# Copyright (C) 2003-2005 Vincent Hanquez <tab AT snarc.org>
|
||||
# Copyright (C) 2003-2014 Yann Leboulanger <asterix AT lagaule.org>
|
||||
# Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
|
||||
# Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
|
||||
# Travis Shirk <travis AT pobox.com>
|
||||
# Copyright (C) 2005-2008 Nikos Kouremenos <kourem AT gmail.com>
|
||||
# Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
|
||||
# Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
|
||||
# Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
|
||||
# Julien Pivotto <roidelapluie AT gmail.com>
|
||||
# Stephan Erb <steve-e AT h3c.de>
|
||||
# Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
|
||||
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
|
||||
#
|
||||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gajim.gtk.dialogs import ErrorDialog
|
||||
from gajim.gtk.dialogs import InformationDialog
|
||||
from gajim.gtk.dialogs import ChangeNickDialog
|
||||
from gajim.gtk.dialogs import FTOverwriteConfirmationDialog
|
||||
from gajim.gtk.dialogs import InputDialog
|
||||
from gajim.gtk.dialogs import ConfirmationDialogDoubleRadio
|
||||
from gajim.gtk.dialogs import InputDialogCheck
|
||||
from gajim.gtk.dialogs import DoubleInputDialog
|
||||
from gajim.gtk.dialogs import InputTextDialog
|
||||
from gajim.gtk.dialogs import PlainConnectionDialog
|
||||
from gajim.gtk.dialogs import ConfirmationDialogDoubleCheck
|
||||
from gajim.gtk.dialogs import ConfirmationDialogCheck
|
||||
from gajim.gtk.dialogs import YesNoDialog
|
||||
from gajim.gtk.dialogs import WarningDialog
|
||||
from gajim.gtk.dialogs import NonModalConfirmationDialog
|
||||
from gajim.gtk.dialogs import ConfirmationDialog
|
||||
from gajim.gtk.dialogs import AspellDictError
|
||||
from gajim.gtk.dialogs import HigDialog
|
||||
from gajim.gtk.dialogs import SSLErrorDialog
|
||||
|
||||
from gajim.gtk.about import AboutDialog
|
||||
from gajim.gtk.join_groupchat import JoinGroupchatWindow
|
||||
from gajim.gtk.add_contact import AddNewContactWindow
|
||||
from gajim.gtk.start_chat import StartChatDialog
|
||||
from gajim.gtk.xml_console import XMLConsoleWindow
|
||||
from gajim.gtk.privacy_list import PrivacyListsWindow
|
||||
from gajim.gtk.single_message import SingleMessageWindow
|
||||
from gajim.gtk.server_info import ServerInfoDialog
|
|
@ -0,0 +1,66 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import nbxmpp
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common.const import DEVS_CURRENT
|
||||
from gajim.common.const import DEVS_PAST
|
||||
from gajim.common.const import ARTISTS
|
||||
from gajim.common.const import THANKS
|
||||
|
||||
|
||||
class AboutDialog(Gtk.AboutDialog):
|
||||
def __init__(self):
|
||||
Gtk.AboutDialog.__init__(self)
|
||||
self.set_transient_for(app.interface.roster.window)
|
||||
self.set_name('Gajim')
|
||||
self.set_version(app.version)
|
||||
self.set_copyright('Copyright © 2003-2018 Gajim Team')
|
||||
self.set_license_type(Gtk.License.GPL_3_0_ONLY)
|
||||
self.set_website('https://gajim.org/')
|
||||
|
||||
gtk_ver = '%i.%i.%i' % (
|
||||
Gtk.get_major_version(),
|
||||
Gtk.get_minor_version(),
|
||||
Gtk.get_micro_version())
|
||||
gobject_ver = '.'.join(map(str, GObject.pygobject_version))
|
||||
|
||||
comments = []
|
||||
comments.append(_('A GTK+ XMPP client'))
|
||||
comments.append(_('GTK+ Version: %s' % gtk_ver))
|
||||
comments.append(_('PyGObject Version: %s') % gobject_ver)
|
||||
comments.append(_('python-nbxmpp Version: %s') % nbxmpp.__version__)
|
||||
self.set_comments("\n".join(comments))
|
||||
|
||||
self.add_credit_section(_('Current Developers'), DEVS_CURRENT)
|
||||
self.add_credit_section(_('Past Developers'), DEVS_PAST)
|
||||
self.add_credit_section(_('Artists'), ARTISTS)
|
||||
|
||||
thanks = list(THANKS)
|
||||
thanks.append('')
|
||||
thanks.append(_('Last but not least'))
|
||||
thanks.append(_('we would like to thank all the package maintainers.'))
|
||||
self.add_credit_section(_('Thanks'), thanks)
|
||||
|
||||
self.set_translator_credits(_('translator-credits'))
|
||||
self.set_logo_icon_name('org.gajim.Gajim')
|
||||
|
||||
self.connect(
|
||||
'response', lambda dialog, *args: Gtk.AboutDialog.do_close(dialog))
|
||||
|
||||
self.show()
|
|
@ -0,0 +1,483 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import ged
|
||||
from gajim.common import helpers
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk.util import get_builder
|
||||
|
||||
|
||||
class AddNewContactWindow(Gtk.ApplicationWindow):
|
||||
|
||||
uid_labels = {'jabber': _('Jabber ID'),
|
||||
'gadu-gadu': _('GG Number'),
|
||||
'icq': _('ICQ Number')}
|
||||
|
||||
def __init__(self, account=None, jid=None, user_nick=None, group=None):
|
||||
Gtk.ApplicationWindow.__init__(self)
|
||||
self.set_application(app.app)
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.set_show_menubar(False)
|
||||
self.set_resizable(False)
|
||||
self.set_title(_('Add Contact'))
|
||||
|
||||
self.connect('destroy', self._on_destroy)
|
||||
self.connect('key-press-event', self._on_key_press)
|
||||
|
||||
self.account = account
|
||||
self.adding_jid = False
|
||||
|
||||
# fill accounts with active accounts
|
||||
accounts = app.get_enabled_accounts_with_labels()
|
||||
|
||||
if not accounts:
|
||||
return
|
||||
|
||||
if not account:
|
||||
self.account = accounts[0][0]
|
||||
|
||||
self.xml = get_builder('add_new_contact_window.ui')
|
||||
self.add(self.xml.get_object('add_contact_box'))
|
||||
self.xml.connect_signals(self)
|
||||
|
||||
for w in ('account_combobox', 'account_label', 'prompt_label',
|
||||
'uid_label', 'uid_entry', 'protocol_combobox',
|
||||
'protocol_jid_combobox', 'protocol_label', 'nickname_entry',
|
||||
'message_scrolledwindow', 'save_message_checkbutton',
|
||||
'register_hbox', 'add_button', 'message_textview',
|
||||
'connected_label', 'group_comboboxentry',
|
||||
'auto_authorize_checkbutton', 'save_message_revealer',
|
||||
'nickname_label', 'group_label'):
|
||||
self.__dict__[w] = self.xml.get_object(w)
|
||||
|
||||
self.subscription_table = [self.uid_label, self.uid_entry,
|
||||
self.nickname_label, self.nickname_entry,
|
||||
self.group_label, self.group_comboboxentry]
|
||||
|
||||
self.add_button.grab_default()
|
||||
|
||||
self.agents = {'jabber': []}
|
||||
self.gateway_prompt = {}
|
||||
# types to which we are not subscribed but account has an agent for it
|
||||
self.available_types = []
|
||||
for acct in accounts:
|
||||
for j in app.contacts.get_jid_list(acct[0]):
|
||||
if app.jid_is_transport(j):
|
||||
type_ = app.get_transport_name_from_jid(j, False)
|
||||
if not type_:
|
||||
continue
|
||||
if type_ in self.agents:
|
||||
self.agents[type_].append(j)
|
||||
else:
|
||||
self.agents[type_] = [j]
|
||||
self.gateway_prompt[j] = {'desc': None, 'prompt': None}
|
||||
# Now add the one to which we can register
|
||||
for acct in accounts:
|
||||
for type_ in app.connections[acct[0]].available_transports:
|
||||
if type_ in self.agents:
|
||||
continue
|
||||
self.agents[type_] = []
|
||||
for jid_ in app.connections[acct[0]].available_transports[type_]:
|
||||
if jid_ not in self.agents[type_]:
|
||||
self.agents[type_].append(jid_)
|
||||
self.gateway_prompt[jid_] = {'desc': None,
|
||||
'prompt': None}
|
||||
self.available_types.append(type_)
|
||||
|
||||
uf_type = {'jabber': 'XMPP', 'gadu-gadu': 'Gadu Gadu', 'icq': 'ICQ'}
|
||||
# Jabber as first
|
||||
liststore = self.protocol_combobox.get_model()
|
||||
liststore.append(['XMPP', 'xmpp', 'jabber'])
|
||||
for type_ in self.agents:
|
||||
if type_ == 'jabber':
|
||||
continue
|
||||
if type_ in uf_type:
|
||||
liststore.append([uf_type[type_], type_ + '-online', type_])
|
||||
else:
|
||||
liststore.append([type_, type_ + '-online', type_])
|
||||
|
||||
if account:
|
||||
for service in self.agents[type_]:
|
||||
app.connections[account].request_gateway_prompt(service)
|
||||
self.protocol_combobox.set_active(0)
|
||||
self.auto_authorize_checkbutton.show()
|
||||
|
||||
if jid:
|
||||
self.jid_escaped = True
|
||||
type_ = app.get_transport_name_from_jid(jid)
|
||||
if not type_:
|
||||
type_ = 'jabber'
|
||||
if type_ == 'jabber':
|
||||
self.uid_entry.set_text(jid)
|
||||
else:
|
||||
uid, transport = app.get_name_and_server_from_jid(jid)
|
||||
self.uid_entry.set_text(uid.replace('%', '@', 1))
|
||||
# set protocol_combobox
|
||||
model = self.protocol_combobox.get_model()
|
||||
iter_ = model.get_iter_first()
|
||||
i = 0
|
||||
while iter_:
|
||||
if model[iter_][2] == type_:
|
||||
self.protocol_combobox.set_active(i)
|
||||
break
|
||||
iter_ = model.iter_next(iter_)
|
||||
i += 1
|
||||
|
||||
# set protocol_jid_combobox
|
||||
self.protocol_jid_combobox.set_active(0)
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
iter_ = model.get_iter_first()
|
||||
i = 0
|
||||
while iter_:
|
||||
if model[iter_][0] == transport:
|
||||
self.protocol_jid_combobox.set_active(i)
|
||||
break
|
||||
iter_ = model.iter_next(iter_)
|
||||
i += 1
|
||||
if user_nick:
|
||||
self.nickname_entry.set_text(user_nick)
|
||||
self.nickname_entry.grab_focus()
|
||||
else:
|
||||
self.jid_escaped = False
|
||||
self.uid_entry.grab_focus()
|
||||
group_names = []
|
||||
for acct in accounts:
|
||||
for g in app.groups[acct[0]].keys():
|
||||
if g not in helpers.special_groups and g not in group_names:
|
||||
group_names.append(g)
|
||||
group_names.sort()
|
||||
i = 0
|
||||
for g in group_names:
|
||||
self.group_comboboxentry.append_text(g)
|
||||
if group == g:
|
||||
self.group_comboboxentry.set_active(i)
|
||||
i += 1
|
||||
|
||||
self.show_all()
|
||||
|
||||
self.prompt_label.hide()
|
||||
self.save_message_revealer.hide()
|
||||
|
||||
if len(accounts) > 1:
|
||||
liststore = self.account_combobox.get_model()
|
||||
for acc in accounts:
|
||||
liststore.append(acc)
|
||||
|
||||
self.account_combobox.set_active_id(self.account)
|
||||
else:
|
||||
self.account_label.hide()
|
||||
self.account_combobox.hide()
|
||||
|
||||
if len(self.agents) == 1:
|
||||
self.protocol_label.hide()
|
||||
self.protocol_combobox.hide()
|
||||
self.protocol_jid_combobox.hide()
|
||||
|
||||
if self.account:
|
||||
message_buffer = self.message_textview.get_buffer()
|
||||
msg = helpers.from_one_line(helpers.get_subscription_request_msg(
|
||||
self.account))
|
||||
message_buffer.set_text(msg)
|
||||
|
||||
app.ged.register_event_handler('gateway-prompt-received', ged.GUI1,
|
||||
self._nec_gateway_prompt_received)
|
||||
app.ged.register_event_handler('presence-received', ged.GUI1,
|
||||
self._nec_presence_received)
|
||||
|
||||
def _on_destroy(self, widget):
|
||||
app.ged.remove_event_handler('presence-received', ged.GUI1,
|
||||
self._nec_presence_received)
|
||||
app.ged.remove_event_handler('gateway-prompt-received', ged.GUI1,
|
||||
self._nec_gateway_prompt_received)
|
||||
|
||||
def on_register_button_clicked(self, widget):
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
row = self.protocol_jid_combobox.get_active()
|
||||
jid = model[row][0]
|
||||
app.connections[self.account].request_register_agent_info(jid)
|
||||
|
||||
def _on_key_press(self, widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.destroy()
|
||||
|
||||
def on_cancel_button_clicked(self, widget):
|
||||
"""
|
||||
When Cancel button is clicked
|
||||
"""
|
||||
self.destroy()
|
||||
|
||||
def on_message_textbuffer_changed(self, widget):
|
||||
self.save_message_revealer.show()
|
||||
self.save_message_revealer.set_reveal_child(True)
|
||||
|
||||
def on_add_button_clicked(self, widget):
|
||||
"""
|
||||
When Subscribe button is clicked
|
||||
"""
|
||||
jid = self.uid_entry.get_text().strip()
|
||||
if not jid:
|
||||
ErrorDialog(
|
||||
_('%s Missing') % self.uid_label.get_text(),
|
||||
_('You must supply the %s of the new contact.' %
|
||||
self.uid_label.get_text())
|
||||
)
|
||||
return
|
||||
|
||||
model = self.protocol_combobox.get_model()
|
||||
row = self.protocol_combobox.get_active_iter()
|
||||
type_ = model[row][2]
|
||||
if type_ != 'jabber':
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
row = self.protocol_jid_combobox.get_active()
|
||||
transport = model[row][0]
|
||||
if self.account and not self.jid_escaped:
|
||||
self.adding_jid = (jid, transport, type_)
|
||||
app.connections[self.account].request_gateway_prompt(
|
||||
transport, jid)
|
||||
else:
|
||||
jid = jid.replace('@', '%') + '@' + transport
|
||||
self._add_jid(jid, type_)
|
||||
else:
|
||||
self._add_jid(jid, type_)
|
||||
|
||||
def _add_jid(self, jid, type_):
|
||||
# check if jid is conform to RFC and stringprep it
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat as s:
|
||||
pritext = _('Invalid User ID')
|
||||
ErrorDialog(pritext, str(s))
|
||||
return
|
||||
|
||||
# No resource in jid
|
||||
if jid.find('/') >= 0:
|
||||
pritext = _('Invalid User ID')
|
||||
ErrorDialog(pritext, _('The user ID must not contain a resource.'))
|
||||
return
|
||||
|
||||
if jid == app.get_jid_from_account(self.account):
|
||||
pritext = _('Invalid User ID')
|
||||
ErrorDialog(pritext, _('You cannot add yourself to your roster.'))
|
||||
return
|
||||
|
||||
if not app.account_is_connected(self.account):
|
||||
ErrorDialog(
|
||||
_('Account Offline'),
|
||||
_('Your account must be online to add new contacts.')
|
||||
)
|
||||
return
|
||||
|
||||
nickname = self.nickname_entry.get_text() or ''
|
||||
# get value of account combobox, if account was not specified
|
||||
if not self.account:
|
||||
model = self.account_combobox.get_model()
|
||||
index = self.account_combobox.get_active()
|
||||
self.account = model[index][1]
|
||||
|
||||
# Check if jid is already in roster
|
||||
if jid in app.contacts.get_jid_list(self.account):
|
||||
c = app.contacts.get_first_contact_from_jid(self.account, jid)
|
||||
if _('Not in Roster') not in c.groups and c.sub in ('both', 'to'):
|
||||
ErrorDialog(
|
||||
_('Contact already in roster'),
|
||||
_('This contact is already listed in your roster.'))
|
||||
return
|
||||
|
||||
if type_ == 'jabber':
|
||||
message_buffer = self.message_textview.get_buffer()
|
||||
start_iter = message_buffer.get_start_iter()
|
||||
end_iter = message_buffer.get_end_iter()
|
||||
message = message_buffer.get_text(start_iter, end_iter, True)
|
||||
if self.save_message_checkbutton.get_active():
|
||||
msg = helpers.to_one_line(message)
|
||||
app.config.set_per('accounts', self.account,
|
||||
'subscription_request_msg', msg)
|
||||
else:
|
||||
message = ''
|
||||
group = self.group_comboboxentry.get_child().get_text()
|
||||
groups = []
|
||||
if group:
|
||||
groups = [group]
|
||||
auto_auth = self.auto_authorize_checkbutton.get_active()
|
||||
app.interface.roster.req_sub(
|
||||
self, jid, message, self.account,
|
||||
groups=groups, nickname=nickname, auto_auth=auto_auth)
|
||||
self.destroy()
|
||||
|
||||
def on_account_combobox_changed(self, widget):
|
||||
account = widget.get_active_id()
|
||||
message_buffer = self.message_textview.get_buffer()
|
||||
message_buffer.set_text(helpers.get_subscription_request_msg(account))
|
||||
self.account = account
|
||||
|
||||
def on_protocol_jid_combobox_changed(self, widget):
|
||||
model = widget.get_model()
|
||||
iter_ = widget.get_active_iter()
|
||||
if not iter_:
|
||||
return
|
||||
jid_ = model[iter_][0]
|
||||
model = self.protocol_combobox.get_model()
|
||||
iter_ = self.protocol_combobox.get_active_iter()
|
||||
type_ = model[iter_][2]
|
||||
|
||||
desc = None
|
||||
if self.agents[type_] and jid_ in self.gateway_prompt:
|
||||
desc = self.gateway_prompt[jid_]['desc']
|
||||
|
||||
if desc:
|
||||
self.prompt_label.set_markup(desc)
|
||||
self.prompt_label.show()
|
||||
else:
|
||||
self.prompt_label.hide()
|
||||
|
||||
prompt = None
|
||||
if self.agents[type_] and jid_ in self.gateway_prompt:
|
||||
prompt = self.gateway_prompt[jid_]['prompt']
|
||||
if not prompt:
|
||||
if type_ in self.uid_labels:
|
||||
prompt = self.uid_labels[type_]
|
||||
else:
|
||||
prompt = _('User ID:')
|
||||
self.uid_label.set_text(prompt)
|
||||
|
||||
def on_protocol_combobox_changed(self, widget):
|
||||
model = widget.get_model()
|
||||
iter_ = widget.get_active_iter()
|
||||
type_ = model[iter_][2]
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
model.clear()
|
||||
if len(self.agents[type_]):
|
||||
for jid_ in self.agents[type_]:
|
||||
model.append([jid_])
|
||||
self.protocol_jid_combobox.set_active(0)
|
||||
desc = None
|
||||
if self.agents[type_]:
|
||||
jid_ = self.agents[type_][0]
|
||||
if jid_ in self.gateway_prompt:
|
||||
desc = self.gateway_prompt[jid_]['desc']
|
||||
|
||||
if desc:
|
||||
self.prompt_label.set_markup(desc)
|
||||
self.prompt_label.show()
|
||||
else:
|
||||
self.prompt_label.hide()
|
||||
|
||||
if len(self.agents[type_]) > 1:
|
||||
self.protocol_jid_combobox.show()
|
||||
else:
|
||||
self.protocol_jid_combobox.hide()
|
||||
prompt = None
|
||||
if self.agents[type_]:
|
||||
jid_ = self.agents[type_][0]
|
||||
if jid_ in self.gateway_prompt:
|
||||
prompt = self.gateway_prompt[jid_]['prompt']
|
||||
if not prompt:
|
||||
if type_ in self.uid_labels:
|
||||
prompt = self.uid_labels[type_]
|
||||
else:
|
||||
prompt = _('User ID:')
|
||||
self.uid_label.set_text(prompt)
|
||||
|
||||
if type_ == 'jabber':
|
||||
self.message_scrolledwindow.show()
|
||||
self.save_message_checkbutton.show()
|
||||
else:
|
||||
self.message_scrolledwindow.hide()
|
||||
self.save_message_checkbutton.hide()
|
||||
if type_ in self.available_types:
|
||||
self.register_hbox.show()
|
||||
self.auto_authorize_checkbutton.hide()
|
||||
self.connected_label.hide()
|
||||
self._subscription_table_hide()
|
||||
self.add_button.set_sensitive(False)
|
||||
else:
|
||||
self.register_hbox.hide()
|
||||
if type_ != 'jabber':
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
row = self.protocol_jid_combobox.get_active()
|
||||
jid = model[row][0]
|
||||
contact = app.contacts.get_first_contact_from_jid(
|
||||
self.account, jid)
|
||||
if contact is None or contact.show in ('offline', 'error'):
|
||||
self._subscription_table_hide()
|
||||
self.connected_label.show()
|
||||
self.add_button.set_sensitive(False)
|
||||
self.auto_authorize_checkbutton.hide()
|
||||
return
|
||||
self._subscription_table_show()
|
||||
self.auto_authorize_checkbutton.show()
|
||||
self.connected_label.hide()
|
||||
self.add_button.set_sensitive(True)
|
||||
|
||||
def transport_signed_in(self, jid):
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
row = self.protocol_jid_combobox.get_active()
|
||||
_jid = model[row][0]
|
||||
if _jid == jid:
|
||||
self.register_hbox.hide()
|
||||
self.connected_label.hide()
|
||||
self._subscription_table_show()
|
||||
self.auto_authorize_checkbutton.show()
|
||||
self.add_button.set_sensitive(True)
|
||||
|
||||
def transport_signed_out(self, jid):
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
row = self.protocol_jid_combobox.get_active()
|
||||
_jid = model[row][0]
|
||||
if _jid == jid:
|
||||
self._subscription_table_hide()
|
||||
self.auto_authorize_checkbutton.hide()
|
||||
self.connected_label.show()
|
||||
self.add_button.set_sensitive(False)
|
||||
|
||||
def _nec_presence_received(self, obj):
|
||||
if app.jid_is_transport(obj.jid):
|
||||
if obj.old_show == 0 and obj.new_show > 1:
|
||||
self.transport_signed_in(obj.jid)
|
||||
elif obj.old_show > 1 and obj.new_show == 0:
|
||||
self.transport_signed_out(obj.jid)
|
||||
|
||||
def _nec_gateway_prompt_received(self, obj):
|
||||
if self.adding_jid:
|
||||
jid, transport, type_ = self.adding_jid
|
||||
if obj.stanza.getError():
|
||||
ErrorDialog(
|
||||
_('Error while adding transport contact'),
|
||||
_('This error occured while adding a contact for transport '
|
||||
'%(transport)s:\n\n%(error)s') % {
|
||||
'transport': transport,
|
||||
'error': obj.stanza.getErrorMsg()})
|
||||
return
|
||||
if obj.prompt_jid:
|
||||
self._add_jid(obj.prompt_jid, type_)
|
||||
else:
|
||||
jid = jid.replace('@', '%') + '@' + transport
|
||||
self._add_jid(jid, type_)
|
||||
elif obj.jid in self.gateway_prompt:
|
||||
if obj.desc:
|
||||
self.gateway_prompt[obj.jid]['desc'] = obj.desc
|
||||
if obj.prompt:
|
||||
self.gateway_prompt[obj.jid]['prompt'] = obj.prompt
|
||||
|
||||
def _subscription_table_hide(self):
|
||||
for widget in self.subscription_table:
|
||||
widget.hide()
|
||||
|
||||
def _subscription_table_show(self):
|
||||
for widget in self.subscription_table:
|
||||
widget.show()
|
|
@ -0,0 +1,933 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gi.repository import Gtk
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.util import load_icon
|
||||
|
||||
|
||||
class HigDialog(Gtk.MessageDialog):
|
||||
def __init__(self, parent, type_, buttons, pritext, sectext,
|
||||
on_response_ok=None, on_response_cancel=None, on_response_yes=None,
|
||||
on_response_no=None):
|
||||
self.call_cancel_on_destroy = True
|
||||
Gtk.MessageDialog.__init__(self, transient_for=parent,
|
||||
modal=True, destroy_with_parent=True,
|
||||
message_type=type_, buttons=buttons, text=pritext)
|
||||
|
||||
self.format_secondary_markup(sectext)
|
||||
|
||||
self.possible_responses = {Gtk.ResponseType.OK: on_response_ok,
|
||||
Gtk.ResponseType.CANCEL: on_response_cancel,
|
||||
Gtk.ResponseType.YES: on_response_yes,
|
||||
Gtk.ResponseType.NO: on_response_no}
|
||||
|
||||
self.connect('response', self.on_response)
|
||||
self.connect('destroy', self.on_dialog_destroy)
|
||||
|
||||
def on_response(self, dialog, response_id):
|
||||
if response_id not in self.possible_responses:
|
||||
return
|
||||
if not self.possible_responses[response_id]:
|
||||
self.destroy()
|
||||
elif isinstance(self.possible_responses[response_id], tuple):
|
||||
if len(self.possible_responses[response_id]) == 1:
|
||||
self.possible_responses[response_id][0](dialog)
|
||||
else:
|
||||
self.possible_responses[response_id][0](dialog,
|
||||
*self.possible_responses[response_id][1:])
|
||||
else:
|
||||
self.possible_responses[response_id](dialog)
|
||||
|
||||
def on_dialog_destroy(self, widget):
|
||||
if not self.call_cancel_on_destroy:
|
||||
return
|
||||
cancel_handler = self.possible_responses[Gtk.ResponseType.CANCEL]
|
||||
if not cancel_handler:
|
||||
return False
|
||||
if isinstance(cancel_handler, tuple):
|
||||
cancel_handler[0](None, *cancel_handler[1:])
|
||||
else:
|
||||
cancel_handler(None)
|
||||
|
||||
def popup(self):
|
||||
"""
|
||||
Show dialog
|
||||
"""
|
||||
vb = self.get_children()[0].get_children()[0] # Give focus to top vbox
|
||||
# vb.set_flags(Gtk.CAN_FOCUS)
|
||||
vb.grab_focus()
|
||||
self.show_all()
|
||||
|
||||
|
||||
class AspellDictError:
|
||||
def __init__(self, lang):
|
||||
ErrorDialog(
|
||||
_('Dictionary for language "%s" not available') % lang,
|
||||
_('You have to install the dictionary "%s" to use spellchecking, '
|
||||
'or choose another language by setting the speller_language '
|
||||
'option.\n\n'
|
||||
'Highlighting misspelled words feature will not be used') % lang)
|
||||
|
||||
|
||||
class ConfirmationDialog(HigDialog):
|
||||
"""
|
||||
HIG compliant confirmation dialog
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', on_response_ok=None,
|
||||
on_response_cancel=None, transient_for=None):
|
||||
self.user_response_ok = on_response_ok
|
||||
self.user_response_cancel = on_response_cancel
|
||||
HigDialog.__init__(self, transient_for,
|
||||
Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL, pritext, sectext,
|
||||
self.on_response_ok, self.on_response_cancel)
|
||||
self.popup()
|
||||
|
||||
def on_response_ok(self, widget):
|
||||
if self.user_response_ok:
|
||||
if isinstance(self.user_response_ok, tuple):
|
||||
self.user_response_ok[0](*self.user_response_ok[1:])
|
||||
else:
|
||||
self.user_response_ok()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def on_response_cancel(self, widget):
|
||||
if self.user_response_cancel:
|
||||
if isinstance(self.user_response_cancel, tuple):
|
||||
self.user_response_cancel[0](*self.user_response_ok[1:])
|
||||
else:
|
||||
self.user_response_cancel()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
|
||||
class NonModalConfirmationDialog(HigDialog):
|
||||
"""
|
||||
HIG compliant non modal confirmation dialog
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', on_response_ok=None,
|
||||
on_response_cancel=None):
|
||||
self.user_response_ok = on_response_ok
|
||||
self.user_response_cancel = on_response_cancel
|
||||
if hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, Gtk.MessageType.QUESTION,
|
||||
Gtk.ButtonsType.OK_CANCEL, pritext, sectext, self.on_response_ok,
|
||||
self.on_response_cancel)
|
||||
self.set_modal(False)
|
||||
|
||||
def on_response_ok(self, widget):
|
||||
if self.user_response_ok:
|
||||
if isinstance(self.user_response_ok, tuple):
|
||||
self.user_response_ok[0](*self.user_response_ok[1:])
|
||||
else:
|
||||
self.user_response_ok()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def on_response_cancel(self, widget):
|
||||
if self.user_response_cancel:
|
||||
if isinstance(self.user_response_cancel, tuple):
|
||||
self.user_response_cancel[0](*self.user_response_cancel[1:])
|
||||
else:
|
||||
self.user_response_cancel()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
|
||||
class WarningDialog(HigDialog):
|
||||
"""
|
||||
HIG compliant warning dialog
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', transient_for=None):
|
||||
if not transient_for and hasattr(app.interface, 'roster') and \
|
||||
app.interface.roster:
|
||||
transient_for = app.interface.roster.window
|
||||
HigDialog.__init__(self, transient_for, Gtk.MessageType.WARNING,
|
||||
Gtk.ButtonsType.OK, pritext, sectext)
|
||||
self.set_modal(False)
|
||||
self.popup()
|
||||
|
||||
|
||||
class InformationDialog(HigDialog):
|
||||
"""
|
||||
HIG compliant info dialog
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', transient_for=None):
|
||||
if transient_for:
|
||||
parent = transient_for
|
||||
elif hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
|
||||
pritext, sectext)
|
||||
self.set_modal(False)
|
||||
self.popup()
|
||||
|
||||
|
||||
class ErrorDialog(HigDialog):
|
||||
"""
|
||||
HIG compliant error dialog
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', on_response_ok=None,
|
||||
on_response_cancel=None, transient_for=None):
|
||||
if transient_for:
|
||||
parent = transient_for
|
||||
elif hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
|
||||
pritext, sectext, on_response_ok=on_response_ok,
|
||||
on_response_cancel=on_response_cancel)
|
||||
self.popup()
|
||||
|
||||
|
||||
class YesNoDialog(HigDialog):
|
||||
"""
|
||||
HIG compliant YesNo dialog
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', checktext='', text_label=None,
|
||||
on_response_yes=None, on_response_no=None, type_=Gtk.MessageType.QUESTION,
|
||||
transient_for=None):
|
||||
self.user_response_yes = on_response_yes
|
||||
self.user_response_no = on_response_no
|
||||
if transient_for:
|
||||
parent = transient_for
|
||||
elif hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, type_, Gtk.ButtonsType.YES_NO, pritext,
|
||||
sectext, on_response_yes=self.on_response_yes,
|
||||
on_response_no=self.on_response_no)
|
||||
|
||||
vbox = self.get_content_area()
|
||||
if checktext:
|
||||
self.checkbutton = Gtk.CheckButton.new_with_mnemonic(checktext)
|
||||
vbox.pack_start(self.checkbutton, False, True, 0)
|
||||
else:
|
||||
self.checkbutton = None
|
||||
if text_label:
|
||||
label = Gtk.Label(label=text_label)
|
||||
vbox.pack_start(label, False, True, 0)
|
||||
buff = Gtk.TextBuffer()
|
||||
self.textview = Gtk.TextView.new_with_buffer(buff)
|
||||
frame = Gtk.Frame()
|
||||
frame.set_shadow_type(Gtk.ShadowType.IN)
|
||||
frame.add(self.textview)
|
||||
vbox.pack_start(frame, False, True, 0)
|
||||
else:
|
||||
self.textview = None
|
||||
self.set_modal(False)
|
||||
self.popup()
|
||||
|
||||
def on_response_yes(self, widget):
|
||||
if self.user_response_yes:
|
||||
if self.textview:
|
||||
buff = self.textview.get_buffer()
|
||||
start, end = buff.get_bounds()
|
||||
txt = self.textview.get_buffer().get_text(start, end, True)
|
||||
|
||||
if isinstance(self.user_response_yes, tuple):
|
||||
if self.textview:
|
||||
self.user_response_yes[0](self.is_checked(), txt,
|
||||
*self.user_response_yes[1:])
|
||||
else:
|
||||
self.user_response_yes[0](self.is_checked(),
|
||||
*self.user_response_yes[1:])
|
||||
else:
|
||||
if self.textview:
|
||||
self.user_response_yes(self.is_checked(), txt)
|
||||
else:
|
||||
self.user_response_yes(self.is_checked())
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def on_response_no(self, widget):
|
||||
if self.user_response_no:
|
||||
if self.textview:
|
||||
buff = self.textview.get_buffer()
|
||||
start, end = buff.get_bounds()
|
||||
txt = self.textview.get_buffer().get_text(start, end, True)
|
||||
|
||||
if isinstance(self.user_response_no, tuple):
|
||||
if self.textview:
|
||||
self.user_response_no[0](txt, *self.user_response_no[1:])
|
||||
else:
|
||||
self.user_response_no[0](*self.user_response_no[1:])
|
||||
else:
|
||||
if self.textview:
|
||||
self.user_response_no(txt)
|
||||
else:
|
||||
self.user_response_no()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def is_checked(self):
|
||||
"""
|
||||
Get active state of the checkbutton
|
||||
"""
|
||||
if not self.checkbutton:
|
||||
return False
|
||||
return self.checkbutton.get_active()
|
||||
|
||||
|
||||
class ConfirmationDialogCheck(ConfirmationDialog):
|
||||
"""
|
||||
HIG compliant confirmation dialog with checkbutton
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', checktext='', on_response_ok=None,
|
||||
on_response_cancel=None, is_modal=True, transient_for=None):
|
||||
self.user_response_ok = on_response_ok
|
||||
self.user_response_cancel = on_response_cancel
|
||||
|
||||
if transient_for:
|
||||
parent = transient_for
|
||||
elif hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, Gtk.MessageType.QUESTION,
|
||||
Gtk.ButtonsType.OK_CANCEL, pritext, sectext, self.on_response_ok,
|
||||
self.on_response_cancel)
|
||||
|
||||
self.set_default_response(Gtk.ResponseType.OK)
|
||||
|
||||
ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
|
||||
ok_button.grab_focus()
|
||||
|
||||
self.checkbutton = Gtk.CheckButton.new_with_mnemonic(checktext)
|
||||
self.get_content_area().pack_start(self.checkbutton, False, True, 0)
|
||||
self.set_modal(is_modal)
|
||||
self.popup()
|
||||
|
||||
def on_response_ok(self, widget):
|
||||
if self.user_response_ok:
|
||||
if isinstance(self.user_response_ok, tuple):
|
||||
self.user_response_ok[0](self.is_checked(),
|
||||
*self.user_response_ok[1:])
|
||||
else:
|
||||
self.user_response_ok(self.is_checked())
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def on_response_cancel(self, widget):
|
||||
if self.user_response_cancel:
|
||||
if isinstance(self.user_response_cancel, tuple):
|
||||
self.user_response_cancel[0](self.is_checked(),
|
||||
*self.user_response_cancel[1:])
|
||||
else:
|
||||
self.user_response_cancel(self.is_checked())
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def is_checked(self):
|
||||
"""
|
||||
Get active state of the checkbutton
|
||||
"""
|
||||
return self.checkbutton.get_active()
|
||||
|
||||
|
||||
class ConfirmationDialogDoubleCheck(ConfirmationDialog):
|
||||
"""
|
||||
HIG compliant confirmation dialog with 2 checkbuttons
|
||||
"""
|
||||
|
||||
def __init__(self, pritext, sectext='', checktext1='', checktext2='',
|
||||
tooltip1='', tooltip2='', on_response_ok=None, on_response_cancel=None,
|
||||
is_modal=True):
|
||||
self.user_response_ok = on_response_ok
|
||||
self.user_response_cancel = on_response_cancel
|
||||
|
||||
if hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, Gtk.MessageType.QUESTION,
|
||||
Gtk.ButtonsType.OK_CANCEL, pritext, sectext, self.on_response_ok,
|
||||
self.on_response_cancel)
|
||||
|
||||
self.set_default_response(Gtk.ResponseType.OK)
|
||||
|
||||
ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
|
||||
ok_button.grab_focus()
|
||||
|
||||
vbox = self.get_content_area()
|
||||
if checktext1:
|
||||
self.checkbutton1 = Gtk.CheckButton.new_with_mnemonic(checktext1)
|
||||
if tooltip1:
|
||||
self.checkbutton1.set_tooltip_text(tooltip1)
|
||||
vbox.pack_start(self.checkbutton1, False, True, 0)
|
||||
else:
|
||||
self.checkbutton1 = None
|
||||
if checktext2:
|
||||
self.checkbutton2 = Gtk.CheckButton.new_with_mnemonic(checktext2)
|
||||
if tooltip2:
|
||||
self.checkbutton2.set_tooltip_text(tooltip2)
|
||||
vbox.pack_start(self.checkbutton2, False, True, 0)
|
||||
else:
|
||||
self.checkbutton2 = None
|
||||
|
||||
self.set_modal(is_modal)
|
||||
self.popup()
|
||||
|
||||
def on_response_ok(self, widget):
|
||||
if self.user_response_ok:
|
||||
if isinstance(self.user_response_ok, tuple):
|
||||
self.user_response_ok[0](self.is_checked(),
|
||||
*self.user_response_ok[1:])
|
||||
else:
|
||||
self.user_response_ok(self.is_checked())
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def on_response_cancel(self, widget):
|
||||
if self.user_response_cancel:
|
||||
if isinstance(self.user_response_cancel, tuple):
|
||||
self.user_response_cancel[0](*self.user_response_cancel[1:])
|
||||
else:
|
||||
self.user_response_cancel()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def is_checked(self):
|
||||
''' Get active state of the checkbutton '''
|
||||
if self.checkbutton1:
|
||||
is_checked_1 = self.checkbutton1.get_active()
|
||||
else:
|
||||
is_checked_1 = False
|
||||
if self.checkbutton2:
|
||||
is_checked_2 = self.checkbutton2.get_active()
|
||||
else:
|
||||
is_checked_2 = False
|
||||
return [is_checked_1, is_checked_2]
|
||||
|
||||
|
||||
class PlainConnectionDialog(ConfirmationDialogDoubleCheck):
|
||||
"""
|
||||
Dialog that is shown when using an insecure connection
|
||||
"""
|
||||
def __init__(self, account, on_ok, on_cancel):
|
||||
pritext = _('Insecure connection')
|
||||
sectext = _('You are about to connect to the account %(account)s '
|
||||
'(%(server)s) insecurely. This means conversations will not be '
|
||||
'encrypted, and is strongly discouraged.\nAre you sure you want '
|
||||
'to do that?') % {'account': account,
|
||||
'server': app.get_hostname_from_account(account)}
|
||||
checktext1 = _('Yes, I really want to connect insecurely')
|
||||
tooltip1 = _('Gajim will NOT connect unless you check this box')
|
||||
checktext2 = _('_Do not ask me again')
|
||||
ConfirmationDialogDoubleCheck.__init__(self, pritext, sectext,
|
||||
checktext1, checktext2, tooltip1=tooltip1, on_response_ok=on_ok,
|
||||
on_response_cancel=on_cancel, is_modal=False)
|
||||
self.ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
|
||||
self.ok_button.set_sensitive(False)
|
||||
self.checkbutton1.connect('clicked', self.on_checkbutton_clicked)
|
||||
self.set_title(_('Insecure connection'))
|
||||
|
||||
def on_checkbutton_clicked(self, widget):
|
||||
self.ok_button.set_sensitive(widget.get_active())
|
||||
|
||||
class ConfirmationDialogDoubleRadio(ConfirmationDialog):
|
||||
"""
|
||||
HIG compliant confirmation dialog with 2 radios
|
||||
"""
|
||||
def __init__(self, pritext, sectext='', radiotext1='', radiotext2='',
|
||||
on_response_ok=None, on_response_cancel=None, is_modal=True, transient_for=None):
|
||||
self.user_response_ok = on_response_ok
|
||||
self.user_response_cancel = on_response_cancel
|
||||
|
||||
if transient_for is None:
|
||||
transient_for = app.app.get_active_window()
|
||||
HigDialog.__init__(self, transient_for, Gtk.MessageType.QUESTION,
|
||||
Gtk.ButtonsType.OK_CANCEL, pritext, sectext, self.on_response_ok,
|
||||
self.on_response_cancel)
|
||||
|
||||
self.set_default_response(Gtk.ResponseType.OK)
|
||||
|
||||
ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
|
||||
ok_button.grab_focus()
|
||||
|
||||
vbox = self.get_content_area()
|
||||
self.radiobutton1 = Gtk.RadioButton(label=radiotext1)
|
||||
vbox.pack_start(self.radiobutton1, False, True, 0)
|
||||
|
||||
self.radiobutton2 = Gtk.RadioButton(group=self.radiobutton1,
|
||||
label=radiotext2)
|
||||
vbox.pack_start(self.radiobutton2, False, True, 0)
|
||||
|
||||
self.set_modal(is_modal)
|
||||
self.popup()
|
||||
|
||||
def on_response_ok(self, widget):
|
||||
if self.user_response_ok:
|
||||
if isinstance(self.user_response_ok, tuple):
|
||||
self.user_response_ok[0](self.is_checked(),
|
||||
*self.user_response_ok[1:])
|
||||
else:
|
||||
self.user_response_ok(self.is_checked())
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def on_response_cancel(self, widget):
|
||||
if self.user_response_cancel:
|
||||
if isinstance(self.user_response_cancel, tuple):
|
||||
self.user_response_cancel[0](*self.user_response_cancel[1:])
|
||||
else:
|
||||
self.user_response_cancel()
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
def is_checked(self):
|
||||
''' Get active state of the checkbutton '''
|
||||
if self.radiobutton1:
|
||||
is_checked_1 = self.radiobutton1.get_active()
|
||||
else:
|
||||
is_checked_1 = False
|
||||
if self.radiobutton2:
|
||||
is_checked_2 = self.radiobutton2.get_active()
|
||||
else:
|
||||
is_checked_2 = False
|
||||
return [is_checked_1, is_checked_2]
|
||||
|
||||
class FTOverwriteConfirmationDialog(ConfirmationDialog):
|
||||
"""
|
||||
HIG compliant confirmation dialog to overwrite or resume a file transfert
|
||||
"""
|
||||
def __init__(self, pritext, sectext='', propose_resume=True,
|
||||
on_response=None, transient_for=None):
|
||||
if transient_for:
|
||||
parent = transient_for
|
||||
elif hasattr(app.interface, 'roster') and app.interface.roster:
|
||||
parent = app.interface.roster.window
|
||||
else:
|
||||
parent = None
|
||||
HigDialog.__init__(self, parent, Gtk.MessageType.QUESTION,
|
||||
Gtk.ButtonsType.CANCEL, pritext, sectext)
|
||||
|
||||
self.on_response = on_response
|
||||
|
||||
if propose_resume:
|
||||
b = Gtk.Button(label='', stock=Gtk.STOCK_REFRESH)
|
||||
align = b.get_children()[0]
|
||||
hbox = align.get_children()[0]
|
||||
label = hbox.get_children()[1]
|
||||
label.set_text(_('_Resume'))
|
||||
label.set_use_underline(True)
|
||||
self.add_action_widget(b, 100)
|
||||
|
||||
b = Gtk.Button(label='', stock=Gtk.STOCK_SAVE_AS)
|
||||
align = b.get_children()[0]
|
||||
hbox = align.get_children()[0]
|
||||
label = hbox.get_children()[1]
|
||||
label.set_text(_('Re_place'))
|
||||
label.set_use_underline(True)
|
||||
self.add_action_widget(b, 200)
|
||||
|
||||
self.connect('response', self.on_dialog_response)
|
||||
self.show_all()
|
||||
|
||||
def on_dialog_response(self, dialog, response):
|
||||
if self.on_response:
|
||||
if isinstance(self.on_response, tuple):
|
||||
self.on_response[0](response, *self.on_response[1:])
|
||||
else:
|
||||
self.on_response(response)
|
||||
self.call_cancel_on_destroy = False
|
||||
self.destroy()
|
||||
|
||||
|
||||
class CommonInputDialog:
|
||||
"""
|
||||
Common Class for Input dialogs
|
||||
"""
|
||||
|
||||
def __init__(self, title, label_str, is_modal, ok_handler, cancel_handler,
|
||||
transient_for=None):
|
||||
self.dialog = self.xml.get_object('input_dialog')
|
||||
label = self.xml.get_object('label')
|
||||
self.dialog.set_title(title)
|
||||
label.set_markup(label_str)
|
||||
self.cancel_handler = cancel_handler
|
||||
self.vbox = self.xml.get_object('vbox')
|
||||
if transient_for:
|
||||
self.dialog.set_transient_for(transient_for)
|
||||
else:
|
||||
self.dialog.set_transient_for(app.interface.roster.window)
|
||||
|
||||
self.ok_handler = ok_handler
|
||||
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.xml.connect_signals(self)
|
||||
self.dialog.show_all()
|
||||
|
||||
def on_input_dialog_destroy(self, widget):
|
||||
if self.cancel_handler:
|
||||
self.cancel_handler()
|
||||
|
||||
def on_okbutton_clicked(self, widget):
|
||||
user_input = self.get_text()
|
||||
if user_input:
|
||||
user_input = user_input
|
||||
self.cancel_handler = None
|
||||
self.dialog.destroy()
|
||||
if isinstance(self.ok_handler, tuple):
|
||||
self.ok_handler[0](user_input, *self.ok_handler[1:])
|
||||
else:
|
||||
self.ok_handler(user_input)
|
||||
|
||||
def on_cancelbutton_clicked(self, widget):
|
||||
self.dialog.destroy()
|
||||
|
||||
def destroy(self):
|
||||
self.dialog.destroy()
|
||||
|
||||
|
||||
class InputDialog(CommonInputDialog):
|
||||
"""
|
||||
Class for Input dialog
|
||||
"""
|
||||
|
||||
def __init__(self, title, label_str, input_str=None, is_modal=True,
|
||||
ok_handler=None, cancel_handler=None, transient_for=None):
|
||||
self.xml = get_builder('input_dialog.ui')
|
||||
CommonInputDialog.__init__(self, title, label_str, is_modal,
|
||||
ok_handler, cancel_handler,
|
||||
transient_for=transient_for)
|
||||
self.input_entry = self.xml.get_object('input_entry')
|
||||
if input_str:
|
||||
self.set_entry(input_str)
|
||||
|
||||
def on_input_dialog_delete_event(self, widget, event):
|
||||
'''
|
||||
may be implemented by subclasses
|
||||
'''
|
||||
pass
|
||||
|
||||
def set_entry(self, value):
|
||||
self.input_entry.set_text(value)
|
||||
self.input_entry.select_region(0, -1) # select all
|
||||
|
||||
def get_text(self):
|
||||
return self.input_entry.get_text()
|
||||
|
||||
|
||||
class InputDialogCheck(InputDialog):
|
||||
"""
|
||||
Class for Input dialog
|
||||
"""
|
||||
|
||||
def __init__(self, title, label_str, checktext='', input_str=None,
|
||||
is_modal=True, ok_handler=None, cancel_handler=None,
|
||||
transient_for=None):
|
||||
self.xml = get_builder('input_dialog.ui')
|
||||
InputDialog.__init__(self, title, label_str, input_str=input_str,
|
||||
is_modal=is_modal, ok_handler=ok_handler,
|
||||
cancel_handler=cancel_handler,
|
||||
transient_for=transient_for)
|
||||
self.input_entry = self.xml.get_object('input_entry')
|
||||
if input_str:
|
||||
self.input_entry.set_text(input_str)
|
||||
self.input_entry.select_region(0, -1) # select all
|
||||
|
||||
if checktext:
|
||||
self.checkbutton = Gtk.CheckButton.new_with_mnemonic(checktext)
|
||||
self.vbox.pack_start(self.checkbutton, False, True, 0)
|
||||
self.checkbutton.show()
|
||||
|
||||
def on_okbutton_clicked(self, widget):
|
||||
user_input = self.get_text()
|
||||
if user_input:
|
||||
user_input = user_input
|
||||
self.cancel_handler = None
|
||||
self.dialog.destroy()
|
||||
if isinstance(self.ok_handler, tuple):
|
||||
self.ok_handler[0](user_input, self.is_checked(), *self.ok_handler[1:])
|
||||
else:
|
||||
self.ok_handler(user_input, self.is_checked())
|
||||
|
||||
def get_text(self):
|
||||
return self.input_entry.get_text()
|
||||
|
||||
def is_checked(self):
|
||||
"""
|
||||
Get active state of the checkbutton
|
||||
"""
|
||||
try:
|
||||
return self.checkbutton.get_active()
|
||||
except Exception:
|
||||
# There is no checkbutton
|
||||
return False
|
||||
|
||||
|
||||
class ChangeNickDialog(InputDialogCheck):
|
||||
"""
|
||||
Class for changing room nickname in case of conflict
|
||||
"""
|
||||
|
||||
def __init__(self, account, room_jid, title, prompt, check_text=None,
|
||||
change_nick=False, transient_for=None):
|
||||
"""
|
||||
change_nick must be set to True when we are already occupant of the room
|
||||
and we are changing our nick
|
||||
"""
|
||||
InputDialogCheck.__init__(self, title, '', checktext=check_text,
|
||||
input_str='', is_modal=True, ok_handler=None,
|
||||
cancel_handler=None,
|
||||
transient_for=transient_for)
|
||||
self.room_queue = [(account, room_jid, prompt, change_nick)]
|
||||
self.check_next()
|
||||
|
||||
def on_input_dialog_delete_event(self, widget, event):
|
||||
self.on_cancelbutton_clicked(widget)
|
||||
return True
|
||||
|
||||
def setup_dialog(self):
|
||||
self.gc_control = app.interface.msg_win_mgr.get_gc_control(
|
||||
self.room_jid, self.account)
|
||||
if not self.gc_control and \
|
||||
self.room_jid in app.interface.minimized_controls[self.account]:
|
||||
self.gc_control = \
|
||||
app.interface.minimized_controls[self.account][self.room_jid]
|
||||
if not self.gc_control:
|
||||
self.check_next()
|
||||
return
|
||||
label = self.xml.get_object('label')
|
||||
label.set_markup(self.prompt)
|
||||
self.set_entry(self.gc_control.nick + \
|
||||
app.config.get('gc_proposed_nick_char'))
|
||||
|
||||
def check_next(self):
|
||||
if len(self.room_queue) == 0:
|
||||
self.cancel_handler = None
|
||||
self.dialog.destroy()
|
||||
if 'change_nick_dialog' in app.interface.instances:
|
||||
del app.interface.instances['change_nick_dialog']
|
||||
return
|
||||
self.account, self.room_jid, self.prompt, self.change_nick = \
|
||||
self.room_queue.pop(0)
|
||||
self.setup_dialog()
|
||||
|
||||
if app.new_room_nick is not None and not app.gc_connected[
|
||||
self.account][self.room_jid] and self.gc_control.nick != \
|
||||
app.new_room_nick:
|
||||
self.dialog.hide()
|
||||
self.on_ok(app.new_room_nick, True)
|
||||
else:
|
||||
self.dialog.show()
|
||||
|
||||
def on_okbutton_clicked(self, widget):
|
||||
nick = self.get_text()
|
||||
if nick:
|
||||
nick = nick
|
||||
# send presence to room
|
||||
try:
|
||||
nick = helpers.parse_resource(nick)
|
||||
except Exception:
|
||||
# invalid char
|
||||
ErrorDialog(_('Invalid nickname'),
|
||||
_('The nickname contains invalid characters.'))
|
||||
return
|
||||
self.on_ok(nick, self.is_checked())
|
||||
|
||||
def on_ok(self, nick, is_checked):
|
||||
if is_checked:
|
||||
app.new_room_nick = nick
|
||||
app.connections[self.account].join_gc(nick, self.room_jid, None,
|
||||
change_nick=self.change_nick)
|
||||
if app.gc_connected[self.account][self.room_jid]:
|
||||
# We are changing nick, we will change self.nick when we receive
|
||||
# presence that inform that it works
|
||||
self.gc_control.new_nick = nick
|
||||
else:
|
||||
# We are connecting, we will not get a changed nick presence so
|
||||
# change it NOW. We don't already have a nick so it's harmless
|
||||
self.gc_control.nick = nick
|
||||
self.check_next()
|
||||
|
||||
def on_cancelbutton_clicked(self, widget):
|
||||
self.gc_control.new_nick = ''
|
||||
self.check_next()
|
||||
|
||||
def add_room(self, account, room_jid, prompt, change_nick=False):
|
||||
if (account, room_jid, prompt, change_nick) not in self.room_queue:
|
||||
self.room_queue.append((account, room_jid, prompt, change_nick))
|
||||
|
||||
|
||||
class InputTextDialog(CommonInputDialog):
|
||||
"""
|
||||
Class for multilines Input dialog (more place than InputDialog)
|
||||
"""
|
||||
|
||||
def __init__(self, title, label_str, input_str=None, is_modal=True,
|
||||
ok_handler=None, cancel_handler=None, transient_for=None):
|
||||
self.xml = get_builder('input_text_dialog.ui')
|
||||
CommonInputDialog.__init__(self, title, label_str, is_modal,
|
||||
ok_handler, cancel_handler,
|
||||
transient_for=transient_for)
|
||||
self.input_buffer = self.xml.get_object('input_textview').get_buffer()
|
||||
if input_str:
|
||||
self.input_buffer.set_text(input_str)
|
||||
start_iter, end_iter = self.input_buffer.get_bounds()
|
||||
self.input_buffer.select_range(start_iter, end_iter) # select all
|
||||
|
||||
def get_text(self):
|
||||
start_iter, end_iter = self.input_buffer.get_bounds()
|
||||
return self.input_buffer.get_text(start_iter, end_iter, True)
|
||||
|
||||
|
||||
class DoubleInputDialog:
|
||||
"""
|
||||
Class for Double Input dialog
|
||||
"""
|
||||
|
||||
def __init__(self, title, label_str1, label_str2, input_str1=None,
|
||||
input_str2=None, is_modal=True, ok_handler=None, cancel_handler=None,
|
||||
transient_for=None):
|
||||
self.xml = get_builder('dubbleinput_dialog.ui')
|
||||
self.dialog = self.xml.get_object('dubbleinput_dialog')
|
||||
label1 = self.xml.get_object('label1')
|
||||
self.input_entry1 = self.xml.get_object('input_entry1')
|
||||
label2 = self.xml.get_object('label2')
|
||||
self.input_entry2 = self.xml.get_object('input_entry2')
|
||||
self.dialog.set_title(title)
|
||||
label1.set_markup(label_str1)
|
||||
label2.set_markup(label_str2)
|
||||
self.cancel_handler = cancel_handler
|
||||
if input_str1:
|
||||
self.input_entry1.set_text(input_str1)
|
||||
self.input_entry1.select_region(0, -1) # select all
|
||||
if input_str2:
|
||||
self.input_entry2.set_text(input_str2)
|
||||
self.input_entry2.select_region(0, -1) # select all
|
||||
if transient_for:
|
||||
self.dialog.set_transient_for(transient_for)
|
||||
|
||||
self.dialog.set_modal(is_modal)
|
||||
|
||||
self.ok_handler = ok_handler
|
||||
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.xml.connect_signals(self)
|
||||
self.dialog.show_all()
|
||||
|
||||
def on_dubbleinput_dialog_destroy(self, widget):
|
||||
if not self.cancel_handler:
|
||||
return False
|
||||
if isinstance(self.cancel_handler, tuple):
|
||||
self.cancel_handler[0](*self.cancel_handler[1:])
|
||||
else:
|
||||
self.cancel_handler()
|
||||
|
||||
def on_okbutton_clicked(self, widget):
|
||||
user_input1 = self.input_entry1.get_text()
|
||||
user_input2 = self.input_entry2.get_text()
|
||||
self.cancel_handler = None
|
||||
self.dialog.destroy()
|
||||
if not self.ok_handler:
|
||||
return
|
||||
if isinstance(self.ok_handler, tuple):
|
||||
self.ok_handler[0](user_input1, user_input2, *self.ok_handler[1:])
|
||||
else:
|
||||
self.ok_handler(user_input1, user_input2)
|
||||
|
||||
def on_cancelbutton_clicked(self, widget):
|
||||
self.dialog.destroy()
|
||||
if not self.cancel_handler:
|
||||
return
|
||||
if isinstance(self.cancel_handler, tuple):
|
||||
self.cancel_handler[0](*self.cancel_handler[1:])
|
||||
else:
|
||||
self.cancel_handler()
|
||||
|
||||
|
||||
class CertificatDialog(InformationDialog):
|
||||
def __init__(self, parent, account, cert):
|
||||
issuer = cert.get_issuer()
|
||||
subject = cert.get_subject()
|
||||
InformationDialog.__init__(self,
|
||||
_('Certificate for account %s') % account, _('''<b>Issued to:</b>
|
||||
Common Name (CN): %(scn)s
|
||||
Organization (O): %(sorg)s
|
||||
Organizationl Unit (OU): %(sou)s
|
||||
Serial Number: %(sn)s
|
||||
|
||||
<b>Issued by:</b>
|
||||
Common Name (CN): %(icn)s
|
||||
Organization (O): %(iorg)s
|
||||
Organizationl Unit (OU): %(iou)s
|
||||
|
||||
<b>Validity:</b>
|
||||
Issued on: %(io)s
|
||||
Expires on: %(eo)s
|
||||
|
||||
<b>Fingerprint</b>
|
||||
SHA-1 Fingerprint: %(sha1)s
|
||||
|
||||
SHA-256 Fingerprint: %(sha256)s
|
||||
''') % {
|
||||
'scn': subject.commonName, 'sorg': subject.organizationName,
|
||||
'sou': subject.organizationalUnitName,
|
||||
'sn': cert.get_serial_number(), 'icn': issuer.commonName,
|
||||
'iorg': issuer.organizationName,
|
||||
'iou': issuer.organizationalUnitName,
|
||||
'io': cert.get_notBefore().decode('utf-8'),
|
||||
'eo': cert.get_notAfter().decode('utf-8'),
|
||||
'sha1': cert.digest('sha1').decode('utf-8'),
|
||||
'sha256': cert.digest('sha256').decode('utf-8')})
|
||||
surface = load_icon('application-certificate', self, size=32)
|
||||
if surface is not None:
|
||||
img = Gtk.Image.new_from_surface(surface)
|
||||
img.show_all()
|
||||
self.set_image(img)
|
||||
self.set_transient_for(parent)
|
||||
self.set_title(_('Certificate for account %s') % account)
|
||||
|
||||
|
||||
class SSLErrorDialog(ConfirmationDialogDoubleCheck):
|
||||
def __init__(self, account, certificate, pritext, sectext, checktext1,
|
||||
checktext2, on_response_ok=None, on_response_cancel=None):
|
||||
self.account = account
|
||||
self.cert = certificate
|
||||
ConfirmationDialogDoubleCheck.__init__(
|
||||
self, pritext, sectext,
|
||||
checktext1, checktext2, on_response_ok=on_response_ok,
|
||||
on_response_cancel=on_response_cancel, is_modal=False)
|
||||
b = Gtk.Button(_('View cert…'))
|
||||
b.connect('clicked', self.on_cert_clicked)
|
||||
b.show_all()
|
||||
area = self.get_action_area()
|
||||
area.pack_start(b, True, True, 0)
|
||||
|
||||
def on_cert_clicked(self, button):
|
||||
CertificatDialog(self, self.account, self.cert)
|
|
@ -1,5 +1,3 @@
|
|||
# Copyright (C) 2017 Philipp Hörist <philipp AT hoerist.com>
|
||||
#
|
||||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
|
@ -25,7 +23,7 @@ from gajim.common import ged
|
|||
from gajim.common.const import ArchiveState
|
||||
from gajim.gtk.util import load_icon
|
||||
|
||||
log = logging.getLogger('gajim.c.message_archiving')
|
||||
log = logging.getLogger('gajim.gtk.history_sync')
|
||||
|
||||
|
||||
class Pages(IntEnum):
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import nbxmpp
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.common import ged
|
||||
from gajim.common.caps_cache import muc_caps_cache
|
||||
from gajim.common.exceptions import GajimGeneralException
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk.util import get_builder
|
||||
|
||||
|
||||
class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
||||
def __init__(self, account, room_jid, password=None, automatic=None,
|
||||
transient_for=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 Group Chat'))
|
||||
if transient_for:
|
||||
self.set_transient_for(transient_for)
|
||||
|
||||
self.automatic = automatic
|
||||
self.password = password
|
||||
self.requested_jid = None
|
||||
self.room_jid = room_jid
|
||||
self.account = account
|
||||
|
||||
if self.room_jid is None:
|
||||
self.minimal_mode = False
|
||||
else:
|
||||
self.minimal_mode = True
|
||||
|
||||
glade_objects = ['main_box', 'account_label', 'account_combo',
|
||||
'server_label', 'server_combo', 'room_entry',
|
||||
'recently_button', 'recently_popover',
|
||||
'recently_treeview', 'search_button', 'password_label',
|
||||
'password_entry', 'nick_entry', 'bookmark_switch',
|
||||
'autojoin_switch']
|
||||
|
||||
self.builder = get_builder('join_groupchat_window.ui')
|
||||
for obj in glade_objects:
|
||||
setattr(self, obj, self.builder.get_object(obj))
|
||||
|
||||
self.add(self.main_box)
|
||||
|
||||
# Show widgets depending on the mode the window is in
|
||||
if not self.minimal_mode:
|
||||
self.recently_button.show()
|
||||
self.search_button.show()
|
||||
|
||||
accounts = app.get_enabled_accounts_with_labels()
|
||||
account_liststore = self.account_combo.get_model()
|
||||
for acc in accounts:
|
||||
account_liststore.append(acc)
|
||||
|
||||
if not accounts:
|
||||
return
|
||||
|
||||
if not self.account:
|
||||
self.account = accounts[0][0]
|
||||
|
||||
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)
|
||||
|
||||
# Hide account combobox if there is only one account
|
||||
if len(accounts) == 1:
|
||||
self.account_combo.hide()
|
||||
self.account_label.hide()
|
||||
|
||||
self.account_combo.set_active_id(self.account)
|
||||
|
||||
if self.minimal_mode:
|
||||
if '@' in self.room_jid:
|
||||
(room, server) = self.room_jid.split('@')
|
||||
self.room_entry.set_text(room)
|
||||
if not muc_caps_cache.supports(
|
||||
self.room_jid, 'muc_passwordprotected'):
|
||||
self.password_entry.hide()
|
||||
self.password_label.hide()
|
||||
self.nick_entry.grab_focus()
|
||||
else:
|
||||
self.password_entry.grab_focus()
|
||||
else:
|
||||
server = self.room_jid
|
||||
self.room_entry.grab_focus()
|
||||
|
||||
self.server_combo.insert_text(0, server)
|
||||
self.server_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_id()
|
||||
if not app.connections[acc].private_storage_supported:
|
||||
self.bookmark_switch.set_sensitive(False)
|
||||
self.autojoin_switch.set_sensitive(False)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def set_room(self, room_jid):
|
||||
room, server = app.get_name_and_server_from_jid(room_jid)
|
||||
self.room_entry.set_text(room)
|
||||
self.server_combo.get_child().set_text(server)
|
||||
|
||||
def _fill_recent_and_servers(self, account):
|
||||
recently_liststore = self.recently_treeview.get_model()
|
||||
recently_liststore.clear()
|
||||
self.server_combo.remove_all()
|
||||
recent = app.get_recent_groupchats(account)
|
||||
servers = []
|
||||
for groupchat in recent:
|
||||
label = '%s@%s' % (groupchat.room, groupchat.server)
|
||||
|
||||
recently_liststore.append([groupchat.server,
|
||||
groupchat.room,
|
||||
groupchat.nickname,
|
||||
label])
|
||||
servers.append(groupchat.server)
|
||||
|
||||
self.recently_button.set_sensitive(bool(recent))
|
||||
|
||||
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_selected(self, treeview, *args):
|
||||
(model, iter_) = treeview.get_selection().get_selected()
|
||||
self.server_combo.get_child().set_text(model[iter_][0])
|
||||
self.room_entry.set_text(model[iter_][1])
|
||||
self.nick_entry.set_text(model[iter_][2])
|
||||
self.recently_popover.popdown()
|
||||
|
||||
def _on_account_combo_changed(self, combo):
|
||||
account = combo.get_active_id()
|
||||
self.account = account
|
||||
self.nick_entry.set_text(app.nicks[account])
|
||||
self._fill_recent_and_servers(account)
|
||||
|
||||
def _on_jid_detection_changed(self, widget):
|
||||
text = widget.get_text()
|
||||
if text.startswith('xmpp:'):
|
||||
text = text[5:]
|
||||
if '@' in text:
|
||||
room, server = text.split('@', 1)
|
||||
server = server.split('?')[0]
|
||||
widget.set_text('')
|
||||
|
||||
if room:
|
||||
self.room_entry.set_text(room)
|
||||
|
||||
if server:
|
||||
self.server_combo.get_child().set_text(server)
|
||||
else:
|
||||
self.server_combo.grab_focus()
|
||||
|
||||
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_id()
|
||||
nickname = self.nick_entry.get_text()
|
||||
|
||||
invisible_show = app.SHOW_LIST.index('invisible')
|
||||
if app.connections[account].connected == invisible_show:
|
||||
app.interface.raise_dialog('join-while-invisible')
|
||||
return
|
||||
|
||||
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)
|
||||
self.room_jid = self.room_jid.lower()
|
||||
|
||||
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):
|
||||
bookmark_state = switch.get_active()
|
||||
self.autojoin_switch.set_sensitive(bookmark_state)
|
||||
if not bookmark_state:
|
||||
self.autojoin_switch.set_active(False)
|
||||
|
||||
def _add_bookmark(self, account, nickname, password):
|
||||
con = app.connections[account]
|
||||
if not con.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)
|
||||
con.get_module('Bookmarks').add_bookmark(
|
||||
name, self.room_jid, autojoin, 1, password, nickname)
|
||||
|
||||
def _on_destroy(self, *args):
|
||||
if not self.minimal_mode:
|
||||
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().strip()
|
||||
self.requested_jid = server
|
||||
app.connections[self.account].discoverInfo(server)
|
||||
|
||||
def _nec_agent_info_error_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
if obj.jid != self.requested_jid:
|
||||
return
|
||||
self.requested_jid = None
|
||||
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:
|
||||
return
|
||||
if obj.jid != self.requested_jid:
|
||||
return
|
||||
self.requested_jid = None
|
||||
if nbxmpp.NS_MUC not in obj.features:
|
||||
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.\
|
||||
present()
|
||||
else:
|
||||
try:
|
||||
# Object will add itself to the window dict
|
||||
from gajim.disco import ServiceDiscoveryWindow
|
||||
ServiceDiscoveryWindow(
|
||||
self.account, obj.jid,
|
||||
initial_identities=[{'category': 'conference',
|
||||
'type': 'text'}])
|
||||
except GajimGeneralException:
|
||||
pass
|
|
@ -21,7 +21,7 @@ from gajim.common import app
|
|||
from gajim.common import ged
|
||||
from gajim.gtk.util import get_builder
|
||||
|
||||
from gajim.dialogs import HigDialog
|
||||
from gajim.gtk import HigDialog
|
||||
|
||||
log = logging.getLogger('gajim.gtk.mam_preferences')
|
||||
|
||||
|
|
|
@ -0,0 +1,547 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GObject
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import ged
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk.util import get_builder
|
||||
|
||||
|
||||
class PrivacyListWindow:
|
||||
def __init__(self, account, privacy_list_name, action):
|
||||
'''action is 'EDIT' or 'NEW' depending on if we create a new priv list
|
||||
or edit an already existing one'''
|
||||
self.account = account
|
||||
self.privacy_list_name = privacy_list_name
|
||||
|
||||
# Dicts and Default Values
|
||||
self.active_rule = ''
|
||||
self.global_rules = {}
|
||||
self.list_of_groups = {}
|
||||
|
||||
self.max_order = 0
|
||||
|
||||
# Default Edit Values
|
||||
self.edit_rule_type = 'jid'
|
||||
self.allow_deny = 'allow'
|
||||
|
||||
# Connect to gtk builder
|
||||
self.xml = get_builder('privacy_list_window.ui')
|
||||
self.window = self.xml.get_object('privacy_list_edit_window')
|
||||
|
||||
# Add Widgets
|
||||
|
||||
for widget_to_add in ('title_hbox', 'privacy_lists_title_label',
|
||||
'list_of_rules_label', 'add_edit_rule_label', 'delete_open_buttons_hbox',
|
||||
'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton',
|
||||
'list_of_rules_combobox', 'delete_open_buttons_hbox',
|
||||
'delete_rule_button', 'open_rule_button', 'edit_allow_radiobutton',
|
||||
'edit_deny_radiobutton', 'edit_type_jabberid_radiobutton',
|
||||
'edit_type_jabberid_entry', 'edit_type_group_radiobutton',
|
||||
'edit_type_group_combobox', 'edit_type_subscription_radiobutton',
|
||||
'edit_type_subscription_combobox', 'edit_type_select_all_radiobutton',
|
||||
'edit_queries_send_checkbutton', 'edit_send_messages_checkbutton',
|
||||
'edit_view_status_checkbutton', 'edit_all_checkbutton',
|
||||
'edit_order_spinbutton', 'new_rule_button', 'save_rule_button',
|
||||
'privacy_list_refresh_button', 'privacy_list_close_button',
|
||||
'edit_send_status_checkbutton', 'add_edit_vbox',
|
||||
'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton'):
|
||||
self.__dict__[widget_to_add] = self.xml.get_object(widget_to_add)
|
||||
|
||||
self.privacy_lists_title_label.set_label(
|
||||
_('Privacy List <b><i>%s</i></b>') %
|
||||
GLib.markup_escape_text(self.privacy_list_name))
|
||||
|
||||
if len(app.connections) > 1:
|
||||
title = _('Privacy List for %s') % self.account
|
||||
else:
|
||||
title = _('Privacy List')
|
||||
|
||||
self.delete_rule_button.set_sensitive(False)
|
||||
self.open_rule_button.set_sensitive(False)
|
||||
self.privacy_list_active_checkbutton.set_sensitive(False)
|
||||
self.privacy_list_default_checkbutton.set_sensitive(False)
|
||||
self.list_of_rules_combobox.set_sensitive(False)
|
||||
|
||||
# set jabber id completion
|
||||
jids_list_store = Gtk.ListStore(GObject.TYPE_STRING)
|
||||
for jid in app.contacts.get_jid_list(self.account):
|
||||
jids_list_store.append([jid])
|
||||
jid_entry_completion = Gtk.EntryCompletion()
|
||||
jid_entry_completion.set_text_column(0)
|
||||
jid_entry_completion.set_model(jids_list_store)
|
||||
jid_entry_completion.set_popup_completion(True)
|
||||
self.edit_type_jabberid_entry.set_completion(jid_entry_completion)
|
||||
if action == 'EDIT':
|
||||
self.refresh_rules()
|
||||
|
||||
model = self.edit_type_group_combobox.get_model()
|
||||
count = 0
|
||||
for group in app.groups[self.account]:
|
||||
self.list_of_groups[group] = count
|
||||
count += 1
|
||||
model.append([group])
|
||||
self.edit_type_group_combobox.set_active(0)
|
||||
|
||||
self.window.set_title(title)
|
||||
|
||||
app.ged.register_event_handler('privacy-list-received', ged.GUI1,
|
||||
self._nec_privacy_list_received)
|
||||
app.ged.register_event_handler('privacy-lists-received', ged.GUI1,
|
||||
self._nec_privacy_lists_received)
|
||||
|
||||
self.window.show_all()
|
||||
self.add_edit_vbox.hide()
|
||||
|
||||
self.xml.connect_signals(self)
|
||||
|
||||
def on_key_press_event(self, widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.window.destroy()
|
||||
|
||||
def on_privacy_list_edit_window_destroy(self, widget):
|
||||
key_name = 'privacy_list_%s' % self.privacy_list_name
|
||||
if key_name in app.interface.instances[self.account]:
|
||||
del app.interface.instances[self.account][key_name]
|
||||
app.ged.remove_event_handler('privacy-list-received', ged.GUI1,
|
||||
self._nec_privacy_list_received)
|
||||
app.ged.remove_event_handler('privacy-lists-received', ged.GUI1,
|
||||
self._nec_privacy_lists_received)
|
||||
|
||||
def _nec_privacy_lists_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
if obj.active_list == self.privacy_list_name:
|
||||
self.privacy_list_active_checkbutton.set_active(True)
|
||||
else:
|
||||
self.privacy_list_active_checkbutton.set_active(False)
|
||||
if obj.default_list == self.privacy_list_name:
|
||||
self.privacy_list_default_checkbutton.set_active(True)
|
||||
else:
|
||||
self.privacy_list_default_checkbutton.set_active(False)
|
||||
|
||||
def privacy_list_received(self, rules):
|
||||
model = self.list_of_rules_combobox.get_model()
|
||||
model.clear()
|
||||
self.global_rules = {}
|
||||
for rule in rules:
|
||||
if 'type' in rule:
|
||||
text_item = _('Order: %(order)s, action: %(action)s, type: %(type)s'
|
||||
', value: %(value)s') % {'order': rule['order'],
|
||||
'action': rule['action'], 'type': rule['type'],
|
||||
'value': rule['value']}
|
||||
else:
|
||||
text_item = _('Order: %(order)s, action: %(action)s') % \
|
||||
{'order': rule['order'], 'action': rule['action']}
|
||||
if int(rule['order']) > self.max_order:
|
||||
self.max_order = int(rule['order'])
|
||||
self.global_rules[text_item] = rule
|
||||
model.append([text_item])
|
||||
if len(rules) == 0:
|
||||
self.title_hbox.set_sensitive(False)
|
||||
self.list_of_rules_combobox.set_sensitive(False)
|
||||
self.delete_rule_button.set_sensitive(False)
|
||||
self.open_rule_button.set_sensitive(False)
|
||||
self.privacy_list_active_checkbutton.set_sensitive(False)
|
||||
self.privacy_list_default_checkbutton.set_sensitive(False)
|
||||
else:
|
||||
self.list_of_rules_combobox.set_active(0)
|
||||
self.title_hbox.set_sensitive(True)
|
||||
self.list_of_rules_combobox.set_sensitive(True)
|
||||
self.delete_rule_button.set_sensitive(True)
|
||||
self.open_rule_button.set_sensitive(True)
|
||||
self.privacy_list_active_checkbutton.set_sensitive(True)
|
||||
self.privacy_list_default_checkbutton.set_sensitive(True)
|
||||
self.reset_fields()
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').get_privacy_lists()
|
||||
|
||||
def _nec_privacy_list_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
if obj.list_name != self.privacy_list_name:
|
||||
return
|
||||
self.privacy_list_received(obj.rules)
|
||||
|
||||
def refresh_rules(self):
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').get_privacy_list(self.privacy_list_name)
|
||||
|
||||
def on_delete_rule_button_clicked(self, widget):
|
||||
model = self.list_of_rules_combobox.get_model()
|
||||
iter_ = self.list_of_rules_combobox.get_active_iter()
|
||||
_rule = model[iter_][0]
|
||||
tags = []
|
||||
for rule in self.global_rules:
|
||||
if rule != _rule:
|
||||
tags.append(self.global_rules[rule])
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').set_privacy_list(
|
||||
self.privacy_list_name, tags)
|
||||
self.privacy_list_received(tags)
|
||||
self.add_edit_vbox.hide()
|
||||
if not tags: # we removed latest rule
|
||||
if 'privacy_lists' in app.interface.instances[self.account]:
|
||||
win = app.interface.instances[self.account]['privacy_lists']
|
||||
win.remove_privacy_list_from_combobox(self.privacy_list_name)
|
||||
win.draw_widgets()
|
||||
|
||||
def on_open_rule_button_clicked(self, widget):
|
||||
self.add_edit_rule_label.set_label(_('<b>Edit a rule</b>'))
|
||||
active_num = self.list_of_rules_combobox.get_active()
|
||||
if active_num == -1:
|
||||
self.active_rule = ''
|
||||
else:
|
||||
model = self.list_of_rules_combobox.get_model()
|
||||
iter_ = self.list_of_rules_combobox.get_active_iter()
|
||||
self.active_rule = model[iter_][0]
|
||||
if self.active_rule != '':
|
||||
rule_info = self.global_rules[self.active_rule]
|
||||
self.edit_order_spinbutton.set_value(int(rule_info['order']))
|
||||
if 'type' in rule_info:
|
||||
if rule_info['type'] == 'jid':
|
||||
self.edit_type_jabberid_radiobutton.set_active(True)
|
||||
self.edit_type_jabberid_entry.set_text(rule_info['value'])
|
||||
elif rule_info['type'] == 'group':
|
||||
self.edit_type_group_radiobutton.set_active(True)
|
||||
if rule_info['value'] in self.list_of_groups:
|
||||
self.edit_type_group_combobox.set_active(
|
||||
self.list_of_groups[rule_info['value']])
|
||||
else:
|
||||
self.edit_type_group_combobox.set_active(0)
|
||||
elif rule_info['type'] == 'subscription':
|
||||
self.edit_type_subscription_radiobutton.set_active(True)
|
||||
sub_value = rule_info['value']
|
||||
if sub_value == 'none':
|
||||
self.edit_type_subscription_combobox.set_active(0)
|
||||
elif sub_value == 'both':
|
||||
self.edit_type_subscription_combobox.set_active(1)
|
||||
elif sub_value == 'from':
|
||||
self.edit_type_subscription_combobox.set_active(2)
|
||||
elif sub_value == 'to':
|
||||
self.edit_type_subscription_combobox.set_active(3)
|
||||
else:
|
||||
self.edit_type_select_all_radiobutton.set_active(True)
|
||||
else:
|
||||
self.edit_type_select_all_radiobutton.set_active(True)
|
||||
self.edit_send_messages_checkbutton.set_active(False)
|
||||
self.edit_queries_send_checkbutton.set_active(False)
|
||||
self.edit_view_status_checkbutton.set_active(False)
|
||||
self.edit_send_status_checkbutton.set_active(False)
|
||||
self.edit_all_checkbutton.set_active(False)
|
||||
if not rule_info['child']:
|
||||
self.edit_all_checkbutton.set_active(True)
|
||||
else:
|
||||
if 'presence-out' in rule_info['child']:
|
||||
self.edit_send_status_checkbutton.set_active(True)
|
||||
if 'presence-in' in rule_info['child']:
|
||||
self.edit_view_status_checkbutton.set_active(True)
|
||||
if 'iq' in rule_info['child']:
|
||||
self.edit_queries_send_checkbutton.set_active(True)
|
||||
if 'message' in rule_info['child']:
|
||||
self.edit_send_messages_checkbutton.set_active(True)
|
||||
|
||||
if rule_info['action'] == 'allow':
|
||||
self.edit_allow_radiobutton.set_active(True)
|
||||
else:
|
||||
self.edit_deny_radiobutton.set_active(True)
|
||||
self.add_edit_vbox.show()
|
||||
|
||||
def on_edit_all_checkbutton_toggled(self, widget):
|
||||
if widget.get_active():
|
||||
self.edit_send_messages_checkbutton.set_active(True)
|
||||
self.edit_queries_send_checkbutton.set_active(True)
|
||||
self.edit_view_status_checkbutton.set_active(True)
|
||||
self.edit_send_status_checkbutton.set_active(True)
|
||||
self.edit_send_messages_checkbutton.set_sensitive(False)
|
||||
self.edit_queries_send_checkbutton.set_sensitive(False)
|
||||
self.edit_view_status_checkbutton.set_sensitive(False)
|
||||
self.edit_send_status_checkbutton.set_sensitive(False)
|
||||
else:
|
||||
self.edit_send_messages_checkbutton.set_active(False)
|
||||
self.edit_queries_send_checkbutton.set_active(False)
|
||||
self.edit_view_status_checkbutton.set_active(False)
|
||||
self.edit_send_status_checkbutton.set_active(False)
|
||||
self.edit_send_messages_checkbutton.set_sensitive(True)
|
||||
self.edit_queries_send_checkbutton.set_sensitive(True)
|
||||
self.edit_view_status_checkbutton.set_sensitive(True)
|
||||
self.edit_send_status_checkbutton.set_sensitive(True)
|
||||
|
||||
def on_privacy_list_active_checkbutton_toggled(self, widget):
|
||||
name = None
|
||||
if widget.get_active():
|
||||
name = self.privacy_list_name
|
||||
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').set_active_list(name)
|
||||
|
||||
def on_privacy_list_default_checkbutton_toggled(self, widget):
|
||||
name = None
|
||||
if widget.get_active():
|
||||
name = self.privacy_list_name
|
||||
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').set_default_list(name)
|
||||
|
||||
def on_new_rule_button_clicked(self, widget):
|
||||
self.reset_fields()
|
||||
self.add_edit_vbox.show()
|
||||
|
||||
def reset_fields(self):
|
||||
self.edit_type_jabberid_entry.set_text('')
|
||||
self.edit_allow_radiobutton.set_active(True)
|
||||
self.edit_type_jabberid_radiobutton.set_active(True)
|
||||
self.active_rule = ''
|
||||
self.edit_send_messages_checkbutton.set_active(False)
|
||||
self.edit_queries_send_checkbutton.set_active(False)
|
||||
self.edit_view_status_checkbutton.set_active(False)
|
||||
self.edit_send_status_checkbutton.set_active(False)
|
||||
self.edit_all_checkbutton.set_active(False)
|
||||
self.edit_order_spinbutton.set_value(self.max_order + 1)
|
||||
self.edit_type_group_combobox.set_active(0)
|
||||
self.edit_type_subscription_combobox.set_active(0)
|
||||
self.add_edit_rule_label.set_label(_('<b>Add a rule</b>'))
|
||||
|
||||
def get_current_tags(self):
|
||||
if self.edit_type_jabberid_radiobutton.get_active():
|
||||
edit_type = 'jid'
|
||||
edit_value = self.edit_type_jabberid_entry.get_text()
|
||||
elif self.edit_type_group_radiobutton.get_active():
|
||||
edit_type = 'group'
|
||||
model = self.edit_type_group_combobox.get_model()
|
||||
iter_ = self.edit_type_group_combobox.get_active_iter()
|
||||
edit_value = model[iter_][0]
|
||||
elif self.edit_type_subscription_radiobutton.get_active():
|
||||
edit_type = 'subscription'
|
||||
subs = ['none', 'both', 'from', 'to']
|
||||
edit_value = subs[self.edit_type_subscription_combobox.get_active()]
|
||||
elif self.edit_type_select_all_radiobutton.get_active():
|
||||
edit_type = ''
|
||||
edit_value = ''
|
||||
edit_order = str(self.edit_order_spinbutton.get_value_as_int())
|
||||
if self.edit_allow_radiobutton.get_active():
|
||||
edit_deny = 'allow'
|
||||
else:
|
||||
edit_deny = 'deny'
|
||||
child = []
|
||||
if not self.edit_all_checkbutton.get_active():
|
||||
if self.edit_send_messages_checkbutton.get_active():
|
||||
child.append('message')
|
||||
if self.edit_queries_send_checkbutton.get_active():
|
||||
child.append('iq')
|
||||
if self.edit_send_status_checkbutton.get_active():
|
||||
child.append('presence-out')
|
||||
if self.edit_view_status_checkbutton.get_active():
|
||||
child.append('presence-in')
|
||||
if edit_type != '':
|
||||
return {'order': edit_order, 'action': edit_deny,
|
||||
'type': edit_type, 'value': edit_value, 'child': child}
|
||||
return {'order': edit_order, 'action': edit_deny, 'child': child}
|
||||
|
||||
def on_save_rule_button_clicked(self, widget):
|
||||
tags = []
|
||||
current_tags = self.get_current_tags()
|
||||
if int(current_tags['order']) > self.max_order:
|
||||
self.max_order = int(current_tags['order'])
|
||||
if self.active_rule == '':
|
||||
tags.append(current_tags)
|
||||
|
||||
for rule in self.global_rules:
|
||||
if rule != self.active_rule:
|
||||
tags.append(self.global_rules[rule])
|
||||
else:
|
||||
tags.append(current_tags)
|
||||
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').set_privacy_list(
|
||||
self.privacy_list_name, tags)
|
||||
self.refresh_rules()
|
||||
self.add_edit_vbox.hide()
|
||||
if 'privacy_lists' in app.interface.instances[self.account]:
|
||||
win = app.interface.instances[self.account]['privacy_lists']
|
||||
win.add_privacy_list_to_combobox(self.privacy_list_name)
|
||||
win.draw_widgets()
|
||||
|
||||
def on_list_of_rules_combobox_changed(self, widget):
|
||||
self.add_edit_vbox.hide()
|
||||
|
||||
def on_edit_type_radiobutton_changed(self, widget, radiobutton):
|
||||
active_bool = widget.get_active()
|
||||
if active_bool:
|
||||
self.edit_rule_type = radiobutton
|
||||
|
||||
def on_edit_allow_radiobutton_changed(self, widget, radiobutton):
|
||||
active_bool = widget.get_active()
|
||||
if active_bool:
|
||||
self.allow_deny = radiobutton
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
class PrivacyListsWindow:
|
||||
"""
|
||||
Window that is the main window for Privacy Lists; we can list there the
|
||||
privacy lists and ask to create a new one or edit an already there one
|
||||
"""
|
||||
def __init__(self, account):
|
||||
self.account = account
|
||||
self.privacy_lists_save = []
|
||||
|
||||
self.xml = get_builder('privacy_lists_window.ui')
|
||||
|
||||
self.window = self.xml.get_object('privacy_lists_first_window')
|
||||
for widget_to_add in (
|
||||
'list_of_privacy_lists_combobox', 'delete_privacy_list_button',
|
||||
'open_privacy_list_button', 'new_privacy_list_button',
|
||||
'new_privacy_list_entry', 'privacy_lists_refresh_button',
|
||||
'close_privacy_lists_window_button'):
|
||||
self.__dict__[widget_to_add] = self.xml.get_object(widget_to_add)
|
||||
|
||||
self.draw_privacy_lists_in_combobox([])
|
||||
self.privacy_lists_refresh()
|
||||
|
||||
self.enabled = True
|
||||
|
||||
if len(app.connections) > 1:
|
||||
title = _('Privacy Lists for %s') % self.account
|
||||
else:
|
||||
title = _('Privacy Lists')
|
||||
|
||||
self.window.set_title(title)
|
||||
|
||||
app.ged.register_event_handler('privacy-lists-received', ged.GUI1,
|
||||
self._nec_privacy_lists_received)
|
||||
app.ged.register_event_handler('privacy-list-removed', ged.GUI1,
|
||||
self._nec_privacy_lists_removed)
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
self.xml.connect_signals(self)
|
||||
|
||||
def on_key_press_event(self, widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.window.destroy()
|
||||
|
||||
def on_privacy_lists_first_window_destroy(self, widget):
|
||||
if 'privacy_lists' in app.interface.instances[self.account]:
|
||||
del app.interface.instances[self.account]['privacy_lists']
|
||||
app.ged.remove_event_handler('privacy-lists-received', ged.GUI1,
|
||||
self._nec_privacy_lists_received)
|
||||
app.ged.remove_event_handler('privacy-list-removed', ged.GUI1,
|
||||
self._nec_privacy_lists_removed)
|
||||
|
||||
def remove_privacy_list_from_combobox(self, privacy_list):
|
||||
if privacy_list not in self.privacy_lists_save:
|
||||
return
|
||||
|
||||
model = self.list_of_privacy_lists_combobox.get_model()
|
||||
for entry in model:
|
||||
if entry[0] == privacy_list:
|
||||
model.remove(entry.iter)
|
||||
|
||||
self.privacy_lists_save.remove(privacy_list)
|
||||
|
||||
def add_privacy_list_to_combobox(self, privacy_list):
|
||||
if privacy_list in self.privacy_lists_save:
|
||||
return
|
||||
model = self.list_of_privacy_lists_combobox.get_model()
|
||||
model.append([privacy_list])
|
||||
self.privacy_lists_save.append(privacy_list)
|
||||
|
||||
def draw_privacy_lists_in_combobox(self, privacy_lists):
|
||||
self.list_of_privacy_lists_combobox.set_active(-1)
|
||||
self.list_of_privacy_lists_combobox.get_model().clear()
|
||||
self.privacy_lists_save = []
|
||||
for add_item in privacy_lists:
|
||||
self.add_privacy_list_to_combobox(add_item)
|
||||
self.draw_widgets()
|
||||
|
||||
def draw_widgets(self):
|
||||
if len(self.privacy_lists_save) == 0:
|
||||
self.list_of_privacy_lists_combobox.set_sensitive(False)
|
||||
self.open_privacy_list_button.set_sensitive(False)
|
||||
self.delete_privacy_list_button.set_sensitive(False)
|
||||
else:
|
||||
self.list_of_privacy_lists_combobox.set_sensitive(True)
|
||||
self.list_of_privacy_lists_combobox.set_active(0)
|
||||
self.open_privacy_list_button.set_sensitive(True)
|
||||
self.delete_privacy_list_button.set_sensitive(True)
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def on_delete_privacy_list_button_clicked(self, widget):
|
||||
active_list = self.privacy_lists_save[
|
||||
self.list_of_privacy_lists_combobox.get_active()]
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').del_privacy_list(active_list)
|
||||
|
||||
def privacy_list_removed(self, active_list):
|
||||
self.privacy_lists_save.remove(active_list)
|
||||
self.privacy_lists_received(self.privacy_lists_save)
|
||||
|
||||
def _nec_privacy_lists_removed(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
self.privacy_list_removed(obj.list_name)
|
||||
|
||||
def privacy_lists_received(self, lists):
|
||||
privacy_lists = []
|
||||
for privacy_list in lists:
|
||||
privacy_lists.append(privacy_list)
|
||||
self.draw_privacy_lists_in_combobox(privacy_lists)
|
||||
|
||||
def _nec_privacy_lists_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
self.privacy_lists_received(obj.lists)
|
||||
|
||||
def privacy_lists_refresh(self):
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PrivacyLists').get_privacy_lists()
|
||||
|
||||
def on_new_privacy_list_button_clicked(self, widget):
|
||||
name = self.new_privacy_list_entry.get_text()
|
||||
if not name:
|
||||
ErrorDialog(
|
||||
_('Invalid List Name'),
|
||||
_('You must enter a name to create a privacy list.'),
|
||||
transient_for=self.window)
|
||||
return
|
||||
key_name = 'privacy_list_%s' % name
|
||||
if key_name in app.interface.instances[self.account]:
|
||||
app.interface.instances[self.account][key_name].window.present()
|
||||
else:
|
||||
app.interface.instances[self.account][key_name] = \
|
||||
PrivacyListWindow(self.account, name, 'NEW')
|
||||
self.new_privacy_list_entry.set_text('')
|
||||
|
||||
def on_privacy_lists_refresh_button_clicked(self, widget):
|
||||
self.privacy_lists_refresh()
|
||||
|
||||
def on_open_privacy_list_button_clicked(self, widget):
|
||||
name = self.privacy_lists_save[
|
||||
self.list_of_privacy_lists_combobox.get_active()]
|
||||
key_name = 'privacy_list_%s' % name
|
||||
if key_name in app.interface.instances[self.account]:
|
||||
app.interface.instances[self.account][key_name].window.present()
|
||||
else:
|
||||
app.interface.instances[self.account][key_name] = \
|
||||
PrivacyListWindow(self.account, name, 'EDIT')
|
|
@ -1,34 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2017 Philipp Hörist <philipp AT hoerist.com>
|
||||
#
|
||||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from gi.repository import Gtk
|
||||
import nbxmpp
|
||||
from gi.repository import Gtk
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import ged
|
||||
from gajim.gtkgui_helpers import get_icon_pixmap, Color
|
||||
|
||||
log = logging.getLogger('gajim.serverinfo')
|
||||
log = logging.getLogger('gajim.gtk.serverinfo')
|
||||
|
||||
|
||||
class ServerInfoDialog(Gtk.Dialog):
|
||||
|
@ -221,16 +215,18 @@ class FeatureItem(Gtk.Grid):
|
|||
|
||||
def set_feature(self, available, enabled):
|
||||
if not available:
|
||||
self.icon.set_from_pixbuf(
|
||||
get_icon_pixmap('window-close-symbolic', color=[Color.RED]))
|
||||
self.icon.set_from_icon_name('window-close-symbolic',
|
||||
Gtk.IconSize.MENU)
|
||||
self.icon.get_style_context().add_class('error-color')
|
||||
elif enabled is False:
|
||||
self.icon.set_from_pixbuf(
|
||||
get_icon_pixmap('dialog-warning-symbolic',
|
||||
color=[Color.ORANGE]))
|
||||
self.icon.set_from_icon_name('dialog-warning-symbolic',
|
||||
Gtk.IconSize.MENU)
|
||||
self.tooltip += _('\nDisabled in config')
|
||||
self.icon.get_style_context().add_class('warning-color')
|
||||
else:
|
||||
self.icon.set_from_pixbuf(
|
||||
get_icon_pixmap('emblem-ok-symbolic', color=[Color.GREEN]))
|
||||
self.icon.set_from_icon_name('emblem-ok-symbolic',
|
||||
Gtk.IconSize.MENU)
|
||||
self.icon.get_style_context().add_class('success-color')
|
||||
|
||||
def update(self, feature):
|
||||
self.tooltip = feature.tooltip
|
|
@ -0,0 +1,335 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import dataforms
|
||||
from gajim.common import helpers
|
||||
from gajim.common.connection_handlers_events import MessageOutgoingEvent
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import AspellDictError
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.util import get_iconset_name_for
|
||||
from gajim.gtk.util import get_completion_liststore
|
||||
from gajim.gtk.util import move_window
|
||||
from gajim.gtk.util import resize_window
|
||||
from gajim.dataforms_widget import DataFormWidget
|
||||
from gajim.conversation_textview import ConversationTextview
|
||||
|
||||
|
||||
if app.is_installed('GSPELL'):
|
||||
from gi.repository import Gspell
|
||||
|
||||
|
||||
class SingleMessageWindow:
|
||||
"""
|
||||
SingleMessageWindow can send or show a received singled message depending on
|
||||
action argument which can be 'send' or 'receive'
|
||||
"""
|
||||
# Keep a reference on windows so garbage collector don't restroy them
|
||||
instances = []
|
||||
def __init__(self, account, to='', action='', from_whom='', subject='',
|
||||
message='', resource='', session=None, form_node=None):
|
||||
self.instances.append(self)
|
||||
self.account = account
|
||||
self.action = action
|
||||
|
||||
self.subject = subject
|
||||
self.message = message
|
||||
self.to = to
|
||||
self.from_whom = from_whom
|
||||
self.resource = resource
|
||||
self.session = session
|
||||
|
||||
self.xml = get_builder('single_message_window.ui')
|
||||
self.window = self.xml.get_object('single_message_window')
|
||||
self.count_chars_label = self.xml.get_object('count_chars_label')
|
||||
self.from_label = self.xml.get_object('from_label')
|
||||
self.from_entry = self.xml.get_object('from_entry')
|
||||
self.to_label = self.xml.get_object('to_label')
|
||||
self.to_entry = self.xml.get_object('to_entry')
|
||||
self.subject_entry = self.xml.get_object('subject_entry')
|
||||
self.message_scrolledwindow = self.xml.get_object(
|
||||
'message_scrolledwindow')
|
||||
self.message_textview = self.xml.get_object('message_textview')
|
||||
self.message_tv_buffer = self.message_textview.get_buffer()
|
||||
self.conversation_scrolledwindow = self.xml.get_object(
|
||||
'conversation_scrolledwindow')
|
||||
self.conversation_textview = ConversationTextview(
|
||||
account, used_in_history_window=True)
|
||||
self.conversation_textview.tv.show()
|
||||
self.conversation_tv_buffer = self.conversation_textview.tv.get_buffer()
|
||||
self.xml.get_object('conversation_scrolledwindow').add(
|
||||
self.conversation_textview.tv)
|
||||
|
||||
self.form_widget = None
|
||||
parent_box = self.xml.get_object('conversation_scrolledwindow').\
|
||||
get_parent()
|
||||
if form_node:
|
||||
dataform = dataforms.ExtendForm(node=form_node)
|
||||
dataform.type_ = 'submit'
|
||||
self.form_widget = DataFormWidget(dataform)
|
||||
self.form_widget.show_all()
|
||||
parent_box.add(self.form_widget)
|
||||
parent_box.child_set_property(self.form_widget, 'position',
|
||||
parent_box.child_get_property(self.xml.get_object(
|
||||
'conversation_scrolledwindow'), 'position'))
|
||||
self.action = 'form'
|
||||
|
||||
self.send_button = self.xml.get_object('send_button')
|
||||
self.reply_button = self.xml.get_object('reply_button')
|
||||
self.send_and_close_button = self.xml.get_object('send_and_close_button')
|
||||
self.cancel_button = self.xml.get_object('cancel_button')
|
||||
self.close_button = self.xml.get_object('close_button')
|
||||
self.message_tv_buffer.connect('changed', self.update_char_counter)
|
||||
if isinstance(to, list):
|
||||
jid = ', '.join( [i[0].get_full_jid() for i in to])
|
||||
self.to_entry.set_text(jid)
|
||||
self.to_entry.set_sensitive(False)
|
||||
else:
|
||||
self.to_entry.set_text(to)
|
||||
|
||||
if app.config.get('use_speller') and app.is_installed('GSPELL') and action == 'send':
|
||||
lang = app.config.get('speller_language')
|
||||
gspell_lang = Gspell.language_lookup(lang)
|
||||
if gspell_lang is None:
|
||||
AspellDictError(lang)
|
||||
else:
|
||||
spell_buffer = Gspell.TextBuffer.get_from_gtk_text_buffer(
|
||||
self.message_textview.get_buffer())
|
||||
spell_buffer.set_spell_checker(Gspell.Checker.new(gspell_lang))
|
||||
spell_view = Gspell.TextView.get_from_gtk_text_view(
|
||||
self.message_textview)
|
||||
spell_view.set_inline_spell_checking(True)
|
||||
spell_view.set_enable_language_menu(True)
|
||||
|
||||
self.prepare_widgets_for(self.action)
|
||||
|
||||
# set_text(None) raises TypeError exception
|
||||
if self.subject is None:
|
||||
self.subject = ''
|
||||
self.subject_entry.set_text(self.subject)
|
||||
|
||||
|
||||
if to == '':
|
||||
liststore = get_completion_liststore(self.to_entry)
|
||||
self.completion_dict = helpers.get_contact_dict_for_account(account)
|
||||
keys = sorted(self.completion_dict.keys())
|
||||
for jid in keys:
|
||||
contact = self.completion_dict[jid]
|
||||
status_icon = get_iconset_name_for(contact.show)
|
||||
liststore.append((status_icon, jid))
|
||||
else:
|
||||
self.completion_dict = {}
|
||||
self.xml.connect_signals(self)
|
||||
|
||||
# get window position and size from config
|
||||
resize_window(self.window,
|
||||
app.config.get('single-msg-width'),
|
||||
app.config.get('single-msg-height'))
|
||||
move_window(self.window,
|
||||
app.config.get('single-msg-x-position'),
|
||||
app.config.get('single-msg-y-position'))
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
def on_single_message_window_destroy(self, widget):
|
||||
self.instances.remove(self)
|
||||
c = app.contacts.get_contact_with_highest_priority(self.account,
|
||||
self.from_whom)
|
||||
if not c:
|
||||
# Groupchat is maybe already destroyed
|
||||
return
|
||||
if c.is_groupchat() and self.from_whom not in \
|
||||
app.interface.minimized_controls[self.account] and self.action == \
|
||||
'receive' and app.events.get_nb_roster_events(self.account,
|
||||
self.from_whom, types=['chat', 'normal']) == 0:
|
||||
app.interface.roster.remove_groupchat(self.from_whom, self.account)
|
||||
|
||||
def set_cursor_to_end(self):
|
||||
end_iter = self.message_tv_buffer.get_end_iter()
|
||||
self.message_tv_buffer.place_cursor(end_iter)
|
||||
|
||||
def save_pos(self):
|
||||
# save the window size and position
|
||||
x, y = self.window.get_position()
|
||||
app.config.set('single-msg-x-position', x)
|
||||
app.config.set('single-msg-y-position', y)
|
||||
width, height = self.window.get_size()
|
||||
app.config.set('single-msg-width', width)
|
||||
app.config.set('single-msg-height', height)
|
||||
|
||||
def on_single_message_window_delete_event(self, window, ev):
|
||||
self.save_pos()
|
||||
|
||||
def prepare_widgets_for(self, action):
|
||||
if len(app.connections) > 1:
|
||||
if action == 'send':
|
||||
title = _('Single Message using account %s') % self.account
|
||||
else:
|
||||
title = _('Single Message in account %s') % self.account
|
||||
else:
|
||||
title = _('Single Message')
|
||||
|
||||
if action == 'send': # prepare UI for Sending
|
||||
title = _('Send %s') % title
|
||||
self.send_button.show()
|
||||
self.send_and_close_button.show()
|
||||
self.to_label.show()
|
||||
self.to_entry.show()
|
||||
self.reply_button.hide()
|
||||
self.from_label.hide()
|
||||
self.from_entry.hide()
|
||||
self.conversation_scrolledwindow.hide()
|
||||
self.message_scrolledwindow.show()
|
||||
|
||||
if self.message: # we come from a reply?
|
||||
self.message_textview.grab_focus()
|
||||
self.cancel_button.hide()
|
||||
self.close_button.show()
|
||||
self.message_tv_buffer.set_text(self.message)
|
||||
GLib.idle_add(self.set_cursor_to_end)
|
||||
else: # we write a new message (not from reply)
|
||||
self.close_button.hide()
|
||||
if self.to: # do we already have jid?
|
||||
self.subject_entry.grab_focus()
|
||||
|
||||
elif action == 'receive': # prepare UI for Receiving
|
||||
title = _('Received %s') % title
|
||||
self.reply_button.show()
|
||||
self.from_label.show()
|
||||
self.from_entry.show()
|
||||
self.send_button.hide()
|
||||
self.send_and_close_button.hide()
|
||||
self.to_label.hide()
|
||||
self.to_entry.hide()
|
||||
self.conversation_scrolledwindow.show()
|
||||
self.message_scrolledwindow.hide()
|
||||
|
||||
if self.message:
|
||||
self.conversation_textview.print_real_text(self.message)
|
||||
fjid = self.from_whom
|
||||
if self.resource:
|
||||
fjid += '/' + self.resource # Full jid of sender (with resource)
|
||||
self.from_entry.set_text(fjid)
|
||||
self.from_entry.set_property('editable', False)
|
||||
self.subject_entry.set_property('editable', False)
|
||||
self.reply_button.grab_focus()
|
||||
self.cancel_button.hide()
|
||||
self.close_button.show()
|
||||
elif action == 'form': # prepare UI for Receiving
|
||||
title = _('Form %s') % title
|
||||
self.send_button.show()
|
||||
self.send_and_close_button.show()
|
||||
self.to_label.show()
|
||||
self.to_entry.show()
|
||||
self.reply_button.hide()
|
||||
self.from_label.hide()
|
||||
self.from_entry.hide()
|
||||
self.conversation_scrolledwindow.hide()
|
||||
self.message_scrolledwindow.hide()
|
||||
|
||||
self.window.set_title(title)
|
||||
|
||||
def on_cancel_button_clicked(self, widget):
|
||||
self.save_pos()
|
||||
self.window.destroy()
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.save_pos()
|
||||
self.window.destroy()
|
||||
|
||||
def update_char_counter(self, widget):
|
||||
characters_no = self.message_tv_buffer.get_char_count()
|
||||
self.count_chars_label.set_text(str(characters_no))
|
||||
|
||||
def send_single_message(self):
|
||||
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 True
|
||||
if isinstance(self.to, list):
|
||||
sender_list = []
|
||||
for i in self.to:
|
||||
if i[0].resource:
|
||||
sender_list.append(i[0].jid + '/' + i[0].resource)
|
||||
else:
|
||||
sender_list.append(i[0].jid)
|
||||
else:
|
||||
sender_list = [j.strip() for j in self.to_entry.get_text().split(
|
||||
',')]
|
||||
|
||||
subject = self.subject_entry.get_text()
|
||||
begin, end = self.message_tv_buffer.get_bounds()
|
||||
message = self.message_tv_buffer.get_text(begin, end, True)
|
||||
|
||||
if self.form_widget:
|
||||
form_node = self.form_widget.data_form
|
||||
else:
|
||||
form_node = None
|
||||
|
||||
recipient_list = []
|
||||
|
||||
for to_whom_jid in sender_list:
|
||||
if to_whom_jid in self.completion_dict:
|
||||
to_whom_jid = self.completion_dict[to_whom_jid].jid
|
||||
try:
|
||||
to_whom_jid = helpers.parse_jid(to_whom_jid)
|
||||
except helpers.InvalidFormat:
|
||||
ErrorDialog(_('Invalid JID'),
|
||||
_('It is not possible to send a message to %s, this JID is not '
|
||||
'valid.') % to_whom_jid)
|
||||
return True
|
||||
|
||||
if '/announce/' in to_whom_jid:
|
||||
app.connections[self.account].send_motd(to_whom_jid, subject,
|
||||
message)
|
||||
continue
|
||||
|
||||
recipient_list.append(to_whom_jid)
|
||||
|
||||
app.nec.push_outgoing_event(MessageOutgoingEvent(None,
|
||||
account=self.account, jid=recipient_list, message=message,
|
||||
type_='normal', subject=subject, form_node=form_node))
|
||||
|
||||
self.subject_entry.set_text('') # we sent ok, clear the subject
|
||||
self.message_tv_buffer.set_text('') # we sent ok, clear the textview
|
||||
|
||||
def on_send_button_clicked(self, widget):
|
||||
self.send_single_message()
|
||||
|
||||
def on_reply_button_clicked(self, widget):
|
||||
# we create a new blank window to send and we preset RE: and to jid
|
||||
self.subject = _('RE: %s') % self.subject
|
||||
self.message = _('%s wrote:\n') % self.from_whom + self.message
|
||||
# add > at the begining of each line
|
||||
self.message = self.message.replace('\n', '\n> ') + '\n\n'
|
||||
self.window.destroy()
|
||||
SingleMessageWindow(self.account, to=self.from_whom, action='send',
|
||||
from_whom=self.from_whom, subject=self.subject, message=self.message,
|
||||
session=self.session)
|
||||
|
||||
def on_send_and_close_button_clicked(self, widget):
|
||||
if self.send_single_message():
|
||||
return
|
||||
self.save_pos()
|
||||
self.window.destroy()
|
||||
|
||||
def on_single_message_window_key_press_event(self, widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape: # ESCAPE
|
||||
self.save_pos()
|
||||
self.window.destroy()
|
|
@ -0,0 +1,343 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import locale
|
||||
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Pango
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.common.const import AvatarSize
|
||||
|
||||
from gajim.gtk.util import get_iconset_name_for
|
||||
from gajim.gtk.util import get_builder
|
||||
|
||||
|
||||
class StartChatDialog(Gtk.ApplicationWindow):
|
||||
def __init__(self):
|
||||
Gtk.ApplicationWindow.__init__(self)
|
||||
self.set_name('StartChatDialog')
|
||||
self.set_application(app.app)
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.set_show_menubar(False)
|
||||
self.set_title(_('Start new Conversation'))
|
||||
self.set_default_size(-1, 400)
|
||||
self.ready_to_destroy = False
|
||||
|
||||
self.builder = get_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.add(self.box)
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
con = app.connections[account]
|
||||
bookmarks = con.get_module('Bookmarks').bookmarks
|
||||
groupchats = {}
|
||||
for jid, bookmark in bookmarks.items():
|
||||
groupchats[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 not name:
|
||||
name = app.get_nick_from_jid(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):
|
||||
app.interface.raise_dialog('start-chat-not-connected')
|
||||
return
|
||||
try:
|
||||
helpers.parse_jid(row.jid)
|
||||
except helpers.InvalidFormat as e:
|
||||
app.interface.raise_dialog('invalid-jid-with-error', str(e))
|
||||
return
|
||||
|
||||
if row.groupchat:
|
||||
app.interface.join_gc_minimal(row.account, row.jid)
|
||||
else:
|
||||
app.interface.new_chat_from_jid(row.account, row.jid)
|
||||
|
||||
self.ready_to_destroy = True
|
||||
|
||||
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
|
||||
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:
|
||||
muc_icon = get_iconset_name_for(
|
||||
'muc-inactive' if self.new else 'muc-active')
|
||||
image = Gtk.Image.new_from_icon_name(muc_icon, Gtk.IconSize.DND)
|
||||
else:
|
||||
scale = self.get_scale_factor()
|
||||
avatar = app.contacts.get_avatar(
|
||||
account, jid, AvatarSize.ROSTER, scale)
|
||||
if avatar is None:
|
||||
image = Gtk.Image.new_from_icon_name(
|
||||
'avatar-default', Gtk.IconSize.DND)
|
||||
else:
|
||||
image = Gtk.Image.new_from_surface(avatar)
|
||||
|
||||
image.set_size_request(AvatarSize.ROSTER, AvatarSize.ROSTER)
|
||||
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_ellipsize(Pango.EllipsizeMode.END)
|
||||
self.name_label.set_xalign(0)
|
||||
self.name_label.set_width_chars(25)
|
||||
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_ellipsize(Pango.EllipsizeMode.END)
|
||||
self.jid_label.set_xalign(0)
|
||||
self.jid_label.set_width_chars(25)
|
||||
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)
|
|
@ -15,11 +15,13 @@
|
|||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import i18n
|
||||
from gajim.common import configpaths
|
||||
|
||||
|
@ -29,7 +31,7 @@ _icon_theme.append_search_path(configpaths.get('ICONS'))
|
|||
log = logging.getLogger('gajim.gtk.util')
|
||||
|
||||
|
||||
def load_icon(icon_name, widget, size=16,
|
||||
def load_icon(icon_name, widget, size=16, pixbuf=False,
|
||||
flags=Gtk.IconLookupFlags.FORCE_SIZE):
|
||||
|
||||
scale = widget.get_scale_factor()
|
||||
|
@ -40,6 +42,8 @@ def load_icon(icon_name, widget, size=16,
|
|||
try:
|
||||
iconinfo = _icon_theme.lookup_icon_for_scale(
|
||||
icon_name, size, scale, flags)
|
||||
if pixbuf:
|
||||
return iconinfo.load_icon()
|
||||
return iconinfo.load_surface(None)
|
||||
except GLib.GError as e:
|
||||
log.error('Unable to load icon %s: %s', icon_name, str(e))
|
||||
|
@ -75,3 +79,127 @@ def _translate(gui_file, widget):
|
|||
builder.add_objects_from_file(gui_file, [widget])
|
||||
return builder
|
||||
return Gtk.Builder.new_from_file(gui_file)
|
||||
|
||||
|
||||
def get_iconset_name_for(name):
|
||||
if name == 'not in roster':
|
||||
name = 'notinroster'
|
||||
iconset = app.config.get('iconset')
|
||||
if not iconset:
|
||||
iconset = app.config.DEFAULT_ICONSET
|
||||
return '%s-%s' % (iconset, name)
|
||||
|
||||
|
||||
def get_total_screen_geometry():
|
||||
screen = Gdk.Screen.get_default()
|
||||
window = Gdk.Screen.get_root_window(screen)
|
||||
w, h = window.get_width(), window.get_height()
|
||||
log.debug('Get screen geometry: %s %s', w, h)
|
||||
return w, h
|
||||
|
||||
|
||||
def resize_window(window, w, h):
|
||||
"""
|
||||
Resize window, but also checks if huge window or negative values
|
||||
"""
|
||||
screen_w, screen_h = get_total_screen_geometry()
|
||||
if not w or not h:
|
||||
return
|
||||
if w > screen_w:
|
||||
w = screen_w
|
||||
if h > screen_h:
|
||||
h = screen_h
|
||||
window.resize(abs(w), abs(h))
|
||||
|
||||
|
||||
def move_window(window, x, y):
|
||||
"""
|
||||
Move the window, but also check if out of screen
|
||||
"""
|
||||
screen_w, screen_h = get_total_screen_geometry()
|
||||
if x < 0:
|
||||
x = 0
|
||||
if y < 0:
|
||||
y = 0
|
||||
w, h = window.get_size()
|
||||
if x + w > screen_w:
|
||||
x = screen_w - w
|
||||
if y + h > screen_h:
|
||||
y = screen_h - h
|
||||
window.move(x, y)
|
||||
|
||||
|
||||
def get_completion_liststore(entry):
|
||||
"""
|
||||
Create a completion model for entry widget completion list consists of
|
||||
(Pixbuf, Text) rows
|
||||
"""
|
||||
completion = Gtk.EntryCompletion()
|
||||
liststore = Gtk.ListStore(str, str)
|
||||
|
||||
render_pixbuf = Gtk.CellRendererPixbuf()
|
||||
completion.pack_start(render_pixbuf, False)
|
||||
completion.add_attribute(render_pixbuf, 'icon_name', 0)
|
||||
|
||||
render_text = Gtk.CellRendererText()
|
||||
completion.pack_start(render_text, True)
|
||||
completion.add_attribute(render_text, 'text', 1)
|
||||
completion.set_property('text_column', 1)
|
||||
completion.set_model(liststore)
|
||||
entry.set_completion(completion)
|
||||
return liststore
|
||||
|
||||
|
||||
def get_cursor(attr):
|
||||
display = Gdk.Display.get_default()
|
||||
cursor = getattr(Gdk.CursorType, attr)
|
||||
return Gdk.Cursor.new_for_display(display, cursor)
|
||||
|
||||
|
||||
def scroll_to_end(widget):
|
||||
"""Scrolls to the end of a GtkScrolledWindow.
|
||||
|
||||
Args:
|
||||
widget (GtkScrolledWindow)
|
||||
|
||||
Returns:
|
||||
bool: The return value is False so it can be used with GLib.idle_add.
|
||||
"""
|
||||
adj_v = widget.get_vadjustment()
|
||||
if adj_v is None:
|
||||
# This can happen when the Widget is already destroyed when called
|
||||
# from GLib.idle_add
|
||||
return False
|
||||
max_scroll_pos = adj_v.get_upper() - adj_v.get_page_size()
|
||||
adj_v.set_value(max_scroll_pos)
|
||||
|
||||
adj_h = widget.get_hadjustment()
|
||||
adj_h.set_value(0)
|
||||
return False
|
||||
|
||||
|
||||
def at_the_end(widget):
|
||||
"""Determines if a Scrollbar in a GtkScrolledWindow is at the end.
|
||||
|
||||
Args:
|
||||
widget (GtkScrolledWindow)
|
||||
|
||||
Returns:
|
||||
bool: The return value is True if at the end, False if not.
|
||||
"""
|
||||
adj_v = widget.get_vadjustment()
|
||||
max_scroll_pos = adj_v.get_upper() - adj_v.get_page_size()
|
||||
at_the_end = (adj_v.get_value() == max_scroll_pos)
|
||||
return at_the_end
|
||||
|
||||
|
||||
def get_image_button(icon_name, tooltip, toggle=False):
|
||||
if toggle:
|
||||
button = Gtk.ToggleButton()
|
||||
image = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
||||
button.set_image(image)
|
||||
else:
|
||||
button = Gtk.Button.new_from_icon_name(
|
||||
icon_name, Gtk.IconSize.MENU)
|
||||
button.set_tooltip_text(tooltip)
|
||||
return button
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import time
|
||||
|
||||
import nbxmpp
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import ged
|
||||
from gajim.common.const import Option, OptionKind, OptionType
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import util
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.util import get_image_button
|
||||
from gajim.options_dialog import OptionsDialog
|
||||
|
||||
|
||||
UNDECLARED = 'http://www.gajim.org/xmlns/undeclared'
|
||||
|
||||
|
||||
class XMLConsoleWindow(Gtk.Window):
|
||||
def __init__(self, account):
|
||||
Gtk.Window.__init__(self)
|
||||
self.account = account
|
||||
self.enabled = True
|
||||
self.presence = True
|
||||
self.message = True
|
||||
self.iq = True
|
||||
self.stream = True
|
||||
self.incoming = True
|
||||
self.outgoing = True
|
||||
self.filter_dialog = None
|
||||
|
||||
glade_objects = ['textview', 'input', 'scrolled_input', 'headerbar',
|
||||
'scrolled', 'actionbar', 'paned', 'box', 'menubutton']
|
||||
self.builder = get_builder('xml_console_window.ui')
|
||||
for obj in glade_objects:
|
||||
setattr(self, obj, self.builder.get_object(obj))
|
||||
|
||||
self.set_titlebar(self.headerbar)
|
||||
jid = app.get_jid_from_account(account)
|
||||
self.headerbar.set_subtitle(jid)
|
||||
self.set_default_size(600, 600)
|
||||
self.add(self.box)
|
||||
|
||||
self.paned.set_position(self.paned.get_property('max-position'))
|
||||
|
||||
button = get_image_button(
|
||||
'edit-clear-all-symbolic', _('Clear'))
|
||||
button.connect('clicked', self.on_clear)
|
||||
self.actionbar.pack_start(button)
|
||||
|
||||
button = get_image_button(
|
||||
'applications-system-symbolic', _('Filter'))
|
||||
button.connect('clicked', self.on_filter_options)
|
||||
self.actionbar.pack_start(button)
|
||||
|
||||
button = get_image_button(
|
||||
'document-edit-symbolic', _('XML Input'), toggle=True)
|
||||
button.connect('toggled', self.on_input)
|
||||
self.actionbar.pack_start(button)
|
||||
|
||||
button = get_image_button('emblem-ok-symbolic', _('Send'))
|
||||
button.connect('clicked', self.on_send)
|
||||
self.actionbar.pack_end(button)
|
||||
|
||||
self.actionbar.pack_start(self.menubutton)
|
||||
|
||||
self.create_tags()
|
||||
self.show_all()
|
||||
|
||||
self.scrolled_input.hide()
|
||||
self.menubutton.hide()
|
||||
|
||||
self.connect("destroy", self.on_destroy)
|
||||
self.connect('key_press_event', self.on_key_press_event)
|
||||
self.builder.connect_signals(self)
|
||||
|
||||
app.ged.register_event_handler(
|
||||
'stanza-received', ged.GUI1, self._nec_stanza_received)
|
||||
app.ged.register_event_handler(
|
||||
'stanza-sent', ged.GUI1, self._nec_stanza_sent)
|
||||
|
||||
def create_tags(self):
|
||||
buffer_ = self.textview.get_buffer()
|
||||
in_color = app.config.get('inmsgcolor')
|
||||
out_color = app.config.get('outmsgcolor')
|
||||
|
||||
tags = ['presence', 'message', 'stream', 'iq']
|
||||
|
||||
tag = buffer_.create_tag('incoming')
|
||||
tag.set_property('foreground', in_color)
|
||||
tag = buffer_.create_tag('outgoing')
|
||||
tag.set_property('foreground', out_color)
|
||||
|
||||
for tag_name in tags:
|
||||
buffer_.create_tag(tag_name)
|
||||
|
||||
def on_key_press_event(self, widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.destroy()
|
||||
|
||||
def on_row_activated(self, listbox, row):
|
||||
text = row.get_child().get_text()
|
||||
input_text = None
|
||||
if text == 'Presence':
|
||||
input_text = (
|
||||
'<presence>\n'
|
||||
'<show></show>\n'
|
||||
'<status></status>\n'
|
||||
'<priority></priority>\n'
|
||||
'</presence>')
|
||||
elif text == 'Message':
|
||||
input_text = (
|
||||
'<message to="" type="">\n'
|
||||
'<body></body>\n'
|
||||
'</message>')
|
||||
elif text == 'Iq':
|
||||
input_text = (
|
||||
'<iq to="" type="">\n'
|
||||
'<query xmlns=""></query>\n'
|
||||
'</iq>')
|
||||
|
||||
if input_text is not None:
|
||||
buffer_ = self.input.get_buffer()
|
||||
buffer_.set_text(input_text)
|
||||
self.input.grab_focus()
|
||||
|
||||
def on_send(self, *args):
|
||||
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
|
||||
buffer_ = self.input.get_buffer()
|
||||
begin_iter, end_iter = buffer_.get_bounds()
|
||||
stanza = buffer_.get_text(begin_iter, end_iter, True)
|
||||
if stanza:
|
||||
try:
|
||||
node = nbxmpp.Protocol(node=stanza)
|
||||
if node.getNamespace() == UNDECLARED:
|
||||
node.setNamespace(nbxmpp.NS_CLIENT)
|
||||
except Exception as error:
|
||||
ErrorDialog(_('Invalid Node'), str(error))
|
||||
return
|
||||
app.connections[self.account].connection.send(node)
|
||||
buffer_.set_text('')
|
||||
|
||||
def on_input(self, button, *args):
|
||||
if button.get_active():
|
||||
self.paned.get_child2().show()
|
||||
self.menubutton.show()
|
||||
self.input.grab_focus()
|
||||
else:
|
||||
self.paned.get_child2().hide()
|
||||
self.menubutton.hide()
|
||||
|
||||
def on_filter_options(self, *args):
|
||||
if self.filter_dialog:
|
||||
self.filter_dialog.present()
|
||||
return
|
||||
options = [
|
||||
Option(OptionKind.SWITCH, 'Presence',
|
||||
OptionType.VALUE, self.presence,
|
||||
callback=self.on_option, data='presence'),
|
||||
|
||||
Option(OptionKind.SWITCH, 'Message',
|
||||
OptionType.VALUE, self.message,
|
||||
callback=self.on_option, data='message'),
|
||||
|
||||
Option(OptionKind.SWITCH, 'Iq', OptionType.VALUE, self.iq,
|
||||
callback=self.on_option, data='iq'),
|
||||
|
||||
Option(OptionKind.SWITCH, 'Stream\nManagement',
|
||||
OptionType.VALUE, self.stream,
|
||||
callback=self.on_option, data='stream'),
|
||||
|
||||
Option(OptionKind.SWITCH, 'In', OptionType.VALUE, self.incoming,
|
||||
callback=self.on_option, data='incoming'),
|
||||
|
||||
Option(OptionKind.SWITCH, 'Out', OptionType.VALUE, self.outgoing,
|
||||
callback=self.on_option, data='outgoing'),
|
||||
]
|
||||
|
||||
self.filter_dialog = OptionsDialog(self, 'Filter',
|
||||
Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
options, self.account)
|
||||
self.filter_dialog.connect('destroy', self.on_filter_destroyed)
|
||||
|
||||
def on_filter_destroyed(self, win):
|
||||
self.filter_dialog = None
|
||||
|
||||
def on_clear(self, *args):
|
||||
self.textview.get_buffer().set_text('')
|
||||
|
||||
def on_destroy(self, *args):
|
||||
del app.interface.instances[self.account]['xml_console']
|
||||
app.ged.remove_event_handler(
|
||||
'stanza-received', ged.GUI1, self._nec_stanza_received)
|
||||
app.ged.remove_event_handler(
|
||||
'stanza-sent', ged.GUI1, self._nec_stanza_sent)
|
||||
|
||||
def on_enable(self, switch, param):
|
||||
self.enabled = switch.get_active()
|
||||
|
||||
def on_option(self, value, data):
|
||||
setattr(self, data, value)
|
||||
value = not value
|
||||
table = self.textview.get_buffer().get_tag_table()
|
||||
tag = table.lookup(data)
|
||||
if data in ('incoming', 'outgoing'):
|
||||
if value:
|
||||
tag.set_priority(table.get_size() - 1)
|
||||
else:
|
||||
tag.set_priority(0)
|
||||
tag.set_property('invisible', value)
|
||||
|
||||
def _nec_stanza_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
self.print_stanza(obj.stanza_str, 'incoming')
|
||||
|
||||
def _nec_stanza_sent(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
self.print_stanza(obj.stanza_str, 'outgoing')
|
||||
|
||||
def print_stanza(self, stanza, kind):
|
||||
# kind must be 'incoming' or 'outgoing'
|
||||
if not self.enabled:
|
||||
return
|
||||
if not stanza:
|
||||
return
|
||||
|
||||
at_the_end = util.at_the_end(self.scrolled)
|
||||
|
||||
buffer_ = self.textview.get_buffer()
|
||||
end_iter = buffer_.get_end_iter()
|
||||
|
||||
type_ = kind
|
||||
if stanza.startswith('<presence'):
|
||||
type_ = 'presence'
|
||||
elif stanza.startswith('<message'):
|
||||
type_ = 'message'
|
||||
elif stanza.startswith('<iq'):
|
||||
type_ = 'iq'
|
||||
elif stanza.startswith('<r') or stanza.startswith('<a'):
|
||||
type_ = 'stream'
|
||||
|
||||
stanza = '<!-- {kind} {time} -->\n{stanza}\n\n'.format(
|
||||
kind=kind.capitalize(),
|
||||
time=time.strftime('%c'),
|
||||
stanza=stanza.replace('><', '>\n<'))
|
||||
buffer_.insert_with_tags_by_name(end_iter, stanza, type_, kind)
|
||||
|
||||
if at_the_end:
|
||||
GLib.idle_add(util.scroll_to_end, self.scrolled)
|
|
@ -479,7 +479,9 @@ def scale_pixbuf_from_data(data, size):
|
|||
return scale_pixbuf(pixbuf, size)
|
||||
|
||||
def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import ConfirmationDialog
|
||||
from gajim.gtk import FTOverwriteConfirmationDialog
|
||||
def on_continue(response, file_path):
|
||||
if response < 0:
|
||||
return
|
||||
|
@ -509,7 +511,7 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
|
|||
new_file_path = '.'.join(file_path.split('.')[:-1]) + '.png'
|
||||
def on_ok(file_path, pixbuf):
|
||||
pixbuf.savev(file_path, 'png', [], [])
|
||||
dialogs.ConfirmationDialog(_('Extension not supported'),
|
||||
ConfirmationDialog(_('Extension not supported'),
|
||||
_('Image cannot be saved in %(type)s format. Save as '
|
||||
'%(new_filename)s?') % {'type': image_format,
|
||||
'new_filename': new_file_path},
|
||||
|
@ -520,18 +522,18 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
|
|||
# check if we have write permissions
|
||||
if not os.access(file_path, os.W_OK):
|
||||
file_name = os.path.basename(file_path)
|
||||
dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"') % \
|
||||
ErrorDialog(_('Cannot overwrite existing file "%s"') % \
|
||||
file_name, _('A file with this name already exists and you '
|
||||
'do not have permission to overwrite it.'))
|
||||
return
|
||||
dialog2 = dialogs.FTOverwriteConfirmationDialog(
|
||||
dialog2 = FTOverwriteConfirmationDialog(
|
||||
_('This file already exists'), _('What do you want to do?'),
|
||||
propose_resume=False, on_response=(on_continue, file_path))
|
||||
dialog2.set_destroy_with_parent(True)
|
||||
else:
|
||||
dirname = os.path.dirname(file_path)
|
||||
if not os.access(dirname, os.W_OK):
|
||||
dialogs.ErrorDialog(_('Directory "%s" is not writable') % \
|
||||
ErrorDialog(_('Directory "%s" is not writable') % \
|
||||
dirname, _('You do not have permission to create files in '
|
||||
'this directory.'))
|
||||
return
|
||||
|
|
|
@ -69,6 +69,7 @@ from gajim import notify
|
|||
from gajim import message_control
|
||||
from gajim.dialog_messages import get_dialog
|
||||
from gajim.dialogs import ProgressWindow
|
||||
|
||||
from gajim.filechoosers import FileChooserDialog
|
||||
|
||||
from gajim.chat_control_base import ChatControlBase
|
||||
|
@ -111,6 +112,18 @@ from threading import Thread
|
|||
from gajim.common import ged
|
||||
from gajim.common.caps_cache import muc_caps_cache
|
||||
|
||||
from gajim.gtk import JoinGroupchatWindow
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import WarningDialog
|
||||
from gajim.gtk import InformationDialog
|
||||
from gajim.gtk import InputDialog
|
||||
from gajim.gtk import YesNoDialog
|
||||
from gajim.gtk import InputTextDialog
|
||||
from gajim.gtk import PlainConnectionDialog
|
||||
from gajim.gtk import SSLErrorDialog
|
||||
from gajim.gtk import ConfirmationDialogDoubleCheck
|
||||
from gajim.gtk import ChangeNickDialog
|
||||
|
||||
from gajim.common import configpaths
|
||||
|
||||
from gajim.common import optparser
|
||||
|
@ -129,7 +142,7 @@ class Interface:
|
|||
#('DB_ERROR', account, error)
|
||||
if self.db_error_dialog:
|
||||
return
|
||||
self.db_error_dialog = dialogs.ErrorDialog(_('Database Error'), error)
|
||||
self.db_error_dialog = ErrorDialog(_('Database Error'), error)
|
||||
def destroyed(win):
|
||||
self.db_error_dialog = None
|
||||
self.db_error_dialog.connect('destroy', destroyed)
|
||||
|
@ -144,11 +157,11 @@ class Interface:
|
|||
return
|
||||
|
||||
if obj.level == 'error':
|
||||
cls = dialogs.ErrorDialog
|
||||
cls = ErrorDialog
|
||||
elif obj.level == 'warn':
|
||||
cls = dialogs.WarningDialog
|
||||
cls = WarningDialog
|
||||
elif obj.level == 'info':
|
||||
cls = dialogs.InformationDialog
|
||||
cls = InformationDialog
|
||||
else:
|
||||
return
|
||||
|
||||
|
@ -169,7 +182,7 @@ class Interface:
|
|||
self.instances['change_nick_dialog'].add_room(account, room_jid,
|
||||
prompt)
|
||||
else:
|
||||
self.instances['change_nick_dialog'] = dialogs.ChangeNickDialog(
|
||||
self.instances['change_nick_dialog'] = ChangeNickDialog(
|
||||
account, room_jid, title, prompt, transient_for=parent_win)
|
||||
|
||||
@staticmethod
|
||||
|
@ -188,7 +201,7 @@ class Interface:
|
|||
sec_msg = _('Do you accept this request on account %s?') % account
|
||||
if obj.msg:
|
||||
sec_msg = obj.msg + '\n' + sec_msg
|
||||
dialog = dialogs.YesNoDialog(_('HTTP (%(method)s) Authorization for '
|
||||
dialog = YesNoDialog(_('HTTP (%(method)s) Authorization for '
|
||||
'%(url)s (ID: %(id)s)') % {'method': obj.method, 'url': obj.url,
|
||||
'id': obj.iq_id}, sec_msg, on_response_yes=(on_yes, obj),
|
||||
on_response_no=(response, obj, 'no'))
|
||||
|
@ -285,14 +298,14 @@ class Interface:
|
|||
def on_close(dummy):
|
||||
gc_control.error_dialog.destroy()
|
||||
gc_control.error_dialog = None
|
||||
gc_control.error_dialog = dialogs.ErrorDialog(pritext, sectext,
|
||||
gc_control.error_dialog = ErrorDialog(pritext, sectext,
|
||||
on_response_ok=on_close, on_response_cancel=on_close)
|
||||
gc_control.error_dialog.set_modal(False)
|
||||
if gc_control.parent_win:
|
||||
gc_control.error_dialog.set_transient_for(
|
||||
gc_control.parent_win.window)
|
||||
else:
|
||||
d = dialogs.ErrorDialog(pritext, sectext)
|
||||
d = ErrorDialog(pritext, sectext)
|
||||
if gc_control and gc_control.parent_win:
|
||||
d.set_transient_for(gc_control.parent_win.window)
|
||||
d.set_modal(False)
|
||||
|
@ -318,7 +331,7 @@ class Interface:
|
|||
if gc_control.error_dialog:
|
||||
gc_control.error_dialog.destroy()
|
||||
|
||||
gc_control.error_dialog = dialogs.InputDialog(_('Password Required'),
|
||||
gc_control.error_dialog = InputDialog(_('Password Required'),
|
||||
_('A Password is required to join the room %s. Please type it.') % \
|
||||
room_jid, is_modal=False, ok_handler=on_ok,
|
||||
cancel_handler=on_cancel)
|
||||
|
@ -530,7 +543,7 @@ class Interface:
|
|||
status='online', ask='to', resource=obj.resource, keyID=keyID)
|
||||
app.contacts.add_contact(account, contact1)
|
||||
self.roster.add_contact(obj.jid, account)
|
||||
dialogs.InformationDialog(_('Authorization accepted'),
|
||||
InformationDialog(_('Authorization accepted'),
|
||||
_('The contact "%s" has authorized you to see their status.')
|
||||
% obj.jid)
|
||||
|
||||
|
@ -538,7 +551,7 @@ class Interface:
|
|||
def on_yes(is_checked, list_):
|
||||
self.roster.on_req_usub(None, list_)
|
||||
list_ = [(contact, account)]
|
||||
dialogs.YesNoDialog(
|
||||
YesNoDialog(
|
||||
_('Contact "%s" removed subscription from you') % contact.jid,
|
||||
_('You will always see them as offline.\nDo you want to '
|
||||
'remove them from your contact list?'),
|
||||
|
@ -575,7 +588,7 @@ class Interface:
|
|||
config.ServiceRegistrationWindow(obj.agent, obj.config,
|
||||
obj.conn.name, obj.is_form)
|
||||
else:
|
||||
dialogs.ErrorDialog(_('Contact with "%s" cannot be established') % \
|
||||
ErrorDialog(_('Contact with "%s" cannot be established') % \
|
||||
obj.agent, _('Check your connection or try again later.'))
|
||||
|
||||
def handle_event_gc_config(self, obj):
|
||||
|
@ -673,7 +686,7 @@ class Interface:
|
|||
'\n')
|
||||
sectext += _('You are currently connected without your OpenPGP '
|
||||
'key.')
|
||||
dialogs.WarningDialog(_('Wrong passphrase'), sectext)
|
||||
WarningDialog(_('Wrong passphrase'), sectext)
|
||||
else:
|
||||
account = obj.conn.name
|
||||
app.notification.popup(
|
||||
|
@ -716,7 +729,7 @@ class Interface:
|
|||
def on_no():
|
||||
obj.callback(False)
|
||||
|
||||
dialogs.YesNoDialog(_('Untrusted OpenPGP key'), _('The OpenPGP key '
|
||||
YesNoDialog(_('Untrusted OpenPGP key'), _('The OpenPGP key '
|
||||
'used to encrypt this chat is not trusted. Do you really want to '
|
||||
'encrypt this message?'), checktext=_('_Do not ask me again'),
|
||||
on_response_yes=on_yes, on_response_no=on_no)
|
||||
|
@ -764,7 +777,7 @@ class Interface:
|
|||
|
||||
instruction = _('Please copy / paste the refresh token from the website'
|
||||
' that has just been opened.')
|
||||
self.pass_dialog[account] = dialogs.InputTextDialog(
|
||||
self.pass_dialog[account] = InputTextDialog(
|
||||
_('Oauth2 Credentials'), instruction, is_modal=False,
|
||||
ok_handler=on_ok, cancel_handler=on_cancel)
|
||||
|
||||
|
@ -917,7 +930,7 @@ class Interface:
|
|||
|
||||
@staticmethod
|
||||
def handle_event_file_error(title, message):
|
||||
dialogs.ErrorDialog(title, message)
|
||||
ErrorDialog(title, message)
|
||||
|
||||
def handle_event_file_progress(self, account, file_props):
|
||||
if time.time() - self.last_ftwindow_update > 0.5:
|
||||
|
@ -1185,7 +1198,7 @@ class Interface:
|
|||
def on_cancel():
|
||||
obj.conn.change_status('offline', '')
|
||||
|
||||
dlg = dialogs.InputDialog(_('Username Conflict'),
|
||||
dlg = InputDialog(_('Username Conflict'),
|
||||
_('Please type a new username for your local account'),
|
||||
input_str=obj.alt_name, is_modal=True, ok_handler=on_ok,
|
||||
cancel_handler=on_cancel, transient_for=self.roster.window)
|
||||
|
@ -1337,7 +1350,7 @@ class Interface:
|
|||
with open(my_ca_certs, encoding='utf-8') as f:
|
||||
certs = f.read()
|
||||
if pem in certs:
|
||||
dialogs.ErrorDialog(_('Certificate Already in File'),
|
||||
ErrorDialog(_('Certificate Already in File'),
|
||||
_('This certificate is already in file %s, so it\'s '
|
||||
'not added again.') % my_ca_certs)
|
||||
else:
|
||||
|
@ -1384,7 +1397,7 @@ class Interface:
|
|||
if 'ssl_error' in self.instances[account]['online_dialog']:
|
||||
self.instances[account]['online_dialog']['ssl_error'].destroy()
|
||||
self.instances[account]['online_dialog']['ssl_error'] = \
|
||||
dialogs.SSLErrorDialog(obj.conn.name, obj.cert, pritext,
|
||||
SSLErrorDialog(obj.conn.name, obj.cert, pritext,
|
||||
sectext, checktext1, checktext2, on_response_ok=on_ok,
|
||||
on_response_cancel=on_cancel)
|
||||
self.instances[account]['online_dialog']['ssl_error'].set_title(
|
||||
|
@ -1393,7 +1406,7 @@ class Interface:
|
|||
def handle_event_non_anonymous_server(self, obj):
|
||||
account = obj.conn.name
|
||||
server = app.config.get_per('accounts', account, 'hostname')
|
||||
dialogs.ErrorDialog(_('Non Anonymous Server'), sectext='Server "%s"'
|
||||
ErrorDialog(_('Non Anonymous Server'), sectext='Server "%s"'
|
||||
'does not support anonymous connection' % server,
|
||||
transient_for=self.roster.window)
|
||||
|
||||
|
@ -1426,7 +1439,7 @@ class Interface:
|
|||
self.instances[obj.conn.name]['online_dialog']['plain_connection'].\
|
||||
destroy()
|
||||
self.instances[obj.conn.name]['online_dialog']['plain_connection'] = \
|
||||
dialogs.PlainConnectionDialog(obj.conn.name, on_ok, on_cancel)
|
||||
PlainConnectionDialog(obj.conn.name, on_ok, on_cancel)
|
||||
|
||||
def handle_event_insecure_ssl_connection(self, obj):
|
||||
# ('INSECURE_SSL_CONNECTION', account, (connection, connection_type))
|
||||
|
@ -1464,7 +1477,7 @@ class Interface:
|
|||
self.instances[obj.conn.name]['online_dialog']['insecure_ssl'].\
|
||||
destroy()
|
||||
self.instances[obj.conn.name]['online_dialog']['insecure_ssl'] = \
|
||||
dialogs.ConfirmationDialogDoubleCheck(pritext, sectext, checktext1,
|
||||
ConfirmationDialogDoubleCheck(pritext, sectext, checktext1,
|
||||
checktext2, on_response_ok=on_ok, on_response_cancel=on_cancel,
|
||||
is_modal=False)
|
||||
|
||||
|
@ -1506,7 +1519,7 @@ class Interface:
|
|||
self.instances[obj.conn.name]['online_dialog']\
|
||||
['insecure_password'].destroy()
|
||||
self.instances[obj.conn.name]['online_dialog']['insecure_password'] = \
|
||||
dialogs.ConfirmationDialogDoubleCheck(pritext, sectext, checktext1,
|
||||
ConfirmationDialogDoubleCheck(pritext, sectext, checktext1,
|
||||
checktext2, on_response_ok=on_ok, on_response_cancel=on_cancel,
|
||||
is_modal=False)
|
||||
|
||||
|
@ -1749,7 +1762,7 @@ class Interface:
|
|||
try:
|
||||
room_jid = helpers.parse_jid(room_jid)
|
||||
except helpers.InvalidFormat:
|
||||
dialogs.ErrorDialog('Invalid JID',
|
||||
ErrorDialog('Invalid JID',
|
||||
transient_for=app.app.get_active_window())
|
||||
return
|
||||
|
||||
|
@ -1757,7 +1770,7 @@ class Interface:
|
|||
if account is not None and account not in connected_accounts:
|
||||
connected_accounts = None
|
||||
if not connected_accounts:
|
||||
dialogs.ErrorDialog(
|
||||
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())
|
||||
|
@ -1765,10 +1778,10 @@ class Interface:
|
|||
|
||||
def _on_discover_result():
|
||||
if not muc_caps_cache.is_cached(room_jid):
|
||||
dialogs.ErrorDialog(_('JID is not a Groupchat'),
|
||||
ErrorDialog(_('JID is not a Groupchat'),
|
||||
transient_for=app.app.get_active_window())
|
||||
return
|
||||
dialogs.JoinGroupchatWindow(account, room_jid, password=password,
|
||||
JoinGroupchatWindow(account, room_jid, password=password,
|
||||
transient_for=transient_for)
|
||||
|
||||
disco_account = connected_accounts[0] if account is None else account
|
||||
|
@ -1928,7 +1941,7 @@ class Interface:
|
|||
|
||||
path = helpers.get_emoticon_theme_path(emot_theme)
|
||||
if not emoticons.load(path, ascii_emoticons):
|
||||
dialogs.WarningDialog(
|
||||
WarningDialog(
|
||||
_('Emoticons disabled'),
|
||||
_('Your configured emoticons theme could not be loaded.'
|
||||
' See the log for more details.'),
|
||||
|
@ -1948,7 +1961,7 @@ class Interface:
|
|||
|
||||
if app.contacts.get_contact(account, room_jid) and \
|
||||
not app.contacts.get_contact(account, room_jid).is_groupchat():
|
||||
dialogs.ErrorDialog(_('This is not a group chat'),
|
||||
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 '
|
||||
|
@ -1973,7 +1986,7 @@ class Interface:
|
|||
|
||||
invisible_show = app.SHOW_LIST.index('invisible')
|
||||
if app.connections[account].connected == invisible_show:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('You cannot join a group chat while you are invisible'))
|
||||
return
|
||||
|
||||
|
@ -2331,7 +2344,7 @@ class Interface:
|
|||
print(err_str, file=sys.stderr)
|
||||
# it is good to notify the user
|
||||
# in case he or she cannot see the output of the console
|
||||
error_dialog = dialogs.ErrorDialog(_('Could not save your settings and '
|
||||
error_dialog = ErrorDialog(_('Could not save your settings and '
|
||||
'preferences'), err_str)
|
||||
error_dialog.run()
|
||||
sys.exit()
|
||||
|
@ -2923,7 +2936,7 @@ class PassphraseRequest:
|
|||
self.complete(passphrase)
|
||||
return
|
||||
elif result == 'expired':
|
||||
dialogs.ErrorDialog(_('OpenPGP key expired'),
|
||||
ErrorDialog(_('OpenPGP key expired'),
|
||||
_('Your OpenPGP key has expired, you will be connected to '
|
||||
'%s without OpenPGP.') % account)
|
||||
# Don't try to connect with GPG
|
||||
|
|
|
@ -85,7 +85,9 @@ if is_standalone():
|
|||
from gajim.common import app
|
||||
from gajim.common.const import JIDConstant, KindConstant
|
||||
from gajim.common import helpers
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import YesNoDialog
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import ConfirmationDialog
|
||||
from gajim.filechoosers import FileSaveDialog
|
||||
from gajim import gtkgui_helpers
|
||||
|
||||
|
@ -111,8 +113,8 @@ class HistoryManager:
|
|||
|
||||
log_db_path = configpaths.get('LOG_DB')
|
||||
if not os.path.exists(log_db_path):
|
||||
dialogs.ErrorDialog(_('Cannot find history logs database'),
|
||||
'%s does not exist.' % log_db_path)
|
||||
ErrorDialog(_('Cannot find history logs database'),
|
||||
'%s does not exist.' % log_db_path)
|
||||
sys.exit()
|
||||
|
||||
xml = gtkgui_helpers.get_gtk_builder('history_manager.ui')
|
||||
|
@ -250,7 +252,7 @@ class HistoryManager:
|
|||
if is_standalone():
|
||||
Gtk.main_quit()
|
||||
|
||||
dialog = dialogs.YesNoDialog(
|
||||
dialog = YesNoDialog(
|
||||
_('Do you want to clean up the database? '
|
||||
'(STRONGLY NOT RECOMMENDED IF GAJIM IS RUNNING)'),
|
||||
_('Normally allocated database size will not be freed, '
|
||||
|
@ -581,7 +583,7 @@ class HistoryManager:
|
|||
else:
|
||||
pri_text = _(
|
||||
'Do you wish to delete all correspondence with the selected contacts?')
|
||||
dialog = dialogs.ConfirmationDialog('',
|
||||
dialog = ConfirmationDialog('',
|
||||
_('This can not be undone.'), on_response_ok=(on_ok,
|
||||
liststore, list_of_paths))
|
||||
dialog.set_title(_('Deletion Confirmation'))
|
||||
|
@ -620,7 +622,7 @@ class HistoryManager:
|
|||
pri_text = i18n.ngettext(
|
||||
'Do you really want to delete the selected message?',
|
||||
'Do you really want to delete the selected messages?', paths_len)
|
||||
dialog = dialogs.ConfirmationDialog(pri_text,
|
||||
dialog = ConfirmationDialog(pri_text,
|
||||
_('This is an irreversible operation.'), on_response_ok=(on_ok,
|
||||
liststore, list_of_paths))
|
||||
dialog.set_title(_('Deletion Confirmation'))
|
||||
|
|
|
@ -35,7 +35,7 @@ from enum import IntEnum, unique
|
|||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import conversation_textview
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import ErrorDialog
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
|
@ -386,7 +386,7 @@ class HistoryWindow:
|
|||
log_days = app.logger.get_days_with_logs(
|
||||
self.account, self.jid, year, month)
|
||||
except exceptions.PysqliteOperationalError as e:
|
||||
dialogs.ErrorDialog(_('Disk Error'), str(e))
|
||||
ErrorDialog(_('Disk Error'), str(e))
|
||||
return
|
||||
|
||||
for date in log_days:
|
||||
|
@ -439,7 +439,7 @@ class HistoryWindow:
|
|||
logs = app.logger.get_date_has_logs(
|
||||
self.account, self.jid, _date)
|
||||
except exceptions.PysqliteOperationalError as e:
|
||||
dialogs.ErrorDialog(_('Disk Error'), str(e))
|
||||
ErrorDialog(_('Disk Error'), str(e))
|
||||
return
|
||||
|
||||
gtk_month = gtkgui_helpers.make_python_month_gtk_month(_date.month)
|
||||
|
|
|
@ -51,10 +51,12 @@ if __name__ == '__main__':
|
|||
from gajim.common import configpaths
|
||||
configpaths.init()
|
||||
from gajim.common import app
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim.gtkgui_helpers import get_icon_pixmap
|
||||
from gajim.gtk.util import load_icon
|
||||
from gajim.gtk.util import get_cursor
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.common import helpers
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import JoinGroupchatWindow
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('gajim.htmlview')
|
||||
|
@ -554,7 +556,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
if alt:
|
||||
alt += '\n'
|
||||
alt += _('Loading')
|
||||
pixbuf = get_icon_pixmap('gtk-no')
|
||||
pixbuf = load_icon('image-missing', self.textview, pixbuf=True)
|
||||
if mem:
|
||||
# Caveat: GdkPixbuf is known not to be safe to load
|
||||
# images from network... this program is now potentially
|
||||
|
@ -889,11 +891,11 @@ class HtmlTextView(Gtk.TextView):
|
|||
text = text[:47] + '…'
|
||||
tooltip.set_text(text)
|
||||
if not self._changed_cursor:
|
||||
window.set_cursor(gtkgui_helpers.get_cursor('HAND2'))
|
||||
window.set_cursor(get_cursor('HAND2'))
|
||||
self._changed_cursor = True
|
||||
return True
|
||||
if self._changed_cursor:
|
||||
window.set_cursor(gtkgui_helpers.get_cursor('XTERM'))
|
||||
window.set_cursor(get_cursor('XTERM'))
|
||||
self._changed_cursor = False
|
||||
return False
|
||||
|
||||
|
@ -908,14 +910,13 @@ class HtmlTextView(Gtk.TextView):
|
|||
# app.interface.new_chat_from_jid(self.account, jid)
|
||||
|
||||
def on_join_group_chat_menuitem_activate(self, widget, room_jid):
|
||||
dialogs.JoinGroupchatWindow(None, room_jid)
|
||||
JoinGroupchatWindow(None, room_jid)
|
||||
|
||||
def on_add_to_roster_activate(self, widget, jid):
|
||||
dialogs.AddNewContactWindow(self.account, jid)
|
||||
AddNewContactWindow(self.account, jid)
|
||||
|
||||
def make_link_menu(self, event, kind, text):
|
||||
from gajim.gtkgui_helpers import get_gtk_builder
|
||||
xml = get_gtk_builder('chat_context_menu.ui')
|
||||
xml = get_builder('chat_context_menu.ui')
|
||||
menu = xml.get_object('chat_context_menu')
|
||||
childs = menu.get_children()
|
||||
if kind == 'url':
|
||||
|
@ -1114,13 +1115,13 @@ if __name__ == '__main__':
|
|||
y = pointer[2]
|
||||
tags = htmlview.tv.get_iter_at_location(x, y)[1].get_tags()
|
||||
if change_cursor:
|
||||
w.set_cursor(gtkgui_helpers.get_cursor('XTERM'))
|
||||
w.set_cursor(get_cursor('XTERM'))
|
||||
change_cursor = None
|
||||
tag_table = htmlview.tv.get_buffer().get_tag_table()
|
||||
for tag in tags:
|
||||
try:
|
||||
if tag.is_anchor:
|
||||
w.set_cursor(gtkgui_helpers.get_cursor('HAND2'))
|
||||
w.set_cursor(get_cursor('HAND2'))
|
||||
change_cursor = tag
|
||||
elif tag == tag_table.lookup('focus-out-line'):
|
||||
over_line = True
|
||||
|
|
|
@ -37,7 +37,7 @@ from gi.repository import GLib
|
|||
from gajim import common
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import message_control
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import YesNoDialog
|
||||
from gajim.chat_control_base import ChatControlBase
|
||||
from gajim.chat_control import ChatControl
|
||||
from gajim.common import app
|
||||
|
@ -240,7 +240,7 @@ class MessageWindow(object):
|
|||
ctrl.minimize()
|
||||
# destroy window
|
||||
return False
|
||||
dialogs.YesNoDialog(
|
||||
YesNoDialog(
|
||||
_('You are going to close several tabs'),
|
||||
_('Do you really want to close them all?'),
|
||||
checktext=_('_Do not ask me again'), on_response_yes=on_yes1,
|
||||
|
|
|
@ -5,7 +5,7 @@ from gajim import gtkgui_helpers
|
|||
from gajim.common.const import OptionKind, OptionType
|
||||
from gajim.common.exceptions import GajimGeneralException
|
||||
from gajim import dialogs
|
||||
|
||||
from gajim.gtk import ErrorDialog
|
||||
|
||||
class OptionsDialog(Gtk.ApplicationWindow):
|
||||
def __init__(self, parent, title, flags, options, account,
|
||||
|
@ -558,7 +558,7 @@ class GPGOption(DialogOption):
|
|||
secret_keys[_('None')] = _('None')
|
||||
|
||||
if not secret_keys:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Failed to get secret keys'),
|
||||
_('There is no OpenPGP secret key available.'),
|
||||
transient_for=parent)
|
||||
|
|
|
@ -26,16 +26,16 @@ GUI classes related to plug-in management.
|
|||
|
||||
__all__ = ['PluginsWindow']
|
||||
|
||||
from gi.repository import Pango
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import GLib, Gdk
|
||||
from gi.repository import Gdk
|
||||
import os
|
||||
|
||||
from enum import IntEnum, unique
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim.dialogs import WarningDialog, YesNoDialog
|
||||
from gajim.gtk import WarningDialog
|
||||
from gajim.gtk import YesNoDialog
|
||||
from gajim.filechoosers import ArchiveChooserDialog
|
||||
from gajim.common import app
|
||||
from gajim.common import configpaths
|
||||
|
@ -44,6 +44,7 @@ from gajim.plugins.helpers import GajimPluginActivateException
|
|||
from gajim.plugins.plugins_i18n import _
|
||||
from gajim.common.exceptions import PluginsystemError
|
||||
|
||||
|
||||
@unique
|
||||
class Column(IntEnum):
|
||||
PLUGIN = 0
|
||||
|
|
|
@ -30,7 +30,8 @@ from gi.repository import Gdk
|
|||
from gi.repository import GLib
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import InformationDialog
|
||||
from gajim.filechoosers import AvatarChooserDialog
|
||||
from gajim.common.const import AvatarSize
|
||||
from gajim.common import app
|
||||
|
@ -127,7 +128,7 @@ class ProfileWindow(Gtk.ApplicationWindow):
|
|||
def on_ok(path_to_file):
|
||||
sha = app.interface.save_avatar(path_to_file, publish=True)
|
||||
if sha is None:
|
||||
dialogs.ErrorDialog(
|
||||
ErrorDialog(
|
||||
_('Could not load image'), transient_for=self)
|
||||
return
|
||||
|
||||
|
@ -181,7 +182,7 @@ class ProfileWindow(Gtk.ApplicationWindow):
|
|||
except ValueError:
|
||||
if not widget.is_focus():
|
||||
pritext = _('Wrong date format')
|
||||
dialogs.ErrorDialog(pritext, _('Format of the date must be '
|
||||
ErrorDialog(pritext, _('Format of the date must be '
|
||||
'YYYY-MM-DD'), transient_for=self)
|
||||
GLib.idle_add(lambda: widget.grab_focus())
|
||||
return True
|
||||
|
@ -321,7 +322,7 @@ class ProfileWindow(Gtk.ApplicationWindow):
|
|||
# Operation in progress
|
||||
return
|
||||
if app.connections[self.account].connected < 2:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection, you can not publish your contact '
|
||||
'information.'), transient_for=self)
|
||||
return
|
||||
|
@ -363,7 +364,7 @@ class ProfileWindow(Gtk.ApplicationWindow):
|
|||
GLib.source_remove(self.update_progressbar_timeout_id)
|
||||
self.progressbar.set_fraction(0)
|
||||
self.update_progressbar_timeout_id = None
|
||||
dialogs.InformationDialog(_('vCard publication failed'),
|
||||
InformationDialog(_('vCard publication failed'),
|
||||
_('There was an error while publishing your personal information, '
|
||||
'try again later.'), transient_for=self)
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import mimetypes
|
|||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.dialogs import AddNewContactWindow
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
from gajim.common import ged
|
||||
from gajim.common.connection_handlers_events import MessageOutgoingEvent
|
||||
from gajim.common.connection_handlers_events import GcMessageOutgoingEvent
|
||||
|
|
|
@ -58,6 +58,17 @@ from gajim import cell_renderer_image
|
|||
from gajim import tooltips
|
||||
from gajim import message_control
|
||||
from gajim import adhoc_commands
|
||||
from gajim.gtk import JoinGroupchatWindow
|
||||
from gajim.gtk import ConfirmationDialogCheck
|
||||
from gajim.gtk import ConfirmationDialog
|
||||
from gajim.gtk import ErrorDialog
|
||||
from gajim.gtk import InputDialog
|
||||
from gajim.gtk import WarningDialog
|
||||
from gajim.gtk import InformationDialog
|
||||
from gajim.gtk import NonModalConfirmationDialog
|
||||
from gajim.gtk import SingleMessageWindow
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
|
||||
from gajim.common.const import AvatarSize
|
||||
|
||||
from gajim.common import app
|
||||
|
@ -1952,7 +1963,7 @@ class RosterWindow:
|
|||
ft = app.interface.instances['file_transfers']
|
||||
event = app.events.get_first_event(account, jid, event.type_)
|
||||
if event.type_ == 'normal':
|
||||
dialogs.SingleMessageWindow(account, jid,
|
||||
SingleMessageWindow(account, jid,
|
||||
action='receive', from_whom=jid, subject=event.subject,
|
||||
message=event.message, resource=event.resource,
|
||||
session=event.session, form_node=event.form_node)
|
||||
|
@ -2025,7 +2036,7 @@ class RosterWindow:
|
|||
Authorize a contact (by re-sending auth menuitem)
|
||||
"""
|
||||
app.connections[account].send_authorization(jid)
|
||||
dialogs.InformationDialog(_('Authorization sent'),
|
||||
InformationDialog(_('Authorization sent'),
|
||||
_('"%s" will now see your status.') %jid)
|
||||
|
||||
def req_sub(self, widget, jid, txt, account, groups=None, nickname=None,
|
||||
|
@ -2049,7 +2060,7 @@ class RosterWindow:
|
|||
app.contacts.add_contact(account, contact)
|
||||
else:
|
||||
if not _('Not in Roster') in contact.get_shown_groups():
|
||||
dialogs.InformationDialog(_('Subscription request has been '
|
||||
InformationDialog(_('Subscription request has been '
|
||||
'sent'), _('If "%s" accepts this request you will know his '
|
||||
'or her status.') % jid)
|
||||
return
|
||||
|
@ -2064,7 +2075,7 @@ class RosterWindow:
|
|||
Revoke a contact's authorization
|
||||
"""
|
||||
app.connections[account].refuse_authorization(jid)
|
||||
dialogs.InformationDialog(_('Authorization removed'),
|
||||
InformationDialog(_('Authorization removed'),
|
||||
_('Now "%s" will always see you as offline.') %jid)
|
||||
|
||||
def set_state(self, account, state):
|
||||
|
@ -2089,7 +2100,7 @@ class RosterWindow:
|
|||
|
||||
keyid = app.config.get_per('accounts', account, 'keyid')
|
||||
if keyid and not app.connections[account].gpg:
|
||||
dialogs.WarningDialog(_('OpenPGP is not usable'),
|
||||
WarningDialog(_('OpenPGP is not usable'),
|
||||
_('Gajim needs python-gnupg >= 0.3.8\n'
|
||||
'Beware there is an incompatible Python package called gnupg.\n'
|
||||
'You will be connected to %s without OpenPGP.') % account)
|
||||
|
@ -2298,7 +2309,7 @@ class RosterWindow:
|
|||
self.get_status_message(status, on_response)
|
||||
|
||||
if status == 'invisible' and self.connected_rooms(account):
|
||||
dialogs.ConfirmationDialog(
|
||||
ConfirmationDialog(
|
||||
_('You are participating in one or more group chats'),
|
||||
_('Changing your status to invisible will result in '
|
||||
'disconnection from those group chats. Are you sure you want '
|
||||
|
@ -2398,7 +2409,7 @@ class RosterWindow:
|
|||
if checked:
|
||||
app.config.set('quit_on_roster_x_button', True)
|
||||
self.on_quit_request()
|
||||
dialogs.ConfirmationDialogCheck(_('Really quit Gajim?'),
|
||||
ConfirmationDialogCheck(_('Really quit Gajim?'),
|
||||
_('Are you sure you want to quit Gajim?'),
|
||||
_('Always close Gajim'), on_response_ok=on_ok)
|
||||
return True # do NOT destroy the window
|
||||
|
@ -2488,7 +2499,7 @@ class RosterWindow:
|
|||
break
|
||||
|
||||
if transfer_active:
|
||||
dialogs.ConfirmationDialog(_('You have running file transfers'),
|
||||
ConfirmationDialog(_('You have running file transfers'),
|
||||
_('If you quit now, the file(s) being transferred will '
|
||||
'be stopped. Do you still want to quit?'),
|
||||
on_response_ok=(on_continue3, message, pep_dict))
|
||||
|
@ -2520,7 +2531,7 @@ class RosterWindow:
|
|||
break
|
||||
|
||||
if unread or recent:
|
||||
dialogs.ConfirmationDialog(_('You have unread messages'),
|
||||
ConfirmationDialog(_('You have unread messages'),
|
||||
_('Messages will only be available for reading them later '
|
||||
'if you have history enabled and contact is in your '
|
||||
'roster.'), on_response_ok=(on_continue2,
|
||||
|
@ -2694,7 +2705,7 @@ class RosterWindow:
|
|||
return
|
||||
if obj.mtype == 'normal' and obj.popup:
|
||||
# it's single message to be autopopuped
|
||||
dialogs.SingleMessageWindow(obj.conn.name, obj.jid,
|
||||
SingleMessageWindow(obj.conn.name, obj.jid,
|
||||
action='receive', from_whom=obj.jid, subject=obj.subject,
|
||||
message=obj.msgtxt, resource=obj.resource, session=obj.session,
|
||||
form_node=obj.form_node)
|
||||
|
@ -2798,7 +2809,7 @@ class RosterWindow:
|
|||
has_unread_events = True
|
||||
break
|
||||
if has_unread_events:
|
||||
dialogs.ErrorDialog(_('You have unread messages'),
|
||||
ErrorDialog(_('You have unread messages'),
|
||||
_('You must read them before removing this transport.'))
|
||||
return
|
||||
if len(list_) == 1:
|
||||
|
@ -2813,7 +2824,7 @@ class RosterWindow:
|
|||
jids = jids[:-1] + '.'
|
||||
sectext = _('You will no longer be able to send and receive '
|
||||
'messages to contacts from these transports: %s') % jids
|
||||
dialogs.ConfirmationDialog(pritext, sectext,
|
||||
ConfirmationDialog(pritext, sectext,
|
||||
on_response_ok = (remove, list_), transient_for=self.window)
|
||||
|
||||
def _nec_blocking(self, obj):
|
||||
|
@ -2864,7 +2875,7 @@ class RosterWindow:
|
|||
' to continue?')
|
||||
sectext = _('This contact will see you offline and you will not '
|
||||
'receive messages it sends you.')
|
||||
dialogs.ConfirmationDialogCheck(pritext, sectext,
|
||||
ConfirmationDialogCheck(pritext, sectext,
|
||||
_('_Do not ask me again'), on_response_ok=_block_it)
|
||||
|
||||
def on_unblock(self, widget, list_, group=None):
|
||||
|
@ -2943,7 +2954,7 @@ class RosterWindow:
|
|||
if 'rename' in app.interface.instances:
|
||||
del app.interface.instances['rename']
|
||||
|
||||
app.interface.instances['rename'] = dialogs.InputDialog(title,
|
||||
app.interface.instances['rename'] = InputDialog(title,
|
||||
message, old_text, False, (on_renamed, account, row_type, jid,
|
||||
old_text), on_canceled, transient_for=self.window)
|
||||
|
||||
|
@ -2958,7 +2969,7 @@ class RosterWindow:
|
|||
app.connections[account].unsubscribe(contact.jid)
|
||||
self.remove_contact(contact.jid, account, backend=True)
|
||||
|
||||
dialogs.ConfirmationDialogCheck(_('Remove Group'),
|
||||
ConfirmationDialogCheck(_('Remove Group'),
|
||||
_('Do you want to remove group %s from the roster?') % group,
|
||||
_('Also remove all contacts in this group from your roster'),
|
||||
on_response_ok=on_ok)
|
||||
|
@ -3039,14 +3050,14 @@ class RosterWindow:
|
|||
def on_send_single_message_menuitem_activate(self, widget, account,
|
||||
contact=None):
|
||||
if contact is None:
|
||||
dialogs.SingleMessageWindow(account, action='send')
|
||||
SingleMessageWindow(account, action='send')
|
||||
elif isinstance(contact, list):
|
||||
dialogs.SingleMessageWindow(account, contact, 'send')
|
||||
SingleMessageWindow(account, contact, 'send')
|
||||
else:
|
||||
jid = contact.jid
|
||||
if contact.jid == app.get_jid_from_account(account):
|
||||
jid += '/' + contact.resource
|
||||
dialogs.SingleMessageWindow(account, jid, 'send')
|
||||
SingleMessageWindow(account, jid, 'send')
|
||||
|
||||
def on_send_file_menuitem_activate(self, widget, contact, account,
|
||||
resource=None):
|
||||
|
@ -3077,7 +3088,7 @@ class RosterWindow:
|
|||
app.interface.instances[account]['join_gc'].destroy()
|
||||
else:
|
||||
app.interface.instances[account]['join_gc'] = \
|
||||
dialogs.JoinGroupchatWindow(
|
||||
JoinGroupchatWindow(
|
||||
account, None, automatic={'invities': jid_list})
|
||||
break
|
||||
|
||||
|
@ -3147,7 +3158,7 @@ class RosterWindow:
|
|||
dialogs.ChangeStatusMessageDialog(on_response, show)
|
||||
|
||||
def on_add_to_roster(self, widget, contact, account):
|
||||
dialogs.AddNewContactWindow(account, contact.jid, contact.name)
|
||||
AddNewContactWindow(account, contact.jid, contact.name)
|
||||
|
||||
def on_roster_treeview_key_press_event(self, widget, event):
|
||||
"""
|
||||
|
@ -3410,17 +3421,17 @@ class RosterWindow:
|
|||
'your roster.\n') % {'name': contact.get_shown_name(),
|
||||
'jid': contact.jid}
|
||||
if contact.sub == 'to':
|
||||
dialogs.ConfirmationDialog(pritext, sectext + \
|
||||
ConfirmationDialog(pritext, sectext + \
|
||||
_('By removing this contact you also remove authorization '
|
||||
'resulting in them always seeing you as offline.'),
|
||||
on_response_ok=(on_ok2, list_))
|
||||
elif _('Not in Roster') in contact.get_shown_groups():
|
||||
# Contact is not in roster
|
||||
dialogs.ConfirmationDialog(pritext, sectext + \
|
||||
ConfirmationDialog(pritext, sectext + \
|
||||
_('Do you want to continue?'), on_response_ok=(on_ok2,
|
||||
list_))
|
||||
else:
|
||||
dialogs.ConfirmationDialogCheck(pritext, sectext + \
|
||||
ConfirmationDialogCheck(pritext, sectext + \
|
||||
_('By removing this contact you also by default remove '
|
||||
'authorization resulting in them always seeing you as'
|
||||
' offline.'),
|
||||
|
@ -3436,7 +3447,7 @@ class RosterWindow:
|
|||
sectext = _('By removing these contacts:%s\nyou also remove '
|
||||
'authorization resulting in them always seeing you as '
|
||||
'offline.') % jids
|
||||
dialogs.ConfirmationDialog(pritext, sectext,
|
||||
ConfirmationDialog(pritext, sectext,
|
||||
on_response_ok=(on_ok2, list_))
|
||||
|
||||
def on_send_custom_status(self, widget, contact_list, show, group=None):
|
||||
|
@ -3497,7 +3508,7 @@ class RosterWindow:
|
|||
sectext = _('This contact will temporarily see you as %(status)s, '
|
||||
'but only until you change your status. Then they will see '
|
||||
'your global status.') % {'status': show}
|
||||
dialogs.ConfirmationDialogCheck(pritext, sectext,
|
||||
ConfirmationDialogCheck(pritext, sectext,
|
||||
_('_Do not ask me again'), on_response_ok=send_it)
|
||||
|
||||
def on_status_combobox_changed(self, widget):
|
||||
|
@ -3513,7 +3524,7 @@ class RosterWindow:
|
|||
return
|
||||
accounts = list(app.connections.keys())
|
||||
if len(accounts) == 0:
|
||||
dialogs.ErrorDialog(_('No account available'),
|
||||
ErrorDialog(_('No account available'),
|
||||
_('You must create an account before you can chat with other '
|
||||
'contacts.'))
|
||||
self.update_status_combobox()
|
||||
|
@ -3593,7 +3604,7 @@ class RosterWindow:
|
|||
def on_cancel():
|
||||
self.update_status_combobox()
|
||||
|
||||
dialogs.ConfirmationDialog(
|
||||
ConfirmationDialog(
|
||||
_('You are participating in one or more group chats'),
|
||||
_('Changing your status to invisible will result in '
|
||||
'disconnection from those group chats. Are you sure you '
|
||||
|
@ -3637,7 +3648,7 @@ class RosterWindow:
|
|||
config.ManagePEPServicesWindow(account)
|
||||
|
||||
def on_add_new_contact(self, widget, account):
|
||||
dialogs.AddNewContactWindow(account)
|
||||
AddNewContactWindow(account)
|
||||
|
||||
def on_join_gc_activate(self, widget, account):
|
||||
"""
|
||||
|
@ -4140,7 +4151,7 @@ class RosterWindow:
|
|||
|
||||
if not app.connections[account_source].private_storage_supported or \
|
||||
not app.connections[account_dest].private_storage_supported:
|
||||
dialogs.WarningDialog(_('Metacontacts storage not supported by '
|
||||
WarningDialog(_('Metacontacts storage not supported by '
|
||||
'your server'),
|
||||
_('Your server does not support storing metacontacts '
|
||||
'information. So this information will not be saved on next '
|
||||
|
@ -4243,7 +4254,7 @@ class RosterWindow:
|
|||
sectext = _('Metacontacts are a way to regroup several contacts in one '
|
||||
'line. Generally it is used when the same person has several '
|
||||
'XMPP- or transport -accounts.')
|
||||
dlg = dialogs.ConfirmationDialogCheck(pritext, sectext,
|
||||
dlg = ConfirmationDialogCheck(pritext, sectext,
|
||||
_('_Do not ask me again'), on_response_ok=merge_contacts)
|
||||
if not confirm_metacontacts: # First time we see this window
|
||||
dlg.checkbutton.set_active(True)
|
||||
|
@ -4362,7 +4373,7 @@ class RosterWindow:
|
|||
if not os.path.isfile(path):
|
||||
bad_uris.append(a_uri)
|
||||
if len(bad_uris):
|
||||
dialogs.ErrorDialog(_('Invalid file URI:'), '\n'.join(bad_uris))
|
||||
ErrorDialog(_('Invalid file URI:'), '\n'.join(bad_uris))
|
||||
return
|
||||
def _on_send_files(account, jid, uris):
|
||||
c = app.contacts.get_contact_with_highest_priority(account,
|
||||
|
@ -4380,7 +4391,7 @@ class RosterWindow:
|
|||
for uri in uri_splitted:
|
||||
path = helpers.get_file_path_from_dnd_dropped_uri(uri)
|
||||
sec_text += '\n' + os.path.basename(path)
|
||||
dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text,
|
||||
dialog = NonModalConfirmationDialog(prim_text, sec_text,
|
||||
on_response_ok=(_on_send_files, account_dest, jid_dest,
|
||||
uri_splitted))
|
||||
dialog.popup()
|
||||
|
@ -4475,7 +4486,7 @@ class RosterWindow:
|
|||
if (type_dest == 'account' or not self.regroup) and \
|
||||
account_source != account_dest:
|
||||
# add to account in specified group
|
||||
dialogs.AddNewContactWindow(account=account_dest, jid=jid_source,
|
||||
AddNewContactWindow(account=account_dest, jid=jid_source,
|
||||
user_nick=c_source.name, group=grp_dest)
|
||||
return
|
||||
|
||||
|
|
|
@ -28,10 +28,11 @@ from gajim.common import dataforms
|
|||
from gajim.common import ged
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import dialogs
|
||||
from gajim import vcard
|
||||
from gajim import config
|
||||
from gajim import dataforms_widget
|
||||
from gajim.gtk import AddNewContactWindow
|
||||
|
||||
|
||||
class SearchWindow:
|
||||
def __init__(self, account, jid):
|
||||
|
@ -116,7 +117,7 @@ class SearchWindow:
|
|||
if not iter_:
|
||||
return
|
||||
jid = model[iter_][self.jid_column]
|
||||
dialogs.AddNewContactWindow(self.account, jid)
|
||||
AddNewContactWindow(self.account, jid)
|
||||
|
||||
def on_information_button_clicked(self, widget):
|
||||
(model, iter_) = self.result_treeview.get_selection().get_selected()
|
||||
|
|
|
@ -35,7 +35,7 @@ from gajim.common.connection_handlers_events import ChatstateReceivedEvent, \
|
|||
from gajim.common.const import KindConstant
|
||||
from gajim import message_control
|
||||
from gajim import notify
|
||||
from gajim import dialogs
|
||||
from gajim.gtk import SingleMessageWindow
|
||||
|
||||
|
||||
class ChatControlSession(object):
|
||||
|
@ -358,7 +358,7 @@ class ChatControlSession(object):
|
|||
popup = helpers.allow_popup_window(self.conn.name)
|
||||
|
||||
if msg_type == 'normal' and popup: # it's single message to be autopopuped
|
||||
dialogs.SingleMessageWindow(self.conn.name, contact.jid,
|
||||
SingleMessageWindow(self.conn.name, contact.jid,
|
||||
action='receive', from_whom=jid, subject=subject, message=msg,
|
||||
resource=resource, session=self, form_node=form_node)
|
||||
return
|
||||
|
|
|
@ -34,6 +34,8 @@ from gajim import tooltips
|
|||
from gajim import gtkgui_helpers
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.gtk import SingleMessageWindow
|
||||
|
||||
|
||||
class StatusIcon:
|
||||
"""
|
||||
|
@ -163,7 +165,7 @@ class StatusIcon:
|
|||
jid, account)
|
||||
|
||||
def on_single_message_menuitem_activate(self, widget, account):
|
||||
dialogs.SingleMessageWindow(account, action='send')
|
||||
SingleMessageWindow(account, action='send')
|
||||
|
||||
def on_new_chat(self, widget, account):
|
||||
app.app.activate_action('start-chat')
|
||||
|
|
Loading…
Reference in New Issue